FileRenameInfoEx is already handled by NtSetInformationFile, SetFileInformationByHandle need only pass it through correctly.
As of version 5.3, Apple's Metal Developer Tools are dependent on SetFileInformationByHandle to handle FileRenameInfoEx in this fashion.
-- v3: kernelbase: pass FileRenameInfoEx to NtSetInformationFile kernel32/tests: SetFileInfo should accept FileRenameInfoEx
From: Michael Stopa michael.stopa@tensorworks.com.au
The documentation is extremely sparse but it would appear that SetFileInformationByHandle should handle FileRenameInfoEx in basically the same manner as FileRenameInfo, the only difference between the two being how they store the flag for replacing an existing file.
No other flags are being tested as even on MSDN they're only properly explained for NtSetInformationFile, which is wrapped by SetFileInformationByHandle in Wine anyway. --- dlls/kernel32/tests/file.c | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index db3ffc655ce..b05d9a504d9 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -5599,6 +5599,52 @@ static void test_SetFileRenameInfo(void) ok(!ret && GetLastError() == ERROR_ACCESS_DENIED, "FileRenameInfo unexpected result %ld\n", GetLastError()); CloseHandle(file);
+ DeleteFileW(tempFileFrom); + DeleteFileW(tempFileTo1); + DeleteFileW(tempFileTo2); + + // Repeat test again with FileRenameInfoEx + + ret = GetTempPathW(MAX_PATH, tempPath); + ok(ret, "GetTempPathW failed, got error %lu.\n", GetLastError()); + + ret = GetTempFileNameW(tempPath, L"abc", 0, tempFileFrom); + ok(ret, "GetTempFileNameW failed, got error %lu.\n", GetLastError()); + + ret = GetTempFileNameW(tempPath, L"abc", 0, tempFileTo1); + ok(ret, "GetTempFileNameW failed, got error %lu.\n", GetLastError()); + + ret = GetTempFileNameW(tempPath, L"abc", 1, tempFileTo2); + ok(ret, "GetTempFileNameW failed, got error %lu.\n", GetLastError()); + + file = CreateFileW(tempFileFrom, GENERIC_READ | GENERIC_WRITE | DELETE, 0, 0, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create temp file, error %lu.\n", GetLastError()); + + size = sizeof(FILE_RENAME_INFORMATION) + MAX_PATH; + fri = HeapAlloc(GetProcessHeap(), 0, size); + + fri->Flags = 0; + fri->RootDirectory = NULL; + fri->FileNameLength = wcslen(tempFileTo1) * sizeof(WCHAR); + memcpy(fri->FileName, tempFileTo1, fri->FileNameLength + sizeof(WCHAR)); + ret = pSetFileInformationByHandle(file, FileRenameInfoEx, fri, size); + todo_wine ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS, "FileRenameInfoEx unexpected result %ld\n", GetLastError()); + + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS; + ret = pSetFileInformationByHandle(file, FileRenameInfoEx, fri, size); + todo_wine ok(ret, "FileRenameInfoEx failed, error %ld\n", GetLastError()); + + fri->Flags = 0; + fri->FileNameLength = wcslen(tempFileTo2) * sizeof(WCHAR); + memcpy(fri->FileName, tempFileTo2, fri->FileNameLength + sizeof(WCHAR)); + ret = pSetFileInformationByHandle(file, FileRenameInfoEx, fri, size); + todo_wine ok(ret, "FileRenameInfoEx failed, error %ld\n", GetLastError()); + CloseHandle(file); + + file = CreateFileW(tempFileTo2, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + todo_wine ok(file != INVALID_HANDLE_VALUE, "file not renamed, error %ld\n", GetLastError()); + + CloseHandle(file); HeapFree(GetProcessHeap(), 0, fri); DeleteFileW(tempFileFrom); DeleteFileW(tempFileTo1);
From: Michael Stopa michael.stopa@tensorworks.com.au
FileRenameInfoEx is already handled by NtSetInformationFile, SetFileInformationByHandle need only pass it through. --- dlls/kernel32/tests/file.c | 8 ++++---- dlls/kernelbase/file.c | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index b05d9a504d9..c54df336ccb 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -5628,21 +5628,21 @@ static void test_SetFileRenameInfo(void) fri->FileNameLength = wcslen(tempFileTo1) * sizeof(WCHAR); memcpy(fri->FileName, tempFileTo1, fri->FileNameLength + sizeof(WCHAR)); ret = pSetFileInformationByHandle(file, FileRenameInfoEx, fri, size); - todo_wine ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS, "FileRenameInfoEx unexpected result %ld\n", GetLastError()); + ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS, "FileRenameInfoEx unexpected result %ld\n", GetLastError());
fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS; ret = pSetFileInformationByHandle(file, FileRenameInfoEx, fri, size); - todo_wine ok(ret, "FileRenameInfoEx failed, error %ld\n", GetLastError()); + ok(ret, "FileRenameInfoEx failed, error %ld\n", GetLastError());
fri->Flags = 0; fri->FileNameLength = wcslen(tempFileTo2) * sizeof(WCHAR); memcpy(fri->FileName, tempFileTo2, fri->FileNameLength + sizeof(WCHAR)); ret = pSetFileInformationByHandle(file, FileRenameInfoEx, fri, size); - todo_wine ok(ret, "FileRenameInfoEx failed, error %ld\n", GetLastError()); + ok(ret, "FileRenameInfoEx failed, error %ld\n", GetLastError()); CloseHandle(file);
file = CreateFileW(tempFileTo2, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); - todo_wine ok(file != INVALID_HANDLE_VALUE, "file not renamed, error %ld\n", GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "file not renamed, error %ld\n", GetLastError());
CloseHandle(file); HeapFree(GetProcessHeap(), 0, fri); diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 7d8b6844456..042179a8378 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -3658,6 +3658,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetFileInformationByHandle( HANDLE file, FILE_INFO status = NtSetInformationFile( file, &io, info, size, FileIoPriorityHintInformation ); break; case FileRenameInfo: + case FileRenameInfoEx: { FILE_RENAME_INFORMATION *rename_info; UNICODE_STRING nt_name; @@ -3673,7 +3674,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetFileInformationByHandle( HANDLE file, FILE_INFO memcpy( rename_info, info, sizeof(*rename_info) ); memcpy( rename_info->FileName, nt_name.Buffer, nt_name.Length + sizeof(WCHAR) ); rename_info->FileNameLength = nt_name.Length; - status = NtSetInformationFile( file, &io, rename_info, size, FileRenameInformation ); + status = NtSetInformationFile( file, &io, rename_info, size, + class == FileRenameInfo ? FileRenameInformation : FileRenameInformationEx ); HeapFree( GetProcessHeap(), 0, rename_info ); } RtlFreeUnicodeString( &nt_name );
On Fri Jun 13 16:05:50 2025 +0000, Alexandre Julliard wrote:
Please merge that into the existing FileRenameInfo tests, there's no need to duplicate the whole thing.
Fair enough, okay that's done. I've removed the last check of the test from this copy because there's still a `todo_wine` there even in the original test and I don't know what for.