kernel32: Move FindFirst/NextFile functions to kernelbase.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-12-11 10:48:34 +01:00
parent 6731f33d40
commit 9b0877db4a
4 changed files with 414 additions and 487 deletions

View File

@ -50,28 +50,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(file);
/* info structure for FindFirstFile handle */
typedef struct
{
DWORD magic; /* magic number */
HANDLE handle; /* handle to directory */
CRITICAL_SECTION cs; /* crit section protecting this structure */
FINDEX_SEARCH_OPS search_op; /* Flags passed to FindFirst. */
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 */
BYTE data[1]; /* directory data */
} FIND_FIRST_INFO;
#define FIND_FIRST_MAGIC 0xc0ffee11
static const UINT max_entry_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] );
static const WCHAR wildcardsW[] = { '*','?',0 };
static const WCHAR krnl386W[] = {'k','r','n','l','3','8','6','.','e','x','e','1','6',0};
/***********************************************************************
@ -113,58 +91,6 @@ static HANDLE create_file_OF( LPCSTR path, INT mode )
}
/***********************************************************************
* check_dir_symlink
*
* Check if a dir symlink should be returned by FindNextFile.
*/
static BOOL check_dir_symlink( FIND_FIRST_INFO *info, const FILE_BOTH_DIR_INFORMATION *file_info )
{
UNICODE_STRING str;
ANSI_STRING unix_name;
struct stat st, parent_st;
BOOL ret = TRUE;
DWORD len;
str.MaximumLength = info->path.Length + sizeof(WCHAR) + file_info->FileNameLength;
if (!(str.Buffer = HeapAlloc( GetProcessHeap(), 0, str.MaximumLength ))) return TRUE;
memcpy( str.Buffer, info->path.Buffer, info->path.Length );
len = info->path.Length / sizeof(WCHAR);
if (!len || str.Buffer[len-1] != '\\') str.Buffer[len++] = '\\';
memcpy( str.Buffer + len, file_info->FileName, file_info->FileNameLength );
str.Length = len * sizeof(WCHAR) + file_info->FileNameLength;
unix_name.Buffer = NULL;
if (!wine_nt_to_unix_file_name( &str, &unix_name, OPEN_EXISTING, FALSE ) &&
!stat( unix_name.Buffer, &st ))
{
char *p = unix_name.Buffer + unix_name.Length - 1;
/* skip trailing slashes */
while (p > unix_name.Buffer && *p == '/') p--;
while (ret && p > unix_name.Buffer)
{
while (p > unix_name.Buffer && *p != '/') p--;
while (p > unix_name.Buffer && *p == '/') p--;
p[1] = 0;
if (!stat( unix_name.Buffer, &parent_st ) &&
parent_st.st_dev == st.st_dev &&
parent_st.st_ino == st.st_ino)
{
WARN( "suppressing dir symlink %s pointing to parent %s\n",
debugstr_wn( str.Buffer, str.Length/sizeof(WCHAR) ),
debugstr_a( unix_name.Buffer ));
ret = FALSE;
}
}
}
RtlFreeAnsiString( &unix_name );
RtlFreeUnicodeString( &str );
return ret;
}
/***********************************************************************
* FILE_SetDosError
*
@ -662,405 +588,6 @@ BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
}
/*************************************************************************
* FindFirstFileExW (KERNEL32.@)
*
* NOTE: The FindExSearchLimitToDirectories is ignored - it gives the same
* results as FindExSearchNameMatch
*/
HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
LPVOID data, FINDEX_SEARCH_OPS search_op,
LPVOID filter, DWORD flags)
{
WCHAR *mask;
BOOL has_wildcard = FALSE;
FIND_FIRST_INFO *info = NULL;
UNICODE_STRING nt_name;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
NTSTATUS status;
DWORD size, device = 0;
TRACE("%s %d %p %d %p %x\n", debugstr_w(filename), level, data, search_op, filter, flags);
if (flags & ~FIND_FIRST_EX_LARGE_FETCH)
{
FIXME("flags not implemented 0x%08x\n", flags );
}
if (search_op != FindExSearchNameMatch && search_op != FindExSearchLimitToDirectories)
{
FIXME("search_op not implemented 0x%08x\n", search_op);
SetLastError( ERROR_INVALID_PARAMETER );
return INVALID_HANDLE_VALUE;
}
if (level != FindExInfoStandard && level != FindExInfoBasic)
{
FIXME("info level %d not implemented\n", level );
SetLastError( ERROR_INVALID_PARAMETER );
return INVALID_HANDLE_VALUE;
}
if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
{
SetLastError( ERROR_PATH_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
if (!mask && (device = RtlIsDosDeviceName_U( filename )))
{
static const WCHAR dotW[] = {'.',0};
WCHAR *dir = NULL;
/* we still need to check that the directory can be opened */
if (HIWORD(device))
{
if (!(dir = HeapAlloc( GetProcessHeap(), 0, HIWORD(device) + sizeof(WCHAR) )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
}
memcpy( dir, filename, HIWORD(device) );
dir[HIWORD(device)/sizeof(WCHAR)] = 0;
}
RtlFreeUnicodeString( &nt_name );
if (!RtlDosPathNameToNtPathName_U( dir ? dir : dotW, &nt_name, &mask, NULL ))
{
HeapFree( GetProcessHeap(), 0, dir );
SetLastError( ERROR_PATH_NOT_FOUND );
goto error;
}
HeapFree( GetProcessHeap(), 0, dir );
size = 0;
}
else if (!mask || !*mask)
{
SetLastError( ERROR_FILE_NOT_FOUND );
goto error;
}
else
{
nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
has_wildcard = strpbrkW( mask, wildcardsW ) != NULL;
size = has_wildcard ? 8192 : max_entry_size;
}
if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size] ))))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
}
/* check if path is the root of the drive, skipping the \??\ prefix */
info->is_root = FALSE;
if (nt_name.Length >= 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':')
{
DWORD pos = 6;
while (pos * sizeof(WCHAR) < nt_name.Length && nt_name.Buffer[pos] == '\\') pos++;
info->is_root = (pos * sizeof(WCHAR) >= nt_name.Length);
}
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE;
attr.ObjectName = &nt_name;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
status = NtOpenFile( &info->handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
if (status != STATUS_SUCCESS)
{
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
SetLastError( ERROR_PATH_NOT_FOUND );
else
SetLastError( RtlNtStatusToDosError(status) );
goto error;
}
RtlInitializeCriticalSection( &info->cs );
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 (device)
{
WIN32_FIND_DATAW *wfd = data;
memset( wfd, 0, sizeof(*wfd) );
memcpy( wfd->cFileName, filename + HIWORD(device)/sizeof(WCHAR), LOWORD(device) );
wfd->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
CloseHandle( info->handle );
info->handle = 0;
}
else
{
UNICODE_STRING mask_str;
RtlInitUnicodeString( &mask_str, mask );
status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
FileBothDirectoryInformation, FALSE, &mask_str, TRUE );
if (status)
{
FindClose( info );
SetLastError( RtlNtStatusToDosError( status ) );
return INVALID_HANDLE_VALUE;
}
info->data_len = io.Information;
if (!has_wildcard) info->data_size = 0; /* we read everything */
if (!FindNextFileW( info, data ))
{
TRACE( "%s not found\n", debugstr_w(filename) );
FindClose( info );
SetLastError( ERROR_FILE_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
if (!has_wildcard) /* we can't find two files with the same name */
{
CloseHandle( info->handle );
info->handle = 0;
}
}
return info;
error:
HeapFree( GetProcessHeap(), 0, info );
RtlFreeUnicodeString( &nt_name );
return INVALID_HANDLE_VALUE;
}
/*************************************************************************
* FindNextFileW (KERNEL32.@)
*/
BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
{
FIND_FIRST_INFO *info;
FILE_BOTH_DIR_INFORMATION *dir_info;
BOOL ret = FALSE;
NTSTATUS status;
TRACE("%p %p\n", handle, data);
if (!handle || handle == INVALID_HANDLE_VALUE)
{
SetLastError( ERROR_INVALID_HANDLE );
return ret;
}
info = handle;
if (info->magic != FIND_FIRST_MAGIC)
{
SetLastError( ERROR_INVALID_HANDLE );
return ret;
}
RtlEnterCriticalSection( &info->cs );
if (!info->handle) SetLastError( ERROR_NO_MORE_FILES );
else for (;;)
{
if (info->data_pos >= info->data_len) /* need to read some more data */
{
IO_STATUS_BLOCK io;
if (info->data_size)
status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
FileBothDirectoryInformation, FALSE, NULL, FALSE );
else
status = STATUS_NO_MORE_FILES;
if (status)
{
SetLastError( RtlNtStatusToDosError( status ) );
if (status == STATUS_NO_MORE_FILES)
{
CloseHandle( info->handle );
info->handle = 0;
}
break;
}
info->data_len = io.Information;
info->data_pos = 0;
}
dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
else info->data_pos = info->data_len;
/* don't return '.' and '..' in the root of the drive */
if (info->is_root)
{
if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
}
/* check for dir symlink */
if ((dir_info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(dir_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
info->wildcard)
{
if (!check_dir_symlink( info, dir_info )) continue;
}
data->dwFileAttributes = dir_info->FileAttributes;
data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime;
data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
data->ftLastWriteTime = *(FILETIME *)&dir_info->LastWriteTime;
data->nFileSizeHigh = dir_info->EndOfFile.QuadPart >> 32;
data->nFileSizeLow = (DWORD)dir_info->EndOfFile.QuadPart;
data->dwReserved0 = 0;
data->dwReserved1 = 0;
memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
if (info->level != FindExInfoBasic)
{
memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
}
else
data->cAlternateFileName[0] = 0;
TRACE("returning %s (%s)\n",
debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
ret = TRUE;
break;
}
RtlLeaveCriticalSection( &info->cs );
return ret;
}
/*************************************************************************
* FindClose (KERNEL32.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH FindClose( HANDLE handle )
{
FIND_FIRST_INFO *info = handle;
if (!handle || handle == INVALID_HANDLE_VALUE)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__TRY
{
if (info->magic == FIND_FIRST_MAGIC)
{
RtlEnterCriticalSection( &info->cs );
if (info->magic == FIND_FIRST_MAGIC) /* in case someone else freed it in the meantime */
{
info->magic = 0;
if (info->handle) CloseHandle( info->handle );
info->handle = 0;
RtlFreeUnicodeString( &info->path );
info->data_pos = 0;
info->data_len = 0;
RtlLeaveCriticalSection( &info->cs );
info->cs.DebugInfo->Spare[0] = 0;
RtlDeleteCriticalSection( &info->cs );
HeapFree( GetProcessHeap(), 0, info );
}
}
}
__EXCEPT_PAGE_FAULT
{
WARN("Illegal handle %p\n", handle);
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__ENDTRY
return TRUE;
}
/*************************************************************************
* FindFirstFileA (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileA( LPCSTR lpFileName, WIN32_FIND_DATAA *lpFindData )
{
return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData,
FindExSearchNameMatch, NULL, 0);
}
/*************************************************************************
* FindFirstFileExA (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileExA( LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp,
LPVOID lpSearchFilter, DWORD dwAdditionalFlags)
{
HANDLE handle;
WIN32_FIND_DATAA *dataA;
WIN32_FIND_DATAW dataW;
WCHAR *nameW;
if (!(nameW = FILE_name_AtoW( lpFileName, FALSE ))) return INVALID_HANDLE_VALUE;
handle = FindFirstFileExW(nameW, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
if (handle == INVALID_HANDLE_VALUE) return handle;
dataA = lpFindFileData;
dataA->dwFileAttributes = dataW.dwFileAttributes;
dataA->ftCreationTime = dataW.ftCreationTime;
dataA->ftLastAccessTime = dataW.ftLastAccessTime;
dataA->ftLastWriteTime = dataW.ftLastWriteTime;
dataA->nFileSizeHigh = dataW.nFileSizeHigh;
dataA->nFileSizeLow = dataW.nFileSizeLow;
FILE_name_WtoA( dataW.cFileName, -1, dataA->cFileName, sizeof(dataA->cFileName) );
FILE_name_WtoA( dataW.cAlternateFileName, -1, dataA->cAlternateFileName,
sizeof(dataA->cAlternateFileName) );
return handle;
}
/*************************************************************************
* FindFirstFileW (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
{
return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
FindExSearchNameMatch, NULL, 0);
}
/*************************************************************************
* FindNextFileA (KERNEL32.@)
*/
BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
{
WIN32_FIND_DATAW dataW;
if (!FindNextFileW( handle, &dataW )) return FALSE;
data->dwFileAttributes = dataW.dwFileAttributes;
data->ftCreationTime = dataW.ftCreationTime;
data->ftLastAccessTime = dataW.ftLastAccessTime;
data->ftLastWriteTime = dataW.ftLastWriteTime;
data->nFileSizeHigh = dataW.nFileSizeHigh;
data->nFileSizeLow = dataW.nFileSizeLow;
FILE_name_WtoA( dataW.cFileName, -1, data->cFileName, sizeof(data->cFileName) );
FILE_name_WtoA( dataW.cAlternateFileName, -1, data->cAlternateFileName,
sizeof(data->cAlternateFileName) );
return TRUE;
}
/**************************************************************************
* FindFirstStreamW (KERNEL32.@)
*/

View File

@ -475,18 +475,18 @@
@ stdcall -import FindActCtxSectionStringW(long ptr long wstr ptr)
@ stdcall FindAtomA(str)
@ stdcall FindAtomW(wstr)
@ stdcall FindClose(long)
@ stdcall -import FindClose(long)
@ stdcall -import FindCloseChangeNotification(long)
@ stdcall -import FindFirstChangeNotificationA(str long long)
@ stdcall -import FindFirstChangeNotificationW(wstr long long)
@ stdcall FindFirstFileA(str ptr)
@ stdcall FindFirstFileExA(str long ptr long ptr long)
@ stdcall FindFirstFileExW(wstr long ptr long ptr long)
@ stdcall -import FindFirstFileA(str ptr)
@ stdcall -import FindFirstFileExA(str long ptr long ptr long)
@ stdcall -import FindFirstFileExW(wstr long ptr long ptr long)
# @ stub FindFirstFileNameTransactedW
# @ stub FindFirstFileNameW
# @ stub FindFirstFileTransactedA
# @ stub FindFirstFileTransactedW
@ stdcall FindFirstFileW(wstr ptr)
@ stdcall -import FindFirstFileW(wstr ptr)
# @ stub FindFirstStreamTransactedW
@ stdcall FindFirstStreamW(wstr long ptr long)
@ stdcall FindFirstVolumeA(ptr long)
@ -494,9 +494,9 @@
@ stdcall FindFirstVolumeMountPointW(wstr ptr long)
@ stdcall FindFirstVolumeW(ptr long)
@ stdcall -import FindNextChangeNotification(long)
@ stdcall FindNextFileA(long ptr)
@ stdcall -import FindNextFileA(long ptr)
# @ stub FindNextFileNameW
@ stdcall FindNextFileW(long ptr)
@ stdcall -import FindNextFileW(long ptr)
@ stdcall FindNextStreamW(long ptr)
@ stdcall FindNextVolumeA(long ptr long)
@ stub FindNextVolumeMountPointA

View File

@ -43,6 +43,27 @@
WINE_DEFAULT_DEBUG_CHANNEL(file);
/* info structure for FindFirstFile handle */
typedef struct
{
DWORD magic; /* magic number */
HANDLE handle; /* handle to directory */
CRITICAL_SECTION cs; /* crit section protecting this structure */
FINDEX_SEARCH_OPS search_op; /* Flags passed to FindFirst. */
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 */
BYTE data[1]; /* directory data */
} FIND_FIRST_INFO;
#define FIND_FIRST_MAGIC 0xc0ffee11
static const UINT max_entry_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] );
const WCHAR windows_dir[] = {'C',':','\\','w','i','n','d','o','w','s',0};
const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m','3','2',0};
@ -734,6 +755,385 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextChangeNotification( HANDLE handle )
}
/******************************************************************************
* FindFirstFileExA (kernelbase.@)
*/
HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExA( const char *filename, FINDEX_INFO_LEVELS level,
void *data, FINDEX_SEARCH_OPS search_op,
void *filter, DWORD flags )
{
HANDLE handle;
WIN32_FIND_DATAA *dataA = data;
WIN32_FIND_DATAW dataW;
WCHAR *nameW;
if (!(nameW = file_name_AtoW( filename, FALSE ))) return INVALID_HANDLE_VALUE;
handle = FindFirstFileExW( nameW, level, &dataW, search_op, filter, flags );
if (handle == INVALID_HANDLE_VALUE) return handle;
dataA->dwFileAttributes = dataW.dwFileAttributes;
dataA->ftCreationTime = dataW.ftCreationTime;
dataA->ftLastAccessTime = dataW.ftLastAccessTime;
dataA->ftLastWriteTime = dataW.ftLastWriteTime;
dataA->nFileSizeHigh = dataW.nFileSizeHigh;
dataA->nFileSizeLow = dataW.nFileSizeLow;
file_name_WtoA( dataW.cFileName, -1, dataA->cFileName, sizeof(dataA->cFileName) );
file_name_WtoA( dataW.cAlternateFileName, -1, dataA->cAlternateFileName,
sizeof(dataA->cAlternateFileName) );
return handle;
}
/******************************************************************************
* FindFirstFileExW (kernelbase.@)
*/
HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
LPVOID data, FINDEX_SEARCH_OPS search_op,
LPVOID filter, DWORD flags )
{
WCHAR *mask;
BOOL has_wildcard = FALSE;
FIND_FIRST_INFO *info = NULL;
UNICODE_STRING nt_name;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
NTSTATUS status;
DWORD size, device = 0;
TRACE( "%s %d %p %d %p %x\n", debugstr_w(filename), level, data, search_op, filter, flags );
if (flags & ~FIND_FIRST_EX_LARGE_FETCH)
{
FIXME("flags not implemented 0x%08x\n", flags );
}
if (search_op != FindExSearchNameMatch && search_op != FindExSearchLimitToDirectories)
{
FIXME( "search_op not implemented 0x%08x\n", search_op );
SetLastError( ERROR_INVALID_PARAMETER );
return INVALID_HANDLE_VALUE;
}
if (level != FindExInfoStandard && level != FindExInfoBasic)
{
FIXME("info level %d not implemented\n", level );
SetLastError( ERROR_INVALID_PARAMETER );
return INVALID_HANDLE_VALUE;
}
if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, &mask, NULL ))
{
SetLastError( ERROR_PATH_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
if (!mask && (device = RtlIsDosDeviceName_U( filename )))
{
static const WCHAR dotW[] = {'.',0};
WCHAR *dir = NULL;
/* we still need to check that the directory can be opened */
if (HIWORD(device))
{
if (!(dir = HeapAlloc( GetProcessHeap(), 0, HIWORD(device) + sizeof(WCHAR) )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
}
memcpy( dir, filename, HIWORD(device) );
dir[HIWORD(device)/sizeof(WCHAR)] = 0;
}
RtlFreeUnicodeString( &nt_name );
if (!RtlDosPathNameToNtPathName_U( dir ? dir : dotW, &nt_name, &mask, NULL ))
{
HeapFree( GetProcessHeap(), 0, dir );
SetLastError( ERROR_PATH_NOT_FOUND );
goto error;
}
HeapFree( GetProcessHeap(), 0, dir );
size = 0;
}
else if (!mask || !*mask)
{
SetLastError( ERROR_FILE_NOT_FOUND );
goto error;
}
else
{
nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR);
has_wildcard = wcspbrk( mask, L"*?" ) != NULL;
size = has_wildcard ? 8192 : max_entry_size;
}
if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size] ))))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
}
/* check if path is the root of the drive, skipping the \??\ prefix */
info->is_root = FALSE;
if (nt_name.Length >= 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':')
{
DWORD pos = 6;
while (pos * sizeof(WCHAR) < nt_name.Length && nt_name.Buffer[pos] == '\\') pos++;
info->is_root = (pos * sizeof(WCHAR) >= nt_name.Length);
}
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE;
attr.ObjectName = &nt_name;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
status = NtOpenFile( &info->handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
if (status != STATUS_SUCCESS)
{
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
SetLastError( ERROR_PATH_NOT_FOUND );
else
SetLastError( RtlNtStatusToDosError(status) );
goto error;
}
RtlInitializeCriticalSection( &info->cs );
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 (device)
{
WIN32_FIND_DATAW *wfd = data;
memset( wfd, 0, sizeof(*wfd) );
memcpy( wfd->cFileName, filename + HIWORD(device)/sizeof(WCHAR), LOWORD(device) );
wfd->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
CloseHandle( info->handle );
info->handle = 0;
}
else
{
UNICODE_STRING mask_str;
RtlInitUnicodeString( &mask_str, mask );
status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
FileBothDirectoryInformation, FALSE, &mask_str, TRUE );
if (status)
{
FindClose( info );
SetLastError( RtlNtStatusToDosError( status ) );
return INVALID_HANDLE_VALUE;
}
info->data_len = io.Information;
if (!has_wildcard) info->data_size = 0; /* we read everything */
if (!FindNextFileW( info, data ))
{
TRACE( "%s not found\n", debugstr_w(filename) );
FindClose( info );
SetLastError( ERROR_FILE_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
if (!has_wildcard) /* we can't find two files with the same name */
{
CloseHandle( info->handle );
info->handle = 0;
}
}
return info;
error:
HeapFree( GetProcessHeap(), 0, info );
RtlFreeUnicodeString( &nt_name );
return INVALID_HANDLE_VALUE;
}
/******************************************************************************
* FindFirstFileA (kernelbase.@)
*/
HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileA( const char *filename, WIN32_FIND_DATAA *data )
{
return FindFirstFileExA( filename, FindExInfoStandard, data, FindExSearchNameMatch, NULL, 0 );
}
/******************************************************************************
* FindFirstFileW (kernelbase.@)
*/
HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileW( const WCHAR *filename, WIN32_FIND_DATAW *data )
{
return FindFirstFileExW( filename, FindExInfoStandard, data, FindExSearchNameMatch, NULL, 0 );
}
/******************************************************************************
* FindNextFileA (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
{
WIN32_FIND_DATAW dataW;
if (!FindNextFileW( handle, &dataW )) return FALSE;
data->dwFileAttributes = dataW.dwFileAttributes;
data->ftCreationTime = dataW.ftCreationTime;
data->ftLastAccessTime = dataW.ftLastAccessTime;
data->ftLastWriteTime = dataW.ftLastWriteTime;
data->nFileSizeHigh = dataW.nFileSizeHigh;
data->nFileSizeLow = dataW.nFileSizeLow;
file_name_WtoA( dataW.cFileName, -1, data->cFileName, sizeof(data->cFileName) );
file_name_WtoA( dataW.cAlternateFileName, -1, data->cAlternateFileName,
sizeof(data->cAlternateFileName) );
return TRUE;
}
/******************************************************************************
* FindNextFileW (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
{
FIND_FIRST_INFO *info = handle;
FILE_BOTH_DIR_INFORMATION *dir_info;
BOOL ret = FALSE;
NTSTATUS status;
TRACE( "%p %p\n", handle, data );
if (!handle || handle == INVALID_HANDLE_VALUE || info->magic != FIND_FIRST_MAGIC)
{
SetLastError( ERROR_INVALID_HANDLE );
return ret;
}
RtlEnterCriticalSection( &info->cs );
if (!info->handle) SetLastError( ERROR_NO_MORE_FILES );
else for (;;)
{
if (info->data_pos >= info->data_len) /* need to read some more data */
{
IO_STATUS_BLOCK io;
if (info->data_size)
status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
FileBothDirectoryInformation, FALSE, NULL, FALSE );
else
status = STATUS_NO_MORE_FILES;
if (!set_ntstatus( status ))
{
if (status == STATUS_NO_MORE_FILES)
{
CloseHandle( info->handle );
info->handle = 0;
}
break;
}
info->data_len = io.Information;
info->data_pos = 0;
}
dir_info = (FILE_BOTH_DIR_INFORMATION *)(info->data + info->data_pos);
if (dir_info->NextEntryOffset) info->data_pos += dir_info->NextEntryOffset;
else info->data_pos = info->data_len;
/* don't return '.' and '..' in the root of the drive */
if (info->is_root)
{
if (dir_info->FileNameLength == sizeof(WCHAR) && dir_info->FileName[0] == '.') continue;
if (dir_info->FileNameLength == 2 * sizeof(WCHAR) &&
dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue;
}
data->dwFileAttributes = dir_info->FileAttributes;
data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime;
data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime;
data->ftLastWriteTime = *(FILETIME *)&dir_info->LastWriteTime;
data->nFileSizeHigh = dir_info->EndOfFile.QuadPart >> 32;
data->nFileSizeLow = (DWORD)dir_info->EndOfFile.QuadPart;
data->dwReserved0 = 0;
data->dwReserved1 = 0;
memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
if (info->level != FindExInfoBasic)
{
memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 0;
}
else
data->cAlternateFileName[0] = 0;
TRACE( "returning %s (%s)\n",
debugstr_w(data->cFileName), debugstr_w(data->cAlternateFileName) );
ret = TRUE;
break;
}
RtlLeaveCriticalSection( &info->cs );
return ret;
}
/******************************************************************************
* FindClose (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH FindClose( HANDLE handle )
{
FIND_FIRST_INFO *info = handle;
if (!handle || handle == INVALID_HANDLE_VALUE)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__TRY
{
if (info->magic == FIND_FIRST_MAGIC)
{
RtlEnterCriticalSection( &info->cs );
if (info->magic == FIND_FIRST_MAGIC) /* in case someone else freed it in the meantime */
{
info->magic = 0;
if (info->handle) CloseHandle( info->handle );
info->handle = 0;
RtlFreeUnicodeString( &info->path );
info->data_pos = 0;
info->data_len = 0;
RtlLeaveCriticalSection( &info->cs );
info->cs.DebugInfo->Spare[0] = 0;
RtlDeleteCriticalSection( &info->cs );
HeapFree( GetProcessHeap(), 0, info );
}
}
}
__EXCEPT_PAGE_FAULT
{
WARN( "illegal handle %p\n", handle );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__ENDTRY
return TRUE;
}
/******************************************************************************
* GetCompressedFileSizeA (kernelbase.@)
*/

