Also unifies hidden file handling.
Fixes bug [53826](https://bugs.winehq.org/show_bug.cgi?id=53826).
-- v11: ntdll: Try to avoid requesting the file name for a handle. ntdll: Ensure that attributes are kept the same when renaming or hard-linking a file. ntdll: Set xattr in NtCreateFile if inferred and requested attributes don't match. ntdll: Only infer hidden attribute from file name if xattr is not present. ntdll: Handle hidden file names in fd_get_file_info. ntdll: Pass file path into fd_get_file_info if available. ntdll: Do not compute file attributes for info classes that don't need them. ntdll: Handle hidden file names inside get_file_info instead of after it. ntdll: Do not open-code hidden file handling in get_dir_data_entry. ntdll/tests: Add test for file attributes of files with names beginning with a dot.
From: Torge Matthies tmatthies@codeweavers.com
--- dlls/ntdll/tests/file.c | 82 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 98d9e6b3b0a..53cdc8a3ca6 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3971,6 +3971,87 @@ static void test_file_attribute_tag_information(void) CloseHandle( h ); }
+#define lok ok_(__FILE__, line) +#define rename_file(h,f) rename_file_(__LINE__,(h),(f)) +static BOOL rename_file_( int line, HANDLE h, const WCHAR *filename ) +{ + FILE_RENAME_INFORMATION *fri; + UNICODE_STRING ntpath; + IO_STATUS_BLOCK io; + NTSTATUS status; + BOOLEAN ret; + ULONG size; + + ret = pRtlDosPathNameToNtPathName_U( filename, &ntpath, NULL, NULL ); + lok( ret, "RtlDosPathNameToNtPathName_U failed\n" ); + if (!ret) return FALSE; + + size = offsetof( FILE_RENAME_INFORMATION, FileName ) + ntpath.Length; + fri = HeapAlloc( GetProcessHeap(), 0, size ); + lok( fri != NULL, "HeapAlloc failed\n" ); + if (!fri) return FALSE; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; + fri->FileNameLength = ntpath.Length; + memcpy( fri->FileName, ntpath.Buffer, ntpath.Length ); + pRtlFreeUnicodeString( &ntpath ); + + status = pNtSetInformationFile( h, &io, fri, size, FileRenameInformation ); + HeapFree( GetProcessHeap(), 0, fri ); + lok( status == STATUS_SUCCESS, "got %#lx\n", status ); + return status == STATUS_SUCCESS; +} +#undef lok + +static void test_dotfile_file_attributes(void) +{ + char temppath[MAX_PATH], filename[MAX_PATH]; + WCHAR temppathW[MAX_PATH], filenameW[MAX_PATH]; + FILE_BASIC_INFORMATION info = {}; + IO_STATUS_BLOCK io; + NTSTATUS status; + DWORD attrs; + HANDLE h; + + GetTempPathA( MAX_PATH, temppath ); + GetTempFileNameA( temppath, ".foo", 0, filename ); + h = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ok( h != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + if (h == INVALID_HANDLE_VALUE) return; + + status = nt_get_file_attrs(filename, &attrs); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + CloseHandle( h ); + + GetTempPathW( MAX_PATH, temppathW ); + GetTempFileNameW( temppathW, L"foo", 0, filenameW ); + h = CreateFileW( filenameW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ok( h != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + if (h == INVALID_HANDLE_VALUE) return; + + GetTempFileNameW( temppathW, L".foo", 0, filenameW ); + if (!rename_file( h, filenameW )) return; + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + GetTempFileNameW( temppathW, L"foo", 0, filenameW ); + if (!rename_file( h, filenameW )) return; + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + CloseHandle( h ); +} + static void test_file_mode(void) { UNICODE_STRING file_name, pipe_dev_name, mountmgr_dev_name, mailslot_dev_name; @@ -5419,6 +5500,7 @@ START_TEST(file) test_file_id_information(); test_file_access_information(); test_file_attribute_tag_information(); + test_dotfile_file_attributes(); test_file_mode(); test_file_readonly_access(); test_query_volume_information_file();
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/unix/file.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index e80eb368e8a..b5170edbde4 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1303,7 +1303,7 @@ static BOOL is_hidden_file( const UNICODE_STRING *name ) end = p = name->Buffer + name->Length/sizeof(WCHAR); while (p > name->Buffer && p[-1] == '\') p--; while (p > name->Buffer && p[-1] != '\') p--; - return (p < end && *p == '.'); + return (p < end && p + 1 != end && p[0] == '.' && p[1] != '\' && (p[1] != '.' || (p + 2 != end && p[2] != '\'))); }
@@ -2224,6 +2224,7 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I union file_directory_info *info; struct stat st; ULONG name_len, start, dir_size, attributes; + UNICODE_STRING name;
if (get_file_info( names->unix_name, &st, &attributes ) == -1) { @@ -2253,8 +2254,8 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I { if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */
- if (!show_dot_files && names->long_name[0] == '.' && names->long_name[1] && - (names->long_name[1] != '.' || names->long_name[2])) + RtlInitUnicodeString( &name, names->long_name ); + if (is_hidden_file( &name )) attributes |= FILE_ATTRIBUTE_HIDDEN;
fill_file_info( &st, attributes, info, class );
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/unix/file.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index b5170edbde4..babd47fdcc1 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1292,18 +1292,18 @@ static BOOLEAN get_dir_case_sensitivity( const char *dir ) /*********************************************************************** * is_hidden_file * - * Check if the specified file should be hidden based on its name and the show dot files option. + * Check if the specified file should be hidden based on its unix path and the show dot files option. */ -static BOOL is_hidden_file( const UNICODE_STRING *name ) +static BOOL is_hidden_file( const char *name ) { - WCHAR *p, *end; + const char *p, *end;
if (show_dot_files) return FALSE;
- end = p = name->Buffer + name->Length/sizeof(WCHAR); - while (p > name->Buffer && p[-1] == '\') p--; - while (p > name->Buffer && p[-1] != '\') p--; - return (p < end && p + 1 != end && p[0] == '.' && p[1] != '\' && (p[1] != '.' || (p + 2 != end && p[2] != '\'))); + end = p = name + strlen( name ); + while (p > name && p[-1] == '/') p--; + while (p > name && p[-1] != '/') p--; + return (p < end && p + 1 != end && p[0] == '.' && p[1] != '/' && (p[1] != '.' || (p + 2 != end && p[2] != '/'))); }
@@ -1677,6 +1677,9 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st );
+ if (is_hidden_file( path )) + *attr |= FILE_ATTRIBUTE_HIDDEN; + 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 ); @@ -2224,7 +2227,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I union file_directory_info *info; struct stat st; ULONG name_len, start, dir_size, attributes; - UNICODE_STRING name;
if (get_file_info( names->unix_name, &st, &attributes ) == -1) { @@ -2253,11 +2255,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I if (class != FileNamesInformation) { if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */ - - RtlInitUnicodeString( &name, names->long_name ); - if (is_hidden_file( &name )) - attributes |= FILE_ATTRIBUTE_HIDDEN; - fill_file_info( &st, attributes, info, class ); }
@@ -4214,7 +4211,6 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, info->AllocationSize = std.AllocationSize; info->EndOfFile = std.EndOfFile; info->FileAttributes = basic.FileAttributes; - if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } free( unix_name ); } @@ -4245,10 +4241,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; else - { status = fill_file_info( &st, attributes, info, FileBasicInformation ); - if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - } free( unix_name ); } else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status );
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/unix/file.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index babd47fdcc1..1e37b4e0306 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1570,6 +1570,13 @@ static BOOL fd_is_mount_point( int fd, const struct stat *st ) }
+/* get the stat info for a file (by file descriptor) */ +static int fd_get_file_stat( int fd, struct stat *st ) +{ + return fstat( fd, st ); +} + + /* 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 ) { @@ -1577,7 +1584,7 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON int attr_len, ret;
*attr = 0; - ret = fstat( fd, st ); + ret = fd_get_file_stat( fd, st ); if (ret == -1) return ret; *attr |= get_file_attributes( st ); /* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */ @@ -4361,10 +4368,10 @@ 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_stat( fd, &st ) == -1) status = errno_to_status( errno ); else { - fill_file_info( &st, attr, info, class ); + fill_file_info( &st, 0, info, class ); info->DeletePending = FALSE; /* FIXME */ } } @@ -4378,8 +4385,8 @@ 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_stat( fd, &st ) == -1) status = errno_to_status( errno ); + else fill_file_info( &st, 0, ptr, class ); break; case FileEaInformation: { @@ -4388,8 +4395,8 @@ 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_stat( fd, &st ) == -1) status = errno_to_status( errno ); + else fill_file_info( &st, 0, ptr, class ); break; case FileAllInformation: { @@ -4504,7 +4511,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } break; case FileIdInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_stat( fd, &st ) == -1) status = errno_to_status( errno ); else { struct mountmgr_unix_drive drive;
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/unix/file.c | 57 ++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 1e37b4e0306..41f6b51c231 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1578,7 +1578,7 @@ static int fd_get_file_stat( int fd, struct stat *st )
/* 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( int fd, const char *unix_name, unsigned int options, struct stat *st, ULONG *attr ) { char attr_data[65]; int attr_len, ret; @@ -4357,13 +4357,21 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, switch (class) { case FileBasicInformation: - if (fd_get_file_info( fd, options, &st, &attr ) == -1) - status = errno_to_status( errno ); - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - status = STATUS_INVALID_INFO_CLASS; - else - fill_file_info( &st, attr, ptr, class ); - break; + { + char *unix_name; + + if (server_get_unix_name( handle, &unix_name )) + unix_name = NULL; + + if (fd_get_file_info( fd, unix_name, options, &st, &attr ) == -1) + status = errno_to_status( errno ); + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + status = STATUS_INVALID_INFO_CLASS; + else + fill_file_info( &st, attr, ptr, class ); + free( unix_name ); + break; + } case FileStandardInformation: { FILE_STANDARD_INFORMATION *info = ptr; @@ -4403,10 +4411,13 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, FILE_ALL_INFORMATION *info = ptr; char *unix_name;
- if (fd_get_file_info( fd, options, &st, &attr ) == -1) status = errno_to_status( errno ); + status = server_get_unix_name( handle, &unix_name ); + if (fd_get_file_info( fd, unix_name, options, &st, &attr ) == -1) status = errno_to_status( errno ); + else if (status) + break; else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; - else if (!(status = server_get_unix_name( handle, &unix_name ))) + else { LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
@@ -4419,9 +4430,9 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, info->AlignmentInformation.AlignmentRequirement = 1; /* FIXME */
status = fill_name_info( unix_name, &info->NameInformation, &name_len ); - free( unix_name ); io->Information = FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName) + name_len; } + free( unix_name ); } break; case FileMailslotQueryInformation: @@ -4525,16 +4536,24 @@ 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 ); - 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; + char *unix_name; + + if (server_get_unix_name( handle, &unix_name )) + unix_name = NULL; + + if (fd_get_file_info( fd, unix_name, options, &st, &attr ) == -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; + } + free( unix_name ); + break; } - break; default: FIXME("Unsupported class (%d)\n", class); status = STATUS_NOT_IMPLEMENTED;
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/tests/file.c | 4 ++-- dlls/ntdll/unix/file.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 53cdc8a3ca6..0e032bed3c7 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4025,7 +4025,7 @@ static void test_dotfile_file_attributes(void)
status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + todo_wine ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes );
CloseHandle( h );
@@ -4040,7 +4040,7 @@ static void test_dotfile_file_attributes(void)
status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + todo_wine ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes );
GetTempFileNameW( temppathW, L"foo", 0, filenameW ); if (!rename_file( h, filenameW )) return; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 41f6b51c231..600751fd0ec 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1591,6 +1591,9 @@ static int fd_get_file_info( int fd, const char *unix_name, unsigned int options if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
+ if (unix_name && is_hidden_file( unix_name )) + *attr |= FILE_ATTRIBUTE_HIDDEN; + attr_len = xattr_fget( fd, 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: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/unix/file.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 600751fd0ec..a80f80f9f99 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1591,14 +1591,13 @@ static int fd_get_file_info( int fd, const char *unix_name, unsigned int options if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
- if (unix_name && is_hidden_file( unix_name )) - *attr |= FILE_ATTRIBUTE_HIDDEN; - attr_len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); if (attr_len != -1) *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); else { + if (unix_name && is_hidden_file( unix_name )) + *attr |= FILE_ATTRIBUTE_HIDDEN; if (errno == ENOTSUP) return ret; #ifdef ENODATA if (errno == ENODATA) return ret; @@ -1687,14 +1686,13 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st );
- if (is_hidden_file( path )) - *attr |= FILE_ATTRIBUTE_HIDDEN; - 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 ); else { + if (is_hidden_file( path )) + *attr |= FILE_ATTRIBUTE_HIDDEN; if (errno == ENOTSUP) return ret; #ifdef ENODATA if (errno == ENODATA) return ret;
From: Torge Matthies tmatthies@codeweavers.com
And make sure it doesn't get deleted.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53826 Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/tests/file.c | 4 ++-- dlls/ntdll/unix/file.c | 26 +++++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 0e032bed3c7..724072a993b 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4021,11 +4021,11 @@ static void test_dotfile_file_attributes(void)
status = nt_get_file_attrs(filename, &attrs); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes );
status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - todo_wine ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes );
CloseHandle( h );
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index a80f80f9f99..52b49f56c29 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1609,11 +1609,11 @@ static int fd_get_file_info( int fd, const char *unix_name, unsigned int options }
-static int fd_set_dos_attrib( int fd, ULONG attr ) +static int fd_set_dos_attrib( int fd, ULONG attr, BOOL force_set ) { /* we only store the HIDDEN and SYSTEM attributes */ attr &= XATTR_ATTRIBS_MASK; - if (attr != 0) + if (force_set || attr != 0) { /* encode the attributes in Samba 3 ASCII format. Samba 4 has extended * this format with more features, but retains compatibility with the @@ -1627,7 +1627,7 @@ static int fd_set_dos_attrib( int fd, ULONG attr )
/* set the stat info and file attributes for a file (by file descriptor) */ -NTSTATUS fd_set_file_info( int fd, ULONG attr ) +NTSTATUS fd_set_file_info( int fd, ULONG attr, BOOL force_set_xattr ) { struct stat st;
@@ -1646,7 +1646,8 @@ NTSTATUS fd_set_file_info( int fd, ULONG attr ) } if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno );
- if (fd_set_dos_attrib( fd, attr ) == -1 && errno != ENOTSUP) + force_set_xattr = force_set_xattr || st.st_nlink > 1; + if (fd_set_dos_attrib( fd, attr, force_set_xattr ) == -1 && errno != ENOTSUP) WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", errno, strerror( errno ) );
@@ -3972,6 +3973,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU OBJECT_ATTRIBUTES new_attr; UNICODE_STRING nt_name; char *unix_name; + BOOL name_hidden = FALSE; BOOL created = FALSE; NTSTATUS status;
@@ -4014,6 +4016,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU
if (status == STATUS_SUCCESS) { + name_hidden = is_hidden_file( unix_name ); status = open_unix_file( handle, unix_name, access, &new_attr, attributes, sharing, disposition, options, ea_buffer, ea_length ); free( unix_name ); @@ -4041,14 +4044,15 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU break; }
- if (io->Information == FILE_CREATED && (attributes & XATTR_ATTRIBS_MASK)) + if (io->Information == FILE_CREATED && + ((attributes & XATTR_ATTRIBS_MASK) || name_hidden)) { int fd, needs_close;
/* set any DOS extended attributes */ if (!server_get_unix_fd( *handle, 0, &fd, &needs_close, NULL, NULL )) { - if (fd_set_dos_attrib( fd, attributes ) == -1 && errno != ENOTSUP) + if (fd_set_dos_attrib( fd, attributes, TRUE ) == -1 && errno != ENOTSUP) WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)", errno, strerror( errno ) ); if (needs_close) close( fd ); @@ -4584,10 +4588,14 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, { const FILE_BASIC_INFORMATION *info = ptr; LARGE_INTEGER mtime, atime; + char *unix_name;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) return io->u.Status = status;
+ if ((status = server_get_unix_name( handle, &unix_name ))) + unix_name = NULL; + mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart; atime.QuadPart = info->LastAccessTime.QuadPart == -1 ? 0 : info->LastAccessTime.QuadPart;
@@ -4595,9 +4603,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, status = set_file_times( fd, &mtime, &atime );
if (status == STATUS_SUCCESS && info->FileAttributes) - status = fd_set_file_info( fd, info->FileAttributes ); + { + BOOL force_xattr = unix_name && is_hidden_file( unix_name ); + status = fd_set_file_info( fd, info->FileAttributes, force_xattr ); + }
if (needs_close) close( fd ); + free( unix_name ); } else status = STATUS_INVALID_PARAMETER_3; break;
From: Torge Matthies tmatthies@codeweavers.com
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/ntdll/tests/file.c | 2 +- dlls/ntdll/unix/file.c | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 724072a993b..9d3dd5cca29 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4040,7 +4040,7 @@ static void test_dotfile_file_attributes(void)
status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - todo_wine ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes );
GetTempFileNameW( temppathW, L"foo", 0, filenameW ); if (!rename_file( h, filenameW )) return; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 52b49f56c29..02d4a8bc16e 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4570,6 +4570,33 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, }
+static NTSTATUS refresh_file_attrs( HANDLE handle, BOOL force_set_xattr ) +{ + unsigned int options; + BOOL needs_close; + NTSTATUS status; + char *unix_name; + struct stat st; + ULONG attrib; + int fd; + + if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, &options ))) + return status; + if (server_get_unix_name( handle, &unix_name )) + unix_name = NULL; + + if (fd_get_file_info( fd, unix_name, options, &st, &attrib ) == -1) + status = errno_to_status( errno ); + else + status = fd_set_file_info( fd, attrib, force_set_xattr ); + + free( unix_name ); + if (needs_close) + close( fd ); + return status; +} + + /****************************************************************************** * NtSetInformationFile (NTDLL.@) */ @@ -4788,7 +4815,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, FILE_RENAME_INFORMATION *info = ptr; UNICODE_STRING name_str, redir; OBJECT_ATTRIBUTES attr; - char *unix_name; + char *unix_name = NULL;
name_str.Buffer = info->FileName; name_str.Length = info->FileNameLength; @@ -4797,6 +4824,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, get_redirect( &attr, &redir );
status = nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN_IF ); + if (status == STATUS_SUCCESS && is_hidden_file( unix_name )) + status = refresh_file_attrs( handle, TRUE ); if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE) { SERVER_START_REQ( set_fd_name_info ) @@ -4811,9 +4840,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, status = wine_server_call( req ); } SERVER_END_REQ; - - free( unix_name ); } + free( unix_name ); free( redir.Buffer ); } else status = STATUS_INVALID_PARAMETER_3; @@ -4825,7 +4853,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, FILE_LINK_INFORMATION *info = ptr; UNICODE_STRING name_str, redir; OBJECT_ATTRIBUTES attr; - char *unix_name; + char *unix_name = NULL;
name_str.Buffer = info->FileName; name_str.Length = info->FileNameLength; @@ -4834,6 +4862,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, get_redirect( &attr, &redir );
status = nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN_IF ); + if (status == STATUS_SUCCESS && is_hidden_file( unix_name )) + status = refresh_file_attrs( handle, TRUE ); if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE) { SERVER_START_REQ( set_fd_name_info ) @@ -4848,9 +4878,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, status = wine_server_call( req ); } SERVER_END_REQ; - - free( unix_name ); } + free( unix_name ); free( redir.Buffer ); } else status = STATUS_INVALID_PARAMETER_3;
From: Torge Matthies tmatthies@codeweavers.com
--- dlls/ntdll/unix/file.c | 126 ++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 70 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 02d4a8bc16e..213eb63269d 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1577,8 +1577,40 @@ static int fd_get_file_stat( int fd, struct stat *st ) }
+static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name ) +{ + data_size_t size = 1024; + NTSTATUS ret; + char *name; + + for (;;) + { + if (!(name = malloc( size + 1 ))) return STATUS_NO_MEMORY; + + SERVER_START_REQ( get_handle_unix_name ) + { + req->handle = wine_server_obj_handle( handle ); + wine_server_set_reply( req, name, size ); + ret = wine_server_call( req ); + size = reply->name_len; + } + SERVER_END_REQ; + + if (!ret) + { + name[size] = 0; + *unix_name = name; + break; + } + free( name ); + if (ret != STATUS_BUFFER_OVERFLOW) break; + } + return ret; +} + + /* get the stat info and file attributes for a file (by file descriptor) */ -static int fd_get_file_info( int fd, const char *unix_name, unsigned int options, struct stat *st, ULONG *attr ) +static int fd_get_file_info( int fd, char *unix_name, HANDLE handle, unsigned int options, struct stat *st, ULONG *attr ) { char attr_data[65]; int attr_len, ret; @@ -1598,6 +1630,12 @@ static int fd_get_file_info( int fd, const char *unix_name, unsigned int options { if (unix_name && is_hidden_file( unix_name )) *attr |= FILE_ATTRIBUTE_HIDDEN; + else if (handle && server_get_unix_name( handle, &unix_name )) + { + if (is_hidden_file( unix_name )) + *attr |= FILE_ATTRIBUTE_HIDDEN; + free( unix_name ); + } if (errno == ENOTSUP) return ret; #ifdef ENODATA if (errno == ENODATA) return ret; @@ -1946,38 +1984,6 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr, return STATUS_SUCCESS; }
- -static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name ) -{ - data_size_t size = 1024; - NTSTATUS ret; - char *name; - - for (;;) - { - if (!(name = malloc( size + 1 ))) return STATUS_NO_MEMORY; - - SERVER_START_REQ( get_handle_unix_name ) - { - req->handle = wine_server_obj_handle( handle ); - wine_server_set_reply( req, name, size ); - ret = wine_server_call( req ); - size = reply->name_len; - } - SERVER_END_REQ; - - if (!ret) - { - name[size] = 0; - *unix_name = name; - break; - } - free( name ); - if (ret != STATUS_BUFFER_OVERFLOW) break; - } - return ret; -} - static NTSTATUS fill_name_info( const char *unix_name, FILE_NAME_INFORMATION *info, LONG *name_len ) { WCHAR *nt_name; @@ -4362,21 +4368,13 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, switch (class) { case FileBasicInformation: - { - char *unix_name; - - if (server_get_unix_name( handle, &unix_name )) - unix_name = NULL; - - if (fd_get_file_info( fd, unix_name, options, &st, &attr ) == -1) - status = errno_to_status( errno ); - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - status = STATUS_INVALID_INFO_CLASS; - else - fill_file_info( &st, attr, ptr, class ); - free( unix_name ); - break; - } + if (fd_get_file_info( fd, NULL, handle, options, &st, &attr ) == -1) + status = errno_to_status( errno ); + else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) + status = STATUS_INVALID_INFO_CLASS; + else + fill_file_info( &st, attr, ptr, class ); + break; case FileStandardInformation: { FILE_STANDARD_INFORMATION *info = ptr; @@ -4417,7 +4415,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, char *unix_name;
status = server_get_unix_name( handle, &unix_name ); - if (fd_get_file_info( fd, unix_name, options, &st, &attr ) == -1) status = errno_to_status( errno ); + if (fd_get_file_info( fd, unix_name, NULL, options, &st, &attr ) == -1) status = errno_to_status( errno ); else if (status) break; else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) @@ -4541,24 +4539,16 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } break; case FileAttributeTagInformation: + if (fd_get_file_info( fd, NULL, handle, options, &st, &attr ) == -1) status = errno_to_status( errno ); + else { - char *unix_name; - - if (server_get_unix_name( handle, &unix_name )) - unix_name = NULL; - - if (fd_get_file_info( fd, unix_name, options, &st, &attr ) == -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; - } - free( unix_name ); - break; + 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; } + break; default: FIXME("Unsupported class (%d)\n", class); status = STATUS_NOT_IMPLEMENTED; @@ -4575,22 +4565,18 @@ static NTSTATUS refresh_file_attrs( HANDLE handle, BOOL force_set_xattr ) unsigned int options; BOOL needs_close; NTSTATUS status; - char *unix_name; struct stat st; ULONG attrib; int fd;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, &options ))) return status; - if (server_get_unix_name( handle, &unix_name )) - unix_name = NULL;
- if (fd_get_file_info( fd, unix_name, options, &st, &attrib ) == -1) + if (fd_get_file_info( fd, NULL, handle, options, &st, &attrib ) == -1) status = errno_to_status( errno ); else status = fd_set_file_info( fd, attrib, force_set_xattr );
- free( unix_name ); if (needs_close) close( fd ); return status;