Windows: do not lower case direct volume references
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index cf6fcad..9ae6d0a 100644 (file)
@@ -231,8 +231,10 @@ RDR_UserFromAuthGroup( IN GUID *pGuid)
 
     unp = smb_FindUserByName(UuidString, cname, SMB_FLAG_CREATE);
     lock_ObtainMutex(&unp->mx);
-    if (!unp->userp)
+    if (!unp->userp) {
         unp->userp = cm_NewUser();
+        memcpy(&unp->userp->authgroup, pGuid, sizeof(GUID));
+    }
     unp->flags |= SMB_USERNAMEFLAG_SID;
     lock_ReleaseMutex(&unp->mx);
     userp = unp->userp;
@@ -280,8 +282,12 @@ RDR_FlagScpInUse( IN cm_scache_t *scp, IN BOOL bLocked )
 }
 
 /*
- * Obtain the status information for the specified object and
- *
+ * Obtain the status information for the specified object using
+ * an inline bulk status rpc.  cm_BPlusDirEnumBulkStatOne() will
+ * obtain current status for the directory object, the object
+ * which is the focus of the inquiry and as many other objects
+ * in the directory for which there are not callbacks registered
+ * since we are likely to be asked for other objects in the directory.
  */
 static afs_uint32
 RDR_BulkStatLookup( cm_scache_t *dscp,
@@ -306,7 +312,6 @@ RDR_BulkStatLookup( cm_scache_t *dscp,
                   code);
     }
 
-
     if (enump)
     {
         code = cm_BPlusDirEnumBulkStatOne(enump, scp);
@@ -326,7 +331,7 @@ RDR_BulkStatLookup( cm_scache_t *dscp,
 #define RDR_POP_WOW64              0x04
 #define RDR_POP_NO_GETSTATUS       0x08
 
-afs_uint32
+static afs_uint32
 RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                           IN  DWORD             dwMaxEntryLength,
                           IN  cm_scache_t     * dscp,
@@ -336,6 +341,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                           IN  wchar_t         * name,
                           IN  wchar_t         * shortName,
                           IN  DWORD             dwFlags,
+                          IN  afs_uint32        cmError,
                           OUT AFSDirEnumEntry **ppNextEntry,
                           OUT DWORD           * pdwRemainingLength)
 {
@@ -401,7 +407,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                 lock_ReleaseWrite(&scp->rw);
                 code = RDR_BulkStatLookup(dscp, scp, userp, reqp);
                 if (code) {
-                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RXR_BulkStatLookup failed for scp=0x%p code=0x%x",
+                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RDR_BulkStatLookup failed for scp=0x%p code=0x%x",
                              scp, code);
                     return code;
                 }
@@ -415,9 +421,11 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                     bMustFake = TRUE;
             }
         }
-
     }
 
+    /* Populate the error code */
+    smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
+
     /* Populate the real or fake data */
     pCurrentEntry->FileId.Cell = scp->fid.cell;
     pCurrentEntry->FileId.Volume = scp->fid.volume;
@@ -496,8 +504,8 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
     wcsncpy(wname, name, len);
     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
 
-    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d",
-              scp, scp->fileType);
+    osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d dv=%u",
+              scp, scp->fileType, (afs_uint32)scp->dataVersion);
 
     if (!(dwFlags & RDR_POP_NO_GETSTATUS))
         cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -618,7 +626,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
     return code;
 }
 
-afs_uint32
+static afs_uint32
 RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
                                IN  DWORD             dwMaxEntryLength,
                                IN  cm_scache_t     * dscp,
@@ -628,6 +636,7 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
                                IN  wchar_t         * name,
                                IN  wchar_t         * shortName,
                                IN  DWORD             dwFlags,
+                               IN  afs_uint32        cmError,
                                OUT AFSDirEnumEntry **ppNextEntry,
                                OUT DWORD           * pdwRemainingLength)
 {
@@ -659,6 +668,10 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
 
     dwEntryLength = sizeof(AFSDirEnumEntry);
 
+    /* Populate the error code */
+    smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
+
+    /* Populate the fake data */
     pCurrentEntry->FileId.Cell = fidp->cell;
     pCurrentEntry->FileId.Volume = fidp->volume;
     pCurrentEntry->FileId.Vnode = fidp->vnode;
@@ -807,16 +820,20 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
         return;
     }
 
