-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added ntsync7 (+esync/fsync) - Removed a few incompatible/hard to rebase patches (goodbye again threaded server) - Thank you @loathingKernel for much of the hard work WINE_DISABLE_FAST_SYNC=1 to use esync/fsync instead - Need WINEFSYNC=0 and WINEESYNC=0 explicitly set as well to use wineserver sync Add WIP WoW64 MR for some 32-bit games Merry Christmas :)
- Loading branch information
Showing
295 changed files
with
12,723 additions
and
3,628 deletions.
There are no files selected for viewing
269 changes: 269 additions & 0 deletions
269
...Windows-behaviour/0001-ntdll-Test-updated-NtQueryDirectoryFile-mask-reset-behaviour.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
From 58aef4d41bbf3ed4e1335346ed508f1bebf8bca7 Mon Sep 17 00:00:00 2001 | ||
From: Eugene McArdle <[email protected]> | ||
Date: Thu, 19 Dec 2024 09:59:53 +1000 | ||
Subject: [PATCH] ntdll: Test updated NtQueryDirectoryFile mask reset behaviour | ||
|
||
--- | ||
dlls/ntdll/tests/directory.c | 240 +++++++++++++++++++++++++++++++++++ | ||
1 file changed, 240 insertions(+) | ||
|
||
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c | ||
index 52ff9936560..6aec2ff6408 100644 | ||
--- a/dlls/ntdll/tests/directory.c | ||
+++ b/dlls/ntdll/tests/directory.c | ||
@@ -964,6 +964,245 @@ done: | ||
pRtlFreeUnicodeString(&ntdirname); | ||
} | ||
|
||
+static void set_up_mask_test(const char *testdir) | ||
+{ | ||
+ BOOL ret; | ||
+ char buf[MAX_PATH + 5]; | ||
+ HANDLE h; | ||
+ | ||
+ ret = CreateDirectoryA(testdir, NULL); | ||
+ ok( ret, "couldn't create dir '%s', error %ld\n", testdir, GetLastError() ); | ||
+ | ||
+ sprintf(buf, "%s\\%s", testdir, "a-file.h"); | ||
+ h = CreateFileA(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, | ||
+ FILE_ATTRIBUTE_NORMAL, 0); | ||
+ ok( h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf ); | ||
+ CloseHandle(h); | ||
+ | ||
+ sprintf(buf, "%s\\%s", testdir, "another-file.h"); | ||
+ h = CreateFileA(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, | ||
+ FILE_ATTRIBUTE_NORMAL, 0); | ||
+ ok( h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf ); | ||
+ CloseHandle(h); | ||
+} | ||
+ | ||
+static void tear_down_mask_test(const char *testdir) | ||
+{ | ||
+ int ret; | ||
+ char buf[MAX_PATH]; | ||
+ | ||
+ sprintf(buf, "%s\\%s", testdir, "a-file.h"); | ||
+ ret = DeleteFileA(buf); | ||
+ ok( ret || (GetLastError() == ERROR_FILE_NOT_FOUND) || (GetLastError() == ERROR_PATH_NOT_FOUND), | ||
+ "Failed to rm %s, error %ld\n", buf, GetLastError() ); | ||
+ | ||
+ sprintf(buf, "%s\\%s", testdir, "another-file.h"); | ||
+ ret = DeleteFileA(buf); | ||
+ ok( ret || (GetLastError() == ERROR_FILE_NOT_FOUND) || (GetLastError() == ERROR_PATH_NOT_FOUND), | ||
+ "Failed to rm %s, error %ld\n", buf, GetLastError() ); | ||
+ | ||
+ RemoveDirectoryA(testdir); | ||
+} | ||
+ | ||
+ | ||
+/* Performs a query with NtQueryDirectoryFile() */ | ||
+static BOOL test_NtQueryDirectoryFile_mask(HANDLE handle, BOOL restart_scan, UNICODE_STRING *mask, | ||
+ NTSTATUS expected_status, BOOL check_name_and_length, BOOL validate_only) | ||
+{ | ||
+ NTSTATUS status; | ||
+ IO_STATUS_BLOCK io; | ||
+ UINT data_size = sizeof(FILE_DIRECTORY_INFORMATION) + (MAX_PATH * sizeof(wchar_t)); | ||
+ BYTE data[8192]; | ||
+ FILE_DIRECTORY_INFORMATION *dir_info; | ||
+ WCHAR *name; | ||
+ ULONG name_len; | ||
+ WCHAR *mask_value = {0}; | ||
+ ULONG mask_len = 0; | ||
+ | ||
+ if (mask) | ||
+ { | ||
+ mask_len = mask->Length / sizeof(WCHAR); | ||
+ mask_value = mask->Buffer; | ||
+ } | ||
+ | ||
+ /* Perform the query */ | ||
+ status = pNtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, data, data_size, | ||
+ FileDirectoryInformation, TRUE, mask, restart_scan ); | ||
+ | ||
+ if (validate_only && status != expected_status) return FALSE; | ||
+ | ||
+ todo_wine | ||
+ ok( status == expected_status, "unexpected status : 0x%lx Test settings: file mask: '%s', restart: %d, expected status: 0x%lx\n", | ||
+ status, wine_dbgstr_wn(mask_value, mask_len), restart_scan, expected_status ); | ||
+ | ||
+ /* Verify the results if required */ | ||
+ if (status == 0 && check_name_and_length) | ||
+ { | ||
+ dir_info = (FILE_DIRECTORY_INFORMATION *)data; | ||
+ name = dir_info->FileName; | ||
+ name_len = dir_info->FileNameLength / sizeof(WCHAR); | ||
+ | ||
+ todo_wine | ||
+ ok( name_len == mask_len, "unexpected filename length %lu, expected %lu\n", name_len, mask_len ); | ||
+ todo_wine | ||
+ ok( !memcmp(name, mask_value, mask_len), "unexpected filename %s, expected %s\n", | ||
+ wine_dbgstr_wn(name, name_len), wine_dbgstr_wn(mask_value, mask_len) ); | ||
+ } | ||
+ return TRUE; | ||
+} | ||
+ | ||
+static void test_NtQueryDirectoryFile_change_mask(void) | ||
+{ | ||
+ NTSTATUS status; | ||
+ HANDLE dirh; | ||
+ HANDLE dirh_test_multiple_handles; | ||
+ HANDLE dirh_test_fresh_null; | ||
+ HANDLE dirh_test_fresh_empty; | ||
+ char testdir[MAX_PATH]; | ||
+ OBJECT_ATTRIBUTES attr; | ||
+ IO_STATUS_BLOCK io; | ||
+ UNICODE_STRING ntdirname; | ||
+ WCHAR testdir_w[MAX_PATH]; | ||
+ | ||
+ UNICODE_STRING atestfile; | ||
+ UNICODE_STRING anothertestfile; | ||
+ UNICODE_STRING notatestfile; | ||
+ UNICODE_STRING testmask; | ||
+ UNICODE_STRING emptymask; | ||
+ | ||
+ pRtlInitUnicodeString(&atestfile, L"a-file.h"); | ||
+ pRtlInitUnicodeString(&anothertestfile, L"another-file.h"); | ||
+ pRtlInitUnicodeString(¬atestfile, L"not-a-file.h"); | ||
+ pRtlInitUnicodeString(&testmask, L"*.h"); | ||
+ pRtlInitUnicodeString(&emptymask, L""); | ||
+ | ||
+ /* Clean up from prior aborted run, if any, then set up test files */ | ||
+ ok( GetTempPathA(MAX_PATH, testdir), "couldn't get temp dir\n" ); | ||
+ strcat(testdir, "mask.tmp"); | ||
+ tear_down_mask_test(testdir); | ||
+ set_up_mask_test(testdir); | ||
+ | ||
+ pRtlMultiByteToUnicodeN(testdir_w, sizeof(testdir_w), NULL, testdir, strlen(testdir) + 1); | ||
+ if (!pRtlDosPathNameToNtPathName_U(testdir_w, &ntdirname, NULL, NULL)) | ||
+ { | ||
+ ok( 0, "RtlDosPathNametoNtPathName_U failed\n" ); | ||
+ goto done; | ||
+ } | ||
+ InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); | ||
+ | ||
+ /* Open a handle for our test directory */ | ||
+ status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, | ||
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); | ||
+ ok( status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%lx, error %ld\n", testdir, status, GetLastError() ); | ||
+ if (status != STATUS_SUCCESS) | ||
+ { | ||
+ skip("can't test if we can't open the directory\n"); | ||
+ goto done; | ||
+ } | ||
+ | ||
+ /* Open a handle for our test directory to test multiple handles */ | ||
+ status = pNtOpenFile(&dirh_test_multiple_handles, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, | ||
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); | ||
+ ok( status == STATUS_SUCCESS, "failed to open second handle to dir '%s', ret 0x%lx, error %ld\n", testdir, status, GetLastError() ); | ||
+ if (status != STATUS_SUCCESS) | ||
+ { | ||
+ skip("can't test if we can't open a second handle to the directory\n"); | ||
+ goto done; | ||
+ } | ||
+ | ||
+ /* Open a handle for our test directory to test null masks with a fresh handle */ | ||
+ status = pNtOpenFile(&dirh_test_fresh_null, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, | ||
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); | ||
+ ok( status == STATUS_SUCCESS, "failed to open handle to dir '%s' for testing NULL masks, ret 0x%lx, error %ld\n", testdir, status, GetLastError() ); | ||
+ if (status != STATUS_SUCCESS) | ||
+ { | ||
+ skip("can't test NULL masks if we can't open an additional handle to the directory\n"); | ||
+ goto done; | ||
+ } | ||
+ | ||
+ /* Open a handle for our test directory to test empty masks with a fresh handle */ | ||
+ status = pNtOpenFile(&dirh_test_fresh_empty, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, | ||
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); | ||
+ ok( status == STATUS_SUCCESS, "failed to open handle to dir '%s' for testing empty masks, ret 0x%lx, error %ld\n", testdir, status, GetLastError() ); | ||
+ if (status != STATUS_SUCCESS) | ||
+ { | ||
+ skip("can't test empty masks if we can't open an additional handle to the directory\n"); | ||
+ goto done; | ||
+ } | ||
+ | ||
+ /* Verify that NtQueryDirectoryFile mask reset behaviour introduced in Windows 8 is supported */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &atestfile, STATUS_SUCCESS, TRUE, TRUE); | ||
+ if (!winetest_platform_is_wine && !test_NtQueryDirectoryFile_mask(dirh, TRUE, ¬atestfile, STATUS_NO_MORE_FILES, TRUE, TRUE)) | ||
+ { | ||
+ skip("Win8+ NtQueryDirectoryFile mask reset behaviour not supported\n"); | ||
+ goto done; | ||
+ } | ||
+ | ||
+ /* Test that caches for two handles to a single directory do not interfere with each other*/ | ||
+ /* Search for a non-existent file, putting it into a state with an empty cache */ | ||
+ /* This also confirms that using a non-existent mask with a fresh handle returns a different status*/ | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_multiple_handles, TRUE, ¬atestfile, STATUS_NO_SUCH_FILE, TRUE, FALSE); | ||
+ /* Confirm that handle is in a state where it fails to find atestfile */ | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_multiple_handles, FALSE, &atestfile, STATUS_NO_MORE_FILES, TRUE, FALSE); | ||
+ /* Confirm that another handle is able to find atestfile */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &atestfile, STATUS_SUCCESS, TRUE, FALSE); | ||
+ | ||
+ /* All searches for `notatestfile` are expected to fail */ | ||
+ /* Tests should also fail if the scan is not reset, and the mask changes to an incompatible one */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &atestfile, STATUS_SUCCESS, TRUE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &anothertestfile, STATUS_SUCCESS, TRUE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, ¬atestfile, STATUS_NO_MORE_FILES, TRUE, FALSE); | ||
+ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &atestfile, STATUS_SUCCESS, TRUE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, ¬atestfile, STATUS_NO_MORE_FILES, TRUE, FALSE); | ||
+ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &atestfile, STATUS_SUCCESS, TRUE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, &anothertestfile, STATUS_NO_MORE_FILES, TRUE, FALSE); | ||
+ | ||
+ /* Test mask that matches multiple files, do not check results against the mask */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &testmask, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, ¬atestfile, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, ¬atestfile, STATUS_NO_MORE_FILES, FALSE, FALSE); | ||
+ | ||
+ /* Test NULL mask with a previously used handle that last returned an error */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, NULL, STATUS_NO_MORE_FILES, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, NULL, STATUS_NO_MORE_FILES, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, NULL, STATUS_NO_MORE_FILES, FALSE, FALSE); | ||
+ | ||
+ /* Test NULL mask with a previously used handle that last returned STATUS_SUCCESS */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &testmask, STATUS_SUCCESS, FALSE, TRUE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, NULL, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, NULL, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, NULL, STATUS_SUCCESS, FALSE, FALSE); | ||
+ | ||
+ /* Test NULL mask with a fresh handle */ | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_fresh_null, TRUE, NULL, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_fresh_null, FALSE, NULL, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_fresh_null, TRUE, NULL, STATUS_SUCCESS, FALSE, FALSE); | ||
+ | ||
+ /* Test empty mask with a previously used handle that last returned an error */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, ¬atestfile, STATUS_NO_MORE_FILES, FALSE, TRUE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &emptymask, STATUS_NO_MORE_FILES, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, &emptymask, STATUS_NO_MORE_FILES, FALSE, FALSE); | ||
+ | ||
+ /* Test empty mask with a previously used handle that last returned STATUS_SUCCESS */ | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &testmask, STATUS_SUCCESS, FALSE, TRUE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, TRUE, &emptymask, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh, FALSE, &emptymask, STATUS_SUCCESS, FALSE, FALSE); | ||
+ | ||
+ /* Test empty mask with a fresh handle */ | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_fresh_empty, TRUE, &emptymask, STATUS_SUCCESS, FALSE, FALSE); | ||
+ test_NtQueryDirectoryFile_mask(dirh_test_fresh_empty, FALSE, &emptymask, STATUS_SUCCESS, FALSE, FALSE); | ||
+ | ||
+ /* Cleanup */ | ||
+done: | ||
+ tear_down_mask_test(testdir); | ||
+ pRtlFreeUnicodeString(&ntdirname); | ||
+ pRtlFreeUnicodeString(&atestfile); | ||
+ pRtlFreeUnicodeString(&anothertestfile); | ||
+ pRtlFreeUnicodeString(¬atestfile); | ||
+} | ||
+ | ||
static NTSTATUS get_file_id( FILE_INTERNAL_INFORMATION *info, const WCHAR *root, const WCHAR *name ) | ||
{ | ||
OBJECT_ATTRIBUTES attr; | ||
@@ -1157,5 +1396,6 @@ START_TEST(directory) | ||
test_directory_sort( sysdir ); | ||
test_NtQueryDirectoryFile(); | ||
test_NtQueryDirectoryFile_case(); | ||
+ test_NtQueryDirectoryFile_change_mask(); | ||
test_redirection(); | ||
} | ||
-- | ||
GitLab | ||
|
Oops, something went wrong.