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.
-- v8: Added build condition for apple platform
From: Stephane Bacri frisou76@yahoo.fr
--- dlls/kernelbase/file.c | 5 ++++- dlls/ntdll/unix/file.c | 16 ++++++++++++++++ 2 files changed, 20 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 8bc69557057..af3052b92e3 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4668,6 +4668,22 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else status = STATUS_INVALID_PARAMETER_3; break;
+ case FileAllocationInformation: + 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 (ftruncate(fd, (off_t)info->AllocationSize.QuadPart) == -1) + status = errno_to_status( errno ); + + if (needs_close) close( fd ); + } + else status = STATUS_INVALID_PARAMETER_3; + break; + case FilePositionInformation: if (len >= sizeof(FILE_POSITION_INFORMATION)) {
From: Stéphane Bacri frisou76@yahoo.fr
--- dlls/ntdll/tests/file.c | 25 +++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 12 ++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 8465ad4543a..553fc1eb160 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1334,6 +1334,30 @@ 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; + + if( !(handle = create_temp_file(0)) ) return; + + memset( &fas, 0, sizeof(fas) ); + fas.AllocationSize.QuadPart = 1024 * 1024; + 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 == fas.AllocationSize.QuadPart, "incorrect file size after allocation\n" ); + + CloseHandle( handle ); +} + static void test_file_full_size_information(void) { IO_STATUS_BLOCK io; @@ -6114,6 +6138,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(); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index af3052b92e3..177e343a311 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4672,12 +4672,20 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, if (len >= sizeof(FILE_ALLOCATION_INFORMATION)) { const FILE_ALLOCATION_INFORMATION *info = ptr; + int err;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) return io->Status = status;
- if (ftruncate(fd, (off_t)info->AllocationSize.QuadPart) == -1) - status = errno_to_status( errno ); +#ifdef HAVE_POSIX_FALLOCATE + if ((err = posix_fallocate( fd, 0, (off_t)info->AllocationSize.QuadPart )) != 0) + { + if (err == EOPNOTSUPP) WARN( "posix_fallocate not supported on this filesystem\n" ); + else status = errno_to_status( err ); + } +#else + WARN( "setting file allocation information not supported\n" ); +#endif
if (needs_close) close( fd ); }
From: Stéphane Bacri frisou76@yahoo.fr
--- dlls/ntdll/tests/file.c | 25 ++++++++++++++++++++++--- dlls/ntdll/unix/file.c | 12 ++---------- 2 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 553fc1eb160..56f572cb418 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1340,11 +1340,16 @@ static void test_file_setFileAllocationInformation(void) { 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 = 1024 * 1024; + fas.AllocationSize.QuadPart = length; res = pNtSetInformationFile( handle, &io, &fas, sizeof fas, FileAllocationInformation );
ok ( res == STATUS_SUCCESS, "file allocation failed, NtSetInformationFile returned %x\n", res ); @@ -1353,8 +1358,22 @@ static void test_file_setFileAllocationInformation(void) { memset( &info, 0x22, sizeof(info) ); res = GetFileInformationByHandle( handle, &info ); ok( res, "GetFileInformationByHandle failed\n" ); - ok( info.nFileSizeLow == fas.AllocationSize.QuadPart, "incorrect file size after allocation\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 ); }
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 177e343a311..ddbe927a6be 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4672,20 +4672,12 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, if (len >= sizeof(FILE_ALLOCATION_INFORMATION)) { const FILE_ALLOCATION_INFORMATION *info = ptr; - int err;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) return io->Status = status;
-#ifdef HAVE_POSIX_FALLOCATE - if ((err = posix_fallocate( fd, 0, (off_t)info->AllocationSize.QuadPart )) != 0) - { - if (err == EOPNOTSUPP) WARN( "posix_fallocate not supported on this filesystem\n" ); - else status = errno_to_status( err ); - } -#else - WARN( "setting file allocation information not supported\n" ); -#endif + if (fallocate( fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_ZERO_RANGE, 0, (off_t)info->AllocationSize.QuadPart ) == -1) + status = errno_to_status( errno );
if (needs_close) close( fd ); }
From: Stéphane Bacri frisou76@yahoo.fr
--- dlls/ntdll/unix/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index ddbe927a6be..e889fc87fcd 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4676,7 +4676,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) return io->Status = status;
- if (fallocate( fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_ZERO_RANGE, 0, (off_t)info->AllocationSize.QuadPart ) == -1) + if (fallocate( fd, FALLOC_FL_KEEP_SIZE, 0, (off_t)info->AllocationSize.QuadPart ) == -1) status = errno_to_status( errno );
if (needs_close) close( fd );
From: Stéphane Bacri frisou76@yahoo.fr
--- dlls/ntdll/unix/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index e889fc87fcd..45f2a8bad4a 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4672,14 +4672,16 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, if (len >= sizeof(FILE_ALLOCATION_INFORMATION)) { const FILE_ALLOCATION_INFORMATION *info = ptr; - +#ifdef __APPLE__ + WARN( "setting file allocation information not supported on this platform\n" ); +#else 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 ); +#endif } else status = STATUS_INVALID_PARAMETER_3; break;