+    osi_Log1(afsd_logp, "RDR_EnumerateDirectory dv=%u", (afs_uint32)dscp->dataVersion);
+
     /*
      * If there is no enumeration handle, then this is a new query
-     * and we must perform an enumeration for the specified object
+     * and we must perform an enumeration for the specified object.
      */
     if (QueryCB->EnumHandle == (ULONG_PTR)NULL) {
         cm_dirOp_t    dirop;
 
         code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
         if (code == 0) {
-            code = cm_BPlusDirEnumerate(dscp, userp, &req, TRUE, NULL, !bSkipStatus, &enump);
+            code = cm_BPlusDirEnumerate(dscp, userp, &req,
+                                        TRUE /* dir locked */, NULL /* no mask */,
+                                        TRUE /* fetch status? */, &enump);
             if (code) {
                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumerate failure code=0x%x",
                           code);
@@ -830,43 +847,56 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
         enump = (cm_direnum_t *)QueryCB->EnumHandle;
     }
 
-    if (enump && ResultBufferLength) {
-        cm_direnum_entry_t * entryp = NULL;
+    if (enump) {
+        if (ResultBufferLength == 0) {
+            code = cm_BPlusDirEnumBulkStat(enump);
+            if (code) {
+                osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
+                          code);
+            }
+        } else {
+            cm_direnum_entry_t * entryp = NULL;
+
+            pDirEnumResp->SnapshotDataVersion.QuadPart = enump->dataVersion;
 
-      getnextentry:
-        if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
-            osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
-            goto outofspace;
-        }
+          getnextentry:
+            if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
+                osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
+                goto outofspace;
+            }
 
-        code = cm_BPlusDirNextEnumEntry(enump, &entryp);
+            code = cm_BPlusDirNextEnumEntry(enump, &entryp);
 
-        if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
-            cm_scache_t *scp;
-            int stopnow = (code == CM_ERROR_STOPNOW);
+            if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
+                cm_scache_t *scp = NULL;
+                int stopnow = (code == CM_ERROR_STOPNOW);
 
-            if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
-                osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
-                if (stopnow)
-                    goto outofspace;
-                goto getnextentry;
-            }
+                if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
+                    osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
+                    if (stopnow)
+                        goto outofspace;
+                    goto getnextentry;
+                }
 
-            if ( FALSE /* bSkipStatus */) {
-                scp = cm_FindSCache(&entryp->fid);
-                code = 0;
-            } else {
-                code = cm_GetSCache(&entryp->fid, &scp, userp, &req);
-            }
+                if (bSkipStatus) {
+                    code = cm_GetSCache(&entryp->fid, &scp, userp, &req);
+                    if (code) {
+                        osi_Log5(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure cell %u vol %u vnode %u uniq %u code=0x%x",
+                                 entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique, code);
+                    }
+                } else {
+                    code = entryp->errorCode;
+                    scp = code ? NULL : cm_FindSCache(&entryp->fid);
+                }
 
-            if (!code) {
                 if (scp) {
-                    code = RDR_PopulateCurrentEntry(pCurrentEntry, dwMaxEntryLength,
+                    code = RDR_PopulateCurrentEntry( pCurrentEntry, dwMaxEntryLength,
                                                      dscp, scp, userp, &req,
                                                      entryp->name,
                                                      cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
                                                      (bWow64 ? RDR_POP_WOW64 : 0) |
                                                      (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
+                                                     code,
                                                      &pCurrentEntry, &dwMaxEntryLength);
                     cm_ReleaseSCache(scp);
                 } else {
@@ -875,28 +905,16 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
                                                           entryp->name,
                                                           cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
                                                           (bWow64 ? RDR_POP_WOW64 : 0),
+                                                          code,
                                                           &pCurrentEntry, &dwMaxEntryLength);
                 }
                 if (stopnow)
                     goto outofspace;
                 goto getnextentry;
-            } else {
-                osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure scp=0x%p code=0x%x",
-                          scp, code);
-                if (stopnow)
-                    goto outofspace;
-                goto getnextentry;
             }
         }
     }
 
-    if (enump && ResultBufferLength == 0) {
-        code = cm_BPlusDirEnumBulkStat(enump);
-        if (code) {
-            osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
-                      code);
-        }
-    }
   outofspace:
 
     if (code || enump->next == enump->count || ResultBufferLength == 0) {
@@ -918,6 +936,7 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwMaxEntryLength;
 
         pDirEnumResp->EnumHandle = (ULONG_PTR) enump;
+        pDirEnumResp->CurrentDataVersion.QuadPart = dscp->dataVersion;
     }
 
     if (dscp)
@@ -938,8 +957,9 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
                         IN DWORD    ResultBufferLength,
                         IN OUT AFSCommResult **ResultCB)
 {
+    AFSFileEvalResultCB *pEvalResultCB = NULL;
     AFSDirEnumEntry * pCurrentEntry;
-    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
     afs_uint32  code = 0;
     cm_scache_t * scp = NULL;
     cm_scache_t * dscp = NULL;
@@ -979,9 +999,13 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
     }
 
     memset(*ResultCB, 0, size);
-    (*ResultCB)->ResultBufferLength = ResultBufferLength;
-    if (ResultBufferLength)
-        pCurrentEntry = (AFSDirEnumEntry *)&(*ResultCB)->ResultData;
+    (*ResultCB)->ResultBufferLength = 0;
+    dwRemaining = ResultBufferLength;
+    if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
+        pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
+        pCurrentEntry = &pEvalResultCB->DirEnum;
+        dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
+    }
 
     if (ParentID.Cell != 0) {
         parentFid.cell   = ParentID.Cell;
@@ -994,6 +1018,8 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
         if (code) {
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
             (*ResultCB)->ResultStatus = status;
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName cm_GetSCache parentFID failure code=0x%x status=0x%x",
                       code, status);
             free(wszName);
@@ -1040,7 +1066,6 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
          */
         StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
         StringCbCatNW(wszName, cbName, FileName, FileNameLength);
-        cm_strlwr_utf16(wszName);
         bVol = TRUE;
 
         code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
@@ -1062,12 +1087,12 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
             shortName[0] = '\0';
         }
 
