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
From: Stéphane Bacri frisou76@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
From: Stéphane Bacri frisou76@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();
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.
@hans Thanks for your review.
Changes made. Please see answer to __APPLE__ test in test file.
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.
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.
Hans Leidekker (@hans) commented about configure.ac:
port_create \ posix_fadvise \ posix_fallocate \
- fallocate \ prctl \
Please keep these sorted.