From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index 0ace8097352..b2484609689 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -683,7 +683,7 @@ static void test_NtQueryDirectoryFile(void) memset( data, 0x55, data_size ); io.Status = 0xdeadbeef; io.Information = 0xdeadbeef; - status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size + 16, + status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size + 32, FileBothDirectoryInformation, FALSE, NULL, TRUE ); ok( status == STATUS_SUCCESS, "wrong status %lx\n", status ); ok( io.Status == STATUS_SUCCESS, "wrong status %lx\n", io.Status );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 10 +++------- dlls/ntdll/unix/file.c | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index b2484609689..f02a95bc391 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -453,13 +453,12 @@ static void test_NtQueryDirectoryFile(void) { const WCHAR *mask; int found[ARRAY_SIZE(testfiles)]; - BOOL todo_missing; } mask_tests[] = { - {L"*.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, TRUE}, - {L"*.*", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}, TRUE}, - {L"*.**", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}, TRUE}, + {L"*.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}}, + {L"*.*", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}}, + {L"*.**", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}}, {L"*", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"**", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}}, @@ -517,10 +516,7 @@ static void test_NtQueryDirectoryFile(void) RtlInitUnicodeString(&mask, mask_tests[i].mask); test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE); for (j = 0; j < test_dir_count; j++) - { - todo_wine_if(mask_tests[i].todo_missing && !mask_tests[i].found[j]) ok(testfiles[j].nfound == mask_tests[i].found[j], "%S, got %d.\n", testfiles[j].name, testfiles[j].nfound); - } winetest_pop_context(); }
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 1cafe7aa8b7..ce3bc24c5f4 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1487,8 +1487,8 @@ static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRI break; } } - while (mask < mask_end && ((*mask == '.') || (*mask == '*'))) - mask++; /* Ignore trailing '.' or '*' in mask */ + while (mask < mask_end && *mask == '*') + mask++; return (name == name_end && mask == mask_end); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index f02a95bc391..702e348b234 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -72,7 +72,14 @@ static struct testfile_s { { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, { 0, FILE_ATTRIBUTE_NORMAL, {'e','a'}, "normal" }, { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, - { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } + { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'.','a'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'.','a','.','a'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'a','.'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'.','.','a'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'.','a','a'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'a','.', '.'}, "normal" }, }; static const int test_dir_count = ARRAY_SIZE(testfiles); static const int max_test_dir_size = ARRAY_SIZE(testfiles) + 5; /* size of above plus some for .. etc */ @@ -96,7 +103,8 @@ static void set_up_attribute_test(const WCHAR *testdir)
if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0) continue; - lstrcpyW( buf, testdir ); + lstrcpyW( buf, L"\\?\" ); + lstrcatW( buf, testdir ); lstrcatW( buf, backslashW ); lstrcatW( buf, testfiles[i].name ); if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { @@ -131,7 +139,8 @@ static void tear_down_attribute_test(const WCHAR *testdir) WCHAR buf[MAX_PATH]; if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0) continue; - lstrcpyW( buf, testdir ); + lstrcpyW( buf, L"\\?\" ); + lstrcatW( buf, testdir ); lstrcatW( buf, backslashW ); lstrcatW( buf, testfiles[i].name ); if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { @@ -456,12 +465,12 @@ static void test_NtQueryDirectoryFile(void) } mask_tests[] = { - {L"*.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}}, - {L"*.*", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}}, - {L"*.**", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}}, - {L"*", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, - {L"**", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, - {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}}, + {L"*.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1}}, + {L"*.*", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"*.**", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"*", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"**", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, };
OBJECT_ATTRIBUTES attr;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/file.c | 6 ++---- dlls/ntdll/unix/file.c | 8 ++++++-- 2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 940b1441e19..dc9f67e2f03 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -3063,11 +3063,9 @@ static void test_FindFirstFile_wildcards(void) {0, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {0, " *..", ""}, {0, "..* ", ", '.', '..', '..a', '..a.a'"}, - {1, "a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {0, "a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, {0, "*a ", ", '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - - /* a.a.a not found due to short name mismatch, a.a.a -> "AA6BF5~1.A on Windows. */ - {1, "*aa*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {0, "*aa*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
{1, "<.<.<", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, {1, "<.<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index ce3bc24c5f4..89fd942ea3b 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1383,13 +1383,17 @@ static ULONG hash_short_file_name( const WCHAR *name, int length, LPWSTR buffer }
/* Find last dot for start of the extension */ - for (p = name + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p; + p = name; + while (*p == '.') ++p; + for (p = p + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p;
/* Copy first 4 chars, replacing invalid chars with '_' */ - for (i = 4, p = name, dst = buffer; i > 0; i--, p++) + for (i = 4, p = name, dst = buffer; i > 0; p++) { if (p == end || p == ext) break; + if (*p == '.') continue; *dst++ = is_invalid_dos_char(*p) ? '_' : *p; + i--; } /* Pad to 5 chars with '~' */ while (i-- >= 0) *dst++ = '~';
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/file.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 89fd942ea3b..b5bf6f9801d 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -320,13 +320,19 @@ static inline unsigned int dir_info_size( FILE_INFORMATION_CLASS class, unsigned } }
+static BOOL is_wildcard( WCHAR c ) +{ + return c == '*' || c == '?' || c == '>' || c == '<' || c == '"'; +} + static inline BOOL has_wildcard( const UNICODE_STRING *mask ) { int i;
if (!mask) return TRUE; for (i = 0; i < mask->Length / sizeof(WCHAR); i++) - if (mask->Buffer[i] == '*' || mask->Buffer[i] == '?') return TRUE; + if (is_wildcard( mask->Buffer[i] )) return TRUE; + return FALSE; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/file.c | 82 +++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 53 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index b5bf6f9801d..724a9d99b00 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1421,30 +1421,13 @@ static ULONG hash_short_file_name( const WCHAR *name, int length, LPWSTR buffer
/*********************************************************************** - * match_filename + * match_filename_part * - * Check a long file name against a mask. + * Recursive helper for match_filename(). * - * Tests (done in W95 DOS shell - case insensitive): - * *.txt test1.test.txt * - * *st1* test1.txt * - * *.t??????.t* test1.ta.tornado.txt * - * *tornado* test1.ta.tornado.txt * - * t*t test1.ta.tornado.txt * - * ?est* test1.txt * - * ?est??? test1.txt - - * *test1.txt* test1.txt * - * h?l?o*t.dat hellothisisatest.dat * */ -static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRING *mask_str ) +static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, const WCHAR *mask, const WCHAR *mask_end ) { - BOOL mismatch; - const WCHAR *mask = mask_str->Buffer; - const WCHAR *name_end = name + length; - const WCHAR *mask_end = mask + mask_str->Length / sizeof(WCHAR); - const WCHAR *lastjoker = NULL; - const WCHAR *next_to_retry = NULL; - while (name < name_end && mask < mask_end) { switch(*mask) @@ -1453,14 +1436,16 @@ static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRI mask++; while (mask < mask_end && *mask == '*') mask++; /* Skip consecutive '*' */ if (mask == mask_end) return TRUE; /* end of mask is all '*', so match */ - lastjoker = mask;
- /* skip to the next match after the joker(s) */ - if (is_case_sensitive) - while (name < name_end && (*name != *mask)) name++; - else - while (name < name_end && (towupper(*name) != towupper(*mask))) name++; - next_to_retry = name; + while (name < name_end) + { + if (is_case_sensitive) + while (name < name_end && (*name != *mask)) name++; + else + while (name < name_end && (towupper(*name) != towupper(*mask))) name++; + if (match_filename_part( name, name_end, mask, mask_end )) return TRUE; + ++name; + } break; case '?': case '>': @@ -1468,32 +1453,10 @@ static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRI name++; break; default: - if (is_case_sensitive) mismatch = (*mask != *name); - else mismatch = (towupper(*mask) != towupper(*name)); - - if (!mismatch) - { - mask++; - name++; - if (mask == mask_end) - { - if (name == name_end) return TRUE; - if (lastjoker) mask = lastjoker; - } - } - else /* mismatch ! */ - { - if (lastjoker) /* we had an '*', so we can try unlimitedly */ - { - mask = lastjoker; - - /* this scan sequence was a mismatch, so restart - * 1 char after the first char we checked last time */ - next_to_retry++; - name = next_to_retry; - } - else return FALSE; /* bad luck */ - } + if (is_case_sensitive && *mask != *name) return FALSE; + if (!is_case_sensitive && towupper(*mask) != towupper(*name)) return FALSE; + mask++; + name++; break; } } @@ -1503,6 +1466,19 @@ static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRI }
+/*********************************************************************** + * match_filename + * + * Check a file name against a mask. + * + */ +static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRING *mask_str ) +{ + return match_filename_part( name, name + length, mask_str->Buffer, + mask_str->Buffer + mask_str->Length / sizeof(WCHAR)); +} + + /*********************************************************************** * is_legal_8dot3_name *
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 9 +++++++++ dlls/ntdll/unix/file.c | 3 +++ 2 files changed, 12 insertions(+)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index 702e348b234..d4028a92519 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -470,7 +470,16 @@ static void test_NtQueryDirectoryFile(void) {L"*.**", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"*", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"**", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"?", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}}, + {L"?.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}}, + {L"?..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + {L"??", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0}}, + {L"??.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"..*", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, + {L"*..*", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}}, + {L"*..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + {L"..?", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, };
OBJECT_ATTRIBUTES attr; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 724a9d99b00..ab567a63d19 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1474,6 +1474,9 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co */ static BOOLEAN match_filename( const WCHAR *name, int length, const UNICODE_STRING *mask_str ) { + /* Special handling for parent directory. */ + if (length == 2 && name[0] == '.' && name[1] == '.') --length; + return match_filename_part( name, name + length, mask_str->Buffer, mask_str->Buffer + mask_str->Length / sizeof(WCHAR)); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/file.c | 4 +-- dlls/ntdll/tests/directory.c | 64 +++++++++++++++++++++++++++++------- dlls/ntdll/unix/file.c | 40 +++++++++++++++++++++- 3 files changed, 94 insertions(+), 14 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index dc9f67e2f03..e6766bbd08d 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -3077,7 +3077,7 @@ static void test_FindFirstFile_wildcards(void) {1, "<..<", ", '..a', '.a..a', 'a..a'"}, {1, "<..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, ".<.", ", '.', '..', '.a', '.aaa'"}, - {1, "..<", ", '..a'"}, + {0, "..<", ", '..a'"}, {1, "<<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "<<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "<. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, @@ -3087,7 +3087,7 @@ static void test_FindFirstFile_wildcards(void) {1, "<. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, "< ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {0, " <..", ""}, - {1, "..< ", ", '..a'"}, + {0, "..< ", ", '..a'"},
{1, "?", ", '.', '..', 'a'"}, {0, "?.", ", '.', '..', 'a'"}, diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index d4028a92519..c12c5547ade 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -183,7 +183,7 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info)
static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char *testdirA, UNICODE_STRING *mask, - BOOLEAN single_entry, BOOLEAN restart_flag) + BOOLEAN single_entry, BOOLEAN restart_flag, BOOLEAN expect_empty) { UNICODE_STRING dummy_mask; HANDLE dirh, new_dirh; @@ -213,6 +213,12 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char io.Status = 0xdeadbeef; status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size, FileBothDirectoryInformation, single_entry, mask, restart_flag ); + if (expect_empty) + { + ok( status == STATUS_NO_SUCH_FILE, "got %#lx.\n", status ); + pNtClose( dirh ); + return; + } ok (status == STATUS_SUCCESS, "failed to query directory; status %lx\n", status); ok (io.Status == STATUS_SUCCESS, "failed to query directory; status %lx\n", io.Status); data_len = io.Information; @@ -247,7 +253,7 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char } ok(numfiles < max_test_dir_size, "too many loops\n");
- if (mask && !wcspbrk( mask->Buffer, L"*?" )) + if (mask && !wcspbrk( mask->Buffer, L"*?<">" )) for (i = 0; i < test_dir_count; i++) ok(testfiles[i].nfound == (testfiles[i].name == mask->Buffer), "Wrong number %d of %s files found (single_entry=%d,mask=%s)\n", @@ -476,10 +482,36 @@ static void test_NtQueryDirectoryFile(void) {L"??", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0}}, {L"??.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1}}, + {L"<.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1}}, + {L"<..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + {L".<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0}}, + {L"..<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, {L"..*", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, {L"*..*", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}}, {L"*..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {L"..?", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, + {L"a.<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}}, + {L"ea.tmp.tmp<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, + {L"<tmp", {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, + {L"<.tmp", {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, + {L"<name.tmp", {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<nam<tmp", {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<name.<", {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<name<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<.<", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<<", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<a", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0}}, + {L"*a", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0}}, + {L"<aa", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}, + {L"<.a", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0}}, + {L"<..a", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, + {L"<.<.<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1}}, + {L".<.<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0}}, + {L"<<.<", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<.<<", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<<<", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"< ..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, };
OBJECT_ATTRIBUTES attr; @@ -495,6 +527,7 @@ static void test_NtQueryDirectoryFile(void) FILE_POSITION_INFORMATION pos_info; FILE_NAMES_INFORMATION *names; const WCHAR *filename = fbdi->FileName; + BOOLEAN expect_empty; NTSTATUS status; HANDLE dirh, h;
@@ -512,27 +545,36 @@ static void test_NtQueryDirectoryFile(void) } InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL);
- test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, FALSE, TRUE); - test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, FALSE, FALSE); - test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, TRUE); - test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, FALSE, TRUE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, FALSE, FALSE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, TRUE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, FALSE, FALSE);
for (i = 0; i < test_dir_count; i++) { if (testfiles[i].name[0] == '.') continue; /* . and .. as masks are broken on Windows */ mask.Buffer = testfiles[i].name; mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].name) * sizeof(WCHAR); - test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE); - test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, FALSE); - test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, TRUE); - test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, FALSE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, TRUE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE, FALSE); }
for (i = 0; i < ARRAY_SIZE(mask_tests); ++i) { winetest_push_context("mask %s", debugstr_w(mask_tests[i].mask)); RtlInitUnicodeString(&mask, mask_tests[i].mask); - test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE); + expect_empty = TRUE; + for (j = 0; j < ARRAY_SIZE(mask_tests[i].found); ++j) + { + if (mask_tests[i].found[j]) + { + expect_empty = FALSE; + break; + } + } + test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE, expect_empty); for (j = 0; j < test_dir_count; j++) ok(testfiles[j].nfound == mask_tests[i].found[j], "%S, got %d.\n", testfiles[j].name, testfiles[j].nfound); winetest_pop_context(); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index ab567a63d19..8694564b576 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1428,6 +1428,8 @@ static ULONG hash_short_file_name( const WCHAR *name, int length, LPWSTR buffer */ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, const WCHAR *mask, const WCHAR *mask_end ) { + WCHAR c; + while (name < name_end && mask < mask_end) { switch(*mask) @@ -1447,6 +1449,42 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co ++name; } break; + case '<': + { + const WCHAR *next_dot; + BOOL had_dot = FALSE; + + ++mask; + while (name < name_end) + { + next_dot = name; + while (next_dot < name_end && *next_dot != '.') ++next_dot; + if (next_dot == name_end && had_dot) break; + if (next_dot < name_end) + { + had_dot = TRUE; + ++next_dot; + } + if (mask < mask_end) + { + while (name < next_dot) + { + c = *mask; + if (!is_wildcard(c)) + { + if (is_case_sensitive) + while (name < next_dot && (*name != c)) name++; + else + while (name < next_dot && (towupper(*name) != towupper(c))) name++; + } + if (match_filename_part( name, name_end, mask, mask_end )) return TRUE; + ++name; + } + } + name = next_dot; + } + break; + } case '?': case '>': mask++; @@ -1460,7 +1498,7 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co break; } } - while (mask < mask_end && *mask == '*') + while (mask < mask_end && (*mask == '*' || *mask == '<')) mask++; return (name == name_end && mask == mask_end); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 19 +++++++++++++++++++ dlls/ntdll/unix/file.c | 14 ++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index c12c5547ade..d61a1a73b3f 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -485,12 +485,17 @@ static void test_NtQueryDirectoryFile(void) {L"<", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1}}, {L"<.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1}}, {L"<..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + {L"<."", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1}}, {L".<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0}}, {L"..<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, {L"..*", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, {L"*..*", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}}, {L"*..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {L"..?", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, + {L".."", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L""", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}}, + {L"""", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}}, + {L""""", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}}, {L"a.<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}}, {L"ea.tmp.tmp<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {L"<tmp", {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, @@ -499,7 +504,20 @@ static void test_NtQueryDirectoryFile(void) {L"<nam<tmp", {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {L"<name.<", {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {L"<name<", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<"", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1}}, + {L"*"", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"*"tmp"tmp"", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, + {L"n"tmp", {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"ea"", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L""a", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, + {L"""a", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}, + {L"e"a", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"*"tmp", {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {L"<.<", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<"<", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<"<"", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"<"<.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + {L"<.<"", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"<<", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"<a", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0}}, {L"*a", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0}}, @@ -512,6 +530,7 @@ static void test_NtQueryDirectoryFile(void) {L"<.<<", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"<<<", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"< ..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L"<""", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1}}, };
OBJECT_ATTRIBUTES attr; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 8694564b576..eee3610b487 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1441,10 +1441,11 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co
while (name < name_end) { + c = *mask == '"' ? '.' : *mask; if (is_case_sensitive) - while (name < name_end && (*name != *mask)) name++; + while (name < name_end && (*name != c)) name++; else - while (name < name_end && (towupper(*name) != towupper(*mask))) name++; + while (name < name_end && (towupper(*name) != towupper(c))) name++; if (match_filename_part( name, name_end, mask, mask_end )) return TRUE; ++name; } @@ -1469,7 +1470,7 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co { while (name < next_dot) { - c = *mask; + c = *mask == '"' ? '.' : *mask; if (!is_wildcard(c)) { if (is_case_sensitive) @@ -1491,14 +1492,15 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co name++; break; default: - if (is_case_sensitive && *mask != *name) return FALSE; - if (!is_case_sensitive && towupper(*mask) != towupper(*name)) return FALSE; + c = *mask == '"' ? '.' : *mask; + if (is_case_sensitive && c != *name) return FALSE; + if (!is_case_sensitive && towupper(c) != towupper(*name)) return FALSE; mask++; name++; break; } } - while (mask < mask_end && (*mask == '*' || *mask == '<')) + while (mask < mask_end && (*mask == '*' || *mask == '<' || *mask == '"')) mask++; return (name == name_end && mask == mask_end); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 11 +++++++++++ dlls/ntdll/unix/file.c | 12 ++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index d61a1a73b3f..babe0f7a8fe 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -531,6 +531,17 @@ static void test_NtQueryDirectoryFile(void) {L"<<<", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, {L"< ..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {L"<""", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1}}, + {L">", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0}}, + {L">.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0}}, + {L">..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + {L">>", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0}}, + {L">>.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0}}, + {L">>>", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0}}, + {L">>.>>>", {0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1}}, + {L">.>", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1}}, + {L">>.tmp", {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L">>tmp", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {L">>>tmp", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, };
OBJECT_ATTRIBUTES attr; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index eee3610b487..d3bbcdffdc6 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1487,10 +1487,18 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co break; } case '?': - case '>': mask++; name++; break; + case '>': + mask++; + if (*name == '.') + { + while (mask < mask_end && *mask == '>') mask++; + if (mask == mask_end) name++; + } + else name++; + break; default: c = *mask == '"' ? '.' : *mask; if (is_case_sensitive && c != *name) return FALSE; @@ -1500,7 +1508,7 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co break; } } - while (mask < mask_end && (*mask == '*' || *mask == '<' || *mask == '"')) + while (mask < mask_end && (*mask == '*' || *mask == '<' || *mask == '"' || *mask == '>')) mask++; return (name == name_end && mask == mask_end); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/directory.c | 1 + dlls/ntdll/unix/file.c | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index babe0f7a8fe..c05b51860e1 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -483,6 +483,7 @@ static void test_NtQueryDirectoryFile(void) {L"??.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {L"<", {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1}}, + {L"*<a", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0}}, {L"<.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1}}, {L"<..", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, {L"<."", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1}}, diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index d3bbcdffdc6..429f8839ed2 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1442,10 +1442,13 @@ static BOOLEAN match_filename_part( const WCHAR *name, const WCHAR *name_end, co while (name < name_end) { c = *mask == '"' ? '.' : *mask; - if (is_case_sensitive) - while (name < name_end && (*name != c)) name++; - else - while (name < name_end && (towupper(*name) != towupper(c))) name++; + if (!is_wildcard(c)) + { + if (is_case_sensitive) + while (name < name_end && (*name != c)) name++; + else + while (name < name_end && (towupper(*name) != towupper(c))) name++; + } if (match_filename_part( name, name_end, mask, mask_end )) return TRUE; ++name; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernel32/tests/file.c | 133 +++++++++++++++--------------- dlls/kernelbase/file.c | 163 +++++++++++-------------------------- 2 files changed, 118 insertions(+), 178 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index e6766bbd08d..3b8ffc03189 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -3039,71 +3039,77 @@ static void test_FindFirstFile_wildcards(void) "a", "a..a", "a.a", "a.a.a", "aa", "aaa", "aaaa", " .a" }; static const struct { - int todo; const char *pattern, *result; } tests[] = { - {0, "*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, ".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, - {0, "*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, ".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, - {0, "*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {1, "*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"}, - {0, "*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, ".*.", ", '.', '..', '.a', '.aaa'"}, - {0, "..*", ", '.', '..', '..a', '..a.a'"}, - {0, "**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, " *..", ""}, - {0, "..* ", ", '.', '..', '..a', '..a.a'"}, - {0, "a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, - {0, "*a ", ", '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {0, "*aa*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - - {1, "<.<.<", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, - {1, "<.<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, - {1, ".<.<", ", '..a', '..a.a', '.a..a', '.a.a'"}, - {1, "<.<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, - {1, ".<", ", '.', '..', '.a', '.aaa'"}, - {1, "<.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, "<", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, - {1, "<..<", ", '..a', '.a..a', 'a..a'"}, - {1, "<..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, ".<.", ", '.', '..', '.a', '.aaa'"}, - {0, "..<", ", '..a'"}, - {1, "<<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {1, "<<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {1, "<. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, - {1, "< .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, "< . ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, - {1, "<.. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, - {1, "<. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, "< ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, " <..", ""}, - {0, "..< ", ", '..a'"}, - - {1, "?", ", '.', '..', 'a'"}, - {0, "?.", ", '.', '..', 'a'"}, - {0, "?. ", ", '.', '..', 'a'"}, - {1, "??.", ", '.', '..', 'a', 'aa'"}, - {1, "??. ", ", '.', '..', 'a', 'aa'"}, - {1, "???.", ", '.', '..', 'a', 'aa', 'aaa'"}, - {1, "?.??.", ", '.', '..', '.a', 'a', 'a.a', ' .a'"}, - - {1, ">", ", '.', '..', 'a'"}, - {1, ">.", ", '.', '..', 'a'"}, - {1, ">. ", ", '.', '..', 'a'"}, - {1, ">>.", ", '.', '..', 'a', 'aa'"}, - {1, ">>. ", ", '.', '..', 'a', 'aa'"}, - {1, ">>>.", ", '.', '..', 'a', 'aa', 'aaa'"}, - {1, ">.>>.", ", '.', '..', '.a', 'a.a', ' .a'"}, + {"*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, + {"*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, + {"*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + + {"*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"}, + {"*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {".*.", ", '.', '..', '.a', '.aaa'"}, + {"..*", ", '.', '..', '..a', '..a.a'"}, + {"**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {" *..", ""}, + {"..* ", ", '.', '..', '..a', '..a.a'"}, + {"a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"*a ", ", '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"*aa*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {"aa*.", ", '.aaa', 'aa', 'aaa', 'aaaa'"}, + {"aa.*", ", 'aa'"}, + {"aa"*", ", 'aa'"}, + {"*.a", ", '..a', '..a.a', '.a', '.a..a', '.a.a', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {"<.a", ", '..a', '..a.a', '.a', '.a..a', '.a.a', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + + {"<.<.<", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, + {"<.<.< ", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, + {"<.<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {".<.<", ", '..a', '..a.a', '.a..a', '.a.a'"}, + {"<.<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, + {".<", ", '.', '..', '.a', '.aaa'"}, + {"<.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"<", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"<..<", ", '..a', '.a..a', 'a..a'"}, + {"<..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {".<.", ", '.', '..', '.a', '.aaa'"}, + {"..<", ", '..a'"}, + {"<<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"<<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {"<. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"< .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"< . ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"<.. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {"<. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {"< ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {" <..", ""}, + {"..< ", ", '..a'"}, + + {"?", ", '.', '..', 'a'"}, + {"?.", ", '.', '..', 'a'"}, + {"?. ", ", '.', '..', 'a'"}, + {"??.", ", '.', '..', 'a', 'aa'"}, + {"??. ", ", '.', '..', 'a', 'aa'"}, + {"???.", ", '.', '..', 'a', 'aa', 'aaa'"}, + {"?.??.", ", '.', '..', '.a', 'a', 'a.a', ' .a'"}, + + {">", ", '.', '..', 'a'"}, + {">.", ", '.', '..', 'a'"}, + {">. ", ", '.', '..', 'a'"}, + {">>.", ", '.', '..', 'a', 'aa'"}, + {">>. ", ", '.', '..', 'a', 'aa'"}, + {">>>.", ", '.', '..', 'a', 'aa', 'aaa'"}, + {">.>>.", ", '.', '..', '.a', 'a.a', ' .a'"}, };
CreateDirectoryA("test-dir", NULL); @@ -3142,7 +3148,6 @@ static void test_FindFirstFile_wildcards(void) FindClose(handle); }
- todo_wine_if (tests[i].todo) ok(missing[0] == 0 && incorrect[0] == 0, "FindFirstFile with '%s' found correctly %s, found incorrectly %s, and missed %s\n", tests[i].pattern, diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index f842f549061..3f59270b336 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -54,11 +54,9 @@ typedef struct FINDEX_INFO_LEVELS level; /* Level passed to FindFirst */ UNICODE_STRING path; /* NT path used to open the directory */ BOOL is_root; /* is directory the root of the drive? */ - BOOL wildcard; /* did the mask contain wildcard characters? */ UINT data_pos; /* current position in dir data */ UINT data_len; /* length of dir data */ UINT data_size; /* size of data buffer, or 0 when everything has been read */ - WCHAR *mask; /* mask string to match if wildcards are used */ BYTE data[1]; /* directory data */ } FIND_FIRST_INFO;
@@ -1148,6 +1146,43 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExA( const char *filename, FINDEX_I }
+/*********************************************************************** + * fixup_mask + * + * Fixup mask with wildcards for use with NtQueryDirectoryFile(). + */ +static WCHAR *fixup_mask( const WCHAR *mask ) +{ + const WCHAR *mask_end = mask + lstrlenW( mask ), *p; + WCHAR *ret, *dst; + BOOL no_ext; + WCHAR c; + + if (!(ret = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( mask ) + 1) * sizeof(*mask) ))) return NULL; + no_ext = mask < mask_end && mask_end[-1] == '.'; + p = mask_end; + while (p != mask) + { + if (p[-1] == '.') mask_end = p; + else if (p[-1] != ' ') break; + --p; + } + + dst = ret; + while (mask < mask_end) + { + c = *mask++; + while (mask < mask_end && *mask == ' ') ++mask; + if (c == '.' && (mask == mask_end || *mask == '*' || *mask == '?')) c = '"'; + else if (c == '?') c = '>'; + else if (no_ext && c == '*' && mask < mask_end && *mask == '.') c = '<'; + *dst++ = c; + } + *dst = 0; + return ret; +} + + /****************************************************************************** * FindFirstFileExW (kernelbase.@) */ @@ -1162,7 +1197,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; NTSTATUS status; - DWORD size, mask_size = 0, device = 0; + DWORD size, device = 0;
TRACE( "%s %d %p %d %p %lx\n", debugstr_w(filename), level, data, search_op, filter, flags );
@@ -1223,17 +1258,16 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ else { nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR); - has_wildcard = wcspbrk( mask, L"*?" ) != NULL; + has_wildcard = wcspbrk( mask, L"*?<>" ) != NULL; if (has_wildcard) { size = 8192; mask = PathFindFileNameW( filename ); - mask_size = (lstrlenW( mask ) + 1) * sizeof(*mask); } else size = max_entry_size; }
- if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size + mask_size] )))) + if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size] )))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); goto error; @@ -1271,19 +1305,11 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ info->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FIND_FIRST_INFO.cs"); info->path = nt_name; info->magic = FIND_FIRST_MAGIC; - info->wildcard = has_wildcard; info->data_pos = 0; info->data_len = 0; info->data_size = size; info->search_op = search_op; info->level = level; - if (mask_size) - { - info->mask = (WCHAR *)(info->data + size); - memcpy( info->mask, mask, mask_size ); - mask = NULL; - } - else info->mask = NULL;
if (device) { @@ -1297,11 +1323,17 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ } else { + WCHAR *fixedup_mask = mask; UNICODE_STRING mask_str;
- RtlInitUnicodeString( &mask_str, mask ); - status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size, - FileBothDirectoryInformation, FALSE, has_wildcard ? NULL : &mask_str, TRUE ); + if (has_wildcard && !(fixedup_mask = fixup_mask( mask ))) status = STATUS_NO_MEMORY; + else + { + RtlInitUnicodeString( &mask_str, fixedup_mask ); + status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size, + FileBothDirectoryInformation, FALSE, &mask_str, TRUE ); + } + if (fixedup_mask != mask) HeapFree( GetProcessHeap(), 0, fixedup_mask ); if (status) { FindClose( info ); @@ -1384,95 +1416,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *da }
-/*********************************************************************** - * name_has_ext - * - * Check if the file name has extension (skipping leading dots). - */ -static BOOL name_has_ext( const WCHAR *name, const WCHAR *name_end ) -{ - while (name != name_end && *name == '.') ++name; - while (name != name_end && *name != '.') ++name; - return name != name_end; -} - - -/*********************************************************************** - * match_filename - * - * Check if the file name matches mask containing wildcards. - */ -static BOOL match_filename( const WCHAR *name, int length, const WCHAR *mask ) -{ - BOOL mismatch; - const WCHAR *name_end = name + length; - const WCHAR *mask_end = mask + lstrlenW( mask ); - const WCHAR *lastjoker = NULL; - const WCHAR *next_to_retry = NULL; - const WCHAR *asterisk; - - if (mask != mask_end && mask_end[-1] == '.' && (asterisk = wcschr( mask, '*' )) && asterisk == wcsrchr( mask, '*' ) - && name_has_ext( name, name_end )) - { - /* Single '*' mask ending with '.' only matches files without extension. */ - return FALSE; - } - - while (name < name_end && mask < mask_end) - { - switch(*mask) - { - case '*': - mask++; - while (mask < mask_end && *mask == '*') mask++; - if (mask == mask_end) return TRUE; /* end of mask is all '*', so match */ - lastjoker = mask; - - /* skip to the next match after the joker(s) */ - while (name < name_end && towupper( *name ) != towupper( *mask )) name++; - next_to_retry = name; - break; - case '?': - case '>': - mask++; - name++; - break; - default: - mismatch = towupper( *mask ) != towupper( *name ); - - if (!mismatch) - { - mask++; - name++; - if (mask == mask_end) - { - if (name == name_end) return TRUE; - if (lastjoker) mask = lastjoker; - } - } - else /* mismatch ! */ - { - if (lastjoker) /* we had an '*', so we can try unlimitedly */ - { - mask = lastjoker; - - /* this scan sequence was a mismatch, so restart - * 1 char after the first char we checked last time */ - next_to_retry++; - name = next_to_retry; - } - else return FALSE; - } - break; - } - } - - while (mask < mask_end && (*mask == ' ' || *mask == '.' || *mask == '*')) - mask++; - return (name == name_end && mask == mask_end); -} - - /****************************************************************************** * FindNextFileW (kernelbase.@) */ @@ -1533,14 +1476,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *da file_name[0] == '.' && file_name[1] == '.') continue; }
- if (info->mask) - { - if (!match_filename( dir_info->FileName, dir_info->FileNameLength / sizeof(WCHAR), info->mask ) - && (!dir_info->ShortNameLength - || !match_filename( dir_info->ShortName, dir_info->ShortNameLength / sizeof(WCHAR), info->mask ))) - continue; - } - data->dwFileAttributes = dir_info->FileAttributes; data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime; data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=146100
Your paranoid android.
=== debian11b (64 bit WoW report) ===
cmd.exe: batch.c:321: Test failed: unexpected char 0x30 position 0 in line 50 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x32 position 0 in line 51 (got '2 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 52 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x34 position 0 in line 53 (got '4 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 54 (got '------ Testing invocation with CMD /C -------------', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 55 (got '------ Testing invocation with CMD /C -------------', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 56 (got '------ Testing invocation with CMD /C -------------', wanted '2@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 57 (got '------ Testing invocation with CMD /C -------------', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 58 (got '------ Testing invocation with CMD /C -------------', wanted '3@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 59 (got '------ Testing invocation with CMD /C -------------', wanted '3@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 60 (got '------ Testing invocation with CMD /C -------------', wanted '4@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 63 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x65 position 0 in line 65 (got 'error 9009', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 66 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x65 position 0 in line 67 (got 'error 9009', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x32 position 0 in line 68 (got '2 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 69 (got '0 ', wanted '2@space@') batch.c:321: Test failed: unexpected char 0x65 position 0 in line 70 (got 'error 9009', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x34 position 0 in line 71 (got '4 ', wanted '3@space@') batch.c:321: Test failed: unexpected char 0x50 position 0 in line 72 (got 'Passed', wanted '4@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 73 (got '---------- Testing CMD /C quoting -----------------', wanted 'Passed') batch.c:321: Test failed: unexpected char 0x65 position 0 in line 76 (got 'error 9009', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 78 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 80 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x32 position 0 in line 82 (got '2 ', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x32 position 0 in line 83 (got '2 ', wanted '0@space@@or_broken@3@space@') batch.c:321: Test failed: unexpected char 0x32 position 0 in line 84 (got '2 ', wanted '3@space@') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 85 (got '0 ', wanted '2@space@') batch.c:321: Test failed: unexpected char 0x68 position 0 in line 86 (got 'hi', wanted '2@space@') batch.c:321: Test failed: unexpected char 0x68 position 0 in line 87 (got 'hi', wanted '2@space@') batch.c:321: Test failed: unexpected char 0x68 position 0 in line 88 (got 'hi', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 89 (got '------- Testing CMD /C qualifier treatment ------------', wanted '5@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 90 (got '------- Testing CMD /C qualifier treatment ------------', wanted 'hi') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 91 (got '------- Testing CMD /C qualifier treatment ------------', wanted 'hi') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 92 (got '------- Testing CMD /C qualifier treatment ------------', wanted 'hi') batch.c:321: Test failed: unexpected char 0x30 position 0 in line 95 (got '0 ', wanted '1@space@') batch.c:321: Test failed: unexpected char 0x62 position 0 in line 103 (got 'bar ', wanted '0@space@') batch.c:321: Test failed: unexpected char 0x2d position 0 in line 105 (got '--------- Testing special characters --------------', wanted 'bar@space@')
Brendan Shanks spotted the performance regression in FindFirstFile at least on MacOS for the case when a mask selects no or a few files from a large directory which was triggered by my commit 68fecd77eb103b6a6cfa53f8de559fb28b29b7b6 ("kernelbase: Duplicate file name matching code for FindNextFileW().). That happens because before the commit file filtering by name was done before querying all the file attributes and with the commit the whole full directory contents is read and then filtered in kernelbase. At times it wasn't clear to me how else that could be implemented, but now Brendan found some clues ([1], [2]) which directly suggest that. That documentation omits a lot of essential details about how that matching actually works but gives direction and useful clues.
The last patch essentially reverts the referenced commit although leaves the functionality which it was needed for and, in fact, removes all the wine_todo's from FindFirstFile file name matching tests.
1. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fsa/0b03464...
2. http://ubiqx.org/cifs/rfc-draft/draft-leach-cifs-v1-spec-02.html#s3.3
There are related cmd.exe test failures, I am looking into that.