Commit 68fecd77 authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

kernelbase: Duplicate file name matching code for FindNextFileW().

parent 6f3c76c9
......@@ -58,6 +58,7 @@ typedef struct
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;
......@@ -1124,7 +1125,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
NTSTATUS status;
DWORD size, device = 0;
DWORD size, mask_size = 0, device = 0;
TRACE( "%s %d %p %d %p %lx\n", debugstr_w(filename), level, data, search_op, filter, flags );
......@@ -1186,10 +1187,15 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_
{
nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
has_wildcard = wcspbrk( mask, L"*?" ) != NULL;
size = has_wildcard ? 8192 : max_entry_size;
if (has_wildcard)
{
size = 8192;
mask_size = (lstrlenW( mask ) + 1) * sizeof(*mask);
}
else size = max_entry_size;
}
if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size] ))))
if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size + mask_size] ))))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
......@@ -1233,6 +1239,13 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_
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)
{
......@@ -1250,7 +1263,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_
RtlInitUnicodeString( &mask_str, mask );
status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
FileBothDirectoryInformation, FALSE, &mask_str, TRUE );
FileBothDirectoryInformation, FALSE, has_wildcard ? NULL : &mask_str, TRUE );
if (status)
{
FindClose( info );
......@@ -1333,6 +1346,74 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *da
}
/***********************************************************************
* 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;
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++;
return (name == name_end && mask == mask_end);
}
/******************************************************************************
* FindNextFileW (kernelbase.@)
*/
......@@ -1392,6 +1473,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *da
dir_info->FileName[0] == '.' && dir_info->FileName[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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment