[PATCH v3] server: Fail if non-empty directory marked for deletion.
Daniel Lehman
dlehman25 at gmail.com
Thu May 28 01:29:51 CDT 2020
Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
v3: use fdopendir(dup())
v2: use getdents
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 | 51 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 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 06d1d81bdb..e75d489748 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
@@ -2364,6 +2367,36 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
return fd;
}
+static int is_dir_empty( int fd )
+{
+#ifdef HAVE_DIRENT_H
+ 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 );
+ close( fd );
+ return empty;
+#else
+ return 1;
+#endif
+}
+
/* set disposition for the fd */
static void set_fd_disposition( struct fd *fd, int unlink )
{
@@ -2401,6 +2434,24 @@ static void set_fd_disposition( struct fd *fd, int unlink )
return;
}
+ /* can't remove non-empty directories */
+ if (unlink && S_ISDIR(st.st_mode))
+ {
+ int empty;
+
+ if ((empty = is_dir_empty( fd->unix_fd )) == -1)
+ {
+ file_set_error();
+ return;
+ }
+
+ if (!empty)
+ {
+ set_error( STATUS_DIRECTORY_NOT_EMPTY );
+ return;
+ }
+ }
+
fd->closed->unlink = unlink ? 1 : 0;
if (fd->options & FILE_DELETE_ON_CLOSE)
fd->closed->unlink = -1;
--
2.17.1
More information about the wine-devel
mailing list