-        code = RDR_PopulateCurrentEntry(pCurrentEntry, ResultBufferLength,
+        code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
                                         dscp, scp, userp, &req,
                                         FileName, shortName,
                                         (bWow64 ? RDR_POP_WOW64 : 0) |
                                         (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
-                                        NULL, &dwRemaining);
+                                        0, NULL, &dwRemaining);
         if (bHoldFid)
             RDR_FlagScpInUse( scp, FALSE );
         cm_ReleaseSCache(scp);
@@ -1078,6 +1103,7 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
                       code, status);
         } else {
+            pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
             (*ResultCB)->ResultStatus = STATUS_SUCCESS;
             (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
             osi_Log0(afsd_logp, "RDR_EvaluateNodeByName SUCCESS");
@@ -1107,8 +1133,9 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
                       IN DWORD     ResultBufferLength,
                       IN OUT AFSCommResult **ResultCB)
 {
-    AFSDirEnumEntry * pCurrentEntry;
-    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    AFSFileEvalResultCB *pEvalResultCB = NULL;
+    AFSDirEnumEntry * pCurrentEntry = NULL;
+    size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
     afs_uint32  code = 0;
     cm_scache_t * scp = NULL;
     cm_scache_t * dscp = NULL;
@@ -1130,10 +1157,13 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
     }
 
     memset(*ResultCB, 0, size);
-    (*ResultCB)->ResultBufferLength = ResultBufferLength;
+    (*ResultCB)->ResultBufferLength = 0;
     dwRemaining = ResultBufferLength;
-    if (ResultBufferLength)
-        pCurrentEntry = (AFSDirEnumEntry *)&(*ResultCB)->ResultData;
+    if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
+        pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
+        pCurrentEntry = &pEvalResultCB->DirEnum;
+        dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
+    }
 
     RDR_InitReq(&req);
     if ( bWow64 )
@@ -1166,6 +1196,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         if (code) {
             cm_ReleaseSCache(scp);
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             (*ResultCB)->ResultStatus = status;
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
                       code, status);
@@ -1180,6 +1212,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         if (code) {
             cm_ReleaseSCache(scp);
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             (*ResultCB)->ResultStatus = status;
             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
                       code, status);
@@ -1217,11 +1251,11 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         return;
     }
 
-    code = RDR_PopulateCurrentEntry(pCurrentEntry, ResultBufferLength,
+    code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
                                     dscp, scp, userp, &req, NULL, NULL,
                                     (bWow64 ? RDR_POP_WOW64 : 0) |
                                     (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
-                                    NULL, &dwRemaining);
+                                    0, NULL, &dwRemaining);
 
     if (bHoldFid)
         RDR_FlagScpInUse( scp, FALSE );