View File

@ -350,24 +350,24 @@
@ stdcall FillConsoleOutputCharacterW(long long long long ptr)
@ stdcall FindActCtxSectionGuid(long ptr long ptr ptr)
@ stdcall FindActCtxSectionStringW(long ptr long wstr ptr)
@ stdcall FindClose(long) kernel32.FindClose
@ stdcall FindClose(long)
@ stdcall FindCloseChangeNotification(long)
@ stdcall FindFirstChangeNotificationA(str long long)
@ stdcall FindFirstChangeNotificationW(wstr long long)
@ stdcall FindFirstFileA(str ptr) kernel32.FindFirstFileA
@ stdcall FindFirstFileExA(str long ptr long ptr long) kernel32.FindFirstFileExA
@ stdcall FindFirstFileExW(wstr long ptr long ptr long) kernel32.FindFirstFileExW
@ stdcall FindFirstFileA(str ptr)
@ stdcall FindFirstFileExA(str long ptr long ptr long)
@ stdcall FindFirstFileExW(wstr long ptr long ptr long)
# @ stub FindFirstFileNameW
@ stdcall FindFirstFileW(wstr ptr) kernel32.FindFirstFileW
@ stdcall FindFirstFileW(wstr ptr)
@ stdcall FindFirstFreeAce(ptr ptr)
@ stdcall FindFirstStreamW(wstr long ptr long) kernel32.FindFirstStreamW
@ stdcall FindFirstVolumeW(ptr long) kernel32.FindFirstVolumeW
@ stdcall FindNLSString(long long wstr long wstr long ptr)
@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long)
@ stdcall FindNextChangeNotification(long)
@ stdcall FindNextFileA(long ptr) kernel32.FindNextFileA
@ stdcall FindNextFileA(long ptr)
# @ stub FindNextFileNameW
@ stdcall FindNextFileW(long ptr) kernel32.FindNextFileW
@ stdcall FindNextFileW(long ptr)
@ stdcall FindNextStreamW(long ptr) kernel32.FindNextStreamW
@ stdcall FindNextVolumeW(long ptr long) kernel32.FindNextVolumeW
# @ stub FindPackagesByPackageFamily