From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/tests/file.c | 32 ++++++++++---------- dlls/ntdll/unix/file.c | 9 ------ server/fd.c | 66 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 25 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 7743caf71de..413cc55d511 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6218,22 +6218,22 @@ static void test_reparse_points(void) memset( data2, 0xcc, data_size + 1 ); io.Information = 1; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, data2, sizeof(REPARSE_GUID_DATA_BUFFER) - 1 ); - todo_wine ok( status == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", status ); + ok( status == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", status ); ok( io.Information == 1, "got size %#Ix\n", io.Information ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, data2, sizeof(REPARSE_GUID_DATA_BUFFER) ); - todo_wine ok( status == STATUS_BUFFER_OVERFLOW, "got %#lx\n", status ); - todo_wine ok( io.Information == sizeof(REPARSE_GUID_DATA_BUFFER), "expected size %#Ix, got %#Ix\n", data_size, io.Information ); - todo_wine ok( !memcmp( data, data2, sizeof(REPARSE_GUID_DATA_BUFFER) ), "buffers didn't match\n" ); + ok( status == STATUS_BUFFER_OVERFLOW, "got %#lx\n", status ); + ok( io.Information == sizeof(REPARSE_GUID_DATA_BUFFER), "expected size %#Ix, got %#Ix\n", data_size, io.Information ); + ok( !memcmp( data, data2, sizeof(REPARSE_GUID_DATA_BUFFER) ), "buffers didn't match\n" ); status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, data2, data_size - 1); - todo_wine ok( status == STATUS_BUFFER_OVERFLOW, "got %#lx\n", status ); - todo_wine ok( io.Information == data_size - 1, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); - todo_wine ok( !memcmp( data, data2, data_size - 1 ), "buffers didn't match\n" ); + ok( status == STATUS_BUFFER_OVERFLOW, "got %#lx\n", status ); + ok( io.Information == data_size - 1, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); + ok( !memcmp( data, data2, data_size - 1 ), "buffers didn't match\n" );
io.Information = 1; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, data2, data_size + 1); - todo_wine ok( !status, "got %#lx\n", status ); - todo_wine ok( io.Information == data_size, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); - todo_wine ok( !memcmp( data, data2, data_size ), "buffers didn't match\n" ); + ok( !status, "got %#lx\n", status ); + ok( io.Information == data_size, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); + ok( !memcmp( data, data2, data_size ), "buffers didn't match\n" );
status = NtQueryInformationFile( handle, &io, &stat_info, sizeof(stat_info), FileStatInformation ); ok( !status, "got %#lx\n", status ); @@ -6610,9 +6610,9 @@ static void test_reparse_points(void)
io.Information = 1; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, data_size + 1); - todo_wine ok( !status, "got %#lx\n", status ); - todo_wine ok( io.Information == data_size, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); - todo_wine ok( !memcmp( guid_data, guid_data2, data_size ), "buffers didn't match\n" ); + ok( !status, "got %#lx\n", status ); + ok( io.Information == data_size, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); + ok( !memcmp( guid_data, guid_data2, data_size ), "buffers didn't match\n" );
RtlInitUnicodeString( &nameW, L"testreparse_customdir\file" ); status = NtCreateFile( &handle2, GENERIC_ALL, &attr, &io, NULL, 0, 0, FILE_OPEN, 0, NULL, 0 ); @@ -6642,9 +6642,9 @@ static void test_reparse_points(void)
io.Information = 1; status = NtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, data_size + 1); - todo_wine ok( !status, "got %#lx\n", status ); - todo_wine ok( io.Information == data_size, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); - todo_wine ok( !memcmp( guid_data, guid_data2, data_size ), "buffers didn't match\n" ); + ok( !status, "got %#lx\n", status ); + ok( io.Information == data_size, "expected size %#Ix, got %#Ix\n", data_size, io.Information ); + ok( !memcmp( guid_data, guid_data2, data_size ), "buffers didn't match\n" );
RtlInitUnicodeString( &nameW, L"testreparse_customdir" ); status = NtOpenFile( &handle2, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0 ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index f652af80c07..fec3dc97d28 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -6362,15 +6362,6 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap break; }
- case FSCTL_GET_REPARSE_POINT: - if (out_buffer && out_size) - { - FIXME("FSCTL_GET_REPARSE_POINT semi-stub\n"); - status = STATUS_NOT_A_REPARSE_POINT; - } - else status = STATUS_INVALID_USER_BUFFER; - break; - case FSCTL_GET_OBJECT_ID: { FILE_OBJECTID_BUFFER *info = out_buffer; diff --git a/server/fd.c b/server/fd.c index 76272673f7b..50f97afe7f9 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2475,6 +2475,68 @@ static void set_reparse_point( struct fd *fd, struct async *async ) } }
+static void get_reparse_point( struct fd *fd, struct async *async ) +{ + char *reparse_name; + void *buffer; + ssize_t ret; + int data_fd; + size_t len; + char dummy; + + if (!fd->unix_name) + { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return; + } + + if (!get_reply_max_size()) + { + set_error( STATUS_INVALID_USER_BUFFER ); + return; + } + + len = strlen( fd->unix_name ); + if (fd->unix_name[len - 1] != '?') + { + set_error( STATUS_NOT_A_REPARSE_POINT ); + return; + } + + if (get_reply_max_size() < sizeof(REPARSE_GUID_DATA_BUFFER)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return; + } + + if (!(reparse_name = mem_alloc( len + 1 ))) return; + memcpy( reparse_name, fd->unix_name, len + 1 ); + reparse_name[len - 1] = '*'; + + if ((data_fd = open( reparse_name, O_RDONLY )) < 0) + { + file_set_error(); + free( reparse_name ); + return; + } + free( reparse_name ); + + if (!(buffer = mem_alloc( get_reply_max_size() ))) + { + close( data_fd ); + return; + } + + if ((ret = read( data_fd, buffer, get_reply_max_size() )) >= 0) + { + if (ret == get_reply_max_size() && read( data_fd, &dummy, 1 ) == 1) + set_error( STATUS_BUFFER_OVERFLOW ); + set_reply_data_ptr( buffer, ret ); + } + else file_set_error(); + close( data_fd ); +} + static void delete_reparse_point( struct fd *fd, struct async *async ) { const REPARSE_DATA_BUFFER *data = get_req_data(); @@ -2653,6 +2715,10 @@ void default_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) set_reparse_point( fd, async ); break;
+ case FSCTL_GET_REPARSE_POINT: + get_reparse_point( fd, async ); + break; + case FSCTL_DELETE_REPARSE_POINT: delete_reparse_point( fd, async ); break;