Windows: RDR_DeleteFileEntry test for empty directory
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
index cb678bb..0ecfdae 100644 (file)
@@ -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 )
 {
@@ -508,6 +540,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 +563,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;
 
@@ -644,7 +677,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                         } else if (mp[offset] == '\\') {
                             size_t nbNameLen = strlen(cm_NetbiosName);
 
-                            if ( strncmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
+                            if ( strnicmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
                                  mp[offset + nbNameLen + 1] == '\\')
                             {
                                 /* an AFS symlink */
@@ -659,7 +692,7 @@ RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
                                 mbstowcs(wtarget, &mp[offset], wtarget_len);
 #endif
                             } else if ( mp[offset + 1] == '\\' &&
-                                        strncmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
+                                        strnicmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
                                         mp[offset + nbNameLen + 2] == '\\')
                             {
                                 /* an AFS symlink */
@@ -790,8 +823,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);
@@ -807,8 +838,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);
@@ -2290,6 +2327,37 @@ 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,
@@ -5857,31 +5925,56 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         if (cm_volumeInfoReadOnlyFlag && (volType == ROVOL || volType == BACKVOL))
             pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
 
-        flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS;
-        if (scp->volumeCreationDate == 0)
-            flags |= CM_SCACHESYNC_FORCECB;
-        code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, flags);
-        if (code == 0)
+        code = -1;
+
+        if ( volType == ROVOL &&
+             (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
         {
-            sync_done = 1;
+            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)
+        {
+            flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS;
+            if (scp->volumeCreationDate == 0)
+                flags |= CM_SCACHESYNC_FORCECB;
+            code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, flags);
+            if (code == 0)
+            {
+                sync_done = 1;
 
-            Name = volName;
-            OfflineMsg = offLineMsg;
-            MOTD = motd;
-            lock_ReleaseWrite(&scp->rw);
-            scp_locked = 0;
+                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;
 
-            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);
 
-                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);
 
-            } 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 )
@@ -6061,29 +6154,54 @@ RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
 
         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)
+        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)
         {
-            sync_done = 1;
+            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;
+                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;
 
-            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);
 
-                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);
 
-            } 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) {