Windows: Implement dynamic cell detection for RDR
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index 849bd14..44276f4 100644 (file)
 static CHAR * RDR_extentBaseAddress = NULL;
 
 void
-RDR_InitReq(cm_req_t *reqp)
+RDR_InitReq(cm_req_t *reqp, BOOL bWow64)
 {
     cm_InitReq(reqp);
     reqp->flags |= CM_REQ_SOURCE_REDIR;
+    if (bWow64)
+        reqp->flags |= CM_REQ_WOW64;
 }
 
 void
@@ -140,6 +142,7 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
     *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (cm_CachePathLen + TempPathLen) * sizeof(WCHAR));
     *ppRedirInitInfo = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
     (*ppRedirInitInfo)->Flags = smb_hideDotFiles ? AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES : 0;
+    (*ppRedirInitInfo)->Flags |= cm_shortNames ? 0 : AFS_REDIR_INIT_FLAG_DISABLE_SHORTNAMES;
     (*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
     (*ppRedirInitInfo)->GlobalFileId.Cell   = cm_data.rootFid.cell;
     (*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
@@ -748,9 +751,7 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
     cm_scache_t * dscp = NULL;
     cm_req_t      req;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_EnumerateDirectory FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
              DirID.Cell, DirID.Volume, DirID.Vnode, DirID.Unique);
@@ -896,7 +897,7 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
                     code = RDR_PopulateCurrentEntry( pCurrentEntry, dwMaxEntryLength,
                                                      dscp, scp, userp, &req,
                                                      entryp->name,
-                                                     cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
+                                                     cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
                                                      (bWow64 ? RDR_POP_WOW64 : 0) |
                                                      (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
                                                      code,
@@ -906,7 +907,7 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
                     code = RDR_PopulateCurrentEntryNoScp( pCurrentEntry, dwMaxEntryLength,
                                                           dscp, &entryp->fid, userp, &req,
                                                           entryp->name,
-                                                          cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
+                                                          cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
                                                           (bWow64 ? RDR_POP_WOW64 : 0),
                                                           code,
                                                           &pCurrentEntry, &dwMaxEntryLength);
@@ -977,15 +978,13 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
 
     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_EvaluateNodeByName parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
              ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
 
     /* Allocate enough room to add a volume prefix if necessary */
-    cbName = FileNameLength + (CM_PREFIX_VOL_CCH + 1) * sizeof(WCHAR);
+    cbName = FileNameLength + (CM_PREFIX_VOL_CCH + 64) * sizeof(WCHAR);
     wszName = malloc(cbName);
     if (!wszName) {
         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
@@ -1063,12 +1062,24 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
     code = cm_Lookup(dscp, wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
 
     if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
-         (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL)) {
-        /*
-         * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
-         */
+         dscp == cm_data.rootSCachep) {
+
         StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
-        StringCbCatNW(wszName, cbName, FileName, FileNameLength);
+        if (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL) {
+            /*
+             * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
+             */
+            StringCbCatNW(wszName, cbName, FileName, FileNameLength);
+        } else {
+            if (FileName[0] == L'.') {
+                StringCbCatNW(wszName, cbName, &FileName[1], FileNameLength);
+                StringCbCatNW(wszName, cbName, L"%", sizeof(WCHAR));
+            } else {
+                StringCbCatNW(wszName, cbName, FileName, FileNameLength);
+                StringCbCatNW(wszName, cbName, L"#", sizeof(WCHAR));
+            }
+            StringCbCatNW(wszName, cbName, L"root.cell", 9 * sizeof(WCHAR));
+        }
         bVol = TRUE;
 
         code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
@@ -1077,7 +1088,9 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
     if (code == 0 && scp) {
         wchar_t shortName[13]=L"";
 
-        if (bVol) {
+        if (!cm_shortNames) {
+            shortName[0] = L'\0';
+        } else if (bVol) {
             cm_Gen8Dot3VolNameW(scp->fid.cell, scp->fid.volume, shortName, NULL);
         } else if (!cm_Is8Dot3(wszName)) {
             cm_dirFid_t dfid;
@@ -1087,7 +1100,7 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
 
             cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
         } else {
-            shortName[0] = '\0';
+            shortName[0] = L'\0';
         }
 
         code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
@@ -1168,9 +1181,7 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
     }
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     if (SourceID.Cell != 0) {
         cm_SetFid(&Fid, SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
@@ -1304,9 +1315,7 @@ RDR_CreateFileEntry( IN cm_user_t *userp,
               CreateCB->ParentId.Vnode, CreateCB->ParentId.Unique);
     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
     memset(&setAttr, 0, sizeof(cm_attr_t));
 
     *ResultCB = (AFSCommResult *)malloc(size);
@@ -1418,13 +1427,15 @@ RDR_CreateFileEntry( IN cm_user_t *userp,
         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         lock_ReleaseWrite(&dscp->rw);
 
-        dfid.vnode = htonl(scp->fid.vnode);
-        dfid.unique = htonl(scp->fid.unique);
+        if (cm_shortNames) {
+            dfid.vnode = htonl(scp->fid.vnode);
+            dfid.unique = htonl(scp->fid.unique);
 
-        if (!cm_Is8Dot3(FileName))
-            cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
-        else
-            shortName[0] = '\0';
+            if (!cm_Is8Dot3(FileName))
+                cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
+            else
+                shortName[0] = '\0';
+        }
 
         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                         dscp, scp, userp, &req, FileName, shortName,
@@ -1472,9 +1483,7 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
     DWORD               status;
     BOOL                bScpLocked = FALSE;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
     memset(&setAttr, 0, sizeof(cm_attr_t));
 
     osi_Log4(afsd_logp, "RDR_UpdateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
@@ -1688,9 +1697,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     BOOL                bFlushFile = FALSE;
     cm_key_t            key;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
     memset(&setAttr, 0, sizeof(cm_attr_t));
 
     osi_Log4(afsd_logp, "RDR_CleanupFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
@@ -1912,8 +1919,10 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
 
         /* call setattr */
         if (setAttr.mask) {
-            lock_ReleaseWrite(&scp->rw);
-            bScpLocked = FALSE;
+            if (bScpLocked) {
+                lock_ReleaseWrite(&scp->rw);
+                bScpLocked = FALSE;
+            }
             code = cm_SetAttr(scp, &setAttr, userp, &req);
         } else
             code = 0;
@@ -2062,9 +2071,7 @@ RDR_DeleteFileEntry( IN cm_user_t *userp,
              osi_LogSaveStringW(afsd_logp, FileName),
              bCheckOnly);
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
     memset(&setAttr, 0, sizeof(cm_attr_t));
 
     *ResultCB = (AFSCommResult *)malloc( size);
@@ -2235,9 +2242,7 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     afs_uint32             code;
     DWORD                  status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
@@ -2421,13 +2426,15 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         lock_ReleaseWrite(&scp->rw);
 
-        dfid.vnode = htonl(scp->fid.vnode);
-        dfid.unique = htonl(scp->fid.unique);
+        if (cm_shortNames) {
+            dfid.vnode = htonl(scp->fid.vnode);
+            dfid.unique = htonl(scp->fid.unique);
 
-        if (!cm_Is8Dot3(TargetFileName))
-            cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
-        else
-            shortName[0] = '\0';
+            if (!cm_Is8Dot3(TargetFileName))
+                cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
+            else
+                shortName[0] = '\0';
+        }
 
         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
                                  newDscp, scp, userp, &req, TargetFileName, shortName,
@@ -2450,6 +2457,341 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
     return;
 }
 
+/*
+ * AFS does not support cross-directory hard links but RDR_HardLinkFileEntry
+ * is written as if AFS does.  The check for cross-directory links is
+ * implemented in cm_Link().
+ *
+ * Windows supports optional ReplaceIfExists functionality.  The AFS file
+ * server does not.  If the target name already exists and bReplaceIfExists
+ * is true, check to see if the user has insert permission before calling
+ * cm_Unlink() on the existing object.  If the user does not have insert
+ * permission return STATUS_ACCESS_DENIED.
+ */
+
+void
+RDR_HardLinkFileEntry( IN cm_user_t *userp,
+                       IN WCHAR    *SourceFileNameCounted,
+                       IN DWORD     SourceFileNameLength,
+                       IN AFSFileID SourceFileId,
+                       IN AFSFileHardLinkCB *pHardLinkCB,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB)
+{
+
+    AFSFileHardLinkResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    AFSFileID              SourceParentId   = pHardLinkCB->SourceParentId;
+    AFSFileID              TargetParentId   = pHardLinkCB->TargetParentId;
+    WCHAR *                TargetFileNameCounted = pHardLinkCB->TargetName;
+    DWORD                  TargetFileNameLength = pHardLinkCB->TargetNameLength;
+    cm_fid_t               SourceParentFid;
+    cm_fid_t               TargetParentFid;
+    cm_fid_t              SourceFid;
+    cm_fid_t              OrigTargetFid = {0,0,0,0,0};
+    cm_scache_t *          srcDscp = NULL;
+    cm_scache_t *          targetDscp = NULL;
+    cm_scache_t *          srcScp = NULL;
+    cm_dirOp_t             dirop;
+    wchar_t                shortName[13];
+    wchar_t                SourceFileName[260];
+    wchar_t                TargetFileName[260];
+    cm_dirFid_t            dfid;
+    cm_req_t               req;
+    afs_uint32             code;
+    DWORD                  status;
+
+    RDR_InitReq(&req, bWow64);
+
+    StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
+    StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
+
+    osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              SourceParentId.Cell,  SourceParentId.Volume,
+              SourceParentId.Vnode, SourceParentId.Unique);
+    osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
+    osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              TargetParentId.Cell,  TargetParentId.Volume,
+              TargetParentId.Vnode, TargetParentId.Unique);
+    osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
+
+    *ResultCB = (AFSCommResult *)malloc( size);
+    if (!(*ResultCB))
+       return;
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    pResultCB = (AFSFileHardLinkResultCB *)(*ResultCB)->ResultData;
+
+    if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
+    {
+        osi_Log2(afsd_logp, "RDR_HardLinkFileEntry Invalid Name Length: src %u target %u",
+                 SourceFileNameLength, TargetFileNameLength);
+        (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
+        return;
+    }
+
+    SourceFid.cell   = SourceFileId.Cell;
+    SourceFid.volume = SourceFileId.Volume;
+    SourceFid.vnode  = SourceFileId.Vnode;
+    SourceFid.unique = SourceFileId.Unique;
+    SourceFid.hash   = SourceFileId.Hash;
+
+    SourceParentFid.cell   = SourceParentId.Cell;
+    SourceParentFid.volume = SourceParentId.Volume;
+    SourceParentFid.vnode  = SourceParentId.Vnode;
+    SourceParentFid.unique = SourceParentId.Unique;
+    SourceParentFid.hash   = SourceParentId.Hash;
+
+    TargetParentFid.cell   = TargetParentId.Cell;
+    TargetParentFid.volume = TargetParentId.Volume;
+    TargetParentFid.vnode  = TargetParentId.Vnode;
+    TargetParentFid.unique = TargetParentId.Unique;
+    TargetParentFid.hash   = TargetParentId.Hash;
+
+    code = cm_GetSCache(&SourceFid, NULL, &srcScp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source failed code 0x%x", code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        return;
+    }
+
+    code = cm_GetSCache(&TargetParentFid, NULL, &targetDscp, userp, &req);
+    if (code) {
+        osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target parent failed code 0x%x", code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        cm_ReleaseSCache(srcScp);
+        return;
+    }
+
+    lock_ObtainWrite(&targetDscp->rw);
+    code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp targetDscp 0x%p failed code 0x%x", targetDscp, code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&targetDscp->rw);
+        cm_ReleaseSCache(srcScp);
+        cm_ReleaseSCache(targetDscp);
+        return;
+    }
+
+    cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&targetDscp->rw);
+
+    if (targetDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        osi_Log1(afsd_logp, "RDR_HardLinkFileEntry targetDscp 0x%p not a directory", targetDscp);
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(srcScp);
+        cm_ReleaseSCache(targetDscp);
+        return;
+    }
+
+    if ( cm_FidCmp(&SourceParentFid, &TargetParentFid) ) {
+        code = cm_GetSCache(&SourceParentFid, NULL, &srcDscp, userp, &req);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_HardLinkFileEntry 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;
+            cm_ReleaseSCache(srcScp);
+            cm_ReleaseSCache(targetDscp);
+            return;
+        }
+
+        lock_ObtainWrite(&srcDscp->rw);
+        code = cm_SyncOp(srcDscp, NULL, userp, &req, 0,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp srcDscp 0x%p failed code 0x%x", srcDscp, code);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            if ( status == STATUS_INVALID_HANDLE)
+                status = STATUS_OBJECT_PATH_INVALID;
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&srcDscp->rw);
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(targetDscp);
+            cm_ReleaseSCache(srcScp);
+            return;
+        }
+
+        cm_SyncOpDone(srcDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&srcDscp->rw);
+
+        if (srcDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+            osi_Log1(afsd_logp, "RDR_HardLinkFileEntry srcDscp 0x%p not a directory", srcDscp);
+            (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(targetDscp);
+            cm_ReleaseSCache(srcScp);
+            return;
+        }
+    } else {
+        srcDscp = targetDscp;
+    }
+
+    /* Obtain the target FID if it exists */
+    code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+    if (code == 0) {
+        code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
+        cm_EndDirOp(&dirop);
+    }
+
+    if (OrigTargetFid.vnode) {
+
+        /* An object exists with the target name */
+        if (!pHardLinkCB->bReplaceIfExists) {
+            osi_Log0(afsd_logp, "RDR_HardLinkFileEntry target name collision and !ReplaceIfExists");
+            (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_COLLISION;
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(targetDscp);
+            cm_ReleaseSCache(srcScp);
+            return;
+        }
+
+        lock_ObtainWrite(&targetDscp->rw);
+        code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT | PRSFS_DELETE,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&srcDscp->rw);
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(targetDscp);
+            cm_ReleaseSCache(srcScp);
+            return;
+        }
+        cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&targetDscp->rw);
+
+        code = cm_Unlink(targetDscp, NULL, TargetFileName, userp, &req);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_Unlink code 0x%x", code);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&srcDscp->rw);
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(targetDscp);
+            cm_ReleaseSCache(srcScp);
+            return;
+        }
+    }
+
+    code = cm_Link( targetDscp, TargetFileName, srcScp, 0, userp, &req);
+    if (code == 0) {
+        cm_fid_t TargetFid;
+        cm_scache_t *targetScp = 0;
+        DWORD dwRemaining;
+
+        (*ResultCB)->ResultBufferLength = ResultBufferLength;
+        dwRemaining = ResultBufferLength - sizeof( AFSFileHardLinkResultCB) + sizeof( AFSDirEnumEntry);
+        (*ResultCB)->ResultStatus = 0;
+
+        pResultCB->SourceParentDataVersion.QuadPart = srcDscp->dataVersion;
+        pResultCB->TargetParentDataVersion.QuadPart = targetDscp->dataVersion;
+
+        osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p SUCCESS",
+                 srcDscp, targetDscp);
+
+        code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
+        if (code == 0) {
+            code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
+            cm_EndDirOp(&dirop);
+        }
+
+        if (code != 0) {
+            osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_BPlusDirLookup failed code 0x%x",
+                     code);
+            (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(srcScp);
+            cm_ReleaseSCache(targetDscp);
+            return;
+        }
+
+        osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+                  TargetFid.cell,  TargetFid.volume,
+                  TargetFid.vnode, TargetFid.unique);
+
+        code = cm_GetSCache(&TargetFid, &targetDscp->fid, &targetScp, userp, &req);
+        if (code) {
+            osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target failed code 0x%x", code);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(srcScp);
+            cm_ReleaseSCache(targetDscp);
+            return;
+        }
+
+        /* Make sure the source vnode is current */
+        lock_ObtainWrite(&targetScp->rw);
+        code = cm_SyncOp(targetScp, NULL, userp, &req, 0,
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp scp 0x%p failed code 0x%x",
+                     targetScp, code);
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&targetScp->rw);
+            cm_ReleaseSCache(targetScp);
+            if (srcDscp != targetDscp)
+                cm_ReleaseSCache(srcDscp);
+            cm_ReleaseSCache(srcScp);
+            cm_ReleaseSCache(targetDscp);
+            return;
+        }
+
+        cm_SyncOpDone(targetScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&targetScp->rw);
+
+        if (cm_shortNames) {
+            dfid.vnode = htonl(targetScp->fid.vnode);
+            dfid.unique = htonl(targetScp->fid.unique);
+
+            if (!cm_Is8Dot3(TargetFileName))
+                cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
+            else
+                shortName[0] = '\0';
+        }
+
+        RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
+                                 targetDscp, targetScp, userp, &req, TargetFileName, shortName,
+                                 RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
+                                 0, NULL, &dwRemaining);
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+        cm_ReleaseSCache(targetScp);
+
+        osi_Log0(afsd_logp, "RDR_HardLinkFileEntry SUCCESS");
+    } else {
+        osi_Log3(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p failed code 0x%x",
+                 srcDscp, targetDscp, code);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+    }
+
+    cm_ReleaseSCache(srcScp);
+    if (srcDscp != targetDscp)
+        cm_ReleaseSCache(srcDscp);
+    cm_ReleaseSCache(targetDscp);
+    return;
+}
+
 void
 RDR_FlushFileEntry( IN cm_user_t *userp,
                     IN AFSFileID FileId,
@@ -2466,9 +2808,7 @@ RDR_FlushFileEntry( IN cm_user_t *userp,
     char        dbgstr[1024];
 #endif
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
               FileId.Cell, FileId.Volume,
@@ -2647,9 +2987,7 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_OpenFileEntry File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
               FileId.Cell, FileId.Volume,
@@ -2825,9 +3163,7 @@ RDR_ReleaseFileAccess( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
               FileId.Cell, FileId.Volume,
@@ -3001,7 +3337,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
     }
     lock_ReleaseWrite(&scp->rw);
 
-    dwResultBufferLength = (DWORD)(sizeof( AFSSetFileExtentsCB) + sizeof( AFSSetFileExtentsCB) * (length.QuadPart / cm_data.blockSize + 1));
+    dwResultBufferLength = (DWORD)(sizeof( AFSSetFileExtentsCB) + sizeof( AFSFileExtentCB) * (length.QuadPart / cm_data.blockSize + 1));
     pResultCB = (AFSSetFileExtentsCB *)malloc( dwResultBufferLength );
     if (!pResultCB)
         return CM_ERROR_RETRY;
@@ -3117,6 +3453,9 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
             case RXKADNOAUTH:
             case CM_ERROR_QUOTA:
             case CM_ERROR_LOCK_CONFLICT:
+            case EIO:
+            case CM_ERROR_INVAL_NET_RESP:
+            case CM_ERROR_UNKNOWN:
                 /*
                  * these are fatal errors.  deliver what we can
                  * and halt.
@@ -3188,9 +3527,7 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
     cm_req_t    req;
     BOOLEAN     bBufRelease = TRUE;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
     req.flags |= CM_REQ_NORETRY;
 
     osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
@@ -3392,10 +3729,12 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                 buf_Release(bufp);
 
             if (QueueLength) {
+                req.flags &= ~CM_REQ_NORETRY;
                 cm_QueueBKGRequest(scp, RDR_BkgFetch, QueueOffset.LowPart, QueueOffset.HighPart,
                                    QueueLength, 0, userp, &req);
                 osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
                          QueueOffset.HighPart, QueueOffset.LowPart, QueueLength);
+                req.flags |= CM_REQ_NORETRY;
             }
         } else {
             /* No error from buf_Get() can be fatal */
@@ -3407,6 +3746,7 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
     if (BeginOffset.QuadPart != EndOffset.QuadPart) {
         afs_uint32 length = (afs_uint32)(EndOffset.QuadPart - BeginOffset.QuadPart);
 
+        req.flags &= ~CM_REQ_NORETRY;
         cm_QueueBKGRequest(scp, RDR_BkgFetch, BeginOffset.LowPart, BeginOffset.HighPart,
                            length, 0, userp, &req);
         osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
@@ -3452,9 +3792,7 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
     char dbgstr[1024];
 #endif
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
               FileId.Cell, FileId.Volume,
@@ -3835,9 +4173,6 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
                           pExtent->CacheOffset.LowPart);
                 osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
                           wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
-#ifdef DEBUG
-                DebugBreak();
-#endif
             }
             buf_Release(bufp);
         }
