[PATCH] server: Fail if non-empty directory marked for deletion.

Daniel Lehman dlehman25 at gmail.com
Sat May 23 16:30:20 CDT 2020


Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>

---
needed by std::filesystem::remove_all, which removes files with:
- CreateFileW
- SetFileInformationByHandle(FileDispositionInfoEx) // currently unimplemented
- SetFileInformationByHandle(FileDispositionInfo) - DeleteFile = TRUE
- CloseHandle

---
 dlls/ntdll/tests/file.c |  3 ---
 server/fd.c             | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 31c18454f0..1d0682a633 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -3185,17 +3185,14 @@ todo_wine
     CloseHandle( handle2 );
     fdi.DoDeleteFile = TRUE;
     res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
-    todo_wine
     ok( res == STATUS_DIRECTORY_NOT_EMPTY, "unexpected FileDispositionInformation result (expected STATUS_DIRECTORY_NOT_EMPTY, got %x)\n", res );
     fileDeleted = DeleteFileA( buffer );
     ok( fileDeleted, "File should have been deleted\n" );
     buffer[dirpos] = '\0';
     CloseHandle( handle );
     fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
-    todo_wine
     ok( !fileDeleted, "Directory shouldn't have been deleted\n" );
     fileDeleted = RemoveDirectoryA( buffer );
-todo_wine
     ok( fileDeleted, "Directory should have been deleted\n" );
 }
 
diff --git a/server/fd.c b/server/fd.c
index 39fb419f25..db1559865b 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -93,6 +93,9 @@
 #ifdef HAVE_SYS_SYSCALL_H
 #include <sys/syscall.h>
 #endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -2359,6 +2362,37 @@ static void set_fd_disposition( struct fd *fd, int unlink )
         return;
     }
 
+#ifdef HAVE_DIRENT_H
+    /* can't remove non-empty directories */
+    if (unlink && S_ISDIR(st.st_mode))
+    {
+        DIR *dir;
+        int empty;
+        struct dirent *de;
+
+        if (!(dir = fdopendir( fd->unix_fd )))
+        {
+            file_set_error();
+            return;
+        }
+
+        empty = 1;
+        while ((de = readdir( dir )))
+        {
+            if (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." )) continue;
+            empty = 0;
+            break;
+        }
+        closedir( dir );
+
+        if (!empty)
+        {
+            set_error( STATUS_DIRECTORY_NOT_EMPTY );
+            return;
+        }
+    }
+#endif
+
     fd->closed->unlink = unlink ? 1 : 0;
     if (fd->options & FILE_DELETE_ON_CLOSE)
         fd->closed->unlink = -1;
-- 
2.25.1




More information about the wine-devel mailing list