bozo: Introduce bnode_Wait()
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index 849bd14..cffb9b5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2008 Secure Endpoints, Inc.
- * Copyright (c) 2009-2011 Your File System, Inc.
+ * Copyright (c) 2009-2014 Your File System, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 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
@@ -106,17 +108,77 @@ RDR_FID2fid( AFSFileID *FileId, cm_fid_t *fid)
     fid->hash = FileId->Hash;
 }
 
+unsigned long
+RDR_ExtAttributes(cm_scache_t *scp)
+{
+    unsigned long attrs;
+
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+        scp->fid.vnode & 0x1)
+    {
+        attrs = SMB_ATTR_DIRECTORY;
+#ifdef SPECIAL_FOLDERS
+        attrs |= SMB_ATTR_SYSTEM;              /* FILE_ATTRIBUTE_SYSTEM */
+#endif /* SPECIAL_FOLDERS */
+    } else if ( scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                scp->fileType == CM_SCACHETYPE_DFSLINK ||
+                scp->fileType == CM_SCACHETYPE_INVALID)
+    {
+        attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
+    } else if ( scp->fileType == CM_SCACHETYPE_SYMLINK) {
+        attrs = SMB_ATTR_REPARSE_POINT;
+    } else {
+        attrs = 0;
+    }
+
+    if ((scp->unixModeBits & 0200) == 0)
+        attrs |= SMB_ATTR_READONLY;            /* Read-only */
+
+    if (attrs == 0)
+        attrs = SMB_ATTR_NORMAL;               /* FILE_ATTRIBUTE_NORMAL */
+
+    return attrs;
+}
+
 DWORD
 RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
 {
     extern char cm_CachePath[];
     extern cm_config_data_t cm_data;
     extern int smb_hideDotFiles;
-    size_t cm_CachePathLen = strlen(cm_CachePath);
+    size_t CachePathLen;
+    DWORD TempPathLen;
     size_t err;
-    DWORD TempPathLen = ExpandEnvironmentStringsW(L"%TEMP%", NULL, 0);
     MEMORYSTATUSEX memStatus;
     DWORD maxMemoryCacheSize;
+    char FullCachePath[MAX_PATH];
+    char TempPath[MAX_PATH];
+    char FullTempPath[MAX_PATH];
+
+    /*
+     * The %TEMP% environment variable may be relative instead
+     * of absolute which can result in the redirector referring
+     * to a different directory than the service.  The full path
+     * must therefore be obtained first.
+     */
+
+    CachePathLen = GetFullPathNameA(cm_CachePath, MAX_PATH, FullCachePath, NULL);
+    if (CachePathLen == 0) {
+        osi_Log0(afsd_logp, "RDR_SetInitParams Unable to obtain Full Cache Path");
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
+
+    TempPathLen = ExpandEnvironmentStringsA("%TEMP%", TempPath, MAX_PATH);
+    if (TempPathLen == 0) {
+        osi_Log0(afsd_logp, "RDR_SetInitParams Unable to expand %%TEMP%%");
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
+
+    TempPathLen = GetFullPathNameA(TempPath, MAX_PATH, FullTempPath, NULL);
+    if (TempPathLen == 0) {
+        osi_Log0(afsd_logp, "RDR_SetInitParams Unable to obtain Full Temp Path");
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
 
     memStatus.dwLength = sizeof(memStatus);
     if (GlobalMemoryStatusEx(&memStatus)) {
@@ -137,9 +199,11 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
         maxMemoryCacheSize = 65536;
     }
 
-    *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (cm_CachePathLen + TempPathLen) * sizeof(WCHAR));
+    *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (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)->Flags |= cm_directIO ? AFS_REDIR_INIT_PERFORM_SERVICE_IO : 0;
     (*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
     (*ppRedirInitInfo)->GlobalFileId.Cell   = cm_data.rootFid.cell;
     (*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
@@ -150,6 +214,7 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
     (*ppRedirInitInfo)->CacheBlockSize = cm_data.blockSize;
     (*ppRedirInitInfo)->MaxPathLinkCount = MAX_FID_COUNT;
     (*ppRedirInitInfo)->NameArrayLength = MAX_FID_COUNT;
+    (*ppRedirInitInfo)->GlobalReparsePointPolicy = rdr_ReparsePointPolicy;
     if (cm_virtualCache || cm_data.bufferSize <= maxMemoryCacheSize) {
         osi_Log0(afsd_logp, "RDR_SetInitParams Initializing Memory Extent Interface");
         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = (LONGLONG)cm_data.bufDataBaseAddress;
@@ -159,8 +224,8 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
     } else {
         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = 0;
         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = 0;
-        (*ppRedirInitInfo)->CacheFileNameLength = (ULONG) (cm_CachePathLen * sizeof(WCHAR));
-        err = mbstowcs((*ppRedirInitInfo)->CacheFileName, cm_CachePath, (cm_CachePathLen + 1) *sizeof(WCHAR));
+        (*ppRedirInitInfo)->CacheFileNameLength = (ULONG) (CachePathLen * sizeof(WCHAR));
+        err = mbstowcs((*ppRedirInitInfo)->CacheFileName, FullCachePath, (CachePathLen + 1) *sizeof(WCHAR));
         if (err == -1) {
             free(*ppRedirInitInfo);
             osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
@@ -170,9 +235,14 @@ RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRed
     }
     (*ppRedirInitInfo)->DumpFileLocationOffset = FIELD_OFFSET(AFSRedirectorInitInfo, CacheFileName) + (*ppRedirInitInfo)->CacheFileNameLength;
     (*ppRedirInitInfo)->DumpFileLocationLength = (TempPathLen - 1) * sizeof(WCHAR);
-    ExpandEnvironmentStringsW(L"%TEMP%",
-                              (LPWSTR)(((PBYTE)(*ppRedirInitInfo)) + (*ppRedirInitInfo)->DumpFileLocationOffset),
-                              TempPathLen);
+
+    err = mbstowcs((((PBYTE)(*ppRedirInitInfo)) + (*ppRedirInitInfo)->DumpFileLocationOffset),
+                   FullTempPath, (TempPathLen + 1) *sizeof(WCHAR));
+    if (err == -1) {
+        free(*ppRedirInitInfo);
+        osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
+        return STATUS_OBJECT_NAME_INVALID;
+    }
 
     osi_Log0(afsd_logp,"RDR_SetInitParams Success");
     return 0;
@@ -412,7 +482,8 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                 if (code) {
                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RDR_BulkStatLookup failed for scp=0x%p code=0x%x",
                              scp, code);
-                    return code;
+                   if (code != CM_ERROR_NOACCESS)
+                       return code;
                 }
                 lock_ObtainWrite(&scp->rw);
                 /*
@@ -462,7 +533,8 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
 
     pCurrentEntry->EndOfFile = scp->length;
-    pCurrentEntry->AllocationSize = scp->length;
+    pCurrentEntry->AllocationSize.QuadPart =
+       ((scp->length.QuadPart/1024)+1)*1024;
 
     if (bMustFake) {
         switch (scp->fileType) {
@@ -471,6 +543,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
             break;
         case CM_SCACHETYPE_MOUNTPOINT:
         case CM_SCACHETYPE_INVALID:
+        case CM_SCACHETYPE_DFSLINK:
             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
             break;
         case CM_SCACHETYPE_SYMLINK:
@@ -493,7 +566,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                 pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
         }
     } else
-        pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
+        pCurrentEntry->FileAttributes = RDR_ExtAttributes(scp);
     pCurrentEntry->EaSize = 0;
     pCurrentEntry->Links = scp->linkCount;
 
@@ -513,14 +586,12 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
     if (!(dwFlags & RDR_POP_NO_GETSTATUS))
         cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-    if ((dwFlags & RDR_POP_NO_GETSTATUS) || !cm_HaveCallback(scp)) {
-        pCurrentEntry->TargetNameOffset = 0;
-        pCurrentEntry->TargetNameLength = 0;
-    }
-    else
+    pCurrentEntry->TargetNameOffset = 0;
+    pCurrentEntry->TargetNameLength = 0;
+    if (!(dwFlags & RDR_POP_NO_GETSTATUS) && cm_HaveCallback(scp)) {
     switch (scp->fileType) {
     case CM_SCACHETYPE_MOUNTPOINT:
-        if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
+       {
             if ((code2 = cm_ReadMountPoint(scp, userp, reqp)) == 0) {
                 cm_scache_t *targetScp = NULL;
 
@@ -538,23 +609,26 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
 #endif
                 pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
 
-                code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
-
-                if (code2 == 0) {
-                    pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
-                    pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
-                    pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
-                    pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
-                    pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
-
-                    osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
-                              pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
-                              pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
-
-                    cm_ReleaseSCache(targetScp);
-                } else {
-                    osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
-                              scp, code2);
+               if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
+                   code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
+                   if (code2 == 0) {
+                       pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
+                       pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
+                       pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
+                       pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
+                       pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
+
+                       osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+                                 pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
+                                 pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
+
+                       cm_ReleaseSCache(targetScp);
+                   } else {
+                       osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
+                                 scp, code2);
+                       if (code2 == CM_ERROR_TOO_MANY_SYMLINKS)
+                           code = CM_ERROR_TOO_MANY_SYMLINKS;
+                   }
                 }
             } else {
                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_ReadMountPoint failed scp=0x%p code=0x%x",
@@ -569,38 +643,109 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
             wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
 
             if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
-                char * mp;
 
                 code2 = cm_HandleLink(scp, userp, reqp);
                 if (code2 == 0) {
-                    mp = scp->mountPointStringp;
-                    len = strlen(mp);
-                    if ( len != 0 ) {
-                        /* Strip off the msdfs: prefix from the target name for the file system */
-                        if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
-                            osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
-                            pCurrentEntry->FileType = scp->fileType;
-
-                            if (!strncmp("msdfs:", mp, 6)) {
-                                mp += 6;
-                                len -= 6;
-                            }
+                    if (scp->mountPointStringp[0]) {
+                        char * mp;
+                        char * s;
+                        size_t offset = 0;
+                       size_t wtarget_len = 0;
+
+                        len = strlen(scp->mountPointStringp) + 1;
+                        mp = strdup(scp->mountPointStringp);
+
+                        for (s=mp; *s; s++) {
+                            if (*s == '/')
+                                *s = '\\';
                         }
-                        /* only send one slash to the redirector */
-                        if (mp[0] == '\\' && mp[1] == '\\') {
-                            mp++;
-                            len--;
+
+                        if (strncmp("msdfs:", mp, 6) == 0) {
+                            offset = 6;
                         }
+
+
+                        if ( mp[offset + 1] == ':' && mp[offset] != '\\') {
+                            /* Local drive letter.  Must return <drive>:\<path> */
+                            pCurrentEntry->FileType = CM_SCACHETYPE_DFSLINK;
+                            wtarget_len = len - offset;
 #ifdef UNICODE
-                        cch = MultiByteToWideChar( CP_UTF8, 0, mp,
-                                                   len * sizeof(char),
-                                                   wtarget,
-                                                   len * sizeof(WCHAR));
+                            cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                       wtarget_len * sizeof(char),
+                                                       wtarget,
+                                                       wtarget_len * sizeof(WCHAR));
 #else
-                        mbstowcs(wtarget, mp, len);
+                            mbstowcs(wtarget, &mp[offset], wtarget_len);
 #endif
-                    }
-                    pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
+                        } else if (mp[offset] == '\\') {
+                            size_t nbNameLen = strlen(cm_NetbiosName);
+
+                            if ( strnicmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
+                                 mp[offset + nbNameLen + 1] == '\\')
+                            {
+                                /* an AFS symlink */
+                                pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+                                wtarget_len = len - offset;
+#ifdef UNICODE
+                                cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                           wtarget_len * sizeof(char),
+                                                           wtarget,
+                                                           wtarget_len * sizeof(WCHAR));
+#else
+                                mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+                            } else if ( mp[offset + 1] == '\\' &&
+                                        strnicmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
+                                        mp[offset + nbNameLen + 2] == '\\')
+                            {
+                                /* an AFS symlink */
+                                pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+                                wtarget_len = len - offset - 1;
+#ifdef UNICODE
+                                cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset + 1],
+                                                           wtarget_len * sizeof(char),
+                                                           wtarget,
+                                                           wtarget_len * sizeof(WCHAR));
+#else
+                                mbstowcs(wtarget, &mp[offset + 1], wtarget_len);
+#endif
+                            } else {
+                                /*
+                                 * treat as a UNC path. Needs to be \<server>\<share\<path>
+                                 */
+                                pCurrentEntry->FileType = CM_SCACHETYPE_DFSLINK;
+
+                                if ( mp[offset] == '\\' && mp[offset + 1] == '\\')
+                                     offset++;
+
+                                wtarget_len = len - offset;
+#ifdef UNICODE
+                                cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                           wtarget_len * sizeof(char),
+                                                           wtarget,
+                                                           wtarget_len * sizeof(WCHAR));
+#else
+                                mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+                            }
+                        } else {
+                            /* Relative AFS Symlink */
+                            pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+                            wtarget_len = len - offset;
+#ifdef UNICODE
+                            cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+                                                       wtarget_len * sizeof(char),
+                                                       wtarget,
+                                                       wtarget_len * sizeof(WCHAR));
+#else
+                            mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+                        }
+
+                        free(mp);
+
+                       pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * (wtarget_len - 1));
+                   }
                 } else {
                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
                              scp, code2);
