DEVEL15-windows-largefile-support-20060623
[openafs.git] / src / WINNT / afsd / smb.c
index bea1b0f..3af0993 100644 (file)
 #include <stdio.h>
 #include <time.h>
 
+#include "afsd.h"
 #include <osi.h>
 #include <rx\rx.h>
 #include <rx/rx_prototypes.h>
-
-#include "afsd.h"
 #include <WINNT\afsreg.h>
 
 #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;
@@ -3219,6 +3241,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
 #endif
+#ifdef AFS_LARGEFILES
+               NTNEGOTIATE_CAPABILITY_LARGEFILES |
+#endif
                NTNEGOTIATE_CAPABILITY_NTFIND |
                NTNEGOTIATE_CAPABILITY_RAWMODE |
                NTNEGOTIATE_CAPABILITY_NTSMB;
@@ -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);
@@ -4773,7 +4798,8 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
      * in a readonly volume doesn't mean it shojuld be marked as RO 
      */
     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
-        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
+        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+       newScp->fileType == CM_SCACHETYPE_INVALID)
         attrs = SMB_ATTR_DIRECTORY;
     else
         attrs = 0;
@@ -5692,11 +5718,16 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_OPENWRITE)
-        code = cm_FSync(fidp->scp, userp, &req);
-    else 
+    if (fidp->flags & SMB_FID_OPENWRITE) {
+       cm_scache_t * scp = fidp->scp;
+       cm_HoldSCache(scp);
+       lock_ReleaseMutex(&fidp->mx);
+        code = cm_FSync(scp, userp, &req);
+       cm_ReleaseSCache(scp);
+    } else {
         code = 0;
-    lock_ReleaseMutex(&fidp->mx);
+       lock_ReleaseMutex(&fidp->mx);
+    }
         
     smb_ReleaseFID(fidp);
         
@@ -5758,6 +5789,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     cm_req_t req;
     cm_scache_t *dscp = fidp->NTopen_dscp;
     char *pathp = fidp->NTopen_pathp;
+    cm_scache_t * scp;
 
     osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
              fidp, fidp->fid, vcp);
@@ -5794,33 +5826,38 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         lock_ObtainMutex(&fidp->mx);
     }
 
+    scp = fidp->scp;
+    if (scp)
+       cm_HoldSCache(scp);
+
     /* watch for ioctl closes, and read-only opens */
-    if (fidp->scp != NULL &&
+    if (scp != NULL &&
         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
          == SMB_FID_OPENWRITE) {
         if (dosTime != 0 && dosTime != -1) {
-            fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+            scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
             /* This fixes defect 10958 */
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
         }
-        code = cm_FSync(fidp->scp, userp, &req);
+       lock_ReleaseMutex(&fidp->mx);
+        code = cm_FSync(scp, userp, &req);
+       lock_ObtainMutex(&fidp->mx);
     }
     else 
         code = 0;
 
     /* unlock any pending locks */
-    if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
-        fidp->scp->fileType == CM_SCACHETYPE_FILE) {
+    if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
+        scp->fileType == CM_SCACHETYPE_FILE) {
         cm_key_t key;
-        cm_scache_t * scp;
         long tcode;
 
-        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
+       lock_ReleaseMutex(&fidp->mx);
+
+       /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
            in zero. */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
-        scp = fidp->scp;
-        cm_HoldSCache(scp);
         lock_ObtainMutex(&scp->mx);
 
         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -5841,14 +5878,15 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     post_syncopdone:
 
         lock_ReleaseMutex(&scp->mx);
-        cm_ReleaseSCache(scp);
+       lock_ObtainMutex(&fidp->mx);
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
         char *fullPathp;
 
-        smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
-        if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+       lock_ReleaseMutex(&fidp->mx);
+        smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
+        if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_REMOVED,
@@ -5862,16 +5900,17 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                                  dscp, fullPathp, NULL, TRUE);
         }
         free(fullPathp);
+       lock_ObtainMutex(&fidp->mx);
        fidp->flags &= ~SMB_FID_DELONCLOSE;
     }
 
     /* if this was a newly created file, then clear the creator
      * in the stat cache entry. */
     if (fidp->flags & SMB_FID_CREATED) {
-        lock_ObtainMutex(&fidp->scp->mx);
-       if (fidp->scp->creator == userp)
-           fidp->scp->creator = NULL;
-       lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ObtainMutex(&scp->mx);
+       if (scp->creator == userp)
+           scp->creator = NULL;
+       lock_ReleaseMutex(&scp->mx);
        fidp->flags &= ~SMB_FID_CREATED;
     }
 
@@ -5889,6 +5928,9 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     if (dscp)
        cm_ReleaseSCache(dscp);
 
+    if (scp)
+       cm_ReleaseSCache(scp);
+
     if (pathp)
        free(pathp);
 
@@ -5965,6 +6007,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         if (fidp->curr_chunk == fidp->prev_chunk + 1)
             sequential = 1;
     }
+    lock_ReleaseMutex(&fidp->mx);
 
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -6067,7 +6110,6 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
   done:
     lock_ReleaseMutex(&scp->mx);
-    lock_ReleaseMutex(&fidp->mx);
     if (bufferp) 
         buf_Release(bufferp);
 
@@ -6117,9 +6159,20 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     offset = *offsetp;
 
     lock_ObtainMutex(&fidp->mx);
+    /* make sure we have a writable FD */
+    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
+       osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
+                 fidp->fid, fidp->flags);
+       lock_ReleaseMutex(&fidp->mx);
+        code = CM_ERROR_BADFDOP;
+        goto done;
+    }
+    
     scp = fidp->scp;
-    lock_ObtainMutex(&scp->mx);
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
 
+    lock_ObtainMutex(&scp->mx);
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
@@ -6128,14 +6181,6 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     if (code) 
         goto done;
         
-    /* make sure we have a writable FD */
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
-                 fidp->fid, fidp->flags);
-        code = CM_ERROR_BADFDOP;
-        goto done;
-    }
-
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
     minLength = fileLength;
@@ -6302,6 +6347,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         buf_Release(bufferp);
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
@@ -6323,6 +6369,8 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
     }
 
+    cm_ReleaseSCache(scp);
+
     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
               fidp->fid, code, *writtenp);
     return code;
@@ -6433,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;
@@ -6469,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);
 
@@ -6543,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);
@@ -6613,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;
@@ -6657,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;
@@ -7080,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;
@@ -7113,26 +7196,33 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
     lock_ObtainMutex(&scp->mx);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     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);
-    lock_ReleaseMutex(&fidp->mx);
     smb_ReleaseFID(fidp);
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     return code;
 }
@@ -8582,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;