@@ -3873,7 +4208,9 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
     }
 
     if (scp) {
-        if (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_FLUSH) {
+        if (deleted) {
+            code = 0;
+        } else if (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_FLUSH) {
             lock_ObtainWrite(&scp->rw);
             code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -3948,7 +4285,7 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
 #endif
     char dbgstr[1024];
 #endif
-    RDR_InitReq(&req);
+    RDR_InitReq(&req, FALSE);
 
     for ( fileno = 0, pNextFileCB = &ReleaseFileExtentsResultCB->Files[0];
           fileno < ReleaseFileExtentsResultCB->FileCount;
@@ -4241,10 +4578,8 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
                                              pExtent->CacheOffset.HighPart,
                                              pExtent->CacheOffset.LowPart);
-#ifdef DEBUG
-                                    DebugBreak();
-#endif
-                                    if (!deleted) {
+
+                                   if (!deleted) {
                                         buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
                                         dirty++;
                                     }
@@ -4302,9 +4637,6 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                                  wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
                     else
                         osi_Log0(afsd_logp, "... coffset cannot be found");
-#ifdef DEBUG
-                    DebugBreak();
-#endif
                 }
                 buf_Release(bufp);
             } else {
@@ -4404,7 +4736,7 @@ RDR_ReleaseFailedSetFileExtents( IN cm_user_t *userp,
     cm_scache_t *    scp = NULL;
     int              dirty = 0;
 
-    RDR_InitReq(&req);
+    RDR_InitReq(&req, FALSE);
 
     osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFileExtents %d.%d.%d.%d",
               SetFileExtentsResultCB->FileId.Cell, SetFileExtentsResultCB->FileId.Volume,
@@ -4478,6 +4810,9 @@ RDR_PioctlOpen( IN cm_user_t *userp,
 {
     cm_fid_t    ParentFid;
     cm_fid_t    RootFid;
+    cm_req_t    req;
+
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
     if (!(*ResultCB))
@@ -4502,7 +4837,7 @@ RDR_PioctlOpen( IN cm_user_t *userp,
     RootFid.hash = pPioctlCB->RootId.Hash;
 
     /* Create the pioctl index */
-    RDR_SetupIoctl(pPioctlCB->RequestId, &ParentFid, &RootFid, userp);
+    RDR_SetupIoctl(pPioctlCB->RequestId, &ParentFid, &RootFid, userp, &req);
 
     return;
 }
@@ -4545,9 +4880,7 @@ RDR_PioctlWrite( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
     if (!(*ResultCB))
@@ -4559,7 +4892,7 @@ RDR_PioctlWrite( IN cm_user_t *userp,
 
     pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
 
-    code = RDR_IoctlWrite(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer, &req);
+    code = RDR_IoctlWrite(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer);
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
@@ -4586,9 +4919,7 @@ RDR_PioctlRead( IN cm_user_t *userp,
     DWORD       status;
     afs_uint32  pflags = (bIsLocalSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
     if (!(*ResultCB))
@@ -4601,7 +4932,7 @@ RDR_PioctlRead( IN cm_user_t *userp,
     pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
 
     code = RDR_IoctlRead(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer,
-                         &pResultCB->BytesProcessed, &req, pflags);
+                         &pResultCB->BytesProcessed, pflags);
     if (code) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
@@ -4632,9 +4963,7 @@ RDR_ByteRangeLockSync( IN cm_user_t     *userp,
 
     ProcessId.QuadPart = pBRLRequestCB->ProcessId;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_ByteRangeLockSync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
               FileId.Cell, FileId.Volume,
@@ -4761,9 +5090,7 @@ RDR_ByteRangeUnlock( IN cm_user_t     *userp,
 
     ProcessId.QuadPart = pBRURequestCB->ProcessId;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_ByteRangeUnlock File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
               FileId.Cell, FileId.Volume,
@@ -4877,9 +5204,7 @@ RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
 
     ProcessId.QuadPart = pBRURequestCB->ProcessId;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_ByteRangeUnlockAll File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
               FileId.Cell, FileId.Volume,
@@ -4956,7 +5281,6 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     DWORD       Length;
     cm_scache_t *scp = NULL;
     cm_volume_t *volp = NULL;
-    cm_vol_state_t *volstatep = NULL;
     afs_uint32   volType;
     cm_cell_t   *cellp = NULL;
     cm_fid_t    Fid;
@@ -4974,10 +5298,10 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     char *OfflineMsg;
     char *MOTD;
     struct rx_connection * rxconnp;
+    int sync_done = 0;
+    int scp_locked = 0;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_GetVolumeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
              FileId.Cell, FileId.Volume,
@@ -5017,18 +5341,7 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         return;
     }
     lock_ObtainWrite(&scp->rw);
-
-    code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) {
-        lock_ReleaseWrite(&scp->rw);
-        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-        (*ResultCB)->ResultStatus = status;
-        (*ResultCB)->ResultBufferLength = 0;
-        osi_Log3(afsd_logp, "RDR_GetVolumeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
-                 scp, code, status);
-        return;
-    }
+    scp_locked = 1;
 
     pResultCB->SectorsPerAllocationUnit = 1;
     pResultCB->BytesPerSector = 1024;
@@ -5037,7 +5350,7 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     pResultCB->VolumeID = scp->fid.volume;
     pResultCB->Characteristics = FILE_REMOTE_DEVICE;
     pResultCB->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK |
-        FILE_SUPPORTS_REPARSE_POINTS;
+        FILE_SUPPORTS_HARD_LINKS | FILE_SUPPORTS_REPARSE_POINTS;
 
     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
@@ -5060,26 +5373,35 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
             code = CM_ERROR_NOSUCHVOLUME;
             goto _done;
         }
-        volstatep = cm_VolumeStateByID(volp, scp->fid.volume);
         volType = cm_VolumeType(volp, scp->fid.volume);
 
         pResultCB->Characteristics |= ((volType == ROVOL || volType == BACKVOL) ? FILE_READ_ONLY_DEVICE : 0);
 
-        Name = volName;
-       OfflineMsg = offLineMsg;
-       MOTD = motd;
-       lock_ReleaseWrite(&scp->rw);
-       do {
-           code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
-           if (code) continue;
-
-           rxconnp = cm_GetRxConn(connp);
-           code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
-                                        &volStat, &Name, &OfflineMsg, &MOTD);
-           rx_PutConnection(rxconnp);
-
-       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code));
-       code = cm_MapRPCError(code, &req);
+        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code == 0)
+        {
+            sync_done = 1;
+
+            Name = volName;
+            OfflineMsg = offLineMsg;
+            MOTD = motd;
+            lock_ReleaseWrite(&scp->rw);
+            scp_locked = 0;
+
+            do {
+                code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+                if (code) continue;
+
+                rxconnp = cm_GetRxConn(connp);
+                code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
+                                              &volStat, &Name, &OfflineMsg, &MOTD);
+                rx_PutConnection(rxconnp);
+
+            } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
+            code = cm_MapRPCError(code, &req);
+        }
+
         if (code == 0) {
             if (volStat.MaxQuota)
             {
@@ -5105,24 +5427,33 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                 }
             }
         } else {
+            /*
+             * Lie about the available space.  Out of quota errors will need
+             * detected when the file server rejects the store data.
+             */
             pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
-
-            pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( volp->namep, -1, pResultCB->VolumeLabel,
-                                                           (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
             code = 0;
         }
+
+        pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( volp->namep, -1, pResultCB->VolumeLabel,
+                                                       (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
         if ( pResultCB->VolumeLabelLength )
             pResultCB->VolumeLabelLength--;
 
-        lock_ObtainWrite(&scp->rw);
+        if (sync_done) {
+            if (!scp_locked) {
+                lock_ObtainWrite(&scp->rw);
+                scp_locked = 1;
+            }
+            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        }
     }
     pResultCB->VolumeLabelLength *= sizeof(WCHAR);  /* convert to bytes from chars */
 
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-
   _done:
-    lock_ReleaseWrite(&scp->rw);
+    if (scp_locked)
+        lock_ReleaseWrite(&scp->rw);
     if (volp)
        cm_PutVolume(volp);
     cm_ReleaseSCache(scp);
@@ -5160,10 +5491,10 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
     char *OfflineMsg;
     char *MOTD;
     struct rx_connection * rxconnp;
+    int sync_done = 0;
+    int scp_locked = 0;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     osi_Log4(afsd_logp, "RDR_GetVolumeSizeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
              FileId.Cell, FileId.Volume,
@@ -5203,24 +5534,13 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
         return;
     }
     lock_ObtainWrite(&scp->rw);
-
-    code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) {
-        lock_ReleaseWrite(&scp->rw);
-        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-        (*ResultCB)->ResultStatus = status;
-        (*ResultCB)->ResultBufferLength = 0;
-        osi_Log3(afsd_logp, "RDR_GetVolumeSizeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
-                 scp, code, status);
-        return;
-    }
+    scp_locked = 1;
 
     pResultCB->SectorsPerAllocationUnit = 1;
     pResultCB->BytesPerSector = 1024;
 
     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
-         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
+        scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
     {
         pResultCB->TotalAllocationUnits.QuadPart = 100;
         pResultCB->AvailableAllocationUnits.QuadPart = 0;
@@ -5232,21 +5552,32 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
         }
 
         volType = cm_VolumeType(volp, scp->fid.volume);
-        Name = volName;
-       OfflineMsg = offLineMsg;
-       MOTD = motd;
-       lock_ReleaseWrite(&scp->rw);
-       do {
-           code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
-           if (code) continue;
-
-           rxconnp = cm_GetRxConn(connp);
-           code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
-                                        &volStat, &Name, &OfflineMsg, &MOTD);
-           rx_PutConnection(rxconnp);
-
-       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code));
-       code = cm_MapRPCError(code, &req);
+
+        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code == 0)
+        {
+            sync_done = 1;
+
+            Name = volName;
+            OfflineMsg = offLineMsg;
+            MOTD = motd;
+            lock_ReleaseWrite(&scp->rw);
+            scp_locked = 0;
+
+            do {
+                code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+                if (code) continue;
+
+                rxconnp = cm_GetRxConn(connp);
+                code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
+                                              &volStat, &Name, &OfflineMsg, &MOTD);
+                rx_PutConnection(rxconnp);
+
+            } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
+            code = cm_MapRPCError(code, &req);
+        }
+
         if (code == 0) {
             if (volStat.MaxQuota)
             {
@@ -5272,18 +5603,27 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
                 }
             }
         } else {
-
+            /*
+             * Lie about the available space.  Out of quota errors will need
+             * detected when the file server rejects the store data.
+             */
             pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
             code = 0;
         }
-        lock_ObtainWrite(&scp->rw);
-    }
 
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (sync_done) {
+            if (!scp_locked) {
+                lock_ObtainWrite(&scp->rw);
+                scp_locked = 1;
+            }
+            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        }
+    }
 
   _done:
