Windows: .readonly space reporting
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index dead109..dce0be5 100644 (file)
@@ -984,7 +984,7 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
              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");
@@ -1062,15 +1062,39 @@ 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>
-         */
-        StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
-        StringCbCatNW(wszName, cbName, FileName, FileNameLength);
-        bVol = TRUE;
+         dscp == cm_data.rootSCachep) {
+
+        if (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL) {
+            /*
+             * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
+             */
+            StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
+            StringCbCatNW(wszName, cbName, FileName, FileNameLength);
+            bVol = TRUE;
 
-        code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+            code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+        }
+#ifdef AFS_FREELANCE_CLIENT
+        else if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID &&
+                 dscp->fid.vnode == 1 && dscp->fid.unique == 1) {
+            /*
+             * If this is the Freelance volume root directory then treat unrecognized
+             * names as cell names and attempt to find the appropriate "root.cell".
+             */
+            StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
+            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);
+        }
+#endif
     }
 
     if (code == 0 && scp) {
@@ -1772,7 +1796,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     }
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-    if ((bLastHandle || bFlushFile) &&
+    if (bLastHandle && (scp->fileType == CM_SCACHETYPE_FILE) &&
         scp->redirBufCount > 0)
     {
         LARGE_INTEGER heldExtents;
@@ -1838,14 +1862,9 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
 
     /* If not a readonly object, flush dirty data and update metadata */
     if (!(scp->flags & CM_SCACHEFLAG_RO)) {
-        if ((bLastHandle || bFlushFile) &&
-             buf_DirtyBuffersExist(&scp->fid)) {
-            if (!bScpLocked) {
-                lock_ObtainWrite(&scp->rw);
-                bScpLocked = TRUE;
-            }
-            code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
-                             CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if ((scp->fileType == CM_SCACHETYPE_FILE) && (bLastHandle || bFlushFile)) {
+            /* Serialize with any outstanding AsyncStore operation */
+            code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
             if (code == 0) {
                 if (bScpLocked) {
                     lock_ReleaseWrite(&scp->rw);
@@ -1907,8 +1926,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;
@@ -2443,6 +2464,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,
@@ -2931,8 +3287,7 @@ HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
 
 /* do the background fetch. */
 afs_int32
-RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
-             cm_user_t *userp, cm_req_t *reqp)
+RDR_BkgFetch(cm_scache_t *scp, void *rockp, cm_user_t *userp, cm_req_t *reqp)
 {
     osi_hyper_t length;
     osi_hyper_t base;
@@ -2960,15 +3315,12 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
     fetched.LowPart = 0;
     fetched.HighPart = 0;
     tblocksize = ConvertLongToLargeInteger(cm_data.buf_blockSize);
-    base.LowPart = p1;
-    base.HighPart = p2;
-    length.LowPart = p3;
-    length.HighPart = p4;
-
+    base = ((rock_BkgFetch_t *)rockp)->base;
+    length = ((rock_BkgFetch_t *)rockp)->length;
     end = LargeIntegerAdd(base, length);
 
     osi_Log5(afsd_logp, "Starting BKG Fetch scp 0x%p offset 0x%x:%x length 0x%x:%x",
-             scp, p2, p1, p4, p3);
+             scp, base.HighPart, base.LowPart, length.HighPart, length.LowPart);
 
     /*
      * Make sure we have a callback.
@@ -3104,6 +3456,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.
@@ -3377,10 +3732,21 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                 buf_Release(bufp);
 
             if (QueueLength) {
-                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);
+                rock_BkgFetch_t * rockp = malloc(sizeof(*rockp));
+
+                if (rockp) {
+                    req.flags &= ~CM_REQ_NORETRY;
+                    rockp->base = QueueOffset;
+                    rockp->length.LowPart = QueueLength;
+                    rockp->length.HighPart = 0;
+
+                    cm_QueueBKGRequest(scp, RDR_BkgFetch, rockp, 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 {
+                    code = ENOMEM;
+                }
             }
         } else {
             /* No error from buf_Get() can be fatal */
@@ -3391,11 +3757,20 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
 
     if (BeginOffset.QuadPart != EndOffset.QuadPart) {
         afs_uint32 length = (afs_uint32)(EndOffset.QuadPart - BeginOffset.QuadPart);
+        rock_BkgFetch_t * rockp = malloc(sizeof(*rockp));
 
-        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",
-                  BeginOffset.HighPart, BeginOffset.LowPart, length);
+        if (rockp) {
+            req.flags &= ~CM_REQ_NORETRY;
+            rockp->base = QueueOffset;
+            rockp->length.LowPart = QueueLength;
+            rockp->length.HighPart = 0;
+
+            cm_QueueBKGRequest(scp, RDR_BkgFetch, rockp, userp, &req);
+            osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
+                     BeginOffset.HighPart, BeginOffset.LowPart, length);
+        } else {
+            code = ENOMEM;
+        }
     }
     cm_ReleaseSCache(scp);
 
@@ -3430,6 +3805,7 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
     int         released = 0;
     int         deleted = 0;
     DWORD       status;
+    rock_BkgStore_t *rockp;
 #ifdef ODS_DEBUG
 #ifdef VALIDATE_CHECK_SUM
     char md5dbg[33], md5dbg2[33], md5dbg3[33];
@@ -3853,7 +4229,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);
@@ -3881,15 +4259,32 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
                     {
                         length += cm_data.buf_blockSize;
                     } else {
-                        if (!(offset.QuadPart == 0 && length == 0))
-                            cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
-                                                length, 0, userp, &req);
+                        if (!(offset.QuadPart == 0 && length == 0)) {
+                            rockp = malloc(sizeof(*rockp));
+                            if (rockp) {
+                                rockp->length = length;
+                                rockp->offset = offset;
+
+                                cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
+
+                                /* rock is freed by cm_BkgStore */
+                            }
+                        }
                         offset.QuadPart = ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart;
                         length = cm_data.buf_blockSize;
                     }
                 }
-                cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
-                                   length, 0, userp, &req);
+
+                /* Store whatever is left */
+                rockp = malloc(sizeof(*rockp));
+                if (rockp) {
+                    rockp->length = length;
+                    rockp->offset = offset;
+
+                    cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
+
+                    /* rock is freed by cm_BkgStore */
+                }
             }
         }
         cm_ReleaseSCache(scp);
