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

Signed-off-by: Daniel Lehman <dlehman25@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Daniel Lehman 2020-05-28 20:28:09 -07:00 committed by Alexandre Julliard
parent 306c40e673
commit a302ab44ac
2 changed files with 57 additions and 20 deletions

View File

@ -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" );
}

View File

@ -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;