@@ -1234,6 +1268,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         osi_Log2(afsd_logp, "RDR_EvaluateNodeByID FAILURE code=0x%x status=0x%x",
                  code, status);
     } else {
+        pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID SUCCESS");
@@ -1295,6 +1331,8 @@ RDR_CreateFileEntry( IN cm_user_t *userp,
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         osi_Log2(afsd_logp, "RDR_CreateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                   code, status);
         return;
@@ -1393,7 +1431,7 @@ RDR_CreateFileEntry( IN cm_user_t *userp,
         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                         dscp, scp, userp, &req, FileName, shortName,
                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
-                                        NULL, &dwRemaining);
+                                        0, NULL, &dwRemaining);
 
         if (bHoldFid)
             RDR_FlagScpInUse( scp, FALSE );
@@ -1468,6 +1506,8 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                   code, status);
         return;
@@ -1598,10 +1638,12 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
 
         pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
 
+        pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                         dscp, scp, userp, &req, NULL, NULL,
                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
-                                        NULL, &dwRemaining);
+                                        0, NULL, &dwRemaining);
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
         osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
     } else {
@@ -1630,7 +1672,8 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
                       IN DWORD ResultBufferLength,
                       IN OUT AFSCommResult **ResultCB)
 {
-    size_t size = sizeof(AFSCommResult);
+    AFSFileCleanupResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
     cm_fid_t            Fid;
     cm_fid_t            parentFid;
     afs_uint32          code = 0;
@@ -1645,6 +1688,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     BOOL                bScpLocked = FALSE;
     BOOL                bDscpLocked = FALSE;
     BOOL                bFlushFile = FALSE;
+    cm_key_t            key;
 
     RDR_InitReq(&req);
     if ( bWow64 )
@@ -1678,6 +1722,8 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
         code = cm_GetSCache(&parentFid, &dscp, userp, &req);
         if (code) {
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
             (*ResultCB)->ResultStatus = status;
             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                      code, status);
@@ -1733,7 +1779,9 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     }
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-    if (scp->redirBufCount > 0) {
+    if ((bLastHandle || bFlushFile) &&
+        scp->redirBufCount > 0)
+    {
         LARGE_INTEGER heldExtents;
         AFSFileExtentCB extentList[1024];
         DWORD extentCount = 0;
@@ -1796,18 +1844,25 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     }
 
     if (bLastHandle || bFlushFile) {
-        if (bScpLocked) {
-            lock_ReleaseWrite(&scp->rw);
-            bScpLocked = FALSE;
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code == 0) {
+            if (bScpLocked) {
+                lock_ReleaseWrite(&scp->rw);
+                bScpLocked = FALSE;
+            }
+
+            code = cm_FSync(scp, userp, &req, bScpLocked);
         }
-        code = buf_CleanVnode(scp, userp, &req);
         if (bLastHandle && code)
             goto on_error;
     }
 
     if (bUnlockFile || bDeleteFile) {
-        cm_key_t    key;
-
         if (!bScpLocked) {
             lock_ObtainWrite(&scp->rw);
             bScpLocked = TRUE;
@@ -1820,9 +1875,9 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
             goto on_error;
         }
 
-        /* the scp is now locked and current */
         key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
 
+        /* the scp is now locked and current */
         code = cm_UnlockByKey(scp, key,
                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
                               userp, &req);
@@ -1888,6 +1943,44 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     } else
         code = 0;
 
+    /* Now drop the lock enforcing the share access */
+    if ( CleanupCB->FileAccess != AFS_FILE_ACCESS_NOLOCK) {
+        unsigned int sLockType;
+        LARGE_INTEGER LOffset, LLength;
+
+        if (CleanupCB->FileAccess == AFS_FILE_ACCESS_SHARED)
+            sLockType = LOCKING_ANDX_SHARED_LOCK;
+        else
+            sLockType = 0;
+
+        key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, CleanupCB->Identifier);
+
+        LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+        LOffset.LowPart = SMB_FID_QLOCK_LOW;
+        LLength.HighPart = 0;
+        LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+
+        code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
+        if (code == 0)
+        {
+            code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
+
+            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+            if (code == CM_ERROR_RANGE_NOT_LOCKED)
+            {
+                osi_Log3(afsd_logp, "RDR_CleanupFileEntry Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
+                         CleanupCB->FileAccess, CleanupCB->ProcessId, CleanupCB->Identifier);
+
+            }
+        }
+    }
+
   on_error:
     if (bDscpLocked)
         lock_ReleaseWrite(&dscp->rw);
@@ -1905,14 +1998,21 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
     }
 
+    if ( ResultBufferLength >=  sizeof( AFSFileCleanupResultCB))
+    {
+        (*ResultCB)->ResultBufferLength = sizeof( AFSFileCleanupResultCB);
+        pResultCB = (AFSFileCleanupResultCB *)&(*ResultCB)->ResultData;
+        pResultCB->ParentDataVersion.QuadPart = dscp ? dscp->dataVersion : 0;
+    } else {
+        (*ResultCB)->ResultBufferLength = 0;
+    }
+
     if (code == 0) {
         (*ResultCB)->ResultStatus = 0;
-        (*ResultCB)->ResultBufferLength = 0;
         osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
     } else {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
-        (*ResultCB)->ResultBufferLength = 0;
         osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
                   code, status);
     }
@@ -1982,6 +2082,8 @@ RDR_DeleteFileEntry( IN cm_user_t *userp,
     code = cm_GetSCache(&parentFid, &dscp, userp, &req);
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         (*ResultCB)->ResultStatus = status;
         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
                   code, status);
@@ -2115,8 +2217,12 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
     cm_fid_t               SourceParentFid;
     cm_fid_t               TargetParentFid;
+    cm_fid_t              SourceFid;
+    cm_fid_t              OrigTargetFid = {0,0,0,0,0};
+    cm_fid_t              TargetFid;
     cm_scache_t *          oldDscp;
     cm_scache_t *          newDscp;
+    cm_dirOp_t dirop;
     wchar_t                shortName[13];
     wchar_t                SourceFileName[260];
     wchar_t                TargetFileName[260];
@@ -2175,6 +2281,8 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     if (code) {
         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         (*ResultCB)->ResultStatus = status;
         return;
     }
@@ -2185,6 +2293,8 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     if (code) {
         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        if ( status == STATUS_INVALID_HANDLE)
+            status = STATUS_OBJECT_PATH_INVALID;
         (*ResultCB)->ResultStatus = status;
         lock_ReleaseWrite(&oldDscp->rw);
         cm_ReleaseSCache(oldDscp);
@@ -2236,11 +2346,17 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         return;
     }
 
