Windows: CM_ERROR_INEXACT_MATCH is not a fatal error
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index 3efcb04..940deda 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2008 Secure Endpoints, Inc.
- * Copyright (c) 2009-2013 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
@@ -108,6 +108,38 @@ 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 )
 {
@@ -182,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;
@@ -449,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);
                 /*
@@ -499,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) {
@@ -508,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:
@@ -530,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;
 
@@ -550,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;
 
@@ -575,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",
@@ -606,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);
@@ -651,6 +759,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
         pCurrentEntry->TargetNameOffset = 0;
         pCurrentEntry->TargetNameLength = 0;
     }
+    }
     lock_ReleaseWrite(&scp->rw);
 
     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
@@ -718,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);
@@ -735,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);
@@ -933,7 +1046,8 @@ RDR_EnumerateDirectory( IN cm_user_t *userp,
                                                      entryp->name,
                                                      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);
@@ -991,8 +1105,8 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
                         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)
 {
@@ -1165,7 +1279,8 @@ RDR_EvaluateNodeByName( IN cm_user_t *userp,
                                         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 );
@@ -1321,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)
@@ -1579,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) {
@@ -1594,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;
@@ -2040,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);
@@ -2054,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;
@@ -2195,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;
@@ -2220,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;
@@ -2242,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)
@@ -2452,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;
@@ -2778,7 +2923,7 @@ RDR_HardLinkFileEntry( IN cm_user_t *userp,
             cm_EndDirOp(&dirop);
         }
 
-        if (code != 0) {
+       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;
@@ -5217,7 +5362,7 @@ RDR_PioctlOpen( IN cm_user_t *userp,
     cm_fid_t    RootFid;
     cm_req_t    req;
 
-    RDR_InitReq(&req, bWow64);
+    cm_InitReq(&req);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
     if (!(*ResultCB))
@@ -5285,7 +5430,7 @@ RDR_PioctlWrite( IN cm_user_t *userp,
     cm_req_t    req;
     DWORD       status;
 
-    RDR_InitReq(&req, bWow64);
+    cm_InitReq(&req);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
     if (!(*ResultCB))
@@ -5324,7 +5469,7 @@ RDR_PioctlRead( IN cm_user_t *userp,
     DWORD       status;
     afs_uint32  pflags = (bIsLocalSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
 
-    RDR_InitReq(&req, bWow64);
+    cm_InitReq(&req);
 
     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
     if (!(*ResultCB))
@@ -5417,7 +5562,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);
@@ -5465,7 +5610,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);
 
@@ -5543,7 +5688,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);
@@ -5581,7 +5726,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);
 
@@ -5644,7 +5789,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);
@@ -5660,7 +5805,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);
 
@@ -5702,7 +5847,6 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     char *OfflineMsg;
     char *MOTD;
     struct rx_connection * rxconnp;
-    int sync_done = 0;
     int scp_locked = 0;
 
     RDR_InitReq(&req, bWow64);
@@ -5753,8 +5897,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_HARD_LINKS | 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)
@@ -5763,7 +5907,8 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
 
         pResultCB->AvailableAllocationUnits.QuadPart = 0;
-        pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
+        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);
@@ -5775,43 +5920,63 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         if ( pResultCB->CellLength )
             pResultCB->CellLength--;
     } else {
-        memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
-
-        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);
 
-        if (volType == ROVOL || volType == BACKVOL)
+        if (cm_volumeInfoReadOnlyFlag && (volType == ROVOL || volType == BACKVOL))
             pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
-        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
-                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (code == 0)
-        {
-            sync_done = 1;
-
-            Name = volName;
-            OfflineMsg = offLineMsg;
-            MOTD = motd;
-            lock_ReleaseWrite(&scp->rw);
-            scp_locked = 0;
-
-            do {
-                code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
-                if (code) continue;
+        code = -1;
 
-                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 ( 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));
+
         if (code == 0) {
             if (volType == ROVOL || volType == BACKVOL) {
                 pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;
@@ -5829,7 +5994,10 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                     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.
@@ -5872,14 +6040,6 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         /* do not include the trailing nul */
         if ( pResultCB->CellLength )
             pResultCB->CellLength--;
-
-        if (sync_done) {
-            if (!scp_locked) {
-                lock_ObtainWrite(&scp->rw);
-                scp_locked = 1;
-            }
-            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        }
     }
     pResultCB->VolumeLabelLength *= sizeof(WCHAR);  /* convert to bytes from chars */
     pResultCB->CellLength *= sizeof(WCHAR);         /* convert to bytes from chars */
@@ -5923,7 +6083,6 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
     char *OfflineMsg;
     char *MOTD;
     struct rx_connection * rxconnp;
-    int sync_done = 0;
     int scp_locked = 0;
 
     RDR_InitReq(&req, bWow64);
@@ -5977,37 +6136,54 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
         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);
 
-        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
-                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (code == 0)
-        {
-            sync_done = 1;
+        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 ( 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) {
@@ -6036,14 +6212,6 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
             code = 0;
         }
-
-        if (sync_done) {
-            if (!scp_locked) {
-                lock_ObtainWrite(&scp->rw);
-                scp_locked = 1;
-            }
-            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        }
     }
 
   _done:
@@ -6696,7 +6864,14 @@ RDR_WriteFile( IN cm_user_t     *userp,
 
     /* Ensure that the caller can access this file */
     lock_ObtainWrite(&scp->rw);
-    code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+    /*
+     * 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,