@@ -614,6 +759,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
         pCurrentEntry->TargetNameOffset = 0;
         pCurrentEntry->TargetNameLength = 0;
     }
+    }
     lock_ReleaseWrite(&scp->rw);
 
     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
@@ -681,8 +827,6 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
     pCurrentEntry->FileId.Unique = fidp->unique;
     pCurrentEntry->FileId.Hash = fidp->hash;
 
-    pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
-
     pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
 
     cm_LargeSearchTimeFromUnixTime(&ft, 0);
@@ -698,8 +842,14 @@ RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
 
     pCurrentEntry->EndOfFile.QuadPart = 0;
     pCurrentEntry->AllocationSize.QuadPart = 0;
-    pCurrentEntry->FileAttributes = 0;
+    if (fidp->vnode & 0x1) {
+        pCurrentEntry->FileType = CM_SCACHETYPE_DIRECTORY;
+        pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
+    } else {
+        pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
+        pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
     pCurrentEntry->EaSize = 0;
+    }
     pCurrentEntry->Links = 0;
 
     len = wcslen(shortName);
@@ -748,9 +898,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,9 +1044,10 @@ 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),
+                                                    (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0) |
+                                                    RDR_POP_EVALUATE_SYMLINKS,
                                                      code,
                                                      &pCurrentEntry, &dwMaxEntryLength);
                     cm_ReleaseSCache(scp);
