This patchset aims to fix #46070 without supplying unix_name for all server files.
-- v3: kernelbase: Replace FileAllInformation with FileStatInformation in GetFileInformationByHandle(). ntdll: Implement NtQueryInformationFile FileStatInformation.
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- include/winternl.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/include/winternl.h b/include/winternl.h index 52af87320a5..04778c5cd59 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1633,6 +1633,20 @@ typedef struct _FILE_ALL_INFORMATION { FILE_NAME_INFORMATION NameInformation; } FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;
+typedef struct _FILE_STAT_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG EffectiveAccess; +} FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION; + typedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION { ULONG Flags; } FILE_IO_COMPLETION_NOTIFICATION_INFORMATION, *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION;
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/ntdll/tests/file.c | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index da3611f74f2..3ea5eeea01f 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4357,6 +4357,57 @@ static void test_file_attribute_tag_information(void) CloseHandle( h ); }
+static void test_file_stat_information(void) +{ + BY_HANDLE_FILE_INFORMATION info; + FILE_STAT_INFORMATION fsd; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE h; + BOOL ret; + + if (!(h = create_temp_file(0))) return; + + memset( &fsd, 0x11, sizeof(fsd) ); + status = pNtQueryInformationFile( h, &io, &fsd, sizeof(fsd), FileStatInformation ); + if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS) + { + skip( "FileStatInformation not supported\n" ); + CloseHandle( h ); + return; + } + ok( status == STATUS_SUCCESS, "query FileStatInformation returned %#lx\n", status ); + + memset( &info, 0x22, sizeof(info) ); + ret = GetFileInformationByHandle( h, &info ); + ok( ret, "GetFileInformationByHandle failed\n" ); + + ok( fsd.FileId.u.LowPart == info.nFileIndexLow, "expected %08lx, got %08lx\n", info.nFileIndexLow, fsd.FileId.u.LowPart ); + ok( fsd.FileId.u.HighPart == info.nFileIndexHigh, "expected %08lx, got %08lx\n", info.nFileIndexHigh, fsd.FileId.u.HighPart ); + ok( fsd.CreationTime.u.LowPart == info.ftCreationTime.dwLowDateTime, "expected %08lx, got %08lx\n", + info.ftCreationTime.dwLowDateTime, fsd.CreationTime.u.LowPart ); + ok( fsd.CreationTime.u.HighPart == info.ftCreationTime.dwHighDateTime, "expected %08lx, got %08lx\n", + info.ftCreationTime.dwHighDateTime, fsd.CreationTime.u.HighPart ); + ok( fsd.LastAccessTime.u.LowPart == info.ftLastAccessTime.dwLowDateTime, "expected %08lx, got %08lx\n", + info.ftLastAccessTime.dwLowDateTime, fsd.LastAccessTime.u.LowPart ); + ok( fsd.LastAccessTime.u.HighPart == info.ftLastAccessTime.dwHighDateTime, "expected %08lx, got %08lx\n", + info.ftLastAccessTime.dwHighDateTime, fsd.LastAccessTime.u.HighPart ); + ok( fsd.LastWriteTime.u.LowPart == info.ftLastWriteTime.dwLowDateTime, "expected %08lx, got %08lx\n", + info.ftLastWriteTime.dwLowDateTime, fsd.LastWriteTime.u.LowPart ); + ok( fsd.LastWriteTime.u.HighPart == info.ftLastWriteTime.dwHighDateTime, "expected %08lx, got %08lx\n", + info.ftLastWriteTime.dwHighDateTime, fsd.LastWriteTime.u.HighPart ); + /* TODO: ChangeTime */ + /* TODO: AllocationSize */ + ok( fsd.EndOfFile.u.LowPart == info.nFileSizeLow, "expected %08lx, got %08lx\n", info.nFileSizeLow, fsd.EndOfFile.u.LowPart ); + ok( fsd.EndOfFile.u.HighPart == info.nFileSizeHigh, "expected %08lx, got %08lx\n", info.nFileSizeHigh, fsd.EndOfFile.u.HighPart ); + ok( fsd.FileAttributes == info.dwFileAttributes, "expected %08lx, got %08lx\n", info.dwFileAttributes, fsd.FileAttributes ); + ok( !fsd.ReparseTag, "got reparse tag %#lx\n", fsd.ReparseTag ); + ok( fsd.NumberOfLinks == info.nNumberOfLinks, "expected %08lx, got %08lx\n", info.nNumberOfLinks, fsd.NumberOfLinks ); + ok( fsd.EffectiveAccess == FILE_ALL_ACCESS, "got %08lx\n", fsd.EffectiveAccess ); + + CloseHandle( h ); +} + static void rename_file( HANDLE h, const WCHAR *filename ) { FILE_RENAME_INFORMATION *fri; @@ -5900,6 +5951,7 @@ START_TEST(file) test_file_id_information(); test_file_access_information(); test_file_attribute_tag_information(); + test_file_stat_information(); test_dotfile_file_attributes(); test_file_mode(); test_file_readonly_access();
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/ntdll/tests/file.c | 2 +- dlls/ntdll/unix/file.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 3ea5eeea01f..9dd49c925b7 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4372,7 +4372,7 @@ static void test_file_stat_information(void) status = pNtQueryInformationFile( h, &io, &fsd, sizeof(fsd), FileStatInformation ); if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS) { - skip( "FileStatInformation not supported\n" ); + win_skip( "FileStatInformation not supported\n" ); CloseHandle( h ); return; } diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index ee68e4dee9b..d292d934efa 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4334,7 +4334,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, 0, /* FileRenameInformationEx */ 0, /* FileRenameInformationExBypassAccessCheck */ 0, /* FileDesiredStorageClassInformation */ - 0, /* FileStatInformation */ + sizeof(FILE_STAT_INFORMATION), /* FileStatInformation */ 0, /* FileMemoryPartitionInformation */ 0, /* FileStatLxInformation */ 0, /* FileCaseSensitiveInformation */ @@ -4549,6 +4549,34 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; } break; + case FileStatInformation: + 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 + { + FILE_STAT_INFORMATION *info = ptr; + FILE_BASIC_INFORMATION basic; + FILE_STANDARD_INFORMATION std; + + fill_file_info( &st, attr, &basic, FileBasicInformation ); + fill_file_info( &st, attr, &std, FileStandardInformation ); + + info->FileId.QuadPart = st.st_ino; + info->CreationTime = basic.CreationTime; + info->LastAccessTime = basic.LastAccessTime; + info->LastWriteTime = basic.LastWriteTime; + info->ChangeTime = basic.ChangeTime; + 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->NumberOfLinks = std.NumberOfLinks; + info->EffectiveAccess = FILE_ALL_ACCESS; /* FIXME */ + } + break; default: FIXME("Unsupported class (%d)\n", class); status = STATUS_NOT_IMPLEMENTED;
From: Jinoh Kang jinoh.kang.kr@gmail.com
It also fixes the game Unity of Command II (same bug).
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46070 --- dlls/kernelbase/file.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 67a7a34249a..2b59db43041 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -3043,27 +3043,26 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlushFileBuffers( HANDLE file ) BOOL WINAPI DECLSPEC_HOTPATCH GetFileInformationByHandle( HANDLE file, BY_HANDLE_FILE_INFORMATION *info ) { FILE_FS_VOLUME_INFORMATION volume_info; - FILE_ALL_INFORMATION all_info; + FILE_STAT_INFORMATION stat_info; IO_STATUS_BLOCK io; NTSTATUS status;
- status = NtQueryInformationFile( file, &io, &all_info, sizeof(all_info), FileAllInformation ); - if (status == STATUS_BUFFER_OVERFLOW) status = STATUS_SUCCESS; + status = NtQueryInformationFile( file, &io, &stat_info, sizeof(stat_info), FileStatInformation ); if (!set_ntstatus( status )) return FALSE;
- info->dwFileAttributes = all_info.BasicInformation.FileAttributes; - info->ftCreationTime.dwHighDateTime = all_info.BasicInformation.CreationTime.u.HighPart; - info->ftCreationTime.dwLowDateTime = all_info.BasicInformation.CreationTime.u.LowPart; - info->ftLastAccessTime.dwHighDateTime = all_info.BasicInformation.LastAccessTime.u.HighPart; - info->ftLastAccessTime.dwLowDateTime = all_info.BasicInformation.LastAccessTime.u.LowPart; - info->ftLastWriteTime.dwHighDateTime = all_info.BasicInformation.LastWriteTime.u.HighPart; - info->ftLastWriteTime.dwLowDateTime = all_info.BasicInformation.LastWriteTime.u.LowPart; + info->dwFileAttributes = stat_info.FileAttributes; + info->ftCreationTime.dwHighDateTime = stat_info.CreationTime.u.HighPart; + info->ftCreationTime.dwLowDateTime = stat_info.CreationTime.u.LowPart; + info->ftLastAccessTime.dwHighDateTime = stat_info.LastAccessTime.u.HighPart; + info->ftLastAccessTime.dwLowDateTime = stat_info.LastAccessTime.u.LowPart; + info->ftLastWriteTime.dwHighDateTime = stat_info.LastWriteTime.u.HighPart; + info->ftLastWriteTime.dwLowDateTime = stat_info.LastWriteTime.u.LowPart; info->dwVolumeSerialNumber = 0; - info->nFileSizeHigh = all_info.StandardInformation.EndOfFile.u.HighPart; - info->nFileSizeLow = all_info.StandardInformation.EndOfFile.u.LowPart; - info->nNumberOfLinks = all_info.StandardInformation.NumberOfLinks; - info->nFileIndexHigh = all_info.InternalInformation.IndexNumber.u.HighPart; - info->nFileIndexLow = all_info.InternalInformation.IndexNumber.u.LowPart; + info->nFileSizeHigh = stat_info.EndOfFile.u.HighPart; + info->nFileSizeLow = stat_info.EndOfFile.u.LowPart; + info->nNumberOfLinks = stat_info.NumberOfLinks; + info->nFileIndexHigh = stat_info.FileId.u.HighPart; + info->nFileIndexLow = stat_info.FileId.u.LowPart;
status = NtQueryVolumeInformationFile( file, &io, &volume_info, sizeof(volume_info), FileFsVolumeInformation ); if (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW)
Looks good to me, thanks. I think even with !5083 this is still useful because it's requesting only the needed information, though they now solve different things (so the MRs are not mutually exclusive).
For the bug, though, it's enough, so I'll probably remove the Wine-Bug tag from the other MR and keep it just for the name.
This merge request was approved by Gabriel Ivăncescu.