From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/tests/file.c | 32 +++++++++++++-------- server/fd.c | 61 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 12 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index b75ddff30bf..7743caf71de 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6455,22 +6455,22 @@ static void test_reparse_points(void) CloseHandle( handle2 );
status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, NULL, 0, NULL, 0 ); - todo_wine ok( status == STATUS_INVALID_BUFFER_SIZE, "got %#lx\n", status ); + ok( status == STATUS_INVALID_BUFFER_SIZE, "got %#lx\n", status ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, 1, NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, data_size, NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, sizeof(REPARSE_DATA_BUFFER), NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); data->ReparseDataLength = 0; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, data_size, NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, sizeof(REPARSE_GUID_DATA_BUFFER), NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status );
data->ReparseTag = 0; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, sizeof(REPARSE_DATA_BUFFER), NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_TAG_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_TAG_INVALID, "got %#lx\n", status );
data->ReparseTag = 3; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, sizeof(REPARSE_DATA_BUFFER), NULL, 0 ); @@ -6481,7 +6481,7 @@ static void test_reparse_points(void) todo_wine ok( !status, "got %#lx\n", status );
status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, data, sizeof(REPARSE_DATA_BUFFER), NULL, 0 ); - todo_wine ok( status == STATUS_NOT_A_REPARSE_POINT, "got %#lx\n", status ); + ok( status == STATUS_NOT_A_REPARSE_POINT, "got %#lx\n", status );
/* Create a dangling symlink, and then open it without * FILE_OPEN_REPARSE_POINT but with FILE_OPEN_IF. This creates the target. @@ -6623,15 +6623,15 @@ static void test_reparse_points(void)
guid_data->ReparseDataLength = 0; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, guid_data, data_size, NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, guid_data, sizeof(REPARSE_GUID_DATA_BUFFER), NULL, 0 ); - todo_wine ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); + ok( status == STATUS_IO_REPARSE_DATA_INVALID, "got %#lx\n", status ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, guid_data, sizeof(REPARSE_DATA_BUFFER), NULL, 0 ); - todo_wine ok( !status, "got %#lx\n", status ); + ok( !status, "got %#lx\n", status );
swprintf( path, ARRAY_SIZE(path), L"%s/testreparse_customdir/file", temp_path ); handle2 = CreateFileW( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); - todo_wine ok( handle2 != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); + ok( handle2 != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); CloseHandle( handle2 );
/* Set the "directory" bit on our custom tag. */ @@ -6667,6 +6667,14 @@ static void test_reparse_points(void)
ret = DeleteFileW( path ); todo_wine ok( ret == TRUE, "got error %lu\n", GetLastError() ); + if (!ret) + { + guid_data->ReparseDataLength = 0; + status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_DELETE_REPARSE_POINT, guid_data, sizeof(REPARSE_DATA_BUFFER), NULL, 0 ); + ok( !status, "got %#lx\n", status ); + ret = DeleteFileW( path ); + ok( ret == TRUE, "got error %lu\n", GetLastError() ); + }
status = NtSetInformationFile( handle, &io, &fdi, sizeof(fdi), FileDispositionInformation ); ok( !status, "got %#lx\n", status ); diff --git a/server/fd.c b/server/fd.c index e96280d757e..76272673f7b 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2474,6 +2474,63 @@ static void set_reparse_point( struct fd *fd, struct async *async ) free( reparse_name ); } } + +static void delete_reparse_point( struct fd *fd, struct async *async ) +{ + const REPARSE_DATA_BUFFER *data = get_req_data(); + char *base_name; + size_t len; + + if (!fd->unix_name) + { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return; + } + + if (!get_req_data_size()) + { + set_error( STATUS_INVALID_BUFFER_SIZE ); + return; + } + + len = strlen( fd->unix_name ); + if (fd->unix_name[len - 1] != '?') + { + set_error( STATUS_NOT_A_REPARSE_POINT ); + return; + } + + if (get_req_data_size() != sizeof(REPARSE_DATA_BUFFER) || data->ReparseDataLength) + { + set_error( STATUS_IO_REPARSE_DATA_INVALID ); + return; + } + + if (!data->ReparseTag) + { + set_error( STATUS_IO_REPARSE_TAG_INVALID ); + return; + } + + if (!(base_name = mem_alloc( len ))) + return; + memcpy( base_name, fd->unix_name, len - 1 ); + base_name[len - 1] = 0; + + if (rename( fd->unix_name, base_name ) < 0) + { + file_set_error(); + free( base_name ); + return; + } + + fd->unix_name[len - 1] = '*'; + unlink( fd->unix_name ); + + free( fd->unix_name ); + fd->closed->unix_name = fd->unix_name = base_name; +} + /* default read() routine */ void no_fd_read( struct fd *fd, struct async *async, file_pos_t pos ) { @@ -2596,6 +2653,10 @@ void default_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) set_reparse_point( fd, async ); break;
+ case FSCTL_DELETE_REPARSE_POINT: + delete_reparse_point( fd, async ); + break; + default: set_error( STATUS_NOT_SUPPORTED ); }