+    /* Obtain the original FID just for debugging purposes */
+    code = cm_BeginDirOp( oldDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+    if (code == 0) {
+        code = cm_BPlusDirLookup(&dirop, SourceFileName, &SourceFid);
+        code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
+        cm_EndDirOp(&dirop);
+    }
+
     code = cm_Rename( oldDscp, NULL, SourceFileName,
                       newDscp, TargetFileName, userp, &req);
     if (code == 0) {
-        cm_dirOp_t dirop;
-        cm_fid_t   targetFid;
         cm_scache_t *scp = 0;
         DWORD dwRemaining;
 
@@ -2256,7 +2372,7 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
 
         code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
         if (code == 0) {
-            code = cm_BPlusDirLookup(&dirop, TargetFileName, &targetFid);
+            code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
             cm_EndDirOp(&dirop);
         }
 
@@ -2270,10 +2386,10 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         }
 
         osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
-                  targetFid.cell,  targetFid.volume,
-                  targetFid.vnode, targetFid.unique);
+                  TargetFid.cell,  TargetFid.volume,
+                  TargetFid.vnode, TargetFid.unique);
 
-        code = cm_GetSCache(&targetFid, &scp, userp, &req);
+        code = cm_GetSCache(&TargetFid, &scp, userp, &req);
         if (code) {
             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
@@ -2312,7 +2428,7 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                  newDscp, scp, userp, &req, TargetFileName, shortName,
                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
-                                 NULL, &dwRemaining);
+                                 0, NULL, &dwRemaining);
         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
         cm_ReleaseSCache(scp);
 
@@ -2600,9 +2716,13 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
         osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
                  scp);
         pResultCB->GrantedAccess = OpenCB->DesiredAccess;
+        pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
         code = 0;
-    } else {
+    }
+    else
+    {
         int count = 0;
+
         do {
             if (count++ > 0) {
                 Sleep(350);
@@ -2610,15 +2730,64 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
                          "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
                          scp, userp, code);
             }
-            code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OPEN_ALWAYS, userp, &req, &ldp);
+            code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OpenCB->ShareAccess,
+                                  OPEN_ALWAYS,
+                                  OpenCB->ProcessId, OpenCB->Identifier,
+                                  userp, &req, &ldp);
             if (code == 0)
                 code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
     }
 
+    /*
+     * If we are restricting sharing, we should do so with a suitable
+     * share lock.
+     */
+    if (code == 0 && scp->fileType == CM_SCACHETYPE_FILE && !(OpenCB->ShareAccess & FILE_SHARE_WRITE)) {
+        cm_key_t key;
+        LARGE_INTEGER LOffset, LLength;
+        int sLockType;
+
+        LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+        LOffset.LowPart = SMB_FID_QLOCK_LOW;
+        LLength.HighPart = 0;
+        LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+        /*
+         * If we are not opening the file for writing, then we don't
+         * try to get an exclusive lock.  No one else should be able to
+         * get an exclusive lock on the file anyway, although someone
+         * else can get a shared lock.
+         */
+        if ((OpenCB->ShareAccess & FILE_SHARE_READ) || !(OpenCB->DesiredAccess & AFS_ACCESS_WRITE))
+        {
+            sLockType = LOCKING_ANDX_SHARED_LOCK;
+        } else {
+            sLockType = 0;
+        }
+
+        key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, OpenCB->Identifier);
+
+        lock_ObtainWrite(&scp->rw);
+        code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+        lock_ReleaseWrite(&scp->rw);
+
+        if (code) {
+            code = CM_ERROR_SHARING_VIOLATION;
+            pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
+        } else {
+            if (sLockType == LOCKING_ANDX_SHARED_LOCK)
+                pResultCB->FileAccess = AFS_FILE_ACCESS_SHARED;
+            else
+                pResultCB->FileAccess = AFS_FILE_ACCESS_EXCLUSIVE;
+        }
+    } else {
+        pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
+    }
+
     cm_ReleaseUser(sysUserp);
-    if (bHoldFid)
+    if (code == 0 && bHoldFid)
         RDR_FlagScpInUse( scp, FALSE );
     cm_ReleaseSCache(scp);
 
@@ -2635,6 +2804,91 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
     return;
 }
 