-    lock_ReleaseWrite(&scp->rw);
+    if (scp_locked)
+        lock_ReleaseWrite(&scp->rw);
     if (volp)
        cm_PutVolume(volp);
     cm_ReleaseSCache(scp);
@@ -5306,7 +5646,7 @@ RDR_HoldFid( IN cm_user_t     *userp,
     DWORD       Length;
     cm_req_t    req;
 
-    RDR_InitReq(&req);
+    RDR_InitReq(&req, FALSE);
 
     osi_Log1(afsd_logp, "RDR_HoldFid Count=%u", pHoldFidCB->Count);
 
@@ -5366,7 +5706,7 @@ RDR_ReleaseFid( IN cm_user_t     *userp,
     DWORD       Length;
     cm_req_t    req;
 
-    RDR_InitReq(&req);
+    RDR_InitReq(&req, FALSE);
 
     osi_Log1(afsd_logp, "RDR_ReleaseFid Count=%u", pReleaseFidCB->Count);
 
@@ -5529,9 +5869,7 @@ RDR_PipeWrite( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
     if (!(*ResultCB))
@@ -5569,9 +5907,7 @@ RDR_PipeRead( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
     if (!(*ResultCB))
@@ -5606,9 +5942,7 @@ RDR_PipeSetInfo( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
     if (!(*ResultCB))
@@ -5638,9 +5972,7 @@ RDR_PipeQueryInfo( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
     if (!(*ResultCB))
@@ -5706,9 +6038,7 @@ RDR_PipeTransceive( IN cm_user_t     *userp,
     DWORD       status;
     DWORD Length = ResultBufferLength + sizeof( AFSCommResult);
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    RDR_InitReq(&req, bWow64);
 
     *ResultCB = (AFSCommResult *)malloc( Length);
     if (!(*ResultCB))