-- v4: kernelbase: For FILE_FLAG_BACKUP_SEMANTICS also handle FILE_ATTRIBUTE_DIRECTORY in CreateFile. kernel32/tests: Test FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY.
From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/kernel32/tests/file.c | 57 +++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index d3cd0fbcd9f..3f12cefea1b 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -1626,13 +1626,14 @@ static void test_CreateFileA(void)
static void test_CreateFileW(void) { - HANDLE hFile; + HANDLE hFile, hFile2; WCHAR temp_path[MAX_PATH]; WCHAR filename[MAX_PATH]; static const WCHAR emptyW[]={'\0'}; static const WCHAR prefix[] = {'p','f','x',0}; static const WCHAR bogus[] = { '\', '\', '.', '\', 'B', 'O', 'G', 'U', 'S', 0 }; DWORD ret; + BY_HANDLE_FILE_INFORMATION info;
ret = GetTempPathW(MAX_PATH, temp_path); if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) @@ -1711,6 +1712,60 @@ static void test_CreateFileW(void) CloseHandle(hFile); ret = RemoveDirectoryW(filename); ok(ret, "DeleteFileW: error %ld\n", GetLastError()); + + /* Test FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY */ + hFile = CreateFileW(filename, 0, 0, NULL, CREATE_NEW, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + ret = GetFileInformationByHandle(hFile, &info); + ok(ret, "GetFileInformationByHandle error %lu\n", GetLastError()); + ok(!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY), "created file is a directory\n"); + hFile2 = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + ok(hFile2 != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + CloseHandle(hFile2); + CloseHandle(hFile); + + hFile = CreateFileW(filename, 0, 0, NULL, CREATE_NEW, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + ret = GetFileInformationByHandle(hFile, &info); + ok(ret, "GetFileInformationByHandle error %lu\n", GetLastError()); + ok(!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY), "created file is a directory\n"); + hFile2 = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY, NULL); + ok(hFile2 != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + CloseHandle(hFile2); + CloseHandle(hFile); + + hFile = CreateFileW(filename, 0, 0, NULL, CREATE_NEW, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + ret = GetFileInformationByHandle(hFile, &info); + ok(ret, "GetFileInformationByHandle error %lu\n", GetLastError()); + todo_wine + ok(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY, "created file is not a directory\n"); + hFile2 = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY, NULL); + ok(hFile2 != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + CloseHandle(hFile2); + CloseHandle(hFile); + + hFile = CreateFileW(filename, 0, 0, NULL, CREATE_NEW, + FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + ret = GetFileInformationByHandle(hFile, &info); + ok(ret, "GetFileInformationByHandle error %lu\n", GetLastError()); + ok(!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY), "created file is a directory\n"); + hFile2 = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY, NULL); + ok(hFile2 != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + CloseHandle(hFile2); + hFile2 = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY, NULL); + ok(hFile2 != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); + CloseHandle(hFile2); + CloseHandle(hFile); }
static void test_CreateFile2(void)
From: Dmitry Timoshkov dmitry@baikal.ru
Looks like this behaviour depends on FILE_FLAG_POSIX_SEMANTICS and activated when a file is being created.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58636 Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/kernel32/tests/file.c | 1 - dlls/kernelbase/file.c | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 3f12cefea1b..a43d9fcd1a8 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -1743,7 +1743,6 @@ static void test_CreateFileW(void) ok(hFile != INVALID_HANDLE_VALUE, "CreateFileW error %lu\n", GetLastError()); ret = GetFileInformationByHandle(hFile, &info); ok(ret, "GetFileInformationByHandle error %lu\n", GetLastError()); - todo_wine ok(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY, "created file is not a directory\n"); hFile2 = CreateFileW(filename, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY, NULL); diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index b34a3bb25b8..b3ebbe2321c 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -758,12 +758,16 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileA( LPCSTR name, DWORD access, DWORD sh return CreateFileW( nameW, access, sharing, sa, creation, attributes, template ); }
-static UINT get_nt_file_options( DWORD attributes ) +static UINT get_nt_file_options( DWORD attributes, BOOL create ) { UINT options = 0;
if (attributes & FILE_FLAG_BACKUP_SEMANTICS) + { options |= FILE_OPEN_FOR_BACKUP_INTENT; + if ((attributes & FILE_FLAG_POSIX_SEMANTICS) && create) + options |= (attributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_DIRECTORY_FILE : 0; + } else options |= FILE_NON_DIRECTORY_FILE; if (attributes & FILE_FLAG_DELETE_ON_CLOSE) @@ -864,7 +868,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO status = NtCreateFile( &ret, access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &io, NULL, attributes & FILE_ATTRIBUTE_VALID_FLAGS, sharing, nt_disposition[creation - CREATE_NEW], - get_nt_file_options( attributes ), NULL, 0 ); + get_nt_file_options( attributes, creation == CREATE_NEW ), NULL, 0 ); if (status) { if (vxd_name && vxd_name[0]) @@ -3423,7 +3427,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH ReOpenFile( HANDLE handle, DWORD access, DWORD s }
status = NtCreateFile( &file, access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &io, NULL, - 0, sharing, FILE_OPEN, FILE_NON_DIRECTORY_FILE | get_nt_file_options( attributes ), NULL, 0 ); + 0, sharing, FILE_OPEN, FILE_NON_DIRECTORY_FILE | get_nt_file_options( attributes, FALSE ), NULL, 0 ); if (!set_ntstatus( status )) return INVALID_HANDLE_VALUE; return file;
On Thu Aug 28 09:04:20 2025 +0000, Alexandre Julliard wrote:
Yes, we want to test both.
If I interpret what I'm observing correctly, it looks like this behaviour is activated only when creating a new directory.
Now you are going to need tests for the other creation types (CREATE_ALWAYS, OPEN_ALWAYS, etc.)...