+void
+RDR_ReleaseFileAccess( IN cm_user_t *userp,
+                       IN AFSFileID FileId,
+                       IN AFSFileAccessReleaseCB *ReleaseFileCB,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB)
+{
+    cm_key_t key;
+    unsigned int sLockType;
+    LARGE_INTEGER LOffset, LLength;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_ReleaseFileAccess out of memory");
+       return;
+    }
+
+    memset( *ResultCB, '\0', sizeof( AFSCommResult));
+
+    if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_NOLOCK)
+        return;
+
+    /* Process the release */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_ReleaseFileAccess cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_SHARED)
+        sLockType = LOCKING_ANDX_SHARED_LOCK;
+    else
+        sLockType = 0;
+
+    key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, ReleaseFileCB->Identifier);
+
+    LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+    LOffset.LowPart = SMB_FID_QLOCK_LOW;
+    LLength.HighPart = 0;
+    LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+    lock_ObtainWrite(&scp->rw);
+
+    code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
+    if (code == 0)
+    {
+        code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
+
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+        if (code == CM_ERROR_RANGE_NOT_LOCKED)
+        {
+            osi_Log3(afsd_logp, "RDR_ReleaseFileAccess Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
+                     ReleaseFileCB->FileAccess, ReleaseFileCB->ProcessId, ReleaseFileCB->Identifier);
+        }
+    }
+
+    lock_ReleaseWrite(&scp->rw);
+
+    osi_Log0(afsd_logp, "RDR_ReleaseFileAccessEntry SUCCESS");
+}
+
 static const char *
 HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
 {
@@ -2713,7 +2967,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
     FileId.Hash = scp->fid.hash;
 
     if ((GetTickCount() - reqp->startTime) / 1000 > HardDeadtimeout * 5) {
-        RDR_SetFileStatus( &scp->fid, STATUS_IO_TIMEOUT);
+        RDR_SetFileStatus( &scp->fid, &userp->authgroup, STATUS_IO_TIMEOUT);
         return 0;
     }
 
@@ -2743,7 +2997,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
         osi_Log2(afsd_logp, "RDR_BkgFetch cm_SyncOp failure scp=0x%p code=0x%x",
                  scp, code);
         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
-        RDR_SetFileStatus( &scp->fid, status);
+        RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
         return code;
     }
     lock_ReleaseWrite(&scp->rw);
@@ -2774,7 +3028,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
              * we need to re-queue this extent fetch.
              */
             force_retry = 1;
-            continue;
+            break;
         }
 
         if (!rwheld) {
@@ -2784,14 +3038,6 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
 
         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
         if (code == 0) {
-            if (bufp->flags & CM_BUF_DIRTY) {
-                if (rwheld) {
-                    lock_ReleaseWrite(&scp->rw);
-                    rwheld = 0;
-                }
-                cm_BufWrite(scp, &bufp->offset, cm_chunkSize, 0, userp, reqp);
-            }
-
             if (!(bufp->qFlags & CM_BUF_QREDIR)) {
 #ifdef VALIDATE_CHECK_SUM
 #ifdef ODS_DEBUG
@@ -2799,18 +3045,15 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
                 char dbgstr[1024];
 #endif
 #endif
-                if (!rwheld) {
-                    lock_ObtainWrite(&scp->rw);
-                    rwheld = 1;
-                }
+                if (bufp->flags & CM_BUF_DIRTY)
+                    cm_BufWrite(scp, &bufp->offset, cm_data.buf_blockSize, CM_BUF_WRITE_SCP_LOCKED, userp, reqp);
+
                 lock_ObtainWrite(&buf_globalLock);
                 if (!(bufp->flags & CM_BUF_DIRTY) &&
                     bufp->cmFlags == 0 &&
                     !(bufp->qFlags & CM_BUF_QREDIR)) {
                     buf_InsertToRedirQueue(scp, bufp);
                     lock_ReleaseWrite(&buf_globalLock);
-                    lock_ReleaseWrite(&scp->rw);
-                    rwheld = 0;
 
 #ifdef VALIDATE_CHECK_SUM
                     buf_ComputeCheckSum(bufp);
@@ -2855,12 +3098,6 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
                 osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
                           bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
             }
-
-            if (rwheld) {
-                lock_ReleaseWrite(&scp->rw);
-                rwheld = 0;
-            }
-
         } else {
             /*
              * depending on what the error from cm_GetBuffer is
@@ -2892,6 +3129,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
                  * non-fatal errors.  re-queue the exent
                  */
                 code = CM_ERROR_RETRY;
+                force_retry = 1;
             }
         }
 
@@ -2919,7 +3157,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
 
     if (reportErrorToRedir) {
         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
-        RDR_SetFileStatus( &scp->fid, status);
+        RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
     }
 
     osi_Log4(afsd_logp, "Ending BKG Fetch scp 0x%p code 0x%x fetched 0x%x:%x",
@@ -2986,7 +3224,6 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
         osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync cm_GetSCache FID failure code=0x%x",
                   code);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-        RDR_SetFileStatus( &scp->fid, status);
         return FALSE;
     }
 
@@ -3004,7 +3241,7 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
         osi_Log2(afsd_logp, "RDR_RequestFileExtentsAsync cm_SyncOp failure scp=0x%p code=0x%x",
                  scp, code);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-        RDR_SetFileStatus( &scp->fid, status);
+        RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
         return FALSE;
     }
 
@@ -3042,7 +3279,7 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                     break;
                 default:
                     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-                    RDR_SetFileStatus(&FileId, status);
+                    RDR_SetFileStatus(&FileId, &userp->authgroup, status);
                     bHaveBuffer = FALSE;
                     code = 0;
                 }
@@ -3058,21 +3295,22 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                 else
                     minLength = scp->length;
 
