[PATCH v10 0/2] MR7115: Added support of case FileAllocationInformation in SetFileInformationByHandle
This MR intends to add support for the case FileAllocationInformation in function SetFileInformationByHandle of library kernelbase.dll. The code is based on my understanding of [MS documentation](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntif...) No test was added, because other cases that could have helped doing so (FileEndOfFileInformation) do not have neither. -- v10: Added tests for class FILE_INFORMATION_ALLOCATION in setFileInformationByHandle Added support for class FILE_INFORMATION_ALLOCATION in setFileInformationByHandle https://gitlab.winehq.org/wine/wine/-/merge_requests/7115
From: Stéphane Bacri <frisou76(a)yahoo.fr> --- configure | 6 ++++++ configure.ac | 1 + dlls/kernelbase/file.c | 5 ++++- dlls/ntdll/unix/file.c | 19 +++++++++++++++++++ include/config.h.in | 3 +++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/configure b/configure index c2d47a7c5db..bc9c6731c2f 100755 --- a/configure +++ b/configure @@ -21086,6 +21086,12 @@ if test "x$ac_cv_func_posix_fallocate" = xyes then : printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "fallocate" "ac_cv_func_fallocate" +if test "x$ac_cv_func_fallocate" = xyes +then : + printf "%s\n" "#define HAVE_FALLOCATE 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "prctl" "ac_cv_func_prctl" if test "x$ac_cv_func_prctl" = xyes diff --git a/configure.ac b/configure.ac index dd139950e10..0c1d5806dd1 100644 --- a/configure.ac +++ b/configure.ac @@ -2075,6 +2075,7 @@ AC_CHECK_FUNCS(\ port_create \ posix_fadvise \ posix_fallocate \ + fallocate \ prctl \ sched_getcpu \ sched_yield \ diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index f0dedfe3b14..416892ef14c 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -3678,7 +3678,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetFileInformationByHandle( HANDLE file, FILE_INFO switch (class) { case FileNameInfo: - case FileAllocationInfo: case FileStreamInfo: case FileIdBothDirectoryInfo: case FileIdBothDirectoryRestartInfo: @@ -3693,6 +3692,10 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetFileInformationByHandle( HANDLE file, FILE_INFO SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); return FALSE; + case FileAllocationInfo: + status = NtSetInformationFile( file, &io, info, size, FileAllocationInformation ); + break; + case FileEndOfFileInfo: status = NtSetInformationFile( file, &io, info, size, FileEndOfFileInformation ); break; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index faef06ae084..c0afde83062 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4693,6 +4693,25 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else status = STATUS_INVALID_PARAMETER_3; break; + case FileAllocationInformation: +#ifdef HAVE_FALLOCATE + if (len >= sizeof(FILE_ALLOCATION_INFORMATION)) + { + const FILE_ALLOCATION_INFORMATION *info = ptr; + if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) + return io->Status = status; + + if (fallocate( fd, FALLOC_FL_KEEP_SIZE, 0, (off_t)info->AllocationSize.QuadPart ) == -1) + status = errno_to_status( errno ); + + if (needs_close) close( fd ); + } + else status = STATUS_INVALID_PARAMETER_3; +#else + WARN( "setting file allocation information not supported on this platform\n" ); +#endif + break; + case FilePositionInformation: if (len >= sizeof(FILE_POSITION_INFORMATION)) { diff --git a/include/config.h.in b/include/config.h.in index 6033d8674f3..57add31fc95 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -321,6 +321,9 @@ /* Define to 1 if you have the 'posix_fallocate' function. */ #undef HAVE_POSIX_FALLOCATE +/* Define to 1 if you have the 'fallocate' function. */ +#undef HAVE_FALLOCATE + /* Define to 1 if you have the 'prctl' function. */ #undef HAVE_PRCTL -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7115
From: Stéphane Bacri <frisou76(a)yahoo.fr> --- dlls/ntdll/tests/file.c | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index cc0afdbdb64..addb9983033 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1334,6 +1334,59 @@ static void test_file_io_completion(void) pNtClose( h ); } +static void test_file_setFileAllocationInformation(void) { +#ifdef HAVE_FALLOCATE + FILE_ALLOCATION_INFORMATION fas; + IO_STATUS_BLOCK io; + HANDLE handle; + int res; + char* buffer; + DWORD bytesWritten, bytesRead, size; + DWORD length = 64*1024; + LARGE_INTEGER distanceToMove; + + distanceToMove.QuadPart = 0; + + if( !(handle = create_temp_file(0)) ) return; + + memset( &fas, 0, sizeof(fas) ); + fas.AllocationSize.QuadPart = length; + res = pNtSetInformationFile( handle, &io, &fas, sizeof fas, FileAllocationInformation ); + + ok ( res == STATUS_SUCCESS, "file allocation failed, NtSetInformationFile returned %x\n", res ); + ok ( io.Status == STATUS_SUCCESS, "file allocation failed, io.Status is %lx\n", io.Status ); + + size = GetFileSize( handle, NULL ); + ok( size == 0, "incorrect file size after allocation: should be 0, got %lx\n", size ); + + buffer = malloc(length); + memset( buffer, 0xa5, length ); + res = WriteFile( handle, buffer, length, &bytesWritten, NULL ); + ok ( res != 0 , "couldn't write to file after allocation\n"); + ok ( bytesWritten == length, "couldn't write to whole or part of file after allocation: allocated %lx, written %lx\n", length, bytesWritten ); + size = GetFileSize( handle, NULL); + ok ( size == bytesWritten, "wrong file size after write: should be 0x10000, got 0x%lx\n", size); + + memset( buffer, 0, length ); + SetFilePointerEx( handle, distanceToMove, NULL, FILE_BEGIN ); + res = ReadFile( handle, buffer, length, &bytesRead, NULL ); + ok ( res != 0 , "couldn't read file after allocation\n" ); + ok ( bytesRead == length, "couldn't read whole or part of file after allocation: allocated %lx, read %lx\n", length, bytesRead ); + ok ( *buffer == (char)0xa5, "data read from allocated file doesn't match written pattern: wrote 0xa5, got 0x%x\n", *buffer & 0xff ); + + fas.AllocationSize.QuadPart = 2 * length; + size = GetFileSize( handle, NULL ); + ok ( size == bytesWritten, "wrong file size after new lengthier allocation: should be 0x10000, got 0x%lx\n", size); + + fas.AllocationSize.QuadPart = length / 2; + size = GetFileSize( handle, NULL ); + ok ( size == bytesWritten, "wrong file size after new shorter allocation: should be 0x10000, got 0x%lx\n", size); + + free(buffer); + CloseHandle( handle ); +#endif +} + static void test_file_full_size_information(void) { IO_STATUS_BLOCK io; @@ -6185,6 +6238,7 @@ START_TEST(file) test_file_access_information(); test_file_attribute_tag_information(); test_file_stat_information(); + test_file_setFileAllocationInformation(); test_dotfile_file_attributes(); test_file_mode(); test_file_readonly_access(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7115
On Sun Feb 23 20:42:26 2025 +0000, Stéphane Bacri wrote:
changed this line in [version 10 of the diff](/wine/wine/-/merge_requests/7115/diffs?diff_id=159907&start_sha=b427d8f4c40eba75e012fa0cab5894d6c5de3668#a6054b4d823544828fc181519321938fe40b14ff_6233_6242) I assumed the position and the test were not correct. Fixed this with the newly introduced HAVE_FALLOCATE inside the test itself.
Please be more a bit more specific in next comment if this assumption was not correct. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7115#note_95695
@hans Thanks for your review. Changes made. Please see answer to __APPLE__ test in test file. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7115#note_95696
Hans Leidekker (@hans) commented about dlls/ntdll/tests/file.c:
pNtClose( h ); }
+static void test_file_setFileAllocationInformation(void) { +#ifdef HAVE_FALLOCATE + FILE_ALLOCATION_INFORMATION fas;
You can't use this define either, just call the test unconditionally. You could add a stub implementation for macOS that succeeds and prints a FIXME. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7115#note_95697
Hans Leidekker (@hans) commented about dlls/ntdll/tests/file.c:
+ size = GetFileSize( handle, NULL); + ok ( size == bytesWritten, "wrong file size after write: should be 0x10000, got 0x%lx\n", size); + + memset( buffer, 0, length ); + SetFilePointerEx( handle, distanceToMove, NULL, FILE_BEGIN ); + res = ReadFile( handle, buffer, length, &bytesRead, NULL ); + ok ( res != 0 , "couldn't read file after allocation\n" ); + ok ( bytesRead == length, "couldn't read whole or part of file after allocation: allocated %lx, read %lx\n", length, bytesRead ); + ok ( *buffer == (char)0xa5, "data read from allocated file doesn't match written pattern: wrote 0xa5, got 0x%x\n", *buffer & 0xff ); + + fas.AllocationSize.QuadPart = 2 * length; + size = GetFileSize( handle, NULL ); + ok ( size == bytesWritten, "wrong file size after new lengthier allocation: should be 0x10000, got 0x%lx\n", size); + + fas.AllocationSize.QuadPart = length / 2; + size = GetFileSize( handle, NULL ); You need to set the allocation size before these GetFileSize() calls.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7115#note_95698
Hans Leidekker (@hans) commented about configure.ac:
port_create \ posix_fadvise \ posix_fallocate \ + fallocate \ prctl \ Please keep these sorted.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7115#note_95699
participants (2)
-
Hans Leidekker (@hans) -
Stéphane Bacri