@@ -906,7 +1055,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);
@@ -954,9 +1103,10 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
                         IN WCHAR   *FileNameCounted,
                         IN DWORD    FileNameLength,
                         IN BOOL     CaseSensitive,
+                        IN BOOL     LastComponent,
                         IN BOOL     bWow64,
-                        IN BOOL     bHoldFid,
                         IN BOOL     bNoFollow,
+                        IN BOOL     bHoldFid,
                         IN DWORD    ResultBufferLength,
                         IN OUT AFSCommResult **ResultCB)
 {
@@ -974,18 +1124,17 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
     size_t        cbName;
     BOOL          bVol = FALSE;
     wchar_t       FileName[260];
+    afs_uint32    lookupFlags;
 
     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");
@@ -1060,24 +1209,60 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
         return;
     }
 
-    code = cm_Lookup(dscp, wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+    lookupFlags = CM_FLAG_NOMOUNTCHASE;
+
+    if ( !LastComponent )
+        lookupFlags |= CM_FLAG_CHECKPATH;
+    code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
+
+    if (!CaseSensitive &&
+        (code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)) {
+        lookupFlags |= CM_FLAG_CASEFOLD;
+        code = cm_Lookup(dscp, wszName, lookupFlags, 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);
+        }
+#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);
+            code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+        }
+#endif
     }
 
     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,14 +1272,15 @@ 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,
                                         dscp, scp, userp, &req,
                                         FileName, shortName,
                                         (bWow64 ? RDR_POP_WOW64 : 0) |
-                                        (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
+                                       (bNoFollow ? 0 : RDR_POP_FOLLOW_MOUNTPOINTS) |
+                                       RDR_POP_EVALUATE_SYMLINKS,
                                         0, NULL, &dwRemaining);
         if (bHoldFid)
             RDR_FlagScpInUse( scp, FALSE );
@@ -1168,9 +1354,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);
@@ -1252,7 +1436,8 @@ RDR_EvaluateNodeByID( IN cm_user_t *userp,
     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)),
+                                   (bNoFollow ? 0 : RDR_POP_FOLLOW_MOUNTPOINTS) |
+                                   RDR_POP_EVALUATE_SYMLINKS,
                                     0, NULL, &dwRemaining);
 
     if (bHoldFid)
@@ -1304,9 +1489,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 +1601,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 +1657,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",
@@ -1512,7 +1695,6 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
     }
 
     lock_ObtainWrite(&dscp->rw);
-    bScpLocked = TRUE;
     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) {
@@ -1527,7 +1709,6 @@ RDR_UpdateFileEntry( IN cm_user_t *userp,
 
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     lock_ReleaseWrite(&dscp->rw);
-    bScpLocked = FALSE;
 
     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
@@ -1688,9 +1869,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",
@@ -1777,7 +1956,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;
@@ -1843,21 +2022,30 @@ 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);
-                    bScpLocked = FALSE;
+                cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
+
+                code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+                                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+                /*
+                 * If we only have 'i' bits, then we should still be able to
+                 * set flush the file.
+                 */
+                if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
+                    code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
+                                     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 = cm_FSync(scp, userp, &req, bScpLocked);
+                }
             }
             if (bLastHandle && code)
                 goto unlock;
@@ -1912,8 +2100,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;
@@ -1964,7 +2154,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
             bScpLocked = TRUE;
         }
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+                        CM_SCACHESYNC_LOCK);
         if (code) {
             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp (2) failure scp=0x%p code=0x%x",
                      scp, code);
@@ -1978,7 +2168,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
                               userp, &req);
 
-        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
 
         if (code)
             goto on_error;
@@ -2062,9 +2252,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);
@@ -2121,7 +2309,7 @@ RDR_DeleteFileEntry( IN cm_user_t *userp,
     }
 
     code = cm_Lookup(dscp, FileName, 0, userp, &req, &scp);
-    if (code) {
+    if (code && code != CM_ERROR_INEXACT_MATCH) {
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
         (*ResultCB)->ResultStatus = status;
         (*ResultCB)->ResultBufferLength = 0;
@@ -2146,10 +2334,41 @@ RDR_DeleteFileEntry( IN cm_user_t *userp,
         return;
     }
 
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+        cm_dirOp_t dirop;
+
+        lock_ReleaseWrite(&scp->rw);
+
+        code = cm_BeginDirOp(scp, userp, &req, CM_DIRLOCK_READ,
+                             CM_DIROP_FLAG_NONE, &dirop);
+        if (code == 0) {
+            /* is the directory empty? if not, CM_ERROR_NOTEMPTY */
+            afs_uint32 bEmpty;
+
+            code = cm_BPlusDirIsEmpty(&dirop, &bEmpty);
+            if (code == 0 && !bEmpty)
+                code = CM_ERROR_NOTEMPTY;
+
+            cm_EndDirOp(&dirop);
+        }
+
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            (*ResultCB)->ResultBufferLength = 0;
+            cm_ReleaseSCache(scp);
+            cm_ReleaseSCache(dscp);
+            osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                     scp, code, status);
+            return;
+        }
+        lock_ObtainWrite(&scp->rw);
+    }
+
     if (!bCheckOnly) {
         /* Drop all locks since the file is being deleted */
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+                        CM_SCACHESYNC_LOCK);
         if (code) {
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
             (*ResultCB)->ResultStatus = status;
@@ -2168,7 +2387,7 @@ RDR_DeleteFileEntry( IN cm_user_t *userp,
                               CM_UNLOCK_FLAG_BY_FID,
                               userp, &req);
 
-        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
         lock_ReleaseWrite(&scp->rw);
 
         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
@@ -2235,9 +2454,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));
@@ -2380,7 +2597,7 @@ RDR_RenameFileEntry( IN cm_user_t *userp,
             cm_EndDirOp(&dirop);
         }
 