-                if (LargeIntegerGreaterThanOrEqualTo(bufp->offset, minLength)) {
+                if (!bHaveBuffer &&
+                    LargeIntegerGreaterThanOrEqualTo(bufp->offset, minLength)) {
                     memset(bufp->datap, 0, cm_data.buf_blockSize);
                     bufp->dataVersion = scp->dataVersion;
                     bHaveBuffer = TRUE;
                 }
-                lock_ReleaseRead(&scp->rw);
-
-                if ((RequestExtentsCB->Flags & AFS_EXTENT_FLAG_CLEAN) &&
-                     ByteOffset.QuadPart <= bufp->offset.QuadPart &&
-                     EndOffset.QuadPart >= bufp->offset.QuadPart + cm_data.blockSize) {
+                else if ((RequestExtentsCB->Flags & AFS_EXTENT_FLAG_CLEAN) &&
+                         ByteOffset.QuadPart <= bufp->offset.QuadPart &&
+                         EndOffset.QuadPart >= bufp->offset.QuadPart + cm_data.blockSize)
+                {
                     memset(bufp->datap, 0, cm_data.blockSize);
                     bufp->dataVersion = scp->dataVersion;
                     buf_SetDirty(bufp, &req, 0, cm_data.blockSize, userp);
                     bHaveBuffer = TRUE;
                 }
+                lock_ReleaseRead(&scp->rw);
             }
 
             /*
@@ -3094,12 +3332,10 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                     char dbgstr[1024];
 #endif
 #endif
-                    lock_ObtainWrite(&scp->rw);
                     lock_ObtainWrite(&buf_globalLock);
                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
                         buf_InsertToRedirQueue(scp, bufp);
                         lock_ReleaseWrite(&buf_globalLock);
-                        lock_ReleaseWrite(&scp->rw);
 
 #ifdef VALIDATE_CHECK_SUM
                         buf_ComputeCheckSum(bufp);
@@ -3131,7 +3367,6 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                                  bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
                     } else {
                         lock_ReleaseWrite(&buf_globalLock);
-                        lock_ReleaseWrite(&scp->rw);
                     }
                 } else {
                     if (bBufRelease) {
@@ -3140,11 +3375,9 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                          * However, we know the buffer is in recent use so move the buffer to the
                          * front of the queue
                          */
-                        lock_ObtainWrite(&scp->rw);
                         lock_ObtainWrite(&buf_globalLock);
                         buf_MoveToHeadOfRedirQueue(scp, bufp);
                         lock_ReleaseWrite(&buf_globalLock);
-                        lock_ReleaseWrite(&scp->rw);
 
                         osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
                                  bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
@@ -3207,6 +3440,7 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
     cm_req_t    req;
     int         dirty = 0;
     int         released = 0;
+    int         deleted = 0;
     DWORD       status;
 #ifdef ODS_DEBUG
 #ifdef VALIDATE_CHECK_SUM
@@ -3246,13 +3480,20 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
                   code, status);
     }
 
+    deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
+
     /*
      * We do not stop processing as a result of being unable to find the cm_scache object.
      * If this occurs something really bad has happened since the cm_scache object must have
      * been recycled while extents were held by the redirector.  However, we will be resilient
      * and carry on without it.
+     *
+     * If the file is known to be deleted, there is no point attempting to ask the
+     * file server about it or update the attributes.
      */
-    if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart) {
+    if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart &&
+        !deleted)
+    {
         cm_attr_t setAttr;
 
         memset(&setAttr, 0, sizeof(cm_attr_t));
@@ -3312,13 +3553,9 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
                           pExtent->CacheOffset.LowPart);
 
                 /* Move the buffer to the front of the queue */
-                if (scp)
-                    lock_ObtainWrite(&scp->rw);
                 lock_ObtainWrite(&buf_globalLock);
                 buf_MoveToHeadOfRedirQueue(scp, bufp);
                 lock_ReleaseWrite(&buf_globalLock);
-                if (scp)
-                    lock_ReleaseWrite(&scp->rw);
                 buf_Release(bufp);
                 continue;
             }
