Daniel Lehman : server: Fail if non-empty directory marked for deletion.

Alexandre Julliard julliard at winehq.org
Tue Jun 9 15:27:47 CDT 2020


Module: wine
Branch: master
Commit: a302ab44acaf72ecc9b0307c82a7d11f759e6a72
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=a302ab44acaf72ecc9b0307c82a7d11f759e6a72

Author: Daniel Lehman <dlehman25 at gmail.com>
Date:   Thu May 28 20:28:09 2020 -0700

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

Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/tests/file.c |  3 --
 server/fd.c             | 74 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 57 insertions(+), 20 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 06d1d81bdb..7ea8ac273e 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -23,6 +23,7 @@
 #include "wine/port.h"
 
 #include <assert.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -2364,6 +2365,31 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
     return fd;
 }
 
+static int is_dir_empty( int fd )
+{
+    DIR *dir;
+    int empty;
+    struct dirent *de;
+
+    if ((fd = dup( fd )) == -1)
+        return -1;
+
+    if (!(dir = fdopendir( fd )))
+    {
+        close( fd );
+        return -1;
+    }
+
+    empty = 1;
+    while (empty && (de = readdir( dir )))
+    {
+        if (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." )) continue;
+        empty = 0;
+    }
+    closedir( dir );
+    return empty;
+}
+
 /* set disposition for the fd */
 static void set_fd_disposition( struct fd *fd, int unlink )
 {
@@ -2381,24 +2407,38 @@ static void set_fd_disposition( struct fd *fd, int unlink )
         return;
     }
 
-    if (fstat( fd->unix_fd, &st ) == -1)
+    if (unlink)
     {
-        file_set_error();
-        return;
-    }
-
-    /* can't unlink special files */
-    if (unlink && !S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
-    {
-        set_error( STATUS_INVALID_PARAMETER );
-        return;
-    }
-
-    /* can't unlink files we don't have permission to write */
-    if (unlink && !(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) && !S_ISDIR(st.st_mode))
-    {
-        set_error( STATUS_CANNOT_DELETE );
-        return;
+        if (fstat( fd->unix_fd, &st ) == -1)
+        {
+            file_set_error();
+            return;
+        }
+        if (S_ISREG( st.st_mode ))  /* can't unlink files we don't have permission to write */
+        {
+            if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+            {
+                set_error( STATUS_CANNOT_DELETE );
+                return;
+            }
+        }
+        else if (S_ISDIR( st.st_mode ))  /* can't remove non-empty directories */
+        {
+            switch (is_dir_empty( fd->unix_fd ))
+            {
+            case -1:
+                file_set_error();
+                return;
+            case 0:
+                set_error( STATUS_DIRECTORY_NOT_EMPTY );
+                return;
+            }
+        }
+        else  /* can't unlink special files */
+        {
+            set_error( STATUS_INVALID_PARAMETER );
+            return;
+        }
     }
 
     fd->closed->unlink = unlink ? 1 : 0;




More information about the wine-cvs mailing list