kernel32: Move FindFirst/NextFile functions to kernelbase.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
6731f33d40
commit
9b0877db4a
|
@ -50,28 +50,6 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(file);
|
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};
|
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
|
* 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.@)
|
* FindFirstStreamW (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -475,18 +475,18 @@
|
||||||
@ stdcall -import FindActCtxSectionStringW(long ptr long wstr ptr)
|
@ stdcall -import FindActCtxSectionStringW(long ptr long wstr ptr)
|
||||||
@ stdcall FindAtomA(str)
|
@ stdcall FindAtomA(str)
|
||||||
@ stdcall FindAtomW(wstr)
|
@ stdcall FindAtomW(wstr)
|
||||||
@ stdcall FindClose(long)
|
@ stdcall -import FindClose(long)
|
||||||
@ stdcall -import FindCloseChangeNotification(long)
|
@ stdcall -import FindCloseChangeNotification(long)
|
||||||
@ stdcall -import FindFirstChangeNotificationA(str long long)
|
@ stdcall -import FindFirstChangeNotificationA(str long long)
|
||||||
@ stdcall -import FindFirstChangeNotificationW(wstr long long)
|
@ stdcall -import FindFirstChangeNotificationW(wstr long long)
|
||||||
@ stdcall FindFirstFileA(str ptr)
|
@ stdcall -import FindFirstFileA(str ptr)
|
||||||
@ stdcall FindFirstFileExA(str long ptr long ptr long)
|
@ stdcall -import FindFirstFileExA(str long ptr long ptr long)
|
||||||
@ stdcall FindFirstFileExW(wstr long ptr long ptr long)
|
@ stdcall -import FindFirstFileExW(wstr long ptr long ptr long)
|
||||||
# @ stub FindFirstFileNameTransactedW
|
# @ stub FindFirstFileNameTransactedW
|
||||||
# @ stub FindFirstFileNameW
|
# @ stub FindFirstFileNameW
|
||||||
# @ stub FindFirstFileTransactedA
|
# @ stub FindFirstFileTransactedA
|
||||||
# @ stub FindFirstFileTransactedW
|
# @ stub FindFirstFileTransactedW
|
||||||
@ stdcall FindFirstFileW(wstr ptr)
|
@ stdcall -import FindFirstFileW(wstr ptr)
|
||||||
# @ stub FindFirstStreamTransactedW
|
# @ stub FindFirstStreamTransactedW
|
||||||
@ stdcall FindFirstStreamW(wstr long ptr long)
|
@ stdcall FindFirstStreamW(wstr long ptr long)
|
||||||
@ stdcall FindFirstVolumeA(ptr long)
|
@ stdcall FindFirstVolumeA(ptr long)
|
||||||
|
@ -494,9 +494,9 @@
|
||||||
@ stdcall FindFirstVolumeMountPointW(wstr ptr long)
|
@ stdcall FindFirstVolumeMountPointW(wstr ptr long)
|
||||||
@ stdcall FindFirstVolumeW(ptr long)
|
@ stdcall FindFirstVolumeW(ptr long)
|
||||||
@ stdcall -import FindNextChangeNotification(long)
|
@ stdcall -import FindNextChangeNotification(long)
|
||||||
@ stdcall FindNextFileA(long ptr)
|
@ stdcall -import FindNextFileA(long ptr)
|
||||||
# @ stub FindNextFileNameW
|
# @ stub FindNextFileNameW
|
||||||
@ stdcall FindNextFileW(long ptr)
|
@ stdcall -import FindNextFileW(long ptr)
|
||||||
@ stdcall FindNextStreamW(long ptr)
|
@ stdcall FindNextStreamW(long ptr)
|
||||||
@ stdcall FindNextVolumeA(long ptr long)
|
@ stdcall FindNextVolumeA(long ptr long)
|
||||||
@ stub FindNextVolumeMountPointA
|
@ stub FindNextVolumeMountPointA
|
||||||
|
|
|
@ -43,6 +43,27 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(file);
|
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 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};
|
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.@)
|
* GetCompressedFileSizeA (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -350,24 +350,24 @@
|
||||||
@ stdcall FillConsoleOutputCharacterW(long long long long ptr)
|
@ stdcall FillConsoleOutputCharacterW(long long long long ptr)
|
||||||
@ stdcall FindActCtxSectionGuid(long ptr long ptr ptr)
|
@ stdcall FindActCtxSectionGuid(long ptr long ptr ptr)
|
||||||
@ stdcall FindActCtxSectionStringW(long ptr long wstr ptr)
|
@ stdcall FindActCtxSectionStringW(long ptr long wstr ptr)
|
||||||
@ stdcall FindClose(long) kernel32.FindClose
|
@ stdcall FindClose(long)
|
||||||
@ stdcall FindCloseChangeNotification(long)
|
@ stdcall FindCloseChangeNotification(long)
|
||||||
@ stdcall FindFirstChangeNotificationA(str long long)
|
@ stdcall FindFirstChangeNotificationA(str long long)
|
||||||
@ stdcall FindFirstChangeNotificationW(wstr long long)
|
@ stdcall FindFirstChangeNotificationW(wstr long long)
|
||||||
@ stdcall FindFirstFileA(str ptr) kernel32.FindFirstFileA
|
@ stdcall FindFirstFileA(str ptr)
|
||||||
@ stdcall FindFirstFileExA(str long ptr long ptr long) kernel32.FindFirstFileExA
|
@ stdcall FindFirstFileExA(str long ptr long ptr long)
|
||||||
@ stdcall FindFirstFileExW(wstr long ptr long ptr long) kernel32.FindFirstFileExW
|
@ stdcall FindFirstFileExW(wstr long ptr long ptr long)
|
||||||
# @ stub FindFirstFileNameW
|
# @ stub FindFirstFileNameW
|
||||||
@ stdcall FindFirstFileW(wstr ptr) kernel32.FindFirstFileW
|
@ stdcall FindFirstFileW(wstr ptr)
|
||||||
@ stdcall FindFirstFreeAce(ptr ptr)
|
@ stdcall FindFirstFreeAce(ptr ptr)
|
||||||
@ stdcall FindFirstStreamW(wstr long ptr long) kernel32.FindFirstStreamW
|
@ stdcall FindFirstStreamW(wstr long ptr long) kernel32.FindFirstStreamW
|
||||||
@ stdcall FindFirstVolumeW(ptr long) kernel32.FindFirstVolumeW
|
@ stdcall FindFirstVolumeW(ptr long) kernel32.FindFirstVolumeW
|
||||||
@ stdcall FindNLSString(long long wstr long wstr long ptr)
|
@ stdcall FindNLSString(long long wstr long wstr long ptr)
|
||||||
@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long)
|
@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long)
|
||||||
@ stdcall FindNextChangeNotification(long)
|
@ stdcall FindNextChangeNotification(long)
|
||||||
@ stdcall FindNextFileA(long ptr) kernel32.FindNextFileA
|
@ stdcall FindNextFileA(long ptr)
|
||||||
# @ stub FindNextFileNameW
|
# @ stub FindNextFileNameW
|
||||||
@ stdcall FindNextFileW(long ptr) kernel32.FindNextFileW
|
@ stdcall FindNextFileW(long ptr)
|
||||||
@ stdcall FindNextStreamW(long ptr) kernel32.FindNextStreamW
|
@ stdcall FindNextStreamW(long ptr) kernel32.FindNextStreamW
|
||||||
@ stdcall FindNextVolumeW(long ptr long) kernel32.FindNextVolumeW
|
@ stdcall FindNextVolumeW(long ptr long) kernel32.FindNextVolumeW
|
||||||
# @ stub FindPackagesByPackageFamily
|
# @ stub FindPackagesByPackageFamily
|
||||||
|
|
Loading…
Reference in New Issue