@@ -3345,19 +3582,12 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
                              (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
                         {
                             if (bufp->qFlags & CM_BUF_QREDIR) {
-                                if (scp)
-                                    lock_ObtainWrite(&scp->rw);
                                 lock_ObtainWrite(&buf_globalLock);
                                 if (bufp->qFlags & CM_BUF_QREDIR) {
                                     buf_RemoveFromRedirQueue(scp, bufp);
-                                    lock_ReleaseWrite(&scp->rw);
                                     buf_ReleaseLocked(bufp, TRUE);
-                                } else {
-                                    if (scp)
-                                        lock_ReleaseWrite(&scp->rw);
                                 }
-                                if (scp)
-                                    lock_ReleaseWrite(&buf_globalLock);
+                                lock_ReleaseWrite(&buf_globalLock);
                             }
 #ifdef ODS_DEBUG
                             snprintf( dbgstr, 1024,
@@ -3641,7 +3871,12 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
 
     if (scp) {
         if (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_FLUSH) {
-            code = buf_CleanVnode(scp, userp, &req);
+            lock_ObtainWrite(&scp->rw);
+            code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+                             CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            lock_ReleaseWrite(&scp->rw);
+            if (code == 0)
+                code = cm_FSync(scp, userp, &req, FALSE);
         }
         else if (dirty) {
             osi_hyper_t offset = {0,0};
@@ -3721,6 +3956,7 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
         cm_scache_t *    scp = NULL;
         int              dirty = 0;
         int              released = 0;
+        int              deleted = 0;
         char * p;
 
         userp = RDR_UserFromAuthGroup( &pFileCB->AuthGroup);
@@ -3753,6 +3989,8 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
              */
         }
 
+        deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
+
         /* if the scp was not found, do not perform the length check */
         if (scp && (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart)) {
             cm_attr_t setAttr;
@@ -3812,13 +4050,9 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                               pExtent->CacheOffset.LowPart);
 
                     /* Move the buffer to the front of the queue */
-                    if (scp)
-                        lock_ObtainWrite(&scp->rw);
                     lock_ObtainWrite(&buf_globalLock);
                     buf_MoveToHeadOfRedirQueue(scp, bufp);
                     lock_ReleaseWrite(&buf_globalLock);
-                    if (scp)
-                        lock_ReleaseWrite(&scp->rw);
                     buf_Release(bufp);
                     continue;
                 }
@@ -3854,17 +4088,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                  (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
                             {
                                 if (bufp->qFlags & CM_BUF_QREDIR) {
-                                    if (scp)
-                                        lock_ObtainWrite(&scp->rw);
                                     lock_ObtainWrite(&buf_globalLock);
                                     if (bufp->qFlags & CM_BUF_QREDIR) {
                                         buf_RemoveFromRedirQueue(scp, bufp);
-                                        if (scp)
-                                            lock_ReleaseWrite(&scp->rw);
                                         buf_ReleaseLocked(bufp, TRUE);
-                                    } else {
-                                        if (scp)
-                                            lock_ReleaseWrite(&scp->rw);
                                     }
                                     lock_ReleaseWrite(&buf_globalLock);
                                 }
@@ -3901,8 +4128,8 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #endif
                             }
 
-                            if ( (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
-                                 (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY) )
+                            if ((ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
+                                (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY))
                             {
 #ifdef VALIDATE_CHECK_SUM
                                 if ( buf_ValidateCheckSum(bufp) ) {
@@ -3940,8 +4167,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                                       pExtent->CacheOffset.HighPart,
                                                       pExtent->CacheOffset.LowPart);
 
-                                            buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
-                                            dirty++;
+                                            if (!deleted) {
+                                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                                dirty++;
+                                            }
                                         } else {
 #ifdef ODS_DEBUG
                                             snprintf(dbgstr, 1024,
@@ -3967,8 +4196,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                     }
                                 }
 #else /* !VALIDATE_CHECK_SUM */
-                                buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
-                                dirty++;
+                                if (!deleted) {
+                                    buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                    dirty++;
+                                }
 #ifdef ODS_DEBUG
                                 snprintf(dbgstr, 1024,
                                           "RDR_ProcessReleaseFileExtentsResult dirty! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
@@ -3986,7 +4217,7 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #ifdef ODS_DEBUG
                                 HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
 #endif
-                                if ( !buf_ValidateCheckSum(bufp) ) {
+                                if (!buf_ValidateCheckSum(bufp) ) {
                                     buf_ComputeCheckSum(bufp);
 #ifdef ODS_DEBUG
                                     HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
@@ -4010,8 +4241,10 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #ifdef DEBUG
                                     DebugBreak();
 #endif
-                                    buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
-                                    dirty++;
+                                    if (!deleted) {
+                                        buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
+                                        dirty++;
+                                    }
                                 } else {
                                     buf_ComputeCheckSum(bufp);
 #ifdef ODS_DEBUG
@@ -4210,17 +4443,10 @@ RDR_ReleaseFailedSetFileExtents( IN cm_user_t *userp,
 
             lock_ObtainMutex(&bufp->mx);
             if (bufp->qFlags & CM_BUF_QREDIR) {
-                if (scp)
-                    lock_ObtainWrite(&scp->rw);
                 lock_ObtainWrite(&buf_globalLock);
                 if (bufp->qFlags & CM_BUF_QREDIR) {
                     buf_RemoveFromRedirQueue(scp, bufp);
-                    if (scp)
-                        lock_ReleaseWrite(&scp->rw);
                     buf_ReleaseLocked(bufp, TRUE);
-                } else {
-                    if (scp)
-                        lock_ReleaseWrite(&scp->rw);
                 }
                 lock_ReleaseWrite(&buf_globalLock);
             }
@@ -4857,7 +5083,7 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                                         &volStat, &Name, &OfflineMsg, &MOTD);
            rx_PutConnection(rxconnp);
 
-       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
+       } while (cm_Analyze(connp, userp, &req, &scp->fid, 0, NULL, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
         if (code == 0) {
             pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;