Reimplemented FindFirstFile/FindNextFile on top of
NtQueryDirectoryFile.
This commit is contained in:
parent
f5e1c13070
commit
8f032165c4
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
495
files/dos_fs.c
495
files/dos_fs.c
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue