From: Dmitry Timoshkov Subject: [PATCH 2/6] server: Fail to set delete disposition on a non-empty directory. Message-Id: <20181002155224.79c69f55c3b233e75b3cb576@baikal.ru> Date: Tue, 2 Oct 2018 15:52:24 +0800 Signed-off-by: Dmitry Timoshkov --- dlls/ntdll/tests/file.c | 3 --- server/fd.c | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 1dd58a0926..286873d657 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3037,17 +3037,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 6118f52dd5..7ee22999f0 100644 --- a/server/fd.c +++ b/server/fd.c @@ -31,6 +31,9 @@ #include #include #include +#ifdef HAVE_DIRENT_H +# include +#endif #ifdef HAVE_POLL_H #include #endif @@ -2217,6 +2220,22 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl return fd; } +static int is_directory_empty( struct fd *fd ) +{ + DIR *dir; + int count = 0; + + if ((dir = fdopendir( fd->unix_fd ))) + { + while (readdir( dir ) != NULL && count <= 2) + count++; + + closedir( dir ); + } + + return count <= 2; +} + /* set disposition for the fd */ static void set_fd_disposition( struct fd *fd, int unlink ) { @@ -2254,6 +2273,13 @@ static void set_fd_disposition( struct fd *fd, int unlink ) return; } + /* can't unlink a non-empty directory */ + if (unlink && S_ISDIR( st.st_mode ) && !is_directory_empty( fd )) + { + set_error( STATUS_DIRECTORY_NOT_EMPTY ); + return; + } + fd->closed->unlink = unlink || (fd->options & FILE_DELETE_ON_CLOSE); } -- 2.17.1