-        if (code != 0) {
+       if (code != 0 && code != CM_ERROR_INEXACT_MATCH) {
             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_BPlusDirLookup failed code 0x%x",
                      code);
             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
@@ -2421,13 +2638,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,98 +2669,710 @@ 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_FlushFileEntry( IN cm_user_t *userp,
-                    IN AFSFileID FileId,
-                    IN BOOL bWow64,
-                    IN DWORD ResultBufferLength,
-                    IN OUT AFSCommResult **ResultCB)
+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)
 {
-    cm_scache_t *scp = NULL;
-    cm_fid_t    Fid;
-    afs_uint32  code;
-    cm_req_t    req;
-    DWORD       status;
-#ifdef ODS_DEBUG
-    char        dbgstr[1024];
-#endif
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    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);
 
-    osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
-              FileId.Cell, FileId.Volume,
-              FileId.Vnode, FileId.Unique);
-#ifdef ODS_DEBUG
-    snprintf( dbgstr, 1024,
-              "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
-              FileId.Cell, FileId.Volume,
-              FileId.Vnode, FileId.Unique);
-    OutputDebugStringA( dbgstr);
-#endif
+    StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
+    StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
 
-    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
-    if (!(*ResultCB)) {
-        osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
+    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',
-            sizeof( AFSCommResult));
+            size);
 
-    /* Process the release */
-    Fid.cell = FileId.Cell;
-    Fid.volume = FileId.Volume;
-    Fid.vnode = FileId.Vnode;
-    Fid.unique = FileId.Unique;
-    Fid.hash = FileId.Hash;
+    pResultCB = (AFSFileHardLinkResultCB *)(*ResultCB)->ResultData;
 
-    code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
+    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;
-        osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
-                  code, status);
         return;
     }
 
-    lock_ObtainWrite(&scp->rw);
-    if (scp->flags & CM_SCACHEFLAG_DELETED) {
-        lock_ReleaseWrite(&scp->rw);
-        (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
+    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;
     }
 
-    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+    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(&scp->rw);
-        cm_ReleaseSCache(scp);
-        osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
-                 scp, code, status);
+        lock_ReleaseWrite(&targetDscp->rw);
+        cm_ReleaseSCache(srcScp);
+        cm_ReleaseSCache(targetDscp);
         return;
     }
 
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    lock_ReleaseWrite(&scp->rw);
-
-    code = cm_FSync(scp, userp, &req, FALSE);
-    cm_ReleaseSCache(scp);
+    cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&targetDscp->rw);
 
-    if (code) {
-        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-        (*ResultCB)->ResultStatus = status;
-        osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
-                  code, status);
-    } else {
-        (*ResultCB)->ResultStatus = 0;
-        osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
+    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;
     }
