-- v2: ntdll: Fill FILE_ATTRIBUTE_REPARSE_POINT and the reparse tag in fd_get_file_info().
From: Elizabeth Figura zfigura@codeweavers.com
Since we are essentially adding a flag to get_nt_and_unix_names(), we also pass this flag correctly for other functions, opening the reparse point where the behaviour is implicit: NtQueryAttributesFile(), NtQueryFullAttributesFile(), FileRenameInformation, and FileLinkInformation. --- dlls/ntdll/tests/file.c | 76 ++++++++++++++++------------------ dlls/ntdll/unix/file.c | 63 ++++++++++++++++------------ dlls/ntdll/unix/loader.c | 4 +- dlls/ntdll/unix/process.c | 4 +- dlls/ntdll/unix/registry.c | 2 +- dlls/ntdll/unix/unix_private.h | 2 +- 6 files changed, 77 insertions(+), 74 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 7016ca166f9..ac7a0dcf3db 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6270,25 +6270,22 @@ static void test_reparse_points(void)
status = NtCreateFile( &handle2, GENERIC_ALL, &attr, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, NULL, 0 ); - todo_wine ok( status == STATUS_FILE_IS_A_DIRECTORY, "got %#lx\n", status ); + ok( status == STATUS_FILE_IS_A_DIRECTORY, "got %#lx\n", status ); status = NtCreateFile( &handle2, GENERIC_ALL, &attr, &io, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, NULL, 0 ); - todo_wine ok( !status, "got %#lx\n", status ); - if (!status) - { - status = NtQueryInformationFile( handle2, &io, &tag_info, sizeof(tag_info), FileAttributeTagInformation ); - ok( !status, "got %#lx\n", status ); - todo_wine ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), - "got attributes %#lx\n", tag_info.FileAttributes ); - todo_wine ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); - status = NtQueryInformationFile( handle2, &io, &std_info, sizeof(std_info), FileStandardInformation ); - ok( !status, "got %#lx\n", status ); - ok( !std_info.AllocationSize.QuadPart, "got size %#I64x\n", std_info.AllocationSize.QuadPart ); - ok( !std_info.EndOfFile.QuadPart, "got eof %#I64x\n", std_info.EndOfFile.QuadPart ); - ok( std_info.NumberOfLinks == 1, "got %lu links\n", std_info.NumberOfLinks ); - ok( std_info.Directory == TRUE, "got directory %u\n", std_info.Directory ); - NtClose( handle2 ); - } + ok( !status, "got %#lx\n", status ); + status = NtQueryInformationFile( handle2, &io, &tag_info, sizeof(tag_info), FileAttributeTagInformation ); + ok( !status, "got %#lx\n", status ); + todo_wine ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), + "got attributes %#lx\n", tag_info.FileAttributes ); + todo_wine ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); + status = NtQueryInformationFile( handle2, &io, &std_info, sizeof(std_info), FileStandardInformation ); + ok( !status, "got %#lx\n", status ); + ok( !std_info.AllocationSize.QuadPart, "got size %#I64x\n", std_info.AllocationSize.QuadPart ); + ok( !std_info.EndOfFile.QuadPart, "got eof %#I64x\n", std_info.EndOfFile.QuadPart ); + ok( std_info.NumberOfLinks == 1, "got %lu links\n", std_info.NumberOfLinks ); + ok( std_info.Directory == TRUE, "got directory %u\n", std_info.Directory ); + NtClose( handle2 );
/* alter the target in-place */ data_size = init_reparse_mount_point( &data, L"\??\C:\bogus" ); @@ -6577,34 +6574,31 @@ static void test_reparse_points(void) status = NtOpenFile( &handle2, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT ); - todo_wine ok( !status, "got %#lx\n", status ); + ok( !status, "got %#lx\n", status );
guid_data2 = malloc( data_size + 1 ); - if (!status) - { - memset( guid_data2, 0xcc, data_size + 1 ); - io.Information = 1; - status = NtFsControlFile( handle2, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, sizeof(REPARSE_GUID_DATA_BUFFER) - 1 ); - ok( status == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", status ); - ok( io.Information == 1, "got size %#Ix\n", io.Information ); - status = NtFsControlFile( handle2, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, data_size - 1); - 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( guid_data, guid_data2, data_size - 1 ), "buffers didn't match\n" ); + memset( guid_data2, 0xcc, data_size + 1 ); + io.Information = 1; + status = NtFsControlFile( handle2, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, sizeof(REPARSE_GUID_DATA_BUFFER) - 1 ); + ok( status == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", status ); + ok( io.Information == 1, "got size %#Ix\n", io.Information ); + status = NtFsControlFile( handle2, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, data_size - 1); + 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( guid_data, guid_data2, data_size - 1 ), "buffers didn't match\n" );
- io.Information = 1; - status = NtFsControlFile( handle2, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, data_size + 1); - 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" ); + io.Information = 1; + status = NtFsControlFile( handle2, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, guid_data2, data_size + 1); + 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" );
- ret = ReadFile( handle2, buffer, sizeof(buffer), &size, NULL ); - ok( ret == TRUE, "got error %lu\n", GetLastError() ); - ok( size == 4, "got size %lu\n", size ); - ok( !memcmp( buffer, "data", size ), "got data %s\n", debugstr_an( buffer, size )); + ret = ReadFile( handle2, buffer, sizeof(buffer), &size, NULL ); + ok( ret == TRUE, "got error %lu\n", GetLastError() ); + ok( size == 4, "got size %lu\n", size ); + ok( !memcmp( buffer, "data", size ), "got data %s\n", debugstr_an( buffer, size ));
- CloseHandle( handle2 ); - } + CloseHandle( handle2 );
status = NtOpenFile( &handle2, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0 ); @@ -7227,7 +7221,7 @@ out:
swprintf( path, ARRAY_SIZE(path), L"%s/testreparse_dir", temp_path ); ret = RemoveDirectoryW( path ); - todo_wine ok( ret == TRUE, "got error %lu\n", GetLastError() ); + ok( ret == TRUE, "got error %lu\n", GetLastError() );
CloseHandle( temp_dir ); } diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index a6873bb2f79..23c181650ed 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -3460,7 +3460,7 @@ done:
static NTSTATUS resolve_reparse_point( int fd, int root_fd, OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, unsigned int nt_pos, unsigned int reparse_len, char **unix_name, - int unix_len, int pos, UINT disposition, BOOL is_unix, unsigned int reparse_count ); + int unix_len, int pos, UINT disposition, BOOL open_reparse, BOOL is_unix, unsigned int reparse_count );
/****************************************************************************** @@ -3470,7 +3470,7 @@ static NTSTATUS resolve_reparse_point( int fd, int root_fd, OBJECT_ATTRIBUTES *a */ static NTSTATUS lookup_unix_name( int root_fd, OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, unsigned int nt_pos, char **buffer, int unix_len, int pos, - UINT disposition, BOOL is_unix, unsigned int reparse_count ) + UINT disposition, BOOL open_reparse, BOOL is_unix, unsigned int reparse_count ) { static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 }; const WCHAR *name = attr->ObjectName->Buffer + nt_pos; @@ -3559,14 +3559,21 @@ static NTSTATUS lookup_unix_name( int root_fd, OBJECT_ATTRIBUTES *attr, UNICODE_ memcpy( reparse_name, name, (end - name) * sizeof(WCHAR) ); reparse_name[end - name] = '?';
- if (!find_file_in_dir( root_fd, unix_name, pos, reparse_name, end - name + 1, is_unix ) - && (reparse_fd = openat( root_fd, unix_name, O_RDONLY )) >= 0) + if (!name_len && open_reparse) { - status = resolve_reparse_point( reparse_fd, root_fd, attr, nt_name, nt_pos, next - name, buffer, - unix_len, pos, disposition, is_unix, reparse_count ); - close( reparse_fd ); - free( reparse_name ); - return status; + status = find_file_in_dir( root_fd, unix_name, pos, reparse_name, end - name + 1, is_unix ); + } + else + { + if (!find_file_in_dir( root_fd, unix_name, pos, reparse_name, end - name + 1, is_unix ) + && (reparse_fd = openat( root_fd, unix_name, O_RDONLY )) >= 0) + { + status = resolve_reparse_point( reparse_fd, root_fd, attr, nt_name, nt_pos, next - name, buffer, + unix_len, pos, disposition, open_reparse, is_unix, reparse_count ); + close( reparse_fd ); + free( reparse_name ); + return status; + } } }
@@ -3612,7 +3619,8 @@ static NTSTATUS lookup_unix_name( int root_fd, OBJECT_ATTRIBUTES *attr, UNICODE_ * nt_to_unix_file_name_no_root */ static NTSTATUS nt_to_unix_file_name_no_root( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, - char **unix_name_ret, UINT disposition, unsigned int reparse_count ) + char **unix_name_ret, UINT disposition, + BOOL open_reparse, unsigned int reparse_count ) { static const WCHAR unixW[] = {'u','n','i','x'}; static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 }; @@ -3707,7 +3715,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( OBJECT_ATTRIBUTES *attr, UNICODE_S nt_pos += prefix_len;
status = lookup_unix_name( AT_FDCWD, attr, nt_name, nt_pos, &unix_name, unix_len, - pos, disposition, is_unix, reparse_count ); + pos, disposition, open_reparse, is_unix, reparse_count ); if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE) { *unix_name_ret = unix_name; @@ -3730,7 +3738,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( OBJECT_ATTRIBUTES *attr, UNICODE_S * returned, but the unix name is still filled in properly. */ static NTSTATUS nt_to_unix_file_name( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, - char **name_ret, UINT disposition ) + char **name_ret, UINT disposition, BOOL open_reparse ) { enum server_fd_type type; int root_fd, needs_close; @@ -3740,7 +3748,7 @@ static NTSTATUS nt_to_unix_file_name( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *n NTSTATUS status;
if (!attr->RootDirectory) /* without root dir fall back to normal lookup */ - return nt_to_unix_file_name_no_root( attr, nt_name, name_ret, disposition, 0 ); + return nt_to_unix_file_name_no_root( attr, nt_name, name_ret, disposition, open_reparse, 0 );
name = attr->ObjectName->Buffer; name_len = attr->ObjectName->Length / sizeof(WCHAR); @@ -3761,7 +3769,7 @@ static NTSTATUS nt_to_unix_file_name( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *n else { status = lookup_unix_name( root_fd, attr, nt_name, 0, &unix_name, unix_len, - 1, disposition, FALSE, 0 ); + 1, disposition, open_reparse, FALSE, 0 ); if (needs_close) close( root_fd ); } } @@ -3866,7 +3874,7 @@ static WCHAR *collapse_path( WCHAR *path )
static NTSTATUS resolve_absolute_reparse_point( const WCHAR *target, unsigned int target_len, OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, const WCHAR *remainder, unsigned int remainder_len, - char **unix_name, UINT disposition, unsigned int reparse_count ) + char **unix_name, UINT disposition, BOOL open_reparse, unsigned int reparse_count ) { WCHAR *new_nt_name; char *new_unix_name; @@ -3893,7 +3901,7 @@ static NTSTATUS resolve_absolute_reparse_point( const WCHAR *target, unsigned in attr->RootDirectory = 0; attr->ObjectName = nt_name;
- status = nt_to_unix_file_name_no_root( attr, nt_name, &new_unix_name, disposition, reparse_count ); + status = nt_to_unix_file_name_no_root( attr, nt_name, &new_unix_name, disposition, open_reparse, reparse_count ); if (!status || status == STATUS_NO_SUCH_FILE) { free( *unix_name ); @@ -3905,7 +3913,7 @@ static NTSTATUS resolve_absolute_reparse_point( const WCHAR *target, unsigned in
static NTSTATUS resolve_reparse_point( int fd, int root_fd, OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, unsigned int nt_pos, unsigned int reparse_len, char **unix_name, int unix_len, int pos, - UINT disposition, BOOL is_unix, unsigned int reparse_count ) + UINT disposition, BOOL open_reparse, BOOL is_unix, unsigned int reparse_count ) { const WCHAR *name = attr->ObjectName->Buffer; unsigned int name_len = attr->ObjectName->Length / sizeof(WCHAR); @@ -3947,7 +3955,7 @@ static NTSTATUS resolve_reparse_point( int fd, int root_fd, OBJECT_ATTRIBUTES *a USHORT target_len = data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
status = resolve_absolute_reparse_point( target, target_len, attr, nt_name, remainder, remainder_len, - unix_name, disposition, reparse_count ); + unix_name, disposition, open_reparse, reparse_count ); break; }
@@ -4113,7 +4121,7 @@ static void remove_trailing_backslash( OBJECT_ATTRIBUTES *attr, UNICODE_STRING * * nt_name.Buffer and unix_name must be freed by caller in all cases. */ NTSTATUS get_nt_and_unix_names( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, - char **unix_name_ret, UINT disposition ) + char **unix_name_ret, UINT disposition, BOOL open_reparse ) { ULONG lenA, lenW = attr->ObjectName->Length / sizeof(WCHAR); UNICODE_STRING *orig = attr->ObjectName; @@ -4147,7 +4155,7 @@ NTSTATUS get_nt_and_unix_names( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name #ifndef _WIN64 get_redirect( attr, nt_name ); #endif - status = nt_to_unix_file_name( attr, nt_name, unix_name_ret, disposition ); + status = nt_to_unix_file_name( attr, nt_name, unix_name_ret, disposition, open_reparse ); }
if (!status || status == STATUS_NO_SUCH_FILE) @@ -4274,7 +4282,7 @@ NTSTATUS ntdll_get_unix_file_name( const WCHAR *dos, char **unix_name, UINT disp
if (status) return status; InitializeObjectAttributes( &attr, &nt_name, 0, 0, NULL ); - status = get_nt_and_unix_names( &attr, &true_nt_name, &buffer, disposition ); + status = get_nt_and_unix_names( &attr, &true_nt_name, &buffer, disposition, FALSE ); free( nt_name.Buffer ); free( true_nt_name.Buffer );
@@ -4412,7 +4420,8 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU status = file_id_to_unix_file_name( &new_attr, &unix_name, &nt_name ); if (!status) new_attr.ObjectName = &nt_name; } - else status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, disposition ); + else status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, disposition, + options & FILE_OPEN_REPARSE_POINT );
if (status == STATUS_BAD_DEVICE_TYPE) { @@ -4593,7 +4602,7 @@ NTSTATUS WINAPI NtDeleteFile( OBJECT_ATTRIBUTES *attr ) UNICODE_STRING nt_name; OBJECT_ATTRIBUTES new_attr = *attr;
- if (!(status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN ))) + if (!(status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN, FALSE ))) { if (!(status = open_unix_file( &handle, unix_name, GENERIC_READ | GENERIC_WRITE | DELETE, &new_attr, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, @@ -4617,7 +4626,7 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, UNICODE_STRING nt_name; OBJECT_ATTRIBUTES new_attr = *attr;
- if (!(status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN ))) + if (!(status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN, TRUE ))) { ULONG attributes; struct stat st; @@ -4646,7 +4655,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC UNICODE_STRING nt_name; OBJECT_ATTRIBUTES new_attr = *attr;
- if (!(status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN ))) + if (!(status = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN, TRUE ))) { ULONG attributes; struct stat st; @@ -5167,7 +5176,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, name_str.Length = info->FileNameLength; name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL ); - status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF ); + status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF, TRUE ); if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE) { SERVER_START_REQ( set_fd_name_info ) @@ -5212,7 +5221,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, name_str.Length = info->FileNameLength; name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL ); - status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF ); + status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF, TRUE ); if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE) { SERVER_START_REQ( set_fd_name_info ) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 12b071eebd9..2b200cafa26 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -980,7 +980,7 @@ static NTSTATUS load_so_dll( void *args )
if (get_load_order( nt_name ) == LO_DISABLED) return STATUS_DLL_NOT_FOUND; InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); - if (!get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN )) + if (!get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN, FALSE )) { /* remove .so extension from Windows name */ len = nt_name->Length / sizeof(WCHAR); @@ -1481,7 +1481,7 @@ static NTSTATUS open_main_image( UNICODE_STRING *nt_name, void **module, SECTION if (loadorder == LO_DISABLED) NtTerminateProcess( GetCurrentProcess(), STATUS_DLL_NOT_FOUND );
InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, NULL ); - if (get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN )) return STATUS_DLL_NOT_FOUND; + if (get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN, FALSE )) return STATUS_DLL_NOT_FOUND;
status = open_dll_file( unix_name, &attr, &mapping ); if (!status) diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index cd8b2994c1e..880b070c60e 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -256,7 +256,7 @@ static unsigned int get_pe_file_info( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *n
*handle = 0; memset( info, 0, sizeof(*info) ); - if (!(status = get_nt_and_unix_names( attr, nt_name, unix_name, FILE_OPEN ))) + if (!(status = get_nt_and_unix_names( attr, nt_name, unix_name, FILE_OPEN, FALSE ))) { status = open_unix_file( handle, *unix_name, GENERIC_READ, attr, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, @@ -340,7 +340,7 @@ static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params ) nt_name.Length = wcslen( nt_name.Buffer ) * sizeof(WCHAR);
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL ); - status = get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN ); + status = get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN, FALSE ); if (status) goto done; status = open_unix_file( &handle, unix_name, FILE_TRAVERSE | SYNCHRONIZE, &attr, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 9341e14549b..24515d4dbbe 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -733,7 +733,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f if (roothandle) FIXME("roothandle is not filled\n"); if (iostatus) FIXME("iostatus is not filled\n");
- if (!(ret = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN ))) + if (!(ret = get_nt_and_unix_names( &new_attr, &nt_name, &unix_name, FILE_OPEN, FALSE ))) { ret = open_unix_file( &key, unix_name, GENERIC_READ | SYNCHRONIZE, &new_attr, 0, 0, FILE_OPEN, 0, NULL, 0 ); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 941c05f2bc2..2a552a96c57 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -358,7 +358,7 @@ extern struct async_fileio *alloc_fileio( DWORD size, async_callback_t callback, extern void release_fileio( struct async_fileio *io ); extern NTSTATUS errno_to_status( int err ); extern NTSTATUS get_nt_and_unix_names( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name, - char **unix_name, UINT disposition ); + char **unix_name, UINT disposition, BOOL open_reparse ); extern NTSTATUS unix_to_nt_file_name( const char *unix_name, WCHAR **nt, UINT disposition ); extern NTSTATUS get_full_path( char *name, const WCHAR *curdir, UNICODE_STRING *nt_name ); extern NTSTATUS get_nt_path( const WCHAR *name, UNICODE_STRING *nt_name );
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/tests/file.c | 13 +++++-------- dlls/ntdll/unix/file.c | 1 + 2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index ac7a0dcf3db..87b5ca6a16c 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6375,14 +6375,11 @@ static void test_reparse_points(void)
swprintf( path, ARRAY_SIZE(path), L"%s/testreparse_dirlink", temp_path ); find_handle = FindFirstFileW( path, &find_data ); - todo_wine ok( find_handle != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); - if (find_handle != INVALID_HANDLE_VALUE) - { - todo_wine ok( find_data.dwFileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), - "got attributes %#lx\n", find_data.dwFileAttributes ); - todo_wine ok( find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", find_data.dwReserved0 ); - FindClose( find_handle ); - } + ok( find_handle != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); + todo_wine ok( find_data.dwFileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), + "got attributes %#lx\n", find_data.dwFileAttributes ); + todo_wine ok( find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", find_data.dwReserved0 ); + FindClose( find_handle );
/* Test using the reparse point as a parent. * On some machines this returns STATUS_REPARSE_POINT_NOT_RESOLVED (which diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 23c181650ed..114ca7679aa 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1591,6 +1591,7 @@ static BOOL append_entry( struct dir_data *data, const char *long_name,
long_len = ntdll_umbstowcs( long_name, strlen(long_name), long_nameW, ARRAY_SIZE(long_nameW) ); if (long_len == ARRAY_SIZE(long_nameW)) return TRUE; + if (long_nameW[long_len - 1] == '?') --long_len; long_nameW[long_len] = 0;
if (short_name)
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/tests/file.c | 4 ++-- dlls/ntdll/unix/file.c | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 87b5ca6a16c..040d6d5da94 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6363,7 +6363,7 @@ static void test_reparse_points(void) ret = GetFileAttributesW( L"file" ); ok( ret == FILE_ATTRIBUTE_ARCHIVE, "got %#x\n", ret ); ret = GetFileAttributesW( L"." ); - todo_wine ok( ret == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), "got %#x\n", ret ); + ok( ret == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), "got %#x\n", ret );
SetCurrentDirectoryW( path2 );
@@ -6376,7 +6376,7 @@ static void test_reparse_points(void) swprintf( path, ARRAY_SIZE(path), L"%s/testreparse_dirlink", temp_path ); find_handle = FindFirstFileW( path, &find_data ); ok( find_handle != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); - todo_wine ok( find_data.dwFileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), + ok( find_data.dwFileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), "got attributes %#lx\n", find_data.dwFileAttributes ); todo_wine ok( find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", find_data.dwReserved0 ); FindClose( find_handle ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 114ca7679aa..ba50e6cc45c 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1750,6 +1750,7 @@ static NTSTATUS fd_set_file_info( int fd, UINT attr, BOOL force_set_xattr ) /* get the stat info and file attributes for a file (by name) */ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) { + size_t len = strlen( path ); char *parent_path; char attr_data[65]; int attr_len, ret; @@ -1764,7 +1765,7 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) /* is a symbolic link and a directory, consider these "reparse points" */ if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT; } - else if (S_ISDIR( st->st_mode ) && (parent_path = malloc( strlen(path) + 4 ))) + else if (S_ISDIR( st->st_mode ) && (parent_path = malloc( len + 4 ))) { struct stat parent_st;
@@ -1779,6 +1780,9 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st );
+ if (path[len - 1] == '?') + *attr |= FILE_ATTRIBUTE_REPARSE_POINT; + attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); if (attr_len != -1) *attr |= parse_samba_dos_attrib_data( attr_data, attr_len );
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/tests/file.c | 12 ++++---- dlls/ntdll/unix/file.c | 67 +++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 26 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 040d6d5da94..7f8cfdadcd5 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6239,9 +6239,9 @@ static void test_reparse_points(void)
status = NtQueryInformationFile( handle, &io, &tag_info, sizeof(tag_info), FileAttributeTagInformation ); ok( !status, "got %#lx\n", status ); - todo_wine ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), + ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), "got attributes %#lx\n", tag_info.FileAttributes ); - todo_wine ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); + ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); status = NtQueryInformationFile( handle, &io, &std_info, sizeof(std_info), FileStandardInformation ); ok( !status, "got %#lx\n", status ); ok( !std_info.AllocationSize.QuadPart, "got size %#I64x\n", std_info.AllocationSize.QuadPart ); @@ -6251,9 +6251,9 @@ static void test_reparse_points(void)
status = NtQueryInformationFile( handle2, &io, &tag_info, sizeof(tag_info), FileAttributeTagInformation ); ok( !status, "got %#lx\n", status ); - todo_wine ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), + ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), "got attributes %#lx\n", tag_info.FileAttributes ); - todo_wine ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); + ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); status = NtQueryInformationFile( handle2, &io, &std_info, sizeof(std_info), FileStandardInformation ); ok( !status, "got %#lx\n", status ); ok( !std_info.AllocationSize.QuadPart, "got size %#I64x\n", std_info.AllocationSize.QuadPart ); @@ -6276,9 +6276,9 @@ static void test_reparse_points(void) ok( !status, "got %#lx\n", status ); status = NtQueryInformationFile( handle2, &io, &tag_info, sizeof(tag_info), FileAttributeTagInformation ); ok( !status, "got %#lx\n", status ); - todo_wine ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), + ok( tag_info.FileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT), "got attributes %#lx\n", tag_info.FileAttributes ); - todo_wine ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); + ok( tag_info.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT, "got tag %#lx\n", tag_info.ReparseTag ); status = NtQueryInformationFile( handle2, &io, &std_info, sizeof(std_info), FileStandardInformation ); ok( !status, "got %#lx\n", status ); ok( !std_info.AllocationSize.QuadPart, "got size %#I64x\n", std_info.AllocationSize.QuadPart ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index ba50e6cc45c..3c59f2c63e9 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1665,9 +1665,14 @@ static BOOL fd_is_mount_point( int fd, const struct stat *st ) }
+static unsigned int server_get_unix_name( HANDLE handle, char **unix_name ); + + /* get the stat info and file attributes for a file (by file descriptor) */ -static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULONG *attr ) +static int fd_get_file_info( HANDLE handle, int fd, unsigned int options, + struct stat *st, ULONG *attr, ULONG *reparse_tag ) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; char attr_data[65]; int attr_len, ret;
@@ -1675,9 +1680,23 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON ret = fstat( fd, st ); if (ret == -1) return ret; *attr |= get_file_attributes( st ); + if (reparse_tag) *reparse_tag = 0; /* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */ - if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st )) + if (options & FILE_OPEN_REPARSE_POINT) + { + if (fd_is_mount_point( fd, st )) + { + *attr |= FILE_ATTRIBUTE_REPARSE_POINT; + if (reparse_tag) *reparse_tag = IO_REPARSE_TAG_MOUNT_POINT; + } + } + + attr_len = xattr_fget( fd, XATTR_REPARSE, buffer, sizeof(buffer) ); + if (attr_len >= 0 && attr_len >= sizeof(ULONG)) + { *attr |= FILE_ATTRIBUTE_REPARSE_POINT; + if (reparse_tag) memcpy( reparse_tag, buffer, sizeof(ULONG) ); + }
attr_len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); if (attr_len != -1) @@ -4769,6 +4788,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, struct stat st; int fd, needs_close = FALSE; ULONG attr; + unsigned int reparse_tag; unsigned int options; unsigned int status;
@@ -4794,7 +4814,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, switch (class) { case FileBasicInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) status = errno_to_status( errno ); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; @@ -4805,7 +4825,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, { FILE_STANDARD_INFORMATION *info = ptr;
- if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) + status = errno_to_status( errno ); else { fill_file_info( &st, attr, info, class ); @@ -4822,8 +4843,10 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } break; case FileInternalInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); - else fill_file_info( &st, attr, ptr, class ); + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) + status = errno_to_status( errno ); + else + fill_file_info( &st, attr, ptr, class ); break; case FileEaInformation: { @@ -4832,14 +4855,17 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } break; case FileEndOfFileInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); - else fill_file_info( &st, attr, ptr, class ); + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) + status = errno_to_status( errno ); + else + fill_file_info( &st, attr, ptr, class ); break; case FileAllInformation: { FILE_ALL_INFORMATION *info = ptr;
- if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) + status = errno_to_status( errno ); else { LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName); @@ -4864,11 +4890,14 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } break; case FileNetworkOpenInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); - else fill_file_info( &st, attr, ptr, FileNetworkOpenInformation ); + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) + status = errno_to_status( errno ); + else + fill_file_info( &st, attr, ptr, FileNetworkOpenInformation ); break; case FileIdInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_info( handle, fd, options, &st, &attr, NULL ) == -1) + status = errno_to_status( errno ); else { struct mountmgr_unix_drive drive; @@ -4882,18 +4911,18 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } break; case FileAttributeTagInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_info( handle, fd, options, &st, &attr, &reparse_tag ) == -1) + status = errno_to_status( errno ); else { FILE_ATTRIBUTE_TAG_INFORMATION *info = ptr; info->FileAttributes = attr; - info->ReparseTag = 0; /* FIXME */ - if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st )) - info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + info->ReparseTag = reparse_tag; } break; case FileStatInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_info( handle, fd, options, &st, &attr, &reparse_tag ) == -1) + status = errno_to_status( errno ); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; else @@ -4913,9 +4942,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, info->AllocationSize = std.AllocationSize; info->EndOfFile = std.EndOfFile; info->FileAttributes = attr; - info->ReparseTag = 0; /* FIXME */ - if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st )) - info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + info->ReparseTag = reparse_tag; info->NumberOfLinks = std.NumberOfLinks; info->EffectiveAccess = FILE_ALL_ACCESS; /* FIXME */ }
On Wed Nov 12 04:21:13 2025 +0000, Elizabeth Figura wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/9428/diffs?diff_id=223119&start_sha=9c114c41bb35f260cd48c5dc6ea34a2fa71b7926#a6054b4d823544828fc181519321938fe40b14ff_7384_7384)
Thanks for catching that.