kernelbase: Preprocess wildcarded mask and pass it with NtQueryDirectoryFile().

This commit is contained in:
Paul Gofman 2024-06-03 20:13:21 -06:00 committed by Alexandre Julliard
parent 691ccd64b3
commit e1d2fb8e05
3 changed files with 134 additions and 175 deletions

View file

@ -3039,71 +3039,100 @@ 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'"},
{"*.*.*", ", '.', '..', '..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'"},
{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'"},
{"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'"},
{"a a*.*", ""},
{"a\"*\"a", ", 'a..a', 'a.a.a'"},
{"aa*.*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
{"a ?.*", ""},
{"? a.*", ""},
{"a* a", ""},
{" *a", ", ' .a'"},
{"* *", ", ' .a'"},
{"a* .", ", 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"},
{" ?a", ""},
{"* .a", ", ' .a'"},
{"< .a", ", ' .a'"},
{"** .a", ", ' .a'"},
{"<< .a", ", ' .a'"},
{"aa? ", ", 'aa', 'aaa'"},
{"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'"},
{1, "?", ", '.', '..', 'a'"},
{0, "?.", ", '.', '..', 'a'"},
{0, "?. ", ", '.', '..', 'a'"},
{1, "??.", ", '.', '..', 'a', 'aa'"},
{1, "??. ", ", '.', '..', 'a', 'aa'"},
{1, "???.", ", '.', '..', 'a', 'aa', 'aaa'"},
{1, "?.??.", ", '.', '..', '.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', '.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'"},
{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', '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 +3171,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,

View file

@ -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,34 @@ 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 )
{
unsigned int len = lstrlenW( mask ), i;
BOOL no_ext;
WCHAR *ret;
if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(*mask) ))) return NULL;
memcpy( ret, mask, (len + 1) * sizeof(*mask) );
if (!len) return ret;
no_ext = ret[len - 1] == '.';
while (len && (ret[len - 1] == '.' || ret[len - 1] == ' ')) --len;
for (i = 0; i < len; ++i)
{
if (ret[i] == '.' && (ret[i + 1] == '*' || ret[i + 1] == '?')) ret[i] = '\"';
else if (ret[i] == '?') ret[i] = '>';
}
ret[len] = 0;
if (no_ext && len && ret[len - 1] == '*') ret[len - 1] = '<';
return ret;
}
/******************************************************************************
* FindFirstFileExW (kernelbase.@)
*/
@ -1162,7 +1188,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 +1249,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 +1296,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 +1314,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 +1407,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 +1467,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;

View file

@ -472,7 +472,11 @@ static void test_NtQueryDirectoryFile(void)
mask_tests[] =
{
{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, 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, 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"* *", {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"**", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}},
@ -531,6 +535,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, 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}},