@@ -3922,6 +4317,7 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
     cm_buf_t    *bufp;
     unsigned int fileno, extentno, total_extents = 0;
     AFSReleaseFileExtentsResultFileCB *pNextFileCB;
+    rock_BkgStore_t *rockp;
 #ifdef ODS_DEBUG
 #ifdef VALIDATE_CHECK_SUM
     char md5dbg[33], md5dbg2[33], md5dbg3[33];
@@ -4328,15 +4724,32 @@ RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFi
                      length < cm_chunkSize) {
                     length += cm_data.buf_blockSize;
                 } else {
-                    if (!(offset.QuadPart == 0 && length == 0))
-                        cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
-                                            length, 0, userp, &req);
+                    if (!(offset.QuadPart == 0 && length == 0)) {
+                        rockp = malloc(sizeof(*rockp));
+                        if (rockp) {
+                            rockp->offset = offset;
+                            rockp->length = length;
+
+                            cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
+                        } else {
+                            code = ENOMEM;
+                        }
+                    }
                     offset.QuadPart = pExtent->FileOffset.QuadPart;
                     length = cm_data.buf_blockSize;
                 }
             }
-            cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
-                                length, 0, userp, &req);
+
+            /* Background store the rest */
+            rockp = malloc(sizeof(*rockp));
+            if (rockp) {
+                rockp->offset = offset;
+                rockp->length = length;
+
+                cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
+            } else {
+                code = ENOMEM;
+            }
         }
 
         osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
@@ -4993,7 +5406,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)
@@ -5002,7 +5415,7 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
 
         pResultCB->AvailableAllocationUnits.QuadPart = 0;
-        pResultCB->Characteristics |= FILE_READ_ONLY_DEVICE;
+        pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
         pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
                                                        (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
@@ -5018,7 +5431,8 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         }
         volType = cm_VolumeType(volp, scp->fid.volume);
 
-        pResultCB->Characteristics |= ((volType == ROVOL || volType == BACKVOL) ? FILE_READ_ONLY_DEVICE : 0);
+        if (volType == ROVOL || volType == BACKVOL)
+            pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
         code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -5041,31 +5455,24 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                                               &volStat, &Name, &OfflineMsg, &MOTD);
                 rx_PutConnection(rxconnp);
 
-            } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code));
+            } 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)
-            {
-                pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
-                if (volType == ROVOL || volType == BACKVOL) {
-                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
-                }
-                else
+            if (volType == ROVOL || volType == BACKVOL) {
+                pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;
+                pResultCB->AvailableAllocationUnits.QuadPart = 0;
+            } else {
+                if (volStat.MaxQuota)
                 {
+                    pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
                     pResultCB->AvailableAllocationUnits.QuadPart =
                         min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
                 }
-            }
-            else
-            {
-                pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
-                if (volType == ROVOL || volType == BACKVOL) {
-                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
-                }
                 else
                 {
+                    pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
                     pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
                 }
             }
@@ -5217,31 +5624,24 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
                                               &volStat, &Name, &OfflineMsg, &MOTD);
                 rx_PutConnection(rxconnp);
 
-            } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code));
+            } 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)
-            {
-                pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
-                if (volType == ROVOL || volType == BACKVOL) {
-                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
-                }
-                else
+            if (volType == ROVOL || volType == BACKVOL) {
+                pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;
+                pResultCB->AvailableAllocationUnits.QuadPart = 0;
+            } else {
+                if (volStat.MaxQuota)
                 {
+                    pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
                     pResultCB->AvailableAllocationUnits.QuadPart =
                         min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
                 }
-            }
-            else
-            {
-                pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
-                if (volType == ROVOL || volType == BACKVOL) {
-                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
-                }
                 else
                 {
+                    pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
                     pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
                 }
             }