kernelbase: Duplicate file name matching code for FindNextFileW().
This commit is contained in:
parent
6f3c76c9a5
commit
68fecd77eb
1 changed files with 93 additions and 4 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue