Reimplemented FindFirstFile/FindNextFile on top of

NtQueryDirectoryFile.
This commit is contained in:
Alexandre Julliard 2004-03-17 20:57:09 +00:00
parent f5e1c13070
commit 8f032165c4
3 changed files with 317 additions and 498 deletions

View file

@ -40,6 +40,8 @@
#include "wine/winbase16.h"
#include "kernel_private.h"
#include "wine/exception.h"
#include "excpt.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "async.h"
@ -48,6 +50,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(file);
HANDLE dos_handles[DOS_TABLE_SIZE];
/* info structure for FindFirstFile handle */
typedef struct
{
HANDLE handle; /* handle to directory */
CRITICAL_SECTION cs; /* crit section protecting this structure */
UNICODE_STRING mask; /* file mask */
BOOL is_root; /* is directory the root of the drive? */
UINT data_pos; /* current position in dir data */
UINT data_len; /* length of dir data */
BYTE data[8192]; /* directory data */
} FIND_FIRST_INFO;
static WINE_EXCEPTION_FILTER(page_fault)
{
if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_EXECUTE_HANDLER;
return EXCEPTION_CONTINUE_SEARCH;
}
/**************************************************************************
* Operations on file handles *
**************************************************************************/
@ -557,3 +579,296 @@ BOOL WINAPI ReplaceFileA(LPCSTR lpReplacedFileName,LPCSTR lpReplacementFileName,
SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
return FALSE;
}
/*************************************************************************
* FindFirstFileExW (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
LPVOID data, FINDEX_SEARCH_OPS search_op,
LPVOID filter, DWORD flags)
{
WCHAR buffer[MAX_PATH];
WCHAR *mask, *tmp = buffer;
FIND_FIRST_INFO *info = NULL;
DWORD size;
if ((search_op != FindExSearchNameMatch) || (flags != 0))
{
FIXME("options not implemented 0x%08x 0x%08lx\n", search_op, flags );
return INVALID_HANDLE_VALUE;
}
if (level != FindExInfoStandard)
{
FIXME("info level %d not implemented\n", level );
return INVALID_HANDLE_VALUE;
}
size = RtlGetFullPathName_U( filename, sizeof(buffer), buffer, &mask );
if (!size)
{
SetLastError( ERROR_PATH_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
if (size > sizeof(buffer))
{
tmp = HeapAlloc( GetProcessHeap(), 0, size );
if (!tmp)
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return INVALID_HANDLE_VALUE;
}
size = RtlGetFullPathName_U( filename, size, tmp, &mask );
}
if (!mask || !*mask)
{
SetLastError( ERROR_FILE_NOT_FOUND );
goto error;
}
if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info))))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
}
if (!RtlCreateUnicodeString( &info->mask, mask ))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
goto error;
}
*mask = 0;
/* check if path is the root of the drive */
info->is_root = FALSE;
if (tmp[0] && tmp[1] == ':')
{
WCHAR *p = tmp + 2;
while (*p == '\\') p++;
info->is_root = (*p == 0);
}
info->handle = CreateFileW( tmp, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
if (info->handle == INVALID_HANDLE_VALUE)
{
RtlFreeUnicodeString( &info->mask );
goto error;
}
RtlInitializeCriticalSection( &info->cs );
info->data_pos = 0;
info->data_len = 0;
if (tmp != buffer) HeapFree( GetProcessHeap(), 0, tmp );
if (!FindNextFileW( (HANDLE)info, data ))
{
TRACE( "%s not found\n", debugstr_w(filename) );
FindClose( (HANDLE)info );
SetLastError( ERROR_FILE_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
return (HANDLE)info;
error:
if (tmp != buffer) HeapFree( GetProcessHeap(), 0, tmp );
if (info) HeapFree( GetProcessHeap(), 0, info );
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;
if (handle == INVALID_HANDLE_VALUE)
{
SetLastError( ERROR_INVALID_HANDLE );
return ret;
}
info = (FIND_FIRST_INFO *)handle;
RtlEnterCriticalSection( &info->cs );
for (;;)
{
if (info->data_pos >= info->data_len) /* need to read some more data */
{
IO_STATUS_BLOCK io;
NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
if (io.u.Status)
{
SetLastError( RtlNtStatusToDosError( io.u.Status ) );
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;
memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
data->cAlternateFileName[dir_info->ShortNameLength/sizeof(WCHAR)] = 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 FindClose( HANDLE handle )
{
FIND_FIRST_INFO *info = (FIND_FIRST_INFO *)handle;
if (!handle || handle == INVALID_HANDLE_VALUE) goto error;
__TRY
{
RtlEnterCriticalSection( &info->cs );
if (info->handle) CloseHandle( info->handle );
info->handle = 0;
RtlFreeUnicodeString( &info->mask );
info->mask.Buffer = NULL;
info->data_pos = 0;
info->data_len = 0;
}
__EXCEPT(page_fault)
{
WARN("Illegal handle %p\n", handle);
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__ENDTRY
RtlLeaveCriticalSection( &info->cs );
RtlDeleteCriticalSection( &info->cs );
HeapFree(GetProcessHeap(), 0, info);
return TRUE;
error:
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/*************************************************************************
* 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;
UNICODE_STRING pathW;
if (!lpFileName)
{
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
RtlFreeUnicodeString(&pathW);
if (handle == INVALID_HANDLE_VALUE) return handle;
dataA = (WIN32_FIND_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;
WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
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;
WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
data->cFileName, sizeof(data->cFileName), NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
data->cAlternateFileName,
sizeof(data->cAlternateFileName), NULL, NULL );
return TRUE;
}

View file

@ -270,9 +270,8 @@ static void test__lcreat( void )
} else { /* only NT succeeds */
_lclose(filehandle);
find=FindFirstFileA (slashname, &search_results);
if (INVALID_HANDLE_VALUE==find)
ok (0, "file \"%s\" not found\n", slashname);
else {
if (INVALID_HANDLE_VALUE!=find)
{
ok (0!=FindClose (find), "FindClose complains (%ld)\n", GetLastError ());
slashname[strlen(slashname)-1]=0;
ok (!strcmp (slashname, search_results.cFileName),

View file

@ -92,8 +92,6 @@ typedef struct
#undef VFAT_IOCTL_READDIR_BOTH /* just in case... */
#endif /* linux */
#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
/* Chars we don't want to see in DOS file names */
#define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345"
@ -147,29 +145,6 @@ typedef struct
WCHAR names[1];
} DOS_DIR;
/* Info structure for FindFirstFile handle */
typedef struct
{
char *path; /* unix path */
LPWSTR long_mask;
int drive;
int cur_pos;
CRITICAL_SECTION cs;
union
{
DOS_DIR *dos_dir;
SMB_DIR *smb_dir;
} u;
} FIND_FIRST_INFO;
static WINE_EXCEPTION_FILTER(page_fault)
{
if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_EXECUTE_HANDLER;
return EXCEPTION_CONTINUE_SEARCH;
}
/* return non-zero if c is the end of a directory name */
static inline int is_end_of_name(WCHAR c)
@ -345,97 +320,6 @@ static void DOSFS_ToDosDTAFormat( LPCWSTR name, LPWSTR buffer )
}
/***********************************************************************
* DOSFS_MatchLong
*
* Check a long file name against a mask.
*
* 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 int DOSFS_MatchLong( LPCWSTR mask, LPCWSTR name )
{
LPCWSTR lastjoker = NULL;
LPCWSTR next_to_retry = NULL;
static const WCHAR asterisk_dot_asterisk[] = {'*','.','*',0};
TRACE("(%s, %s)\n", debugstr_w(mask), debugstr_w(name));
if (!strcmpW( mask, asterisk_dot_asterisk )) return 1;
while (*name && *mask)
{
if (*mask == '*')
{
mask++;
while (*mask == '*') mask++; /* Skip consecutive '*' */
lastjoker = mask;
if (!*mask) return 1; /* end of mask is all '*', so match */
/* skip to the next match after the joker(s) */
if (is_case_sensitive) while (*name && (*name != *mask)) name++;
else while (*name && (toupperW(*name) != toupperW(*mask))) name++;
if (!*name) break;
next_to_retry = name;
}
else if (*mask != '?')
{
int mismatch = 0;
if (is_case_sensitive)
{
if (*mask != *name) mismatch = 1;
}
else
{
if (toupperW(*mask) != toupperW(*name)) mismatch = 1;
}
if (!mismatch)
{
mask++;
name++;
if (*mask == '\0')
{
if (*name == '\0')
return 1;
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 0; /* bad luck */
}
}
else /* '?' */
{
mask++;
name++;
}
}
while ((*mask == '.') || (*mask == '*'))
mask++; /* Ignore trailing '.' or '*' in mask */
return (!*name && !*mask);
}
/***********************************************************************
* DOSFS_AddDirEntry
*
@ -1146,385 +1030,6 @@ BOOL WINAPI wine_get_unix_file_name( LPCWSTR dosW, LPSTR buffer, DWORD len )
}
/***********************************************************************
* get_show_dir_symlinks_option
*/
static BOOL get_show_dir_symlinks_option(void)
{
static const WCHAR WineW[] = {'M','a','c','h','i','n','e','\\',
'S','o','f','t','w','a','r','e','\\',
'W','i','n','e','\\','W','i','n','e','\\',
'C','o','n','f','i','g','\\','W','i','n','e',0};
static const WCHAR ShowDirSymlinksW[] = {'S','h','o','w','D','i','r','S','y','m','l','i','n','k','s',0};
char tmp[80];
HKEY hkey;
DWORD dummy;
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW;
BOOL ret = FALSE;
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.ObjectName = &nameW;
attr.Attributes = 0;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
RtlInitUnicodeString( &nameW, WineW );
if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
{
RtlInitUnicodeString( &nameW, ShowDirSymlinksW );
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
{
WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
ret = IS_OPTION_TRUE( str[0] );
}
NtClose( hkey );
}
return ret;
}
/***********************************************************************
* DOSFS_FindNextEx
*/
static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAW *entry )
{
char *p, buffer[MAX_PATHNAME_LEN];
const char *drive_path;
int drive_root;
LPCWSTR long_name, short_name;
BY_HANDLE_FILE_INFORMATION fileinfo;
BOOL is_symlink;
drive_path = info->path + strlen(DRIVE_GetRoot( info->drive ));
while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++;
drive_root = !*drive_path;
lstrcpynA( buffer, info->path, sizeof(buffer) - 1 );
strcat( buffer, "/" );
p = buffer + strlen(buffer);
while (DOSFS_ReadDir( info->u.dos_dir, &long_name, &short_name ))
{
info->cur_pos++;
/* Don't return '.' and '..' in the root of the drive */
if (drive_root && (long_name[0] == '.') &&
(!long_name[1] || ((long_name[1] == '.') && !long_name[2])))
continue;
/* Check the long mask */
if (info->long_mask && *info->long_mask)
{
if (!DOSFS_MatchLong( info->long_mask, long_name )) continue;
}
/* Check the file attributes */
WideCharToMultiByte(CP_UNIXCP, 0, long_name, -1,
p, sizeof(buffer) - (int)(p - buffer), NULL, NULL);
if (!FILE_Stat( buffer, &fileinfo, &is_symlink ))
{
WARN("can't stat %s\n", buffer);
continue;
}
if (is_symlink && (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
static int show_dir_symlinks = -1;
if (show_dir_symlinks == -1)
show_dir_symlinks = get_show_dir_symlinks_option();
if (!show_dir_symlinks) continue;
}
/* We now have a matching entry; fill the result and return */
entry->dwFileAttributes = fileinfo.dwFileAttributes;
entry->ftCreationTime = fileinfo.ftCreationTime;
entry->ftLastAccessTime = fileinfo.ftLastAccessTime;
entry->ftLastWriteTime = fileinfo.ftLastWriteTime;
entry->nFileSizeHigh = fileinfo.nFileSizeHigh;
entry->nFileSizeLow = fileinfo.nFileSizeLow;
if (short_name)
DOSFS_ToDosDTAFormat( short_name, entry->cAlternateFileName );
else
DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE );
lstrcpynW( entry->cFileName, long_name, sizeof(entry->cFileName)/sizeof(entry->cFileName[0]) );
TRACE("returning %s (%s) %02lx %ld\n",
debugstr_w(entry->cFileName), debugstr_w(entry->cAlternateFileName),
entry->dwFileAttributes, entry->nFileSizeLow );
return 1;
}
return 0; /* End of directory */
}
/*************************************************************************
* FindFirstFileExW (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileExW(
LPCWSTR lpFileName,
FINDEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFindFileData,
FINDEX_SEARCH_OPS fSearchOp,
LPVOID lpSearchFilter,
DWORD dwAdditionalFlags)
{
FIND_FIRST_INFO *info;
if (!lpFileName)
{
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0))
{
FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags );
return INVALID_HANDLE_VALUE;
}
switch(fInfoLevelId)
{
case FindExInfoStandard:
{
WIN32_FIND_DATAW * data = (WIN32_FIND_DATAW *) lpFindFileData;
char *p;
INT long_mask_len;
data->dwReserved0 = data->dwReserved1 = 0x0;
if (lpFileName[0] == '\\' && lpFileName[1] == '\\')
{
ERR("UNC path name\n");
if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(FIND_FIRST_INFO)))) break;
info->u.smb_dir = SMB_FindFirst(lpFileName);
if(!info->u.smb_dir)
{
HeapFree(GetProcessHeap(), 0, info);
break;
}
info->drive = -1;
RtlInitializeCriticalSection( &info->cs );
}
else
{
DOS_FULL_NAME full_name;
if (lpFileName[0] && lpFileName[1] == ':')
{
/* don't allow root directories */
if (!lpFileName[2] ||
((lpFileName[2] == '/' || lpFileName[2] == '\\') && !lpFileName[3]))
{
SetLastError(ERROR_FILE_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
}
if (!DOSFS_GetFullName( lpFileName, FALSE, &full_name )) break;
if (!(info = HeapAlloc( GetProcessHeap(), 0, sizeof(FIND_FIRST_INFO)))) break;
RtlInitializeCriticalSection( &info->cs );
info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
strcpy( info->path, full_name.long_name );
p = strrchr( info->path, '/' );
*p++ = '\0';
long_mask_len = MultiByteToWideChar(CP_UNIXCP, 0, p, -1, NULL, 0);
info->long_mask = HeapAlloc( GetProcessHeap(), 0, long_mask_len * sizeof(WCHAR) );
MultiByteToWideChar(CP_UNIXCP, 0, p, -1, info->long_mask, long_mask_len);
info->drive = full_name.drive;
info->cur_pos = 0;
info->u.dos_dir = DOSFS_OpenDir( info->path );
}
if (!FindNextFileW( (HANDLE) info, data ))
{
FindClose( (HANDLE) info );
SetLastError( ERROR_FILE_NOT_FOUND );
break;
}
return (HANDLE) info;
}
break;
default:
FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId );
}
return INVALID_HANDLE_VALUE;
}
/*************************************************************************
* 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;
UNICODE_STRING pathW;
if (!lpFileName)
{
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
if (!RtlCreateUnicodeStringFromAsciiz(&pathW, lpFileName))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
handle = FindFirstFileExW(pathW.Buffer, fInfoLevelId, &dataW, fSearchOp, lpSearchFilter, dwAdditionalFlags);
RtlFreeUnicodeString(&pathW);
if (handle == INVALID_HANDLE_VALUE) return handle;
dataA = (WIN32_FIND_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;
WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
dataA->cFileName, sizeof(dataA->cFileName), NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
dataA->cAlternateFileName, sizeof(dataA->cAlternateFileName), NULL, NULL );
return handle;
}
/*************************************************************************
* FindFirstFileW (KERNEL32.@)
*/
HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData )
{
return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData,
FindExSearchNameMatch, NULL, 0);
}
/*************************************************************************
* FindNextFileW (KERNEL32.@)
*/
BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
{
FIND_FIRST_INFO *info;
BOOL ret = FALSE;
DWORD gle = ERROR_NO_MORE_FILES;
if (handle == INVALID_HANDLE_VALUE)
{
SetLastError( ERROR_INVALID_HANDLE );
return ret;
}
info = (FIND_FIRST_INFO*) handle;
RtlEnterCriticalSection( &info->cs );
if (info->drive == -1)
{
ret = SMB_FindNext( info->u.smb_dir, data );
if(!ret)
{
SMB_CloseDir( info->u.smb_dir );
HeapFree( GetProcessHeap(), 0, info->path );
}
goto done;
}
else if (!info->path || !info->u.dos_dir)
{
goto done;
}
else if (!DOSFS_FindNextEx( info, data ))
{
DOSFS_CloseDir( info->u.dos_dir ); info->u.dos_dir = NULL;
HeapFree( GetProcessHeap(), 0, info->path );
info->path = NULL;
HeapFree( GetProcessHeap(), 0, info->long_mask );
info->long_mask = NULL;
goto done;
}
ret = TRUE;
done:
RtlLeaveCriticalSection( &info->cs );
if( !ret ) SetLastError( gle );
return ret;
}
/*************************************************************************
* 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;
WideCharToMultiByte( CP_ACP, 0, dataW.cFileName, -1,
data->cFileName, sizeof(data->cFileName), NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, dataW.cAlternateFileName, -1,
data->cAlternateFileName,
sizeof(data->cAlternateFileName), NULL, NULL );
return TRUE;
}
/*************************************************************************
* FindClose (KERNEL32.@)
*/
BOOL WINAPI FindClose( HANDLE handle )
{
FIND_FIRST_INFO *info = (FIND_FIRST_INFO*) handle;
if (handle == INVALID_HANDLE_VALUE) goto error;
__TRY
{
RtlEnterCriticalSection( &info->cs );
if (info)
{
if (info->u.dos_dir) DOSFS_CloseDir( info->u.dos_dir );
if (info->path) HeapFree( GetProcessHeap(), 0, info->path );
if (info->long_mask) HeapFree( GetProcessHeap(), 0, info->long_mask );
}
}
__EXCEPT(page_fault)
{
WARN("Illegal handle %p\n", handle);
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__ENDTRY
if (!info) goto error;
RtlLeaveCriticalSection( &info->cs );
RtlDeleteCriticalSection( &info->cs );
HeapFree(GetProcessHeap(), 0, info);
return TRUE;
error:
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/***********************************************************************
* MulDiv (KERNEL32.@)
* RETURNS