From f04b1ce2619cef6f07c4f984eda2136f1b72f137 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Sat, 24 Jun 2006 21:41:54 +0000 Subject: [PATCH] DEVEL15-windows-largefile-support-20060623 This patch adds large file support (> 2GB) to the CIFS server and the cache manager. It also corrects a significant oversight where the definition of struct rx_call was inconsistent due to a failure to define AFS_PTHREAD_ENV prior to including rx.h in all source files. This prevented all errors during rx_Read and rx_Write to be ignored. (cherry picked from commit 015f9ce287c22df7a0b967ee0357d0816b4e0e54) --- src/WINNT/afsd/NTMakefile | 1 + src/WINNT/afsd/cm.h | 3 + src/WINNT/afsd/cm_callback.c | 7 +- src/WINNT/afsd/cm_conn.c | 2 +- src/WINNT/afsd/cm_conn.h | 3 + src/WINNT/afsd/cm_daemon.c | 3 +- src/WINNT/afsd/cm_dcache.c | 276 +++++++++++++++++++++++++++++----- src/WINNT/afsd/cm_dir.c | 2 +- src/WINNT/afsd/cm_freelance.c | 4 +- src/WINNT/afsd/cm_scache.c | 6 +- src/WINNT/afsd/cm_scache.h | 6 +- src/WINNT/afsd/cm_server.c | 12 +- src/WINNT/afsd/cm_server.h | 4 + src/WINNT/afsd/cm_user.c | 2 +- src/WINNT/afsd/cm_utils.c | 2 +- src/WINNT/afsd/cm_vnodeops.c | 14 +- src/WINNT/afsd/cm_volume.c | 3 +- src/WINNT/afsd/smb.c | 111 +++++++++++--- src/WINNT/afsd/smb.h | 7 +- src/WINNT/afsd/smb3.c | 161 +++++++++++++++++++- src/WINNT/afsd/smb3.h | 2 + src/WINNT/afsd/smb_ioctl.c | 45 ++++++ src/WINNT/afsd/smb_ioctl.h | 2 + src/libafsrpc/afsrpc.def | 3 +- 24 files changed, 588 insertions(+), 93 deletions(-) diff --git a/src/WINNT/afsd/NTMakefile b/src/WINNT/afsd/NTMakefile index 198f97012..07ac2224c 100644 --- a/src/WINNT/afsd/NTMakefile +++ b/src/WINNT/afsd/NTMakefile @@ -404,6 +404,7 @@ AFSD_EXELIBS =\ $(DESTDIR)\lib\libafsconf.lib \ $(DESTDIR)\lib\afs\afsreg.lib \ $(DESTDIR)\lib\afs\afsutil.lib \ + $(DESTDIR)\lib\afspthread.lib \ $(LANAHELPERLIB) $(AFSD_EXEFILE): $(OUT)\afsd.obj $(AFSDOBJS) $(OUT)\afsd.res $(RXOBJS) $(AFSD_EXELIBS) diff --git a/src/WINNT/afsd/cm.h b/src/WINNT/afsd/cm.h index ca5225214..cbdd16914 100644 --- a/src/WINNT/afsd/cm.h +++ b/src/WINNT/afsd/cm.h @@ -10,6 +10,9 @@ #ifndef __CM_H_ENV__ #define __CM_H_ENV__ 1 +#ifndef AFS_PTHREAD_ENV +#define AFS_PTHREAD_ENV 1 +#endif #include #ifdef DJGPP /* we need these for vldbentry decl., etc. */ #include diff --git a/src/WINNT/afsd/cm_callback.c b/src/WINNT/afsd/cm_callback.c index b282aaad7..1cf64948a 100644 --- a/src/WINNT/afsd/cm_callback.c +++ b/src/WINNT/afsd/cm_callback.c @@ -21,10 +21,10 @@ #include #include +#include "afsd.h" #include #include -#include "afsd.h" #include #include #include <../afsrdr/kif.h> @@ -475,6 +475,9 @@ SRXAFSCB_InitCallBackState(struct rx_call *callp) lock_ReleaseWrite(&cm_scacheLock); + /* reset the No 64-bit flag on the server */ + cm_SetServerNo64Bit(tsp, 0); + /* we're done with the server structure */ if (tsp) cm_PutServer(tsp); @@ -829,7 +832,7 @@ SRXAFSCB_GetCE64(struct rx_call *callp, long index, AFSDBCacheEntry64 *cep) cep->Length.high = scp->length.HighPart; cep->Length.low = scp->length.LowPart; #else - cep->Length = ((afs_int64)scp->length.HighPart)<<32 | scp->length.LowPart; + cep->Length = (afs_int64) scp->length.QuadPart; #endif cep->DataVersion = scp->dataVersion; cep->callback = afs_data_pointer_to_int32(scp->cbServerp); diff --git a/src/WINNT/afsd/cm_conn.c b/src/WINNT/afsd/cm_conn.c index e52d0b5f2..57563e8d3 100644 --- a/src/WINNT/afsd/cm_conn.c +++ b/src/WINNT/afsd/cm_conn.c @@ -16,10 +16,10 @@ #include #include #include +#include "afsd.h" #include #include #include -#include "afsd.h" osi_rwlock_t cm_connLock; diff --git a/src/WINNT/afsd/cm_conn.h b/src/WINNT/afsd/cm_conn.h index bf97f82a6..9d65a69c8 100644 --- a/src/WINNT/afsd/cm_conn.h +++ b/src/WINNT/afsd/cm_conn.h @@ -91,6 +91,9 @@ typedef struct cm_req { cache managers treat it as "server is down"*/ #include "cm_server.h" +#ifndef AFS_PTHREAD_ENV +#define AFS_PTHREAD_ENV 1 +#endif #include "rx.h" extern void cm_InitConn(void); diff --git a/src/WINNT/afsd/cm_daemon.c b/src/WINNT/afsd/cm_daemon.c index ac210e198..7c8d47e51 100644 --- a/src/WINNT/afsd/cm_daemon.c +++ b/src/WINNT/afsd/cm_daemon.c @@ -21,11 +21,12 @@ #include #include +#include "afsd.h" + #include #include #include -#include "afsd.h" #include "afsicf.h" /* in seconds */ diff --git a/src/WINNT/afsd/cm_dcache.c b/src/WINNT/afsd/cm_dcache.c index c1221fbbd..cc548fd2b 100644 --- a/src/WINNT/afsd/cm_dcache.c +++ b/src/WINNT/afsd/cm_dcache.c @@ -33,6 +33,16 @@ osi_mutex_t cm_bufGetMutex; extern osi_mutex_t cm_Freelance_Lock; #endif +#ifdef AFS_LARGEFILES +/* we can access connp->serverp without holding a lock because that + never changes since the connection is made. */ +#define SERVERHAS64BIT(connp) (!((connp)->serverp->flags & CM_SERVERFLAG_NO64BIT)) +#define SET_SERVERHASNO64BIT(connp) (cm_SetServerNo64Bit((connp)->serverp, TRUE)) +#else +#define SERVERHAS64BIT(connp) (FALSE) +#define SET_SERVERHASNO64BIT(connp) (FALSE) +#endif + /* functions called back from the buffer package when reading or writing data, * or when holding or releasing a vnode pointer. */ @@ -62,8 +72,9 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, long wbytes; char *bufferp; cm_conn_t *connp; - long truncPos; + osi_hyper_t truncPos; cm_bulkIO_t biod; /* bulk IO descriptor */ + int require_64bit_ops = 0; osi_assert(userp != NULL); @@ -78,7 +89,7 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, cm_AFSFidFromFid(&tfid, fidp); lock_ObtainMutex(&scp->mx); - + code = cm_SetupStoreBIOD(scp, offsetp, length, &biod, userp, reqp); if (code) { osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code); @@ -93,7 +104,7 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, cm_ReleaseBIOD(&biod, 1); /* should be a NOOP */ cm_ReleaseSCache(scp); return 0; - } + } /* Serialize StoreData RPC's; for rationale see cm_scache.c */ (void) cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA_EXCL); @@ -101,10 +112,10 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, /* prepare the output status for the store */ scp->mask |= CM_SCACHEMASK_CLIENTMODTIME; cm_StatusFromAttr(&inStatus, scp, NULL); - truncPos = scp->length.LowPart; + truncPos = scp->length; if ((scp->mask & CM_SCACHEMASK_TRUNCPOS) - && scp->truncPos.LowPart < (unsigned long) truncPos) - truncPos = scp->truncPos.LowPart; + && LargeIntegerLessThan(scp->truncPos, truncPos)) + truncPos = scp->truncPos; scp->mask &= ~CM_SCACHEMASK_TRUNCPOS; /* compute how many bytes to write from this buffer */ @@ -117,28 +128,66 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, /* otherwise write out part of buffer before EOF, but not * more than bufferSize bytes. */ - nbytes = thyper.LowPart; - if (nbytes > biod.length) + if (LargeIntegerGreaterThan(thyper, + ConvertLongToLargeInteger(biod.length))) { nbytes = biod.length; + } else { + /* if thyper is less than or equal to biod.length, then we + can safely assume that the value fits in a long. */ + nbytes = thyper.LowPart; + } } - lock_ReleaseMutex(&scp->mx); + if (LargeIntegerGreaterThan(LargeIntegerAdd(biod.offset, + ConvertLongToLargeInteger(nbytes)), + ConvertLongToLargeInteger(LONG_MAX)) || + LargeIntegerGreaterThan(truncPos, + ConvertLongToLargeInteger(LONG_MAX))) { + require_64bit_ops = 1; + } + lock_ReleaseMutex(&scp->mx); + /* now we're ready to do the store operation */ do { code = cm_Conn(&scp->fid, userp, reqp, &connp); if (code) continue; - + + retry: rxconnp = cm_GetRxConn(connp); callp = rx_NewCall(rxconnp); rx_PutConnection(rxconnp); +#ifdef AFS_LARGEFILES + if (SERVERHAS64BIT(connp)) { + osi_Log4(afsd_logp, "CALL StoreData64 scp 0x%p, offset 0x%x:%08x, length 0x%x", + scp, biod.offset.HighPart, biod.offset.LowPart, nbytes); + + code = StartRXAFS_StoreData64(callp, &tfid, &inStatus, + biod.offset.QuadPart, + nbytes, + truncPos.QuadPart); + } else { + + if (require_64bit_ops) { + osi_Log0(afsd_logp, "Skipping StoreData. The operation requires StoreData64"); + code = CM_ERROR_TOOBIG; + } else { + osi_Log4(afsd_logp, "CALL StoreData scp 0x%p, offset 0x%x:%08x, length 0x%x", + scp, biod.offset.HighPart, biod.offset.LowPart, nbytes); + + code = StartRXAFS_StoreData(callp, &tfid, &inStatus, + biod.offset.LowPart, nbytes, truncPos.LowPart); + } + } +#else osi_Log4(afsd_logp, "CALL StoreData scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, biod.offset.HighPart, biod.offset.LowPart, nbytes); code = StartRXAFS_StoreData(callp, &tfid, &inStatus, - biod.offset.LowPart, nbytes, truncPos); + biod.offset.LowPart, nbytes, truncPos.LowPart); +#endif if (code == 0) { /* write the data from the the list of buffers */ @@ -168,18 +217,34 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, } /* while more bytes to write */ } /* if RPC started successfully */ else { - osi_Log2(afsd_logp, "StartRXAFS_StoreData scp 0x%p failed (%lX)",scp,code); + osi_Log2(afsd_logp, "StartRXAFS_StoreData?? scp 0x%p failed (%lX)",scp,code); } + if (code == 0) { - code = EndRXAFS_StoreData(callp, &outStatus, &volSync); - if (code) - osi_Log2(afsd_logp, "EndRXAFS_StoreData scp 0x%p failed (%lX)",scp,code); + if (SERVERHAS64BIT(connp)) { + code = EndRXAFS_StoreData64(callp, &outStatus, &volSync); + if (code) + osi_Log2(afsd_logp, "EndRXAFS_StoreData64 scp 0x%p failed (%lX)", scp, code); + } else { + code = EndRXAFS_StoreData(callp, &outStatus, &volSync); + if (code) + osi_Log2(afsd_logp, "EndRXAFS_StoreData scp 0x%p failed (%lX)",scp,code); + } } + code = rx_EndCall(callp, code); + +#ifdef AFS_LARGEFILES + if (code == RXGEN_OPCODE && SERVERHAS64BIT(connp)) { + SET_SERVERHASNO64BIT(connp); + goto retry; + } +#endif } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code)); + code = cm_MapRPCError(code, reqp); - + if (code) osi_Log2(afsd_logp, "CALL StoreData FAILURE scp 0x%p, code 0x%x", scp, code); else @@ -191,6 +256,7 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL); if (code == 0) { + osi_hyper_t t; /* now, here's something a little tricky: in AFS 3, a dirty * length can't be directly stored, instead, a dirty chunk is * stored that sets the file's size (by writing and by using @@ -209,8 +275,17 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags, * We have to turn off the length dirty bit as soon as we can, * so that we see updates made by other machines. */ - if (outStatus.Length >= scp->length.LowPart) + + if (SERVERHAS64BIT(connp)) { + t.LowPart = outStatus.Length; + t.HighPart = outStatus.Length_hi; + } else { + t = ConvertLongToLargeInteger(outStatus.Length); + } + + if (LargeIntegerGreaterThanOrEqualTo(t, scp->length)) scp->mask &= ~CM_SCACHEMASK_LENGTH; + cm_MergeStatus(scp, &outStatus, &volSync, userp, 0); } else { if (code == CM_ERROR_SPACE) @@ -237,10 +312,11 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp) AFSVolSync volSync; AFSFid tfid; long code; - long truncPos; + osi_hyper_t truncPos; cm_conn_t *connp; struct rx_call *callp; struct rx_connection *rxconnp; + int require_64bit_ops = 0; /* Serialize StoreData RPC's; for rationale see cm_scache.c */ (void) cm_SyncOp(scp, NULL, userp, reqp, 0, @@ -252,12 +328,18 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp) scp->mask &= ~CM_SCACHEMASK_CLIENTMODTIME; /* calculate truncation position */ - truncPos = scp->length.LowPart; + truncPos = scp->length; if ((scp->mask & CM_SCACHEMASK_TRUNCPOS) - && scp->truncPos.LowPart < (unsigned long) truncPos) - truncPos = scp->truncPos.LowPart; + && LargeIntegerLessThan(scp->truncPos, truncPos)) + truncPos = scp->truncPos; scp->mask &= ~CM_SCACHEMASK_TRUNCPOS; + if (LargeIntegerGreaterThan(truncPos, + ConvertLongToLargeInteger(LONG_MAX))) { + + require_64bit_ops = 1; + } + lock_ReleaseMutex(&scp->mx); cm_AFSFidFromFid(&tfid, &scp->fid); @@ -267,18 +349,44 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp) code = cm_Conn(&scp->fid, userp, reqp, &connp); if (code) continue; - + + retry: rxconnp = cm_GetRxConn(connp); callp = rx_NewCall(rxconnp); rx_PutConnection(rxconnp); +#ifdef AFS_LARGEFILES + if (SERVERHAS64BIT(connp)) { + code = StartRXAFS_StoreData64(callp, &tfid, &inStatus, + 0, 0, truncPos.QuadPart); + } else { + if (require_64bit_ops) { + code = CM_ERROR_TOOBIG; + } else { + code = StartRXAFS_StoreData(callp, &tfid, &inStatus, + 0, 0, truncPos.LowPart); + } + } +#else code = StartRXAFS_StoreData(callp, &tfid, &inStatus, - 0, 0, truncPos); + 0, 0, truncPos.LowPart); +#endif - if (code == 0) - code = EndRXAFS_StoreData(callp, &outStatus, &volSync); + if (code == 0) { + if (SERVERHAS64BIT(connp)) + code = EndRXAFS_StoreData64(callp, &outStatus, &volSync); + else + code = EndRXAFS_StoreData(callp, &outStatus, &volSync); + } code = rx_EndCall(callp, code); +#ifdef AFS_LARGEFILES + if (code == RXGEN_OPCODE && SERVERHAS64BIT(connp)) { + SET_SERVERHASNO64BIT(connp); + goto retry; + } +#endif + } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code)); code = cm_MapRPCError(code, reqp); @@ -288,11 +396,19 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp) cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL); if (code == 0) { + osi_hyper_t t; /* * For explanation of handling of CM_SCACHEMASK_LENGTH, * see cm_BufWrite(). */ - if (outStatus.Length >= scp->length.LowPart) + if (SERVERHAS64BIT(connp)) { + t.HighPart = outStatus.Length_hi; + t.LowPart = outStatus.Length; + } else { + t = ConvertLongToLargeInteger(outStatus.Length); + } + + if (LargeIntegerGreaterThanOrEqualTo(t, scp->length)) scp->mask &= ~CM_SCACHEMASK_LENGTH; cm_MergeStatus(scp, &outStatus, &volSync, userp, 0); } @@ -1117,7 +1233,9 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up, cm_req_t *reqp) { long code; - long nbytes; /* bytes in transfer */ + afs_int32 nbytes; /* bytes in transfer */ + afs_int32 nbytes_hi = 0; /* high-order 32 bits of bytes in transfer */ + afs_int64 length_found = 0; long rbytes; /* bytes in rx_Read call */ long temp; AFSFetchStatus afsStatus; @@ -1133,6 +1251,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up, cm_conn_t *connp; int getroot; long t1, t2; + int require_64bit_ops = 0; /* now, the buffer may or may not be filled with good data (buf_GetNew * drops lots of locks, and may indeed return a properly initialized @@ -1182,9 +1301,15 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up, lock_ObtainMutex(&scp->mx); return 0; } - + lock_ReleaseMutex(&scp->mx); + if (LargeIntegerGreaterThan(LargeIntegerAdd(biod.offset, + ConvertLongToLargeInteger(biod.length)), + ConvertLongToLargeInteger(LONG_MAX))) { + require_64bit_ops = 1; + } + #ifdef DISKCACHE95 DPRINTF("cm_GetBuffer: fetching data scpDV=%d bufDV=%d scp=%x bp=%x dcp=%x\n", scp->dataVersion, bufp->dataVersion, scp, bufp, bufp->dcp); @@ -1259,11 +1384,68 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up, code = cm_Conn(&scp->fid, up, reqp, &connp); if (code) continue; - + rxconnp = cm_GetRxConn(connp); callp = rx_NewCall(rxconnp); rx_PutConnection(rxconnp); +#ifdef AFS_LARGEFILES + nbytes = nbytes_hi = 0; + + if (SERVERHAS64BIT(connp)) { + osi_Log4(afsd_logp, "CALL FetchData64 scp 0x%p, off 0x%x:%08x, size 0x%x", + scp, biod.offset.HighPart, biod.offset.LowPart, biod.length); + + code = StartRXAFS_FetchData64(callp, &tfid, biod.offset.QuadPart, biod.length); + + if (code == 0) { + temp = rx_Read(callp, (char *) &nbytes_hi, sizeof(afs_int32)); + if (temp == sizeof(afs_int32)) { + nbytes_hi = ntohl(nbytes_hi); + } else { + nbytes_hi = 0; + code = callp->error; + rx_EndCall(callp, code); + callp = NULL; + } + } + } + + if (code == RXGEN_OPCODE || !SERVERHAS64BIT(connp)) { + if (require_64bit_ops) { + osi_Log0(afsd_logp, "Skipping FetchData. Operation requires FetchData64"); + code = CM_ERROR_TOOBIG; + } else { + if (!callp) { + rxconnp = cm_GetRxConn(connp); + callp = rx_NewCall(rxconnp); + rx_PutConnection(rxconnp); + } + + osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x", + scp, biod.offset.LowPart, biod.length); + + code = StartRXAFS_FetchData(callp, &tfid, biod.offset.LowPart, + biod.length); + + SET_SERVERHASNO64BIT(connp); + } + } + + if (code == 0) { + temp = rx_Read(callp, (char *)&nbytes, sizeof(afs_int32)); + if (temp == sizeof(afs_int32)) { + nbytes = ntohl(nbytes); + FillInt64(length_found, nbytes_hi, nbytes); + if (length_found > biod.length) + code = (callp->error < 0) ? callp->error : -1; + } else { + code = (callp->error < 0) ? callp->error : -1; + } + } + /* for the moment, nbytes_hi will always be 0 if code == 0 + because biod.length is a 32-bit quantity. */ +#else osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x", scp, biod.offset.LowPart, biod.length); @@ -1271,14 +1453,17 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up, biod.length); /* now copy the data out of the pipe and put it in the buffer */ - temp = rx_Read(callp, (char *)&nbytes, 4); - if (temp == 4) { - nbytes = ntohl(nbytes); - if (nbytes > biod.length) + if (code == 0) { + temp = rx_Read(callp, (char *)&nbytes, sizeof(afs_int32)); + if (temp == sizeof(afs_int32)) { + nbytes = ntohl(nbytes); + if (nbytes > biod.length) + code = (callp->error < 0) ? callp->error : -1; + } + else code = (callp->error < 0) ? callp->error : -1; } - else - code = (callp->error < 0) ? callp->error : -1; +#endif if (code == 0) { qdp = biod.bufListEndp; @@ -1368,13 +1553,24 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up, } } - if (code == 0) - code = EndRXAFS_FetchData(callp, &afsStatus, &callback, &volSync); - else - osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error %d", code); - code = rx_EndCall(callp, code); + if (code == 0) { + if (SERVERHAS64BIT(connp)) + code = EndRXAFS_FetchData64(callp, &afsStatus, &callback, &volSync); + else + code = EndRXAFS_FetchData(callp, &afsStatus, &callback, &volSync); + } else { + if (SERVERHAS64BIT(connp)) + osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData64 skipped due to error %d", code); + else + osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error %d", code); + } + + if (callp) + code = rx_EndCall(callp, code); + if (code == RXKADUNKNOWNKEY) osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY"); + osi_Log0(afsd_logp, "CALL FetchData DONE"); } while (cm_Analyze(connp, up, reqp, &scp->fid, &volSync, NULL, NULL, code)); diff --git a/src/WINNT/afsd/cm_dir.c b/src/WINNT/afsd/cm_dir.c index a57047909..3e0dbfee9 100644 --- a/src/WINNT/afsd/cm_dir.c +++ b/src/WINNT/afsd/cm_dir.c @@ -16,9 +16,9 @@ #include #include #include +#include "afsd.h" #include -#include "afsd.h" /* compute how many 32 byte entries an AFS 3 dir requires for storing * the specified name. diff --git a/src/WINNT/afsd/cm_freelance.c b/src/WINNT/afsd/cm_freelance.c index df775f6a1..a875e57c2 100644 --- a/src/WINNT/afsd/cm_freelance.c +++ b/src/WINNT/afsd/cm_freelance.c @@ -12,10 +12,10 @@ #include #include -#include - #include #include "afsd.h" +#include + #ifdef AFS_FREELANCE_CLIENT #include "cm_freelance.h" #include "stdio.h" diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index 309f972e2..1d772c127 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -551,6 +551,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp, lock_ObtainMutex(&cm_Freelance_Lock); scp->length.LowPart = (DWORD)strlen(mp)+4; + scp->length.HighPart = 0; strncpy(scp->mountPointStringp,mp,MOUNTPOINTLEN); scp->mountPointStringp[MOUNTPOINTLEN-1] = '\0'; lock_ReleaseMutex(&cm_Freelance_Lock); @@ -1148,6 +1149,7 @@ void cm_MergeStatus(cm_scache_t *scp, AFSFetchStatus *statusp, AFSVolSync *volp, statusp->FileType = CM_SCACHETYPE_DIRECTORY; statusp->LinkCount = scp->linkCount; statusp->Length = cm_fakeDirSize; + statusp->Length_hi = 0; statusp->DataVersion = cm_data.fakeDirVersion; statusp->Author = 0x1; statusp->Owner = 0x0; @@ -1220,11 +1222,11 @@ void cm_MergeStatus(cm_scache_t *scp, AFSFetchStatus *statusp, AFSVolSync *volp, } if (!(scp->mask & CM_SCACHEMASK_LENGTH)) { scp->length.LowPart = statusp->Length; - scp->length.HighPart = 0; + scp->length.HighPart = statusp->Length_hi; } scp->serverLength.LowPart = statusp->Length; - scp->serverLength.HighPart = 0; + scp->serverLength.HighPart = statusp->Length_hi; scp->linkCount = statusp->LinkCount; scp->dataVersion = statusp->DataVersion; diff --git a/src/WINNT/afsd/cm_scache.h b/src/WINNT/afsd/cm_scache.h index b8abbafe5..78c942eb4 100644 --- a/src/WINNT/afsd/cm_scache.h +++ b/src/WINNT/afsd/cm_scache.h @@ -181,7 +181,7 @@ typedef struct cm_scache { * include locks which have * CM_FILELOCK_FLAG_CLIENTONLY set. */ - + afs_uint32 clientLocks; /* number of locks on ::fileLocks that have CM_FILELOCK_FLAG_CLIENTONLY set. */ @@ -245,6 +245,10 @@ typedef struct cm_scache { #define CM_SCACHEFLAG_ANYWATCH \ (CM_SCACHEFLAG_WATCHED | CM_SCACHEFLAG_WATCHEDSUBTREE) +#define CM_SCACHEFLAG_NO64BITOPS 0x200000 /* only supports + 32-bit fetch/store + operations */ + /* sync flags for calls to the server. The CM_SCACHEFLAG_FETCHING, * CM_SCACHEFLAG_STORING and CM_SCACHEFLAG_SIZESTORING flags correspond to the * below, except for FETCHDATA and STOREDATA, which correspond to non-null diff --git a/src/WINNT/afsd/cm_server.c b/src/WINNT/afsd/cm_server.c index 3d29d271c..84a69af86 100644 --- a/src/WINNT/afsd/cm_server.c +++ b/src/WINNT/afsd/cm_server.c @@ -21,9 +21,9 @@ #include #include +#include "afsd.h" #include #include -#include "afsd.h" osi_rwlock_t cm_serverLock; @@ -226,6 +226,16 @@ void cm_PutServerNoLock(cm_server_t *serverp) osi_assert(serverp->refCount-- > 0); } +void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit) +{ + lock_ObtainMutex(&serverp->mx); + if (no64bit) + serverp->flags |= CM_SERVERFLAG_NO64BIT; + else + serverp->flags &= ~CM_SERVERFLAG_NO64BIT; + lock_ReleaseMutex(&serverp->mx); +} + void cm_SetServerPrefs(cm_server_t * serverp) { unsigned long serverAddr; /* in host byte order */ diff --git a/src/WINNT/afsd/cm_server.h b/src/WINNT/afsd/cm_server.h index 9182a2aad..ba672bad4 100644 --- a/src/WINNT/afsd/cm_server.h +++ b/src/WINNT/afsd/cm_server.h @@ -51,6 +51,8 @@ typedef struct cm_serverRef { #define CM_SERVERFLAG_DOWN 1 /* server is down */ #define CM_SERVERFLAG_PREF_SET 2 /* server preference set by user */ #define CM_SERVERFLAG_PINGING 4 /* a ping against this server in progress */ +#define CM_SERVERFLAG_NO64BIT 8 /* server has no support for + 64-bit operations. */ /* flags for procedures */ #define CM_FLAG_CHECKUPSERVERS 1 /* check working servers */ @@ -105,4 +107,6 @@ extern void cm_FreeServerList(cm_serverRef_t** list); extern void cm_ForceNewConnectionsAllServers(void); +extern void cm_SetServerNo64Bit(cm_server_t * serverp, int no64bit); + #endif /* __CM_SERVER_H_ENV__ */ diff --git a/src/WINNT/afsd/cm_user.c b/src/WINNT/afsd/cm_user.c index 54d3c25bd..0f53e0552 100644 --- a/src/WINNT/afsd/cm_user.c +++ b/src/WINNT/afsd/cm_user.c @@ -16,10 +16,10 @@ #include #include +#include "afsd.h" #include #include -#include "afsd.h" osi_rwlock_t cm_userLock; diff --git a/src/WINNT/afsd/cm_utils.c b/src/WINNT/afsd/cm_utils.c index 8d730149e..d764a6570 100644 --- a/src/WINNT/afsd/cm_utils.c +++ b/src/WINNT/afsd/cm_utils.c @@ -64,10 +64,10 @@ #include #include +#include "afsd.h" #include #include -#include "afsd.h" static osi_once_t cm_utilsOnce; diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 1626e51f8..ce7c606dc 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -3573,7 +3573,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType, } } else if ((scp->exclusiveLocks > 0) || - (scp->sharedLocks > 0 && scp->serverLock != LockRead)) { + (scp->sharedLocks > 0 && scp->serverLock != LockRead)) { /* We are already waiting for some other lock. We should wait for the daemon to catch up instead of generating a @@ -3609,7 +3609,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType, } if (scp->serverLock == LockRead && Which == LockWrite) { - + /* We want to escalate the lock to a LockWrite. Unfortunately that's not really possible without letting go of the current lock. But for now we do @@ -3651,7 +3651,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType, /* am I sane? */ osi_assert(newLock == LockRead); - + code = cm_IntSetLock(scp, userp, newLock, reqp); } @@ -4462,9 +4462,9 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead) /* Check if we already have a sufficient server lock to allow this lock to go through. */ if (IS_LOCK_WAITLOCK(oldFileLock) && - (!SERVERLOCKS_ENABLED(scp) || - scp->serverLock == oldFileLock->lockType || - scp->serverLock == LockWrite)) { + (!SERVERLOCKS_ENABLED(scp) || + scp->serverLock == oldFileLock->lockType || + scp->serverLock == LockWrite)) { oldFileLock->flags &= ~CM_FILELOCK_FLAG_WAITLOCK; @@ -4505,7 +4505,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead) } if (IS_LOCK_ACCEPTED(fileLock) && - INTERSECT_RANGE(oldFileLock->range, fileLock->range)) { + INTERSECT_RANGE(oldFileLock->range, fileLock->range)) { if (oldFileLock->lockType != LockRead || fileLock->lockType != LockRead) { diff --git a/src/WINNT/afsd/cm_volume.c b/src/WINNT/afsd/cm_volume.c index 04e5553cb..83bd7a517 100644 --- a/src/WINNT/afsd/cm_volume.c +++ b/src/WINNT/afsd/cm_volume.c @@ -19,11 +19,10 @@ #endif /* !DJGPP */ #include #include +#include "afsd.h" #include #include -#include "afsd.h" - osi_rwlock_t cm_volumeLock; long diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 968a6219a..3af09939f 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -24,11 +24,10 @@ #include #include +#include "afsd.h" #include #include #include - -#include "afsd.h" #include #include "smb.h" @@ -351,6 +350,8 @@ char * myCrt_Dispatch(int i) return "(2d)ReceiveV3OpenX"; case 0x2e: return "(2e)ReceiveV3ReadX"; + case 0x2f: + return "(2f)ReceiveV3WriteX"; case 0x32: return "(32)ReceiveV3Tran2A"; case 0x33: @@ -2965,11 +2966,32 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp fd = smb_GetSMBParm(inp, 0); count = smb_GetSMBParm(inp, 3); minCount = smb_GetSMBParm(inp, 4); - offset.HighPart = 0; /* too bad */ offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16); - osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x", - fd, offset.LowPart, count); + if (*inp->wctp == 10) { + /* we were sent a request with 64-bit file offsets */ +#ifdef AFS_LARGEFILES + offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16); + + if (LargeIntegerLessThanZero(offset)) { + osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset"); + goto send1; + } +#else + if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) { + osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request."); + goto send1; + } else { + offset.HighPart = 0; + } +#endif + } else { + /* we were sent a request with 32-bit file offsets */ + offset.HighPart = 0; + } + + osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x", + fd, offset.HighPart, offset.LowPart, count); fidp = smb_FindFID(vcp, fd, 0); if (!fidp) @@ -2982,7 +3004,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp key = cm_GenerateKey(vcp->vcID, pid, fd); - LOffset.HighPart = 0; + LOffset.HighPart = offset.HighPart; LOffset.LowPart = offset.LowPart; LLength.HighPart = 0; LLength.LowPart = count; @@ -3218,6 +3240,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) caps = NTNEGOTIATE_CAPABILITY_NTSTATUS | #ifdef DFS_SUPPORT NTNEGOTIATE_CAPABILITY_DFS | +#endif +#ifdef AFS_LARGEFILES + NTNEGOTIATE_CAPABILITY_LARGEFILES | #endif NTNEGOTIATE_CAPABILITY_NTFIND | NTNEGOTIATE_CAPABILITY_RAWMODE | @@ -4580,7 +4605,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack cm_ReleaseUser(userp); return code; } - + #ifdef DFS_SUPPORT if (newScp->fileType == CM_SCACHETYPE_DFSLINK) { cm_ReleaseSCache(newScp); @@ -6456,7 +6481,8 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (code == 0 && written == 0) code = CM_ERROR_PARTIALWRITE; - offset.LowPart += written; + offset = LargeIntegerAdd(offset, + ConvertLongToLargeInteger(written)); count -= written; total_written += written; written = 0; @@ -6492,8 +6518,8 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, fd = smb_GetSMBParm(inp, 0); fidp = smb_FindFID(vcp, fd, 0); - osi_Log2(smb_logp, "Completing Raw Write offset %x count %x", - rwcp->offset.LowPart, rwcp->count); + osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x", + rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count); userp = smb_GetUserFromVCP(vcp, inp); @@ -6566,16 +6592,44 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out fd = smb_GetSMBParm(inp, 0); totalCount = smb_GetSMBParm(inp, 1); count = smb_GetSMBParm(inp, 10); - offset.HighPart = 0; /* too bad */ - offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16); writeMode = smb_GetSMBParm(inp, 7); op = (char *) inp->data; op += smb_GetSMBParm(inp, 11); + offset.HighPart = 0; + offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16); + + if (*inp->wctp == 14) { + /* we received a 64-bit file offset */ +#ifdef AFS_LARGEFILES + offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16); + + if (LargeIntegerLessThanZero(offset)) { + osi_Log2(smb_logp, + "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x", + offset.HighPart, offset.LowPart); + return CM_ERROR_BADSMB; + } +#else + if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) { + osi_Log0(smb_logp, + "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files"); + return CM_ERROR_BADSMB; + } + + offset.HighPart = 0; +#endif + } else { + offset.HighPart = 0; /* 32-bit file offset */ + } + osi_Log4(smb_logp, - "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x", - fd, offset.LowPart, count, writeMode); + "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x", + fd, offset.HighPart, offset.LowPart, count); + osi_Log1(smb_logp, + " WriteRaw WriteMode 0x%x", + writeMode); fd = smb_ChainFID(fd, inp); fidp = smb_FindFID(vcp, fd, 0); @@ -6636,7 +6690,9 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out if (code == 0 && written == 0) code = CM_ERROR_PARTIALWRITE; - offset.LowPart += written; + offset = LargeIntegerAdd(offset, + ConvertLongToLargeInteger(written)); + count -= written; total_written += written; written = 0; @@ -6680,10 +6736,13 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out return code; } + offset = LargeIntegerAdd(offset, + ConvertLongToLargeInteger(count)); + rwcp->code = 0; rwcp->buf = rawBuf; - rwcp->offset.HighPart = 0; - rwcp->offset.LowPart = offset.LowPart + count; + rwcp->offset.HighPart = offset.HighPart; + rwcp->offset.LowPart = offset.LowPart; rwcp->count = totalCount - count; rwcp->writeMode = writeMode; rwcp->alreadyWritten = total_written; @@ -7103,6 +7162,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { long code = 0; + osi_hyper_t new_offset; long offset; int whence; unsigned short fd; @@ -7144,15 +7204,20 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (code == 0) { if (whence == 1) { /* offset from current offset */ - offset += fidp->offset; + new_offset = LargeIntegerAdd(fidp->offset, + ConvertLongToLargeInteger(offset)); } else if (whence == 2) { /* offset from current EOF */ - offset += scp->length.LowPart; + new_offset = LargeIntegerAdd(scp->length, + ConvertLongToLargeInteger(offset)); + } else { + new_offset = ConvertLongToLargeInteger(offset); } - fidp->offset = offset; - smb_SetSMBParm(outp, 0, offset & 0xffff); - smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff); + + fidp->offset = new_offset; + smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff); + smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff); smb_SetSMBDataLength(outp, 0); } lock_ReleaseMutex(&scp->mx); @@ -8607,6 +8672,8 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt, smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED; smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX; smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED; + smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX; + smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED; smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */ smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE; smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A; diff --git a/src/WINNT/afsd/smb.h b/src/WINNT/afsd/smb.h index 856324509..37b1fafb6 100644 --- a/src/WINNT/afsd/smb.h +++ b/src/WINNT/afsd/smb.h @@ -16,6 +16,9 @@ #include +/* Support largefiles by default */ +#define AFS_LARGEFILES + /* basic core protocol SMB structure */ typedef struct smb { unsigned char id[4]; @@ -340,7 +343,7 @@ typedef struct smb_fid { originally (used to close the file if session is terminated) */ - long offset; /* our file pointer */ + osi_hyper_t offset; /* our file pointer */ smb_ioctl_t *ioctlp; /* ptr to ioctl structure */ /* Under NT, we may need to know the * parent directory and pathname used @@ -376,7 +379,7 @@ typedef struct smb_fid { #define SMB_FID_SHARE_READ 0x1000 #define SMB_FID_SHARE_WRITE 0x2000 -#define SMB_FID_QLOCK_HIGH 0x0fe00000 +#define SMB_FID_QLOCK_HIGH 0x7f000000 #define SMB_FID_QLOCK_LOW 0x00000000 #define SMB_FID_QLOCK_LENGTH 1 #define SMB_FID_QLOCK_PID 0 diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 618cf729e..fc2b955ac 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -4670,7 +4670,6 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return CM_ERROR_BADSHARENAME; } #endif /* DFS_SUPPORT */ - /* otherwise, scp points to the parent directory. Do a lookup, * and truncate the file if we find it, otherwise we create the * file. @@ -5250,6 +5249,137 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * return code; } +long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) +{ + osi_hyper_t offset; + long count, written = 0, total_written = 0; + unsigned short fd; + unsigned pid; + smb_fid_t *fidp; + long code = 0; + cm_user_t *userp; + cm_attr_t truncAttr; /* attribute struct used for truncating file */ + char *op; + int inDataBlockCount; + + fd = smb_GetSMBParm(inp, 2); + count = smb_GetSMBParm(inp, 10); + + offset.HighPart = 0; + offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16); + + if (*inp->wctp == 14) { + /* we have a request with 64-bit file offsets */ +#ifdef AFS_LARGEFILES + offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16); +#else + if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) { + /* uh oh */ + osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support"); + /* we shouldn't have received this op if we didn't specify + largefile support */ + return CM_ERROR_BADOP; + } +#endif + } + + op = inp->data + smb_GetSMBParm(inp, 11); + inDataBlockCount = count; + + osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x", + fd, offset.HighPart, offset.LowPart, count); + + fd = smb_ChainFID(fd, inp); + fidp = smb_FindFID(vcp, fd, 0); + if (!fidp) + return CM_ERROR_BADFD; + + lock_ObtainMutex(&fidp->mx); + if (fidp->flags & SMB_FID_IOCTL) { + lock_ReleaseMutex(&fidp->mx); + code = smb_IoctlV3Write(fidp, vcp, inp, outp); + smb_ReleaseFID(fidp); + return code; + } + lock_ReleaseMutex(&fidp->mx); + userp = smb_GetUserFromVCP(vcp, inp); + + /* special case: 0 bytes transferred means there is no data + transferred. A slight departure from SMB_COM_WRITE where this + means that we are supposed to truncate the file at this + position. */ + + { + cm_key_t key; + LARGE_INTEGER LOffset; + LARGE_INTEGER LLength; + + pid = ((smb_t *) inp)->pid; + key = cm_GenerateKey(vcp->vcID, pid, fd); + + LOffset.HighPart = offset.HighPart; + LOffset.LowPart = offset.LowPart; + LLength.HighPart = 0; + LLength.LowPart = count; + + lock_ObtainMutex(&fidp->scp->mx); + code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key); + lock_ReleaseMutex(&fidp->scp->mx); + + if (code) + goto done; + } + + /* + * Work around bug in NT client + * + * When copying a file, the NT client should first copy the data, + * then copy the last write time. But sometimes the NT client does + * these in the wrong order, so the data copies would inadvertently + * cause the last write time to be overwritten. We try to detect this, + * and don't set client mod time if we think that would go against the + * intention. + */ + lock_ObtainMutex(&fidp->mx); + if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) { + fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME; + fidp->scp->clientModTime = time(NULL); + } + lock_ReleaseMutex(&fidp->mx); + + code = 0; + while ( code == 0 && count > 0 ) { +#ifndef DJGPP + code = smb_WriteData(fidp, &offset, count, op, userp, &written); +#else /* DJGPP */ + code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE); +#endif /* !DJGPP */ + if (code == 0 && written == 0) + code = CM_ERROR_PARTIALWRITE; + + offset = LargeIntegerAdd(offset, + ConvertLongToLargeInteger(written)); + count -= written; + total_written += written; + written = 0; + } + + done_writing: + + /* slots 0 and 1 are reserved for request chaining and will be + filled in when we return. */ + smb_SetSMBParm(outp, 2, total_written); + smb_SetSMBParm(outp, 3, 0); /* reserved */ + smb_SetSMBParm(outp, 4, 0); /* reserved */ + smb_SetSMBParm(outp, 5, 0); /* reserved */ + smb_SetSMBDataLength(outp, 0); + + done: + smb_ReleaseFID(fidp); + cm_ReleaseUser(userp); + + return code; +} long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { @@ -5266,12 +5396,33 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fd = smb_GetSMBParm(inp, 2); count = smb_GetSMBParm(inp, 5); - offset.HighPart = 0; /* too bad */ offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16); - osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x", - fd, offset.LowPart, count); - + if (*inp->wctp == 12) { + /* a request with 64-bit offsets */ +#ifdef AFS_LARGEFILES + offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16); + + if (LargeIntegerLessThanZero(offset)) { + osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)", + offset.HighPart, offset.LowPart); + return CM_ERROR_BADSMB; + } +#else + if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) { + osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping"); + return CM_ERROR_BADSMB; + } else { + offset.HighPart = 0; + } +#endif + } else { + offset.HighPart = 0; + } + + osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x", + fd, offset.HighPart, offset.LowPart, count); + fd = smb_ChainFID(fd, inp); fidp = smb_FindFID(vcp, fd, 0); if (!fidp) { diff --git a/src/WINNT/afsd/smb3.h b/src/WINNT/afsd/smb3.h index 2167d9fd6..6a6caa987 100644 --- a/src/WINNT/afsd/smb3.h +++ b/src/WINNT/afsd/smb3.h @@ -175,6 +175,8 @@ extern long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pac extern long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); +extern long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); + extern long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); extern long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); diff --git a/src/WINNT/afsd/smb_ioctl.c b/src/WINNT/afsd/smb_ioctl.c index 86d6e510e..70f4b284f 100644 --- a/src/WINNT/afsd/smb_ioctl.c +++ b/src/WINNT/afsd/smb_ioctl.c @@ -280,6 +280,51 @@ done: return code; } +/* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL + * file descriptor. + */ +long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) +{ + smb_ioctl_t *iop; + long count; + long code; + char *op; + int inDataBlockCount; + + code = 0; + count = smb_GetSMBParm(inp, 10); + iop = fidp->ioctlp; + + smb_IoctlPrepareWrite(fidp, iop); + + op = inp->data + smb_GetSMBParm(inp, 11); + inDataBlockCount = count; + + if (count + iop->inCopied > SMB_IOCTL_MAXDATA) { + code = CM_ERROR_TOOBIG; + goto done; + } + + /* copy data */ + memcpy(iop->inDatap + iop->inCopied, op, count); + + /* adjust counts */ + iop->inCopied += count; + +done: + /* return # of bytes written */ + if (code == 0) { + smb_SetSMBParm(outp, 2, count); + smb_SetSMBParm(outp, 3, 0); /* reserved */ + smb_SetSMBParm(outp, 4, 0); /* reserved */ + smb_SetSMBParm(outp, 5, 0); /* reserved */ + smb_SetSMBDataLength(outp, 0); + } + + return code; +} + + /* called from V3 read to handle IOCTL descriptor reads */ long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { diff --git a/src/WINNT/afsd/smb_ioctl.h b/src/WINNT/afsd/smb_ioctl.h index bce9e849a..bb5ffb05a 100644 --- a/src/WINNT/afsd/smb_ioctl.h +++ b/src/WINNT/afsd/smb_ioctl.h @@ -30,6 +30,8 @@ extern long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb extern long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); +extern long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); + extern long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp); #ifndef DJGPP diff --git a/src/libafsrpc/afsrpc.def b/src/libafsrpc/afsrpc.def index 15bb847f4..4d965b9d8 100644 --- a/src/libafsrpc/afsrpc.def +++ b/src/libafsrpc/afsrpc.def @@ -218,5 +218,4 @@ EXPORTS rx_DebugOnOff @223 rx_InitHost @224 rx_NewServiceHost @225 - - + osi_AssertFailU @226 -- 2.39.5