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.
-- v9: 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
--- dlls/kernelbase/file.c | 5 ++++- dlls/ntdll/unix/file.c | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-)
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..98ff4cffe61 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4693,6 +4693,24 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else status = STATUS_INVALID_PARAMETER_3; break;
+ case FileAllocationInformation: +#ifdef __APPLE__ + WARN( "setting file allocation information not supported on this platform\n" ); +#else + 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; +#endif + break; + case FilePositionInformation: if (len >= sizeof(FILE_POSITION_INFORMATION)) {
From: Stéphane Bacri frisou76@yahoo.fr
--- dlls/ntdll/tests/file.c | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index cc0afdbdb64..a4fbd3d7e95 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1334,6 +1334,49 @@ static void test_file_io_completion(void) pNtClose( h ); }
+static void test_file_setFileAllocationInformation(void) { + FILE_ALLOCATION_INFORMATION fas; + BY_HANDLE_FILE_INFORMATION info; + IO_STATUS_BLOCK io; + HANDLE handle; + int res; + char* buffer; + DWORD bytesWritten, bytesRead; + 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 ); + + memset( &info, 0x22, sizeof(info) ); + res = GetFileInformationByHandle( handle, &info ); + ok( res, "GetFileInformationByHandle failed\n" ); + ok( info.nFileSizeLow == 0, "incorrect file size after allocation: should be 0, got %lx\n", info.nFileSizeLow ); + + 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 ); + + 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 ); + + free(buffer); + CloseHandle( handle ); +} + static void test_file_full_size_information(void) { IO_STATUS_BLOCK io; @@ -6185,6 +6228,9 @@ START_TEST(file) test_file_access_information(); test_file_attribute_tag_information(); test_file_stat_information(); +#ifndef __APPLE__ + test_file_setFileAllocationInformation(); +#endif test_dotfile_file_attributes(); test_file_mode(); test_file_readonly_access();
@hans I cleaned the commit history as you requested and added a prepocessor directive in both code and tests, since MacOS seemingly doesn't provide fallocate. Now, CI seems fully happy.
Hans Leidekker (@hans) commented about dlls/ntdll/tests/file.c:
Please test what happens to the file size (using GetFileSize()) with an allocation size larger than the current file size as well as an allocation size smaller than the current size.
Hans Leidekker (@hans) commented about dlls/ntdll/tests/file.c:
You can't use this ifdef in tests.
Hans Leidekker (@hans) commented about dlls/ntdll/unix/file.c:
This should use a new configure check for fallocate() instead.