-    (*ResultCB)->ResultBufferLength = 0;
+
+    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 && code != CM_ERROR_INEXACT_MATCH) {
+            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_CreateSymlinkEntry( IN cm_user_t *userp,
+                        IN AFSFileID FileId,
+                        IN WCHAR *FileNameCounted,
+                        IN DWORD FileNameLength,
+                        IN AFSCreateSymlinkCB *SymlinkCB,
+                        IN BOOL bWow64,
+                        IN DWORD ResultBufferLength,
+                        IN OUT AFSCommResult **ResultCB)
+{
+    AFSCreateSymlinkResultCB *pResultCB = NULL;
+    size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+    cm_fid_t            parentFid;
+    cm_fid_t            Fid;
+    afs_uint32          code;
+    cm_scache_t *       dscp = NULL;
+    afs_uint32          flags = 0;
+    cm_attr_t           setAttr;
+    cm_scache_t *       scp = NULL;
+    cm_req_t            req;
+    DWORD               status;
+    wchar_t             FileName[260];
+    char               *TargetPath = NULL;
+
+    StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
+    TargetPath = cm_Utf16ToUtf8Alloc( SymlinkCB->TargetName,  SymlinkCB->TargetNameLength / sizeof(WCHAR), NULL);
+
+    osi_Log4( afsd_logp, "RDR_CreateSymlinkEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              SymlinkCB->ParentId.Cell, SymlinkCB->ParentId.Volume,
+              SymlinkCB->ParentId.Vnode, SymlinkCB->ParentId.Unique);
+    osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
+
+    RDR_InitReq(&req, bWow64);
+    memset(&setAttr, 0, sizeof(cm_attr_t));
+
+    *ResultCB = (AFSCommResult *)malloc(size);
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry out of memory");
+        free(TargetPath);
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            size);
+
+    parentFid.cell   = SymlinkCB->ParentId.Cell;
+    parentFid.volume = SymlinkCB->ParentId.Volume;
+    parentFid.vnode  = SymlinkCB->ParentId.Vnode;
+    parentFid.unique = SymlinkCB->ParentId.Unique;
+    parentFid.hash   = SymlinkCB->ParentId.Hash;
+
+    code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
+    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_CreateSymlinkEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
+                  code, status);
+        free(TargetPath);
+        return;
+    }
+
+    lock_ObtainWrite(&dscp->rw);
+    code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&dscp->rw);
+        cm_ReleaseSCache(dscp);
+        osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
+                 dscp, code, status);
+        free(TargetPath);
+        return;
+    }
+
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&dscp->rw);
+
+    if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+        cm_ReleaseSCache(dscp);
+        osi_Log1(afsd_logp, "RDR_CreateSymlinkEntry Not a Directory dscp=0x%p",
+                 dscp);
+        free(TargetPath);
+        return;
+    }
+
+    Fid.cell   = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode  = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash   = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
+    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_CreateSymlinkEntry cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        free(TargetPath);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        free(TargetPath);
+        return;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&scp->rw);
+
+    /* Remove the temporary object */
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+        code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
+    else
+        code = cm_Unlink(dscp, NULL, FileName, userp, &req);
+    cm_ReleaseSCache(scp);
+    scp = NULL;
+    if (code && code != CM_ERROR_NOSUCHFILE) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        cm_ReleaseSCache(dscp);
+        osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry Unable to delete file dscp=0x%p code=0x%x",
+                 dscp, code);
+        free(TargetPath);
+        return;
+    }
+
+    /*
+     * The target path is going to be provided by the redirector in one of the following forms:
+     *
+     * 1. Relative path.
+     * 2. Absolute path prefaced as \??\UNC\<server>\<share>\<path>
+     * 3. Absolute path prefaced as \??\<drive-letter>:\<path>
+     *
+     * Relative paths can be used with just slash conversion.  Absolute paths must be converted.
+     * UNC paths with a server name that matches cm_NetbiosName then the path is an AFS path and
+     * it must be converted to /<server>/<share>/<path>.  Other UNC paths must be converted to
+     * msdfs:\\<server>\<share>\<path>.  Local disk paths should be converted to
+     * msdfs:<drive-letter>:<path>.
+     */
+
+    if ( TargetPath[0] == '\\' ) {
+        size_t nbNameLen = strlen(cm_NetbiosName);
+        size_t len;
+        char  *s;
+
+        if ( strncmp(TargetPath, "\\??\\UNC\\", 8) == 0) {
+
+            if (strncmp(&TargetPath[8], cm_NetbiosName, nbNameLen) == 0 &&
+                TargetPath[8 + nbNameLen] == '\\')
+            {
+                /* AFS path */
+                s = strdup(&TargetPath[8 + nbNameLen]);
+                free(TargetPath);
+                TargetPath = s;
+                for (; *s; s++) {
+                    if (*s == '\\')
+                        *s = '/';
+                }
+            } else {
+                /*
+                 * non-AFS UNC path (msdfs:\\server\share\path)
+                 * strlen("msdfs:\\") == 7 + 1 for the NUL
+                 */
+                len = 8 + strlen(&TargetPath[7]);
+                s = malloc(8 + strlen(&TargetPath[7]));
+                StringCbCopy(s, len, "msdfs:\\");
+                StringCbCat(s, len, &TargetPath[7]);
+                free(TargetPath);
+                TargetPath = s;
+            }
+        } else {
+            /* non-UNC path (msdfs:<drive>:\<path> */
+            s = strdup(&TargetPath[4]);
+            free(TargetPath);
+            TargetPath = s;
+        }
+
+    } else {
+        /* relative paths require slash conversion */
+        char *s = TargetPath;
+        for (; *s; s++) {
+            if (*s == '\\')
+                *s = '/';
+        }
+    }
+
+    /* Use current time */
+    setAttr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
+    setAttr.unixModeBits = 0755;
+    setAttr.clientModTime = time(NULL);
+
+    code = cm_SymLink(dscp, FileName, TargetPath, flags, &setAttr, userp, &req, &scp);
+    free(TargetPath);
+
+    if (code == 0) {
+        wchar_t shortName[13]=L"";
+        cm_dirFid_t dfid;
+        DWORD dwRemaining;
+
+        if (dscp->flags & CM_SCACHEFLAG_ANYWATCH) {
+            smb_NotifyChange(FILE_ACTION_ADDED,
+                             FILE_NOTIFY_CHANGE_DIR_NAME,
+                             dscp, FileName, NULL, TRUE);
+        }
+
+        (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
+
+        (*ResultCB)->ResultBufferLength = sizeof( AFSCreateSymlinkResultCB);
+
+        pResultCB = (AFSCreateSymlinkResultCB *)(*ResultCB)->ResultData;
+
+        dwRemaining = ResultBufferLength - sizeof( AFSCreateSymlinkResultCB) + sizeof( AFSDirEnumEntry);
+
+        lock_ObtainWrite(&dscp->rw);
+        code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            lock_ReleaseWrite(&dscp->rw);
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseSCache(scp);
+            osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
+                      dscp, code, status);
+            return;
+        }
+
+        pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
+        cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&dscp->rw);
+
+        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';
+        }
+
+        code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
+                                        dscp, scp, userp, &req, FileName, shortName,
+                                        RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
+                                        0, NULL, &dwRemaining);
+        cm_ReleaseSCache(scp);
+        (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+        osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry SUCCESS");
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_FILE_DELETED;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry FAILURE code=0x%x status=0x%x",
+                  code, STATUS_FILE_DELETED);
+    }
+
+    cm_ReleaseSCache(dscp);
+
+    return;
+}
+
+
+void
+RDR_FlushFileEntry( IN cm_user_t *userp,
+                    IN AFSFileID FileId,
+                    IN BOOL bWow64,
+                    IN DWORD ResultBufferLength,
+                    IN OUT AFSCommResult **ResultCB)
+{
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+#ifdef ODS_DEBUG
+    char        dbgstr[1024];
+#endif
+
+    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,
+              FileId.Vnode, FileId.Unique);
+#ifdef ODS_DEBUG
+    snprintf( dbgstr, 1024,
+              "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+    OutputDebugStringA( dbgstr);
+#endif
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
+       return;
+    }
+
+    memset( *ResultCB,
+            '\0',
+            sizeof( AFSCommResult));
+
+    /* 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, NULL, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    lock_ObtainWrite(&scp->rw);
+    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseWrite(&scp->rw);
+        (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
+        return;
+    }
+
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    lock_ReleaseWrite(&scp->rw);
+
+    code = cm_FSync(scp, userp, &req, FALSE);
+    cm_ReleaseSCache(scp);
+
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
+                  code, status);
+    } else {
+        (*ResultCB)->ResultStatus = 0;
+        osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
+    }
+    (*ResultCB)->ResultBufferLength = 0;
 
     return;
 }
@@ -2647,9 +3478,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,
@@ -2740,6 +3569,8 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
                                   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));
     }
@@ -2825,9 +3656,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,
@@ -2944,8 +3773,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;
@@ -2973,15 +3801,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.
@@ -3001,7 +3826,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;
@@ -3020,7 +3845,7 @@ RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_
             rwheld = 0;
         }
 
-        code = buf_Get(scp, &offset, reqp, &bufp);
+        code = buf_Get(scp, &offset, reqp, 0, &bufp);
         if (code) {
             /*
              * any error from buf_Get() is non-fatal.
@@ -3117,6 +3942,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 +4016,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",
@@ -3256,7 +4082,7 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
         QueueLength = 0;
         thyper.QuadPart = ByteOffset.QuadPart;
 
-        code = buf_Get(scp, &thyper, &req, &bufp);
+        code = buf_Get(scp, &thyper, &req, 0,  &bufp);
         if (code == 0) {
             lock_ObtainMutex(&bufp->mx);
             bBufRelease = TRUE;
@@ -3265,24 +4091,6 @@ RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
                 bHaveBuffer = TRUE;
             } else if (bufp->flags & CM_BUF_DIRTY) {
                 bHaveBuffer = FALSE;
-#if 0
-                code = buf_CleanAsyncLocked(scp, bufp, &req, 0, NULL);
-                switch (code) {
-                case 0:
-                    bHaveBuffer = TRUE;
-                    break;
-                case CM_ERROR_RETRY:
-                    /* Couldn't flush it, obtain it asynchronously so we don't block the thread. */
-                    bHaveBuffer = FALSE;
-                    code = 0;
-                    break;
-                default:
-                    smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
-                    RDR_SetFileStatus(&FileId, &userp->authgroup, status);
-                    bHaveBuffer = FALSE;
-                    code = 0;
-                }
-#endif
             } else {
                 osi_hyper_t minLength;  /* effective end of file */
 
@@ -3392,10 +4200,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 */
@@ -3406,11 +4225,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));
+
+        if (rockp) {
+            req.flags &= ~CM_REQ_NORETRY;
+            rockp->base = BeginOffset;
+            rockp->length.LowPart = length;
+            rockp->length.HighPart = 0;
 
-        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);
+            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);
 
@@ -3445,6 +4273,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];
@@ -3452,9 +4281,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 +4662,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,10 +4697,16 @@ 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);
+            if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
+                code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
+                                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            }
             lock_ReleaseWrite(&scp->rw);
             if (code == 0)
                 code = cm_FSync(scp, userp, &req, FALSE);
@@ -3889,6 +4719,10 @@ RDR_ReleaseFileExtents( IN cm_user_t *userp,
             lock_ObtainWrite(&scp->rw);
             code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
+                code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
+                                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            }
             lock_ReleaseWrite(&scp->rw);
             if (code == 0) {
                 /*
@@ -3901,15 +4735,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);
@@ -3942,13 +4793,14 @@ 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];
 #endif
     char dbgstr[1024];
 #endif
-    RDR_InitReq(&req);
+    RDR_InitReq(&req, FALSE);
 
     for ( fileno = 0, pNextFileCB = &ReleaseFileExtentsResultCB->Files[0];
           fileno < ReleaseFileExtentsResultCB->FileCount;
@@ -4241,10 +5093,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 +5152,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 {
@@ -4353,15 +5200,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",
@@ -4404,7 +5268,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 +5342,9 @@ RDR_PioctlOpen( IN cm_user_t *userp,
 {
     cm_fid_t    ParentFid;
     cm_fid_t    RootFid;
+    cm_req_t    req;
+
+    cm_InitReq(&req);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
     if (!(*ResultCB))
@@ -4502,7 +5369,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 +5412,7 @@ RDR_PioctlWrite( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req);
-    if ( bWow64 )
-        req.flags |= CM_REQ_WOW64;
+    cm_InitReq(&req);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
     if (!(*ResultCB))
@@ -4559,7 +5424,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 +5451,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;
+    cm_InitReq(&req);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
     if (!(*ResultCB))
@@ -4601,7 +5464,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 +5495,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,
@@ -4683,7 +5544,7 @@ RDR_ByteRangeLockSync( IN cm_user_t     *userp,
 
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+                    CM_SCACHESYNC_LOCK);
     if (code) {
         lock_ReleaseWrite(&scp->rw);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
@@ -4731,7 +5592,7 @@ RDR_ByteRangeLockSync( IN cm_user_t     *userp,
         }
     }
 
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
@@ -4761,9 +5622,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,
@@ -4811,7 +5670,7 @@ RDR_ByteRangeUnlock( IN cm_user_t     *userp,
 
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+                    CM_SCACHESYNC_LOCK);
     if (code) {
         lock_ReleaseWrite(&scp->rw);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
@@ -4849,7 +5708,7 @@ RDR_ByteRangeUnlock( IN cm_user_t     *userp,
         pResultCB->Result[i].Status = status;
     }
 
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
@@ -4877,9 +5736,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,
@@ -4914,7 +5771,7 @@ RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
 
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+                    CM_SCACHESYNC_LOCK);
     if (code) {
         lock_ReleaseWrite(&scp->rw);
         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
@@ -4930,7 +5787,7 @@ RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
 
     code = cm_UnlockByKey(scp, key, 0, userp, &req);
 
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
@@ -4956,9 +5813,7 @@ 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;
     afs_uint32  code;
     cm_req_t    req;
@@ -4974,10 +5829,9 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     char *OfflineMsg;
     char *MOTD;
     struct rx_connection * rxconnp;
+    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 +5871,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;
@@ -5036,8 +5879,8 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     pResultCB->CellID = scp->fid.cell;
     pResultCB->VolumeID = scp->fid.volume;
     pResultCB->Characteristics = FILE_REMOTE_DEVICE;
-    pResultCB->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK |
-        FILE_SUPPORTS_REPARSE_POINTS;
+    pResultCB->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
+        FILE_UNICODE_ON_DISK | 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)
@@ -5046,83 +5889,146 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
 
         pResultCB->AvailableAllocationUnits.QuadPart = 0;
-        pResultCB->Characteristics |= FILE_READ_ONLY_DEVICE;
+        if (cm_volumeInfoReadOnlyFlag)
+            pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
         pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
                                                        (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
         if ( pResultCB->VolumeLabelLength )
             pResultCB->VolumeLabelLength--;
-    } else {
-        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
 
-        volp = cm_GetVolumeByFID(&scp->fid);
-        if (!volp) {
+        pResultCB->CellLength = cm_Utf8ToUtf16( "Freelance.Local", -1, pResultCB->Cell,
+                                                (sizeof(pResultCB->Cell) / sizeof(WCHAR)) + 1);
+        if ( pResultCB->CellLength )
+            pResultCB->CellLength--;
+    } else {
+       volp = cm_FindVolumeByFID(&scp->fid, userp, &req);
+       if (!volp) {
             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);
+        if (cm_volumeInfoReadOnlyFlag && (volType == ROVOL || volType == BACKVOL))
+            pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
-        Name = volName;
-       OfflineMsg = offLineMsg;
-       MOTD = motd;
-       lock_ReleaseWrite(&scp->rw);
-       do {
-           code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
-           if (code) continue;
+        code = -1;
 
-           rxconnp = cm_GetRxConn(connp);
-           code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
-                                        &volStat, &Name, &OfflineMsg, &MOTD);
-           rx_PutConnection(rxconnp);
+        if ( volType == ROVOL &&
+             (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
+        {
+            lock_ObtainRead(&volp->rw);
+            if (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID) {
+                volStat.BlocksInUse = volp->volumeSizeRO / 1024;
+                code = 0;
+            }
+            lock_ReleaseRead(&volp->rw);
+        }
+        
+        if (code == -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 && volType == ROVOL)
+           {
+               lock_ObtainWrite(&volp->rw);
+               volp->volumeSizeRO = volStat.BlocksInUse * 1024;
+               _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_SIZE_VALID);
+               lock_ReleaseWrite(&volp->rw);
+            }
+        }
+
+        if ( scp->volumeCreationDate )
+            cm_LargeSearchTimeFromUnixTime(&ft, scp->volumeCreationDate);
+        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
 
-       } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, 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;
                 }
             }
-        } else {
+       } else if ( code != CM_ERROR_ALLBUSY &&
+                   code != CM_ERROR_ALLOFFLINE &&
+                   code != CM_ERROR_ALLDOWN)
+       {
+            /*
+             * 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) {
+
+            /* add .readonly and .backup if appropriate */
+            switch ( volType) {
+            case ROVOL:
+                pResultCB->VolumeLabelLength--;
+                pResultCB->VolumeLabelLength += cm_Utf8ToUtf16( ".readonly", -1,
+                                                                &pResultCB->VolumeLabel[ pResultCB->VolumeLabelLength],
+                                                                (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) - pResultCB->VolumeLabelLength + 1);
+                break;
+
+            case BACKVOL:
+                pResultCB->VolumeLabelLength--;
+                pResultCB->VolumeLabelLength += cm_Utf8ToUtf16( ".backup", -1,
+                                                                &pResultCB->VolumeLabel[ pResultCB->VolumeLabelLength],
+                                                                (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) - pResultCB->VolumeLabelLength + 1);
+                break;
+            }
+        }
+
+        /* do not include the trailing nul */
         if ( pResultCB->VolumeLabelLength )
             pResultCB->VolumeLabelLength--;
 
-        lock_ObtainWrite(&scp->rw);
+        pResultCB->CellLength = cm_Utf8ToUtf16( volp->cellp->name, -1, pResultCB->Cell,
+                                                (sizeof(pResultCB->Cell) / sizeof(WCHAR)) + 1);
+
+        /* do not include the trailing nul */
+        if ( pResultCB->CellLength )
+            pResultCB->CellLength--;
     }
     pResultCB->VolumeLabelLength *= sizeof(WCHAR);  /* convert to bytes from chars */
-
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    pResultCB->CellLength *= sizeof(WCHAR);         /* convert to bytes from chars */
 
   _done:
-    lock_ReleaseWrite(&scp->rw);
+    if (scp_locked)
+        lock_ReleaseWrite(&scp->rw);
     if (volp)
        cm_PutVolume(volp);
     cm_ReleaseSCache(scp);
@@ -5145,7 +6051,6 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
     cm_scache_t *scp = NULL;
     cm_volume_t *volp = NULL;
     afs_uint32   volType;
-    cm_cell_t   *cellp = NULL;
     cm_fid_t    Fid;
     afs_uint32  code;
     cm_req_t    req;
@@ -5160,10 +6065,9 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
     char *OfflineMsg;
     char *MOTD;
     struct rx_connection * rxconnp;
+    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,87 +6107,98 @@ 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;
     } else {
-        volp = cm_GetVolumeByFID(&scp->fid);
-        if (!volp) {
+       volp = cm_FindVolumeByFID(&scp->fid, userp, &req);
+       if (!volp) {
             code = CM_ERROR_NOSUCHVOLUME;
             goto _done;
         }
 
         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 = -1;
+
+        if ( volType == ROVOL &&
+             (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
+        {
+            lock_ObtainRead(&volp->rw);
+            if (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID) {
+                volStat.BlocksInUse = volp->volumeSizeRO / 1024;
+                code = 0;
+            }
+            lock_ReleaseRead(&volp->rw);
+        }
+        
+        if (code == -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 && volType == ROVOL)
+           {
+               lock_ObtainWrite(&volp->rw);
+               volp->volumeSizeRO = volStat.BlocksInUse * 1024;
+               _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_SIZE_VALID);
+               lock_ReleaseWrite(&volp->rw);
+            }
+        }
+
         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;
                 }
             }
         } 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);
-
   _done:
-    lock_ReleaseWrite(&scp->rw);
+    if (scp_locked)
+        lock_ReleaseWrite(&scp->rw);
     if (volp)
        cm_PutVolume(volp);
     cm_ReleaseSCache(scp);
@@ -5306,7 +6221,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 +6281,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 +6444,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 +6482,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 +6517,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 +6547,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 +6613,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))
@@ -5738,3 +6643,314 @@ RDR_PipeTransceive( IN cm_user_t     *userp,
     (*ResultCB)->ResultStatus = 0;
     osi_Log0(afsd_logp, "RDR_Pipe_Transceive SUCCESS");
 }
+
+void
+RDR_ReadFile( IN cm_user_t     *userp,
+              IN AFSFileID      FileID,
+              IN LARGE_INTEGER *Offset,
+              IN ULONG          BytesToRead,
+              IN PVOID          Buffer,
+              IN BOOL           bWow64,
+              IN BOOL           bCacheBypass,
+              IN DWORD          ResultBufferLength,
+              IN OUT AFSCommResult **ResultCB)
+{
+    AFSFileIOResultCB * pFileIOResultCB;
+    DWORD         status;
+    ULONG         Length;
+    ULONG         ulBytesRead = 0;
+    afs_uint32    code = 0;
+    cm_fid_t      fid;
+    cm_scache_t * scp = NULL;
+    cm_req_t      req;
+
+    RDR_InitReq(&req, bWow64);
+
+    osi_Log4(afsd_logp, "RDR_ReadFile FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+             FileID.Cell, FileID.Volume, FileID.Vnode, FileID.Unique);
+
+    Length = sizeof(AFSFileIOResultCB);
+    if (Length > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+    *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+    (*ResultCB)->ResultBufferLength = Length;
+    pFileIOResultCB = (AFSFileIOResultCB *)(*ResultCB)->ResultData;
+
+    if ( Buffer == NULL) {
+        (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
+        osi_Log0(afsd_logp, "RDR_ReadFile Null IOctl Buffer");
+        return;
+    }
+
+    if (FileID.Cell != 0) {
+        fid.cell   = FileID.Cell;
+        fid.volume = FileID.Volume;
+        fid.vnode  = FileID.Vnode;
+        fid.unique = FileID.Unique;
+        fid.hash   = FileID.Hash;
+
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_ReadFile cm_GetSCache failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_ReadFile Object Name Invalid - Cell = 0");
+        return;
+    }
+
+    /* Ensure that the caller can access this file */
+    lock_ObtainWrite(&scp->rw);
+    code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log2(afsd_logp, "RDR_ReadFile cm_SyncOp failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_FILE_IS_A_DIRECTORY;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log1(afsd_logp, "RDR_ReadFile File is a Directory scp=0x%p",
+                 scp);
+        return;
+    }
+
+    if (scp->fileType != CM_SCACHETYPE_FILE) {
+        (*ResultCB)->ResultStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log1(afsd_logp, "RDR_ReadFile File is a MountPoint or Link scp=0x%p",
+                 scp);
+        return;
+    }
+
+    if ( bCacheBypass) {
+        //
+        // Read the file directly into the buffer bypassing the AFS Cache
+        //
+        code = cm_GetData( scp, Offset, Buffer, BytesToRead, &ulBytesRead, userp, &req);
+    } else {
+        //
+        // Read the file via the AFS Cache
+        //
+        code = raw_ReadData( scp, Offset, BytesToRead, Buffer, &ulBytesRead, userp, &req);
+    }
+
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_ReadFile failure code=0x%x status=0x%x",
+                 code, status);
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+        pFileIOResultCB->Length = ulBytesRead;
+        pFileIOResultCB->DataVersion.QuadPart = scp->dataVersion;
+        pFileIOResultCB->Expiration.QuadPart = scp->cbExpires;
+    }
+
+    lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
+    return;
+}
+
+void
+RDR_WriteFile( IN cm_user_t     *userp,
+               IN AFSFileID      FileID,
+               IN AFSFileIOCB   *FileIOCB,
+               IN LARGE_INTEGER *Offset,
+               IN ULONG          BytesToWrite,
+               IN PVOID          Buffer,
+               IN BOOL           bWow64,
+               IN BOOL           bCacheBypass,
+               IN DWORD          ResultBufferLength,
+               IN OUT AFSCommResult **ResultCB)
+{
+    AFSFileIOResultCB * pFileIOResultCB;
+    DWORD         status;
+    ULONG         Length;
+    ULONG         ulBytesWritten = 0;
+    afs_uint32    code = 0;
+    cm_fid_t      fid;
+    cm_scache_t * scp = NULL;
+    cm_req_t      req;
+
+    RDR_InitReq(&req, bWow64);
+
+    osi_Log4(afsd_logp, "RDR_WriteFile FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+             FileID.Cell, FileID.Volume, FileID.Vnode, FileID.Unique);
+
+    Length = sizeof(AFSFileIOResultCB);
+    if (Length > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+    *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+    (*ResultCB)->ResultBufferLength = Length;
+    pFileIOResultCB = (AFSFileIOResultCB *)(*ResultCB)->ResultData;
+
+    if ( Buffer == NULL) {
+        (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
+        osi_Log0(afsd_logp, "RDR_WriteFile Null IOctl Buffer");
+        return;
+    }
+
+    if (FileID.Cell != 0) {
+        fid.cell   = FileID.Cell;
+        fid.volume = FileID.Volume;
+        fid.vnode  = FileID.Vnode;
+        fid.unique = FileID.Unique;
+        fid.hash   = FileID.Hash;
+
+        code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            osi_Log2(afsd_logp, "RDR_WriteFile cm_GetSCache failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_WriteFile Object Name Invalid - Cell = 0");
+        return;
+    }
+
+    /* Ensure that the caller can access this file */
+    lock_ObtainWrite(&scp->rw);
+    /*
+     * Request PRSFS_WRITE | PRSFS_LOCK in order to bypass the unix mode
+     * check in cm_HaveAccessRights().   By the time RDR_WriteFile is called
+     * it is already too late to deny the write due to the readonly attribute.
+     * The Windows cache may have already accepted the data.  Only if the
+     * user does not have real write permission should the write be denied.
+     */
+    code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE | PRSFS_LOCK,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
+        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    }
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log2(afsd_logp, "RDR_WriteFile cm_SyncOp failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+        (*ResultCB)->ResultStatus = STATUS_FILE_IS_A_DIRECTORY;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log1(afsd_logp, "RDR_WriteFile File is a Directory scp=0x%p",
+                 scp);
+        return;
+    }
+
+    if (scp->fileType != CM_SCACHETYPE_FILE) {
+        (*ResultCB)->ResultStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
+        osi_Log1(afsd_logp, "RDR_WriteFile File is a MountPoint or Link scp=0x%p",
+                 scp);
+        return;
+    }
+
+    if (FileIOCB->EndOfFile.QuadPart != scp->length.QuadPart)
+    {
+        cm_attr_t setAttr;
+
+        memset(&setAttr, 0, sizeof(cm_attr_t));
+        if (FileIOCB->EndOfFile.QuadPart != scp->length.QuadPart) {
+            osi_Log4(afsd_logp, "RDR_WriteFile new length fid vol 0x%x vno 0x%x length 0x%x:%x",
+                     scp->fid.volume, scp->fid.vnode,
+                     FileIOCB->EndOfFile.HighPart,
+                     FileIOCB->EndOfFile.LowPart);
+
+            setAttr.mask |= CM_ATTRMASK_LENGTH;
+            setAttr.length.LowPart = FileIOCB->EndOfFile.LowPart;
+            setAttr.length.HighPart = FileIOCB->EndOfFile.HighPart;
+            lock_ReleaseWrite(&scp->rw);
+            code = cm_SetAttr(scp, &setAttr, userp, &req);
+            osi_Log2(afsd_logp, "RDR_WriteFile cm_SetAttr failure scp=0x%p code 0x%x",
+                     scp, code);
+            code = 0;       /* ignore failure */
+            lock_ObtainWrite(&scp->rw);
+        }
+    }
+
+    /*
+     * The input buffer may contain data beyond the end of the file.
+     * Such data must be discarded.
+     */
+    if ( Offset->QuadPart + BytesToWrite > scp->length.QuadPart)
+    {
+        if ( Offset->QuadPart > scp->length.QuadPart) {
+            (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+            lock_ReleaseWrite(&scp->rw);
+            cm_ReleaseSCache(scp);
+            osi_Log1(afsd_logp, "RDR_WriteFile Nothing to do scp=0x%p",
+                     scp);
+            return;
+        }
+
+        BytesToWrite -= (afs_uint32)(Offset->QuadPart + BytesToWrite - scp->length.QuadPart);
+    }
+
+    if (bCacheBypass) {
+        code = cm_DirectWrite( scp, Offset, BytesToWrite,
+                               CM_DIRECT_SCP_LOCKED,
+                               userp, &req, Buffer, &ulBytesWritten);
+    } else {
+        code = raw_WriteData( scp, Offset, BytesToWrite, Buffer, userp, &req, &ulBytesWritten);
+    }
+
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_WriteFile failure code=0x%x status=0x%x",
+                 code, status);
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+        pFileIOResultCB->Length = ulBytesWritten;
+        pFileIOResultCB->DataVersion.QuadPart = scp->dataVersion;
+        pFileIOResultCB->Expiration.QuadPart = scp->cbExpires;
+    }
+
+    lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
+    return;
+}