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.
-- v4: Used posix_fallocate in place of ftruncate + added related test Merge remote-tracking branch 'main/master' into setFileInformationByHandle
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 ); }
@hans I pushed posix_fallocate version + tests, using other parts of the code as a template.
For unknown reason, the CI still complains about identity with my MRs (I double checked that all my commits where done with user.name / user.email set). If you can/want to use this code, improve it with your better understanding of wine / multi-threading potential issues, please do.
You need to get rid of the merge commits with git-rebase.
And posix_fallocate() has the same problem as ftruncate() with respect to increasing the size of the file.
There's fallocate(FALLOC_FL_KEEP_SIZE) which doesn't increase file size but it's Linux-specific. I guess that's acceptable.
@julliard I still don't get the reason of your concern about the file size increase. That's what the function is aimed to do, as far as I understand it. What is your interpretation of it, if not the same?
It allocates space but it doesn't increase the file size. If you run your test on Windows you'll see a failure, because the file size doesn't change.
@julliard Ok, got you. Thanks. Shall I use fallocate with the KEEP_SIZE flag as suggested by Hans, then?
Yes, something like that.