Author: hbelusca Date: Thu Sep 27 22:07:06 2012 New Revision: 57407
URL: http://svn.reactos.org/svn/reactos?rev=57407&view=rev Log: [KERNEL32] - Reworking the Find* APIs in kernel32. Fixes some kernel32_winetest:file failures. - The FindExInfoBasic information level for FindFirstFileEx, is also implemented. - Update ndk and psdk headers regarding to this work.
CORE-6623 #comment Committed in rev.57407. #resolve
Modified: trunk/reactos/dll/win32/kernel32/client/file/find.c trunk/reactos/include/ndk/iotypes.h trunk/reactos/include/psdk/winbase.h
Modified: trunk/reactos/dll/win32/kernel32/client/file/find.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/f... ============================================================================== --- trunk/reactos/dll/win32/kernel32/client/file/find.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/client/file/find.c [iso-8859-1] Thu Sep 27 22:07:06 2012 @@ -1,452 +1,256 @@ -/* $Id: find.c 53068 2011-08-04 22:18:01Z ion $ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries - * FILE: lib/kernel32/file/find.c + * FILE: dll/win32/kernel32/client/file/find.c * PURPOSE: Find functions - * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) + * PROGRAMMERS: Ariadne (ariadne@xs4all.nl) * Pierre Schweitzer (pierre.schweitzer@reactos.org) - * UPDATE HISTORY: - * Created 01/11/98 + * Hermes BELUSCA - MAITO (hermes.belusca@sfr.fr) */
-/* INCLUDES *****************************************************************/ +/* INCLUDES *******************************************************************/
#include <k32.h> #define NDEBUG #include <debug.h> DEBUG_CHANNEL(kernel32file);
-/* TYPES ********************************************************************/ - -#define FIND_DATA_SIZE 0x4000 - -#define FIND_DEVICE_HANDLE ((HANDLE)0x1) - -typedef struct _KERNEL32_FIND_FILE_DATA -{ - HANDLE DirectoryHandle; - RTL_CRITICAL_SECTION Lock; - PFILE_BOTH_DIR_INFORMATION pFileInfo; - BOOLEAN DirectoryOnly; - BOOLEAN HasMoreData; - BOOLEAN HasData; - BOOLEAN LockInitialized; -} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA; - -typedef struct _KERNEL32_FIND_STREAM_DATA + +/* TYPES **********************************************************************/ + +#define FIND_DATA_SIZE 0x4000 +#define FIND_DEVICE_HANDLE ((HANDLE)0x1) + +typedef enum _FIND_DATA_TYPE +{ + FindFile = 1, + FindStream = 2 +} FIND_DATA_TYPE; + +/* + * FILE_FULL_DIR_INFORMATION and FILE_BOTH_DIR_INFORMATION structures layout. + * + * + * struct FILE_FULL_DIR_INFORMATION | struct FILE_BOTH_DIR_INFORMATION + * ------------------------------------+--------------------------------------- + * ULONG NextEntryOffset; | ULONG NextEntryOffset; + * ULONG FileIndex; | ULONG FileIndex; + * LARGE_INTEGER CreationTime; | LARGE_INTEGER CreationTime; + * LARGE_INTEGER LastAccessTime; | LARGE_INTEGER LastAccessTime; + * LARGE_INTEGER LastWriteTime; | LARGE_INTEGER LastWriteTime; + * LARGE_INTEGER ChangeTime; | LARGE_INTEGER ChangeTime; + * LARGE_INTEGER EndOfFile; | LARGE_INTEGER EndOfFile; + * LARGE_INTEGER AllocationSize; | LARGE_INTEGER AllocationSize; + * ULONG FileAttributes; | ULONG FileAttributes; + * ULONG FileNameLength; | ULONG FileNameLength; + * ULONG EaSize; | ULONG EaSize; + * ------------------------------------+--------------------------------------- + * WCHAR FileName[1]; | CCHAR ShortNameLength; + * | WCHAR ShortName[12]; + * | WCHAR FileName[1]; + * + * Therefore we can use pointers to FILE_FULL_DIR_INFORMATION when one doesn't + * want to refer to the ShortName* fields and FileName (useful for implementing + * the FindExInfoBasic functionality for FindFirstFileEx), however a cast to + * FILE_BOTH_DIR_INFORMATION is required when one wants to use FileName and + * ShortName* fields (needed for the FindExInfoStandard functionality). + * + */ +typedef union _DIR_INFORMATION +{ + PVOID DirInfo; + PFILE_FULL_DIR_INFORMATION FullDirInfo; + PFILE_BOTH_DIR_INFORMATION BothDirInfo; +} DIR_INFORMATION; + +typedef struct _FIND_FILE_DATA +{ + HANDLE Handle; + FINDEX_INFO_LEVELS InfoLevel; + FINDEX_SEARCH_OPS SearchOp; + + /* + * For handling STATUS_BUFFER_OVERFLOW errors emitted by + * NtQueryDirectoryFile in the FildNextFile function. + */ + BOOLEAN HasMoreData; + + /* + * "Pointer" to the next file info structure in the buffer. + * The type is defined by the 'InfoLevel' parameter. + */ + DIR_INFORMATION NextDirInfo; + + BYTE Buffer[FIND_DATA_SIZE]; +} FIND_FILE_DATA, *PFIND_FILE_DATA; + +typedef struct _FIND_STREAM_DATA { STREAM_INFO_LEVELS InfoLevel; - PFILE_STREAM_INFORMATION pFileStreamInfo; - PFILE_STREAM_INFORMATION pCurrent; -} KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA; - -typedef enum _KERNEL32_FIND_DATA_TYPE -{ - FileFind, - StreamFind -} KERNEL32_FIND_DATA_TYPE; - -typedef struct _KERNEL32_FIND_DATA_HEADER -{ - KERNEL32_FIND_DATA_TYPE Type; -} KERNEL32_FIND_DATA_HEADER, *PKERNEL32_FIND_DATA_HEADER; - - -/* FUNCTIONS ****************************************************************/ + PFILE_STREAM_INFORMATION FileStreamInfo; + PFILE_STREAM_INFORMATION CurrentInfo; +} FIND_STREAM_DATA, *PFIND_STREAM_DATA; + +typedef struct _FIND_DATA_HANDLE +{ + FIND_DATA_TYPE Type; + RTL_CRITICAL_SECTION Lock; + + /* + * Pointer to the following finding data, located at + * (this + 1). The type is defined by the 'Type' parameter. + */ + union + { + PFIND_FILE_DATA FindFileData; + PFIND_STREAM_DATA FindStreamData; + } u; + +} FIND_DATA_HANDLE, *PFIND_DATA_HANDLE; + + +/* PRIVATE FUNCTIONS **********************************************************/
static VOID -InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData, - LPCWSTR lpFileName, - ULONG DeviceNameInfo) +CopyDeviceFindData(OUT LPWIN32_FIND_DATAW lpFindFileData, + IN LPCWSTR lpFileName, + IN ULONG DeviceNameInfo) { UNICODE_STRING DeviceName;
- DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF); - DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + (DeviceNameInfo >> 16)); - - /* Return the data */ - RtlZeroMemory(lpFindFileData, - sizeof(*lpFindFileData)); - lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; - RtlCopyMemory(lpFindFileData->cFileName, - DeviceName.Buffer, - DeviceName.Length); + _SEH2_TRY + { + /* DeviceNameInfo == { USHORT Offset; USHORT Length } */ + DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF); + DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + ((DeviceNameInfo >> 16) & 0xFFFF)); + + /* Return the data */ + RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData)); + lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; + RtlCopyMemory(lpFindFileData->cFileName, + DeviceName.Buffer, + DeviceName.Length); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + + return; }
static VOID -InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData, - PFILE_BOTH_DIR_INFORMATION lpFileInfo) -{ - lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes; - - lpFindFileData->ftCreationTime.dwHighDateTime = lpFileInfo->CreationTime.u.HighPart; - lpFindFileData->ftCreationTime.dwLowDateTime = lpFileInfo->CreationTime.u.LowPart; - - lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart; - lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart; - - lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart; - lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart; - - lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart; - lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart; - - memcpy (lpFindFileData->cFileName, lpFileInfo->FileName, lpFileInfo->FileNameLength); - lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0; - - memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName, lpFileInfo->ShortNameLength); - lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0; -} - - -/* - * @implemented - */ -BOOL -WINAPI -InternalFindNextFile ( - HANDLE hFindFile, - PUNICODE_STRING SearchPattern, - PVOID lpFindFileData - ) -{ - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_FILE_DATA IData; - IO_STATUS_BLOCK IoStatusBlock; - BOOLEAN Locked = FALSE; - PFILE_BOTH_DIR_INFORMATION Buffer, FoundFile = NULL; - NTSTATUS Status = STATUS_SUCCESS; - - TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile, SearchPattern); - - if (hFindFile != FIND_DEVICE_HANDLE) - { - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; - if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE || - IHeader->Type != FileFind) - { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - - IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); - - if (SearchPattern == NULL) - { - RtlEnterCriticalSection(&IData->Lock); - Locked = TRUE; - } - - do - { - if (IData->HasData) - { - if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - FoundFile = IData->pFileInfo; - } - - if (IData->pFileInfo->NextEntryOffset != 0) - { - ULONG_PTR BufferEnd; - - IData->pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset); - - /* Be paranoid and make sure that the next entry is completely there */ - BufferEnd = (ULONG_PTR)Buffer + FIND_DATA_SIZE; - if (BufferEnd < (ULONG_PTR)IData->pFileInfo || - BufferEnd < (ULONG_PTR)&IData->pFileInfo->FileNameLength + sizeof(IData->pFileInfo->FileNameLength) || - BufferEnd <= (ULONG_PTR)&IData->pFileInfo->FileName[IData->pFileInfo->FileNameLength]) - { - goto NeedMoreData; - } - } - else - { -NeedMoreData: - IData->HasData = FALSE; - - if (!IData->HasMoreData) - break; - } - } - else - { - IData->pFileInfo = Buffer; - IData->pFileInfo->NextEntryOffset = 0; - Status = NtQueryDirectoryFile (IData->DirectoryHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - (PVOID)IData->pFileInfo, - FIND_DATA_SIZE, - FileBothDirectoryInformation, - FALSE, - SearchPattern, - SearchPattern != NULL); - - if (Status == STATUS_BUFFER_OVERFLOW) - { - IData->HasMoreData = TRUE; - Status = STATUS_SUCCESS; - } - else - { - if (!NT_SUCCESS(Status)) - break; - - IData->HasMoreData = FALSE; - } - - IData->HasData = TRUE; - SearchPattern = NULL; - } - - } while (FoundFile == NULL); - - if (FoundFile != NULL) - { - _SEH2_TRY - { - InternalCopyFindDataW(lpFindFileData, - FoundFile); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - } - _SEH2_END; - } - - if (Locked) - RtlLeaveCriticalSection(&IData->Lock); - } - - if (!NT_SUCCESS(Status)) - { - BaseSetLastNTError (Status); - return FALSE; - } - else if (FoundFile == NULL) - { - SetLastError (ERROR_NO_MORE_FILES); - return FALSE; - } - - return TRUE; -} - - -/* - * @implemented - */ -HANDLE -WINAPI -InternalFindFirstFile ( - LPCWSTR lpFileName, - BOOLEAN DirectoryOnly, - PVOID lpFindFileData - ) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_FILE_DATA IData; - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING NtPathU, FileName, PathFileName; - NTSTATUS Status; - PWSTR NtPathBuffer; - BOOLEAN RemovedLastChar = FALSE; - BOOL bResult; - RTL_RELATIVE_NAME_U DirInfo; - ULONG DeviceNameInfo; - HANDLE hDirectory = NULL; - - TRACE("FindFirstFileW(lpFileName %S)\n", - lpFileName); - - RtlZeroMemory(&PathFileName, - sizeof(PathFileName)); - RtlInitUnicodeString(&FileName, - lpFileName); - - bResult = RtlDosPathNameToNtPathName_U (lpFileName, - &NtPathU, - (PCWSTR *)((ULONG_PTR)&PathFileName.Buffer), - &DirInfo); - if (FALSE == bResult) - { - SetLastError(ERROR_PATH_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } - - /* Save the buffer pointer for later, we need to free it! */ - NtPathBuffer = NtPathU.Buffer; - - /* If there is a file name/pattern then determine it's length */ - if (PathFileName.Buffer != NULL) - { - PathFileName.Length = NtPathU.Length - - (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer); - } - PathFileName.MaximumLength = PathFileName.Length; - - if (DirInfo.RelativeName.Length != 0 && DirInfo.RelativeName.Buffer != PathFileName.Buffer) - { - if (PathFileName.Buffer != NULL) - { - /* This is a relative path to DirInfo.ContainingDirectory, adjust NtPathU! */ - NtPathU.Length = NtPathU.MaximumLength = - (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)DirInfo.RelativeName.Buffer); - NtPathU.Buffer = DirInfo.RelativeName.Buffer; - } - } - else - { - /* This is an absolute path, NtPathU receives the full path */ - DirInfo.ContainingDirectory = NULL; - if (PathFileName.Buffer != NULL) - { - NtPathU.Length = NtPathU.MaximumLength = - (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer); - } - } - - /* Remove the last character of the path (Unless the path is a drive and - ends with ":"). If the caller however supplies a path to a device, such - as "C:\NUL" then the last character gets cut off, which later results in - NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers - a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a - real device with a name eg. "NU" in the system, FindFirstFile will succeed, - rendering the fake DOS device check useless... Why would they invent such a - stupid and broken behavior?! */ - if (NtPathU.Length >= 2 * sizeof(WCHAR) && - NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] != L'\' && - NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':') - { - NtPathU.Length -= sizeof(WCHAR); - RemovedLastChar = TRUE; - } - - TRACE("lpFileName: "%ws"\n", lpFileName); - TRACE("NtPathU: "%wZ"\n", &NtPathU); - TRACE("PathFileName: "%wZ"\n", &PathFileName); - TRACE("RelativeTo: 0x%p\n", DirInfo.ContainingDirectory); - - InitializeObjectAttributes (&ObjectAttributes, - &NtPathU, - OBJ_CASE_INSENSITIVE, - DirInfo.ContainingDirectory, - NULL); - - Status = NtOpenFile (&hDirectory, - FILE_LIST_DIRECTORY | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - - if (Status == STATUS_NOT_A_DIRECTORY && RemovedLastChar) - { - /* Try again, this time with the last character ... */ - NtPathU.Length += sizeof(WCHAR); - - Status = NtOpenFile (&hDirectory, - FILE_LIST_DIRECTORY | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - - NtPathU.Length += sizeof(WCHAR); - } - - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - - /* See if the application tries to look for a DOS device */ - DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName)); - if (DeviceNameInfo != 0) - { - InternalCopyDeviceFindDataW(lpFindFileData, - lpFileName, - DeviceNameInfo); - - return FIND_DEVICE_HANDLE; - } - - BaseSetLastNTError (Status); - return INVALID_HANDLE_VALUE; - } - - if (PathFileName.Length == 0) - { - /* No file part?! */ - NtClose(hDirectory); - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - SetLastError(ERROR_FILE_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } - - IHeader = RtlAllocateHeap (RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(KERNEL32_FIND_DATA_HEADER) + - sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE); - if (NULL == IHeader) - { - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - NtClose(hDirectory); - - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return INVALID_HANDLE_VALUE; - } - - IHeader->Type = FileFind; - IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - IData->DirectoryHandle = hDirectory; - IData->HasMoreData = TRUE; - - /* change pattern: "*.*" --> "*" */ - if (PathFileName.Length == 6 && - RtlCompareMemory(PathFileName.Buffer, - L"*.*", - 6) == 6) - { - PathFileName.Length = 2; - } - - IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); - IData->pFileInfo->FileIndex = 0; - IData->DirectoryOnly = DirectoryOnly; - - bResult = InternalFindNextFile((HANDLE)IHeader, - &PathFileName, - lpFindFileData); - - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - - if (!bResult) - { - FindClose((HANDLE)IHeader); - return INVALID_HANDLE_VALUE; - } - - RtlInitializeCriticalSection(&IData->Lock); - IData->LockInitialized = TRUE; - - return (HANDLE)IHeader; -} - +CopyFindData(OUT LPWIN32_FIND_DATAW lpFindFileData, + IN FINDEX_INFO_LEVELS fInfoLevelId, + IN DIR_INFORMATION DirInfo) +{ +#define ULARGE_INTEGER_2_FILETIME(ft, ul) \ +do { \ + (ft).dwHighDateTime = (ul).u.HighPart; \ + (ft).dwLowDateTime = (ul).u.LowPart ; \ +} while(0) + + _SEH2_TRY + { + RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData)); + + lpFindFileData->dwFileAttributes = DirInfo.FullDirInfo->FileAttributes; + + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftCreationTime, DirInfo.FullDirInfo->CreationTime); + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastAccessTime, DirInfo.FullDirInfo->LastAccessTime); + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastWriteTime, DirInfo.FullDirInfo->LastWriteTime); + + lpFindFileData->nFileSizeHigh = DirInfo.FullDirInfo->EndOfFile.u.HighPart; + lpFindFileData->nFileSizeLow = DirInfo.FullDirInfo->EndOfFile.u.LowPart; + + /* dwReserved0 contains the NTFS reparse point tag, if any. */ + if (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + lpFindFileData->dwReserved0 = DirInfo.FullDirInfo->EaSize; + else + lpFindFileData->dwReserved0 = 0; + + /* Unused dwReserved1 field */ + lpFindFileData->dwReserved1 = 0; + + if (fInfoLevelId == FindExInfoStandard) + { + RtlCopyMemory(lpFindFileData->cFileName, + DirInfo.BothDirInfo->FileName, + DirInfo.BothDirInfo->FileNameLength); + lpFindFileData->cFileName[DirInfo.BothDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; + + RtlCopyMemory(lpFindFileData->cAlternateFileName, + DirInfo.BothDirInfo->ShortName, + DirInfo.BothDirInfo->ShortNameLength); + lpFindFileData->cAlternateFileName[DirInfo.BothDirInfo->ShortNameLength / sizeof(WCHAR)] = UNICODE_NULL; + } + else if (fInfoLevelId == FindExInfoBasic) + { + RtlCopyMemory(lpFindFileData->cFileName, + DirInfo.FullDirInfo->FileName, + DirInfo.FullDirInfo->FileNameLength); + lpFindFileData->cFileName[DirInfo.FullDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; + + lpFindFileData->cAlternateFileName[0] = UNICODE_NULL; + } + else + { + /* Invalid InfoLevelId */ + ASSERT(FALSE); + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + + return; +} + +static VOID +CopyStreamData(IN OUT PFIND_STREAM_DATA FindStreamData, + OUT PWIN32_FIND_STREAM_DATA lpFindStreamData) +{ + _SEH2_TRY + { + ASSERT(FindStreamData->CurrentInfo); + + switch (FindStreamData->InfoLevel) + { + case FindStreamInfoStandard: + { + ULONG StreamNameLen = min(FindStreamData->CurrentInfo->StreamNameLength, + sizeof(lpFindStreamData->cStreamName) - sizeof(WCHAR)); + + RtlZeroMemory(lpFindStreamData, sizeof(*lpFindStreamData)); + + lpFindStreamData->StreamSize.QuadPart = FindStreamData->CurrentInfo->StreamSize.QuadPart; + RtlCopyMemory(lpFindStreamData->cStreamName, + FindStreamData->CurrentInfo->StreamName, + StreamNameLen); + lpFindStreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = UNICODE_NULL; + + break; + } + + default: + { + /* Invalid InfoLevel */ + ASSERT(FALSE); + break; + } + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + + return; +} + + +/* PUBLIC FUNCTIONS ***********************************************************/
/* * @implemented @@ -464,27 +268,23 @@ WIN32_FIND_DATAW FindFileDataW;
lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); - if (!lpFileNameW) - { - return INVALID_HANDLE_VALUE; - } + if (!lpFileNameW) return INVALID_HANDLE_VALUE;
hSearch = FindFirstFileExW(lpFileNameW->Buffer, FindExInfoStandard, &FindFileDataW, FindExSearchNameMatch, NULL, 0); - if (hSearch == INVALID_HANDLE_VALUE) - { - return INVALID_HANDLE_VALUE; - } - - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; + + RtlCopyMemory(lpFindFileData, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); Ansi.Buffer = lpFindFileData->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileData->cFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -496,7 +296,7 @@ RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); Ansi.Buffer = lpFindFileData->cAlternateFileName; Ansi.Length = 0; - Ansi.MaximumLength = 14; + Ansi.MaximumLength = sizeof(lpFindFileData->cAlternateFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -506,6 +306,22 @@ }
return hSearch; +} + + +/* + * @implemented + */ +HANDLE +WINAPI +FindFirstFileW(IN LPCWSTR lpFileName, + OUT LPWIN32_FIND_DATAW lpFindFileData) +{ + return FindFirstFileExW(lpFileName, + FindExInfoStandard, + lpFindFileData, + FindExSearchNameMatch, + NULL, 0); }
@@ -523,16 +339,16 @@ WIN32_FIND_DATAW FindFileDataW;
if (!FindNextFileW(hFindFile, &FindFileDataW)) - { return FALSE; - } - - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + + RtlCopyMemory(lpFindFileData, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); Ansi.Buffer = lpFindFileData->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileData->cFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -543,7 +359,7 @@ RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); Ansi.Buffer = lpFindFileData->cAlternateFileName; Ansi.Length = 0; - Ansi.MaximumLength = 14; + Ansi.MaximumLength = sizeof(lpFindFileData->cAlternateFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -554,79 +370,6 @@ return TRUE; }
- -/* - * @implemented - */ -BOOL -WINAPI -FindClose ( - HANDLE hFindFile - ) -{ - PKERNEL32_FIND_DATA_HEADER IHeader; - - TRACE("FindClose(hFindFile %x)\n",hFindFile); - - if (hFindFile == FIND_DEVICE_HANDLE) - return TRUE; - - if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) - { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; - - switch (IHeader->Type) - { - case FileFind: - { - PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - CloseHandle (IData->DirectoryHandle); - if (IData->LockInitialized) - RtlDeleteCriticalSection(&IData->Lock); - IData->LockInitialized = FALSE; - break; - } - - case StreamFind: - { - PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap (RtlGetProcessHeap(), 0, IData->pFileStreamInfo); - } - break; - } - - default: - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } - - RtlFreeHeap (RtlGetProcessHeap(), 0, IHeader); - - return TRUE; -} - - -/* - * @implemented - */ -HANDLE -WINAPI -FindFirstFileW(IN LPCWSTR lpFileName, - OUT LPWIN32_FIND_DATAW lpFindFileData) -{ - return FindFirstFileExW(lpFileName, - FindExInfoStandard, - lpFindFileData, - FindExSearchNameMatch, - NULL, - 0); -}
/* * @implemented @@ -636,9 +379,261 @@ FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData) { - return InternalFindNextFile(hFindFile, - NULL, - lpFindFileData); + NTSTATUS Status = STATUS_SUCCESS; + DIR_INFORMATION FoundFile = {NULL}; + + TRACE("FindNextFileW(%lx, 0x%p)\n", hFindFile, lpFindFileData); + + if (hFindFile != FIND_DEVICE_HANDLE) + { + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile; + PFIND_FILE_DATA FindFileData; + FINDEX_INFO_LEVELS InfoLevel; + IO_STATUS_BLOCK IoStatusBlock; + DIR_INFORMATION DirInfo = {NULL}, NextDirInfo = {NULL}; + + if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE || + FindDataHandle->Type != FindFile) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + RtlEnterCriticalSection(&FindDataHandle->Lock); + + FindFileData = FindDataHandle->u.FindFileData; + InfoLevel = FindFileData->InfoLevel; + + do + { + if (FindFileData->NextDirInfo.DirInfo == NULL) + { + Status = NtQueryDirectoryFile(FindFileData->Handle, + NULL, NULL, NULL, + &IoStatusBlock, + &FindFileData->Buffer, + sizeof(FindFileData->Buffer), + (InfoLevel == FindExInfoStandard + ? FileBothDirectoryInformation + : FileFullDirectoryInformation), + FALSE, + NULL, /* Use the file pattern from the first call */ + FALSE); + if (Status == STATUS_BUFFER_OVERFLOW) + { + FindFileData->HasMoreData = TRUE; + Status = STATUS_SUCCESS; + } + else + { + if (!NT_SUCCESS(Status)) break; + FindFileData->HasMoreData = FALSE; + } + + FindFileData->NextDirInfo.DirInfo = &FindFileData->Buffer; + } + + DirInfo = FindFileData->NextDirInfo; + + if (DirInfo.FullDirInfo->NextEntryOffset != 0) + { + ULONG_PTR BufferEnd = (ULONG_PTR)&FindFileData->Buffer + sizeof(FindFileData->Buffer); + PWSTR pFileName; + + NextDirInfo.DirInfo = FindFileData->NextDirInfo.DirInfo = + (PVOID)((ULONG_PTR)DirInfo.DirInfo + DirInfo.FullDirInfo->NextEntryOffset); + + pFileName = (InfoLevel == FindExInfoStandard + ? NextDirInfo.BothDirInfo->FileName + : NextDirInfo.FullDirInfo->FileName); + + /* Be paranoid and make sure that the next entry is completely there */ + if (BufferEnd < (ULONG_PTR)NextDirInfo.DirInfo || + BufferEnd < (ULONG_PTR)&NextDirInfo.FullDirInfo->FileNameLength + sizeof(NextDirInfo.FullDirInfo->FileNameLength) || + BufferEnd <= (ULONG_PTR)((ULONG_PTR)pFileName + NextDirInfo.FullDirInfo->FileNameLength)) + { + FindFileData->NextDirInfo.DirInfo = NULL; + } + } + else + { + FindFileData->NextDirInfo.DirInfo = NULL; + } + + if ((FindFileData->SearchOp != FindExSearchLimitToDirectories) || + (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + FoundFile = DirInfo; + } + } while ( FoundFile.DirInfo == NULL && (FindFileData->NextDirInfo.DirInfo || FindFileData->HasMoreData) ); + + if (FoundFile.DirInfo != NULL) + { + /* Return the information */ + CopyFindData(lpFindFileData, InfoLevel, FoundFile); + } + + RtlLeaveCriticalSection(&FindDataHandle->Lock); + } + + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + else if (FoundFile.DirInfo == NULL) + { + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; + } + + return TRUE; +} + + +/* + * @implemented + */ +BOOL +WINAPI +FindClose(HANDLE hFindFile) +{ + TRACE("FindClose(hFindFile %x)\n", hFindFile); + + if (hFindFile == FIND_DEVICE_HANDLE) + return TRUE; + + if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + /* Protect with SEH against closing attempts on invalid handles. */ + _SEH2_TRY + { + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile; + + switch (FindDataHandle->Type) + { + case FindFile: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + NtClose(FindDataHandle->u.FindFileData->Handle); + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + break; + } + + case FindStream: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + if (FindDataHandle->u.FindStreamData->FileStreamInfo != NULL) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, + FindDataHandle->u.FindStreamData->FileStreamInfo); + } + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + break; + } + + default: + { + SetLastError(ERROR_INVALID_HANDLE); + _SEH2_YIELD(return FALSE); + } + } + + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + _SEH2_YIELD(return TRUE); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + BaseSetLastNTError(_SEH2_GetExceptionCode()); + _SEH2_YIELD(return FALSE); + } + _SEH2_END; +} + + +/* + * @unimplemented + */ +HANDLE +WINAPI +FindFirstFileExA(IN LPCSTR lpFileName, + IN FINDEX_INFO_LEVELS fInfoLevelId, + OUT LPVOID lpFindFileData, + IN FINDEX_SEARCH_OPS fSearchOp, + LPVOID lpSearchFilter, + IN DWORD dwAdditionalFlags) +{ + HANDLE hSearch; + NTSTATUS Status; + ANSI_STRING Ansi; + UNICODE_STRING UTF8; + PUNICODE_STRING lpFileNameW; + WIN32_FIND_DATAW FindFileDataW; + LPWIN32_FIND_DATAA lpFindFileDataA = (LPWIN32_FIND_DATAA)lpFindFileData; + + if ((fInfoLevelId != FindExInfoStandard && fInfoLevelId != FindExInfoBasic) || + fSearchOp == FindExSearchLimitToDevices || + dwAdditionalFlags & ~FIND_FIRST_EX_CASE_SENSITIVE /* only supported flag for now */) + { + SetLastError(fSearchOp == FindExSearchLimitToDevices + ? ERROR_NOT_SUPPORTED + : ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } + + lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); + if (!lpFileNameW) return INVALID_HANDLE_VALUE; + + hSearch = FindFirstFileExW(lpFileNameW->Buffer, + fInfoLevelId, + &FindFileDataW, + fSearchOp, + lpSearchFilter, + dwAdditionalFlags); + if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; + + RtlCopyMemory(lpFindFileDataA, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName)); + + RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); + Ansi.Buffer = lpFindFileDataA->cFileName; + Ansi.Length = 0; + Ansi.MaximumLength = sizeof(lpFindFileDataA->cFileName); + Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); + if (!NT_SUCCESS(Status)) + { + FindClose(hSearch); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + if (fInfoLevelId != FindExInfoBasic) + { + RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); + Ansi.Buffer = lpFindFileDataA->cAlternateFileName; + Ansi.Length = 0; + Ansi.MaximumLength = sizeof(lpFindFileDataA->cAlternateFileName); + Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); + if (!NT_SUCCESS(Status)) + { + FindClose(hSearch); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + } + else + { + lpFindFileDataA->cAlternateFileName[0] = ANSI_NULL; + } + + return hSearch; }
@@ -654,123 +649,241 @@ LPVOID lpSearchFilter, IN DWORD dwAdditionalFlags) { - if (fInfoLevelId != FindExInfoStandard) - { - SetLastError(ERROR_INVALID_PARAMETER); + TRACE("FindFirstFileExW(lpFileName %S)\n", lpFileName); + + if ((fInfoLevelId != FindExInfoStandard && fInfoLevelId != FindExInfoBasic) || + fSearchOp == FindExSearchLimitToDevices || + dwAdditionalFlags & ~FIND_FIRST_EX_CASE_SENSITIVE /* only supported flag for now */) + { + SetLastError(fSearchOp == FindExSearchLimitToDevices + ? ERROR_NOT_SUPPORTED + : ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; }
- if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories) - { + if (fSearchOp == FindExSearchNameMatch || + fSearchOp == FindExSearchLimitToDirectories) + { + LPWIN32_FIND_DATAW Win32FindData = (LPWIN32_FIND_DATAW)lpFindFileData; + PFIND_DATA_HANDLE FindDataHandle; + PFIND_FILE_DATA FindFileData; + + UNICODE_STRING NtPath, FilePattern; + PWSTR NtPathBuffer; + RTL_RELATIVE_NAME_U RelativePath; + ULONG DeviceNameInfo = 0; + + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE hDirectory = NULL; + + /* + * May represent many FILE_BOTH_DIR_INFORMATION + * or many FILE_FULL_DIR_INFORMATION structures. + */ + BYTE DirectoryInfo[FIND_DATA_SIZE]; + DIR_INFORMATION DirInfo = {&DirectoryInfo}; + + /* The search filter is always unused */ if (lpSearchFilter) { SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; }
- return InternalFindFirstFile (lpFileName, - fSearchOp == FindExSearchLimitToDirectories, - lpFindFileData); - } - - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; -} - -/* - * @unimplemented - */ -HANDLE -WINAPI -FindFirstFileExA(IN LPCSTR lpFileName, - IN FINDEX_INFO_LEVELS fInfoLevelId, - OUT LPVOID lpFindFileData, - IN FINDEX_SEARCH_OPS fSearchOp, - LPVOID lpSearchFilter, - IN DWORD dwAdditionalFlags) -{ - HANDLE hSearch; - NTSTATUS Status; - ANSI_STRING Ansi; - UNICODE_STRING UTF8; - PUNICODE_STRING lpFileNameW; - WIN32_FIND_DATAW FindFileDataW; - - lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); - if (!lpFileNameW) - { + if (!RtlDosPathNameToNtPathName_U(lpFileName, + &NtPath, + (PCWSTR*)&FilePattern.Buffer, + &RelativePath)) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + + DPRINT("lpFileName = '%S'\n", lpFileName); + DPRINT("FilePattern.Buffer = '%S'\n", FilePattern.Buffer); + DPRINT("RelativePath.RelativeName = '%wZ'\n", &RelativePath.RelativeName); + DPRINT("NtPath.Buffer = '%S'\n", NtPath.Buffer); + DPRINT("NtPath - Before = '%wZ'\n", &NtPath); + + /* Save the buffer pointer for later, we need to free it! */ + NtPathBuffer = NtPath.Buffer; + + /* + * Contrary to what Windows does, check NOW whether or not + * lpFileName is a DOS driver. Therefore we don't have to + * write broken code to check that. + */ + if (!FilePattern.Buffer || !*FilePattern.Buffer) + { + /* No file pattern specified, or DOS device */ + + DeviceNameInfo = RtlIsDosDeviceName_U(lpFileName); + if (DeviceNameInfo != 0) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + /* OK, it's really a DOS device */ + CopyDeviceFindData(Win32FindData, lpFileName, DeviceNameInfo); + return FIND_DEVICE_HANDLE; + } + } + + /* A file pattern was specified, or it was not a DOS device */ + + /* If there is a file pattern then determine its length */ + if (FilePattern.Buffer != NULL) + { + FilePattern.Length = NtPath.Length - + (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer); + } + else + { + FilePattern.Length = 0; + } + FilePattern.MaximumLength = FilePattern.Length; + + if (RelativePath.RelativeName.Length != 0 && + RelativePath.RelativeName.Buffer != FilePattern.Buffer) + { + if (FilePattern.Buffer != NULL) + { + /* This is a relative path to RelativePath.ContainingDirectory, adjust NtPath! */ + NtPath.Length = NtPath.MaximumLength = + (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)RelativePath.RelativeName.Buffer); + NtPath.Buffer = RelativePath.RelativeName.Buffer; + } + } + else + { + /* This is an absolute path, NtPath receives the full path */ + RelativePath.ContainingDirectory = NULL; + if (FilePattern.Buffer != NULL) + { + NtPath.Length = NtPath.MaximumLength = + (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer); + } + } + + DPRINT("NtPath - After = '%wZ'\n", &NtPath); + DPRINT("FilePattern = '%wZ'\n", &FilePattern); + DPRINT("RelativeTo = 0x%p\n", RelativePath.ContainingDirectory); + + InitializeObjectAttributes(&ObjectAttributes, + &NtPath, + (dwAdditionalFlags & FIND_FIRST_EX_CASE_SENSITIVE) ? 0 : OBJ_CASE_INSENSITIVE, + RelativePath.ContainingDirectory, + NULL); + + Status = NtOpenFile(&hDirectory, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + /* Adjust the last error codes */ + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + Status = STATUS_OBJECT_PATH_NOT_FOUND; + else if (Status == STATUS_OBJECT_TYPE_MISMATCH) + Status = STATUS_OBJECT_PATH_NOT_FOUND; + + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + /* + * Fail if there is not any file pattern, + * since we are not looking for a device. + */ + if (FilePattern.Length == 0) + { + NtClose(hDirectory); + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + SetLastError(ERROR_FILE_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + + /* Change pattern: "*.*" --> "*" */ + if (FilePattern.Length == 6 && + RtlCompareMemory(FilePattern.Buffer, L"*.*", 6) == 6) + { + FilePattern.Length = 2; + } + + Status = NtQueryDirectoryFile(hDirectory, + NULL, NULL, NULL, + &IoStatusBlock, + DirInfo.DirInfo, // == &DirectoryInfo + sizeof(DirectoryInfo), + (fInfoLevelId == FindExInfoStandard + ? FileBothDirectoryInformation + : FileFullDirectoryInformation), + TRUE, /* Return a single entry */ + &FilePattern, + TRUE); + + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + if (!NT_SUCCESS(Status)) + { + NtClose(hDirectory); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + ASSERT(DirInfo.FullDirInfo->NextEntryOffset == 0); + + /* Return the information */ + CopyFindData(Win32FindData, fInfoLevelId, DirInfo); + + /* + * Initialization of the search handle. + */ + FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(FIND_DATA_HANDLE) + + sizeof(FIND_FILE_DATA)); + if (!FindDataHandle) + { + NtClose(hDirectory); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + FindDataHandle->Type = FindFile; + FindDataHandle->u.FindFileData = (PFIND_FILE_DATA)(FindDataHandle + 1); + FindFileData = FindDataHandle->u.FindFileData; + + FindFileData->Handle = hDirectory; + FindFileData->InfoLevel = fInfoLevelId; + FindFileData->SearchOp = fSearchOp; + FindFileData->HasMoreData = FALSE; + FindFileData->NextDirInfo.DirInfo = NULL; + + /* The critical section must always be initialized */ + Status = RtlInitializeCriticalSection(&FindDataHandle->Lock); + if (!NT_SUCCESS(Status)) + { + NtClose(hDirectory); + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + return (HANDLE)FindDataHandle; + } + else + { + SetLastError(ERROR_NOT_SUPPORTED); return INVALID_HANDLE_VALUE; - } - - hSearch = FindFirstFileExW(lpFileNameW->Buffer, - fInfoLevelId, - &FindFileDataW, - fSearchOp, - lpSearchFilter, - dwAdditionalFlags); - if (hSearch == INVALID_HANDLE_VALUE) - { - return INVALID_HANDLE_VALUE; - } - - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); - - RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); - Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cFileName; - Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; - Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); - if (!NT_SUCCESS(Status)) - { - FindClose(hSearch); - BaseSetLastNTError(Status); - return INVALID_HANDLE_VALUE; - } - - RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); - Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cAlternateFileName; - Ansi.Length = 0; - Ansi.MaximumLength = 14; - Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); - if (!NT_SUCCESS(Status)) - { - FindClose(hSearch); - BaseSetLastNTError(Status); - return INVALID_HANDLE_VALUE; - } - - return hSearch; -} - - -static VOID -InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData, - OUT LPVOID lpFindStreamData) -{ - ASSERT(IData->pCurrent); - - switch (IData->InfoLevel) - { - case FindStreamInfoStandard: - { - ULONG StreamNameLen; - WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData; - - StreamNameLen = IData->pCurrent->StreamNameLength; - if (StreamNameLen > sizeof(StreamData->cStreamName) - sizeof(WCHAR)) - StreamNameLen = sizeof(StreamData->cStreamName) - sizeof(WCHAR); - - StreamData->StreamSize.QuadPart = IData->pCurrent->StreamSize.QuadPart; - RtlCopyMemory(StreamData->cStreamName, - IData->pCurrent->StreamName, - StreamNameLen); - StreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = L'\0'; - break; - } - - default: - ASSERT(FALSE); - break; } }
@@ -785,11 +898,11 @@ OUT LPVOID lpFindStreamData, IN DWORD dwFlags) { - PKERNEL32_FIND_DATA_HEADER IHeader = NULL; - PKERNEL32_FIND_STREAM_DATA IData = NULL; + PFIND_DATA_HANDLE FindDataHandle = NULL; + PFIND_STREAM_DATA FindStreamData; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING NtPathU; + UNICODE_STRING NtFilePath; HANDLE FileHandle = NULL; NTSTATUS Status; ULONG BufferSize = 0; @@ -801,19 +914,18 @@ return INVALID_HANDLE_VALUE; }
- /* validate & translate the filename */ + /* Validate and translate the filename */ if (!RtlDosPathNameToNtPathName_U(lpFileName, - &NtPathU, - NULL, - NULL)) + &NtFilePath, + NULL, NULL)) { SetLastError(ERROR_PATH_NOT_FOUND); return INVALID_HANDLE_VALUE; }
- /* open the file */ + /* Open the file */ InitializeObjectAttributes(&ObjectAttributes, - &NtPathU, + &NtFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); @@ -822,47 +934,52 @@ 0, &ObjectAttributes, &IoStatusBlock, - NULL, - 0, + NULL, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, - 0, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - goto Cleanup; - } - - /* create the search context */ - IHeader = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - sizeof(KERNEL32_FIND_DATA_HEADER) + - sizeof(KERNEL32_FIND_STREAM_DATA)); - if (IHeader == NULL) + 0, NULL, 0); + if (!NT_SUCCESS(Status)) goto Cleanup; + + /* + * Initialization of the search handle. + */ + FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(FIND_DATA_HANDLE) + + sizeof(FIND_STREAM_DATA)); + if (!FindDataHandle) { Status = STATUS_NO_MEMORY; goto Cleanup; }
- IHeader->Type = StreamFind; - IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); - - /* capture all information about the streams */ - IData->InfoLevel = InfoLevel; - IData->pCurrent = NULL; - IData->pFileStreamInfo = NULL; - + FindDataHandle->Type = FindStream; + FindDataHandle->u.FindStreamData = (PFIND_STREAM_DATA)(FindDataHandle + 1); + FindStreamData = FindDataHandle->u.FindStreamData; + + FindStreamData->InfoLevel = InfoLevel; + FindStreamData->FileStreamInfo = NULL; + FindStreamData->CurrentInfo = NULL; + + /* The critical section must always be initialized */ + Status = RtlInitializeCriticalSection(&FindDataHandle->Lock); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + goto Cleanup; + } + + /* Capture all information about the streams */ do { BufferSize += 0x1000;
- if (IData->pFileStreamInfo == NULL) - { - IData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - BufferSize); - if (IData->pFileStreamInfo == NULL) + if (FindStreamData->FileStreamInfo == NULL) + { + FindStreamData->FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + BufferSize); + if (FindStreamData->FileStreamInfo == NULL) { Status = STATUS_NO_MEMORY; break; @@ -873,8 +990,8 @@ PFILE_STREAM_INFORMATION pfsi;
pfsi = RtlReAllocateHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo, + 0, // HEAP_ZERO_MEMORY, + FindStreamData->FileStreamInfo, BufferSize); if (pfsi == NULL) { @@ -882,12 +999,12 @@ break; }
- IData->pFileStreamInfo = pfsi; + FindStreamData->FileStreamInfo = pfsi; }
Status = NtQueryInformationFile(FileHandle, &IoStatusBlock, - IData->pFileStreamInfo, + FindStreamData->FileStreamInfo, BufferSize, FileStreamInformation);
@@ -895,49 +1012,37 @@
if (NT_SUCCESS(Status)) { - NtClose(FileHandle); - FileHandle = NULL; - - /* select the first stream and return the information */ - IData->pCurrent = IData->pFileStreamInfo; - InternalCopyStreamInfo(IData, - lpFindStreamData); - - /* all done */ + /* Select the first stream and return the information */ + FindStreamData->CurrentInfo = FindStreamData->FileStreamInfo; + CopyStreamData(FindStreamData, lpFindStreamData); + + /* All done */ Status = STATUS_SUCCESS; } + else + { + if (FindStreamData->FileStreamInfo) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, FindStreamData->FileStreamInfo); + } + + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + }
Cleanup: - if (FileHandle != NULL) - { - NtClose(FileHandle); - } - - RtlFreeHeap(RtlGetProcessHeap(), - 0, - NtPathU.Buffer); - - if (!NT_SUCCESS(Status)) - { - if (IHeader != NULL) - { - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo); - } - - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IHeader); - } - + if (FileHandle) NtClose(FileHandle); + + RtlFreeHeap(RtlGetProcessHeap(), 0, NtFilePath.Buffer); + + if (NT_SUCCESS(Status)) + { + return (HANDLE)FindDataHandle; + } + else + { BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; } - - return (HANDLE)IHeader; }
@@ -949,37 +1054,39 @@ FindNextStreamW(IN HANDLE hFindStream, OUT LPVOID lpFindStreamData) { - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_STREAM_DATA IData; - - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream; + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindStream; + PFIND_STREAM_DATA FindStreamData; + if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE || - IHeader->Type != StreamFind) - { - SetLastError (ERROR_INVALID_HANDLE); + FindDataHandle->Type != FindStream) + { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; }
- IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); - - /* select next stream if possible */ - if (IData->pCurrent->NextEntryOffset != 0) - { - IData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo + - IData->pCurrent->NextEntryOffset); + RtlEnterCriticalSection(&FindDataHandle->Lock); + + FindStreamData = FindDataHandle->u.FindStreamData; + + /* Select next stream if possible */ + if (FindStreamData->CurrentInfo->NextEntryOffset != 0) + { + FindStreamData->CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)FindStreamData->FileStreamInfo + + FindStreamData->CurrentInfo->NextEntryOffset); + + /* Return the information */ + CopyStreamData(FindStreamData, lpFindStreamData); + + RtlLeaveCriticalSection(&FindDataHandle->Lock); + return TRUE; } else { + RtlLeaveCriticalSection(&FindDataHandle->Lock); + SetLastError(ERROR_HANDLE_EOF); return FALSE; } - - /* return the information */ - InternalCopyStreamInfo(IData, - lpFindStreamData); - - return TRUE; -} - +}
/* EOF */
Modified: trunk/reactos/include/ndk/iotypes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/iotypes.h?rev=5... ============================================================================== --- trunk/reactos/include/ndk/iotypes.h [iso-8859-1] (original) +++ trunk/reactos/include/ndk/iotypes.h [iso-8859-1] Thu Sep 27 22:07:06 2012 @@ -523,6 +523,22 @@ { PLARGE_INTEGER ReadTimeout; } FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION; + +typedef struct _FILE_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
typedef struct _FILE_BOTH_DIR_INFORMATION {
Modified: trunk/reactos/include/psdk/winbase.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/psdk/winbase.h?rev=... ============================================================================== --- trunk/reactos/include/psdk/winbase.h [iso-8859-1] (original) +++ trunk/reactos/include/psdk/winbase.h [iso-8859-1] Thu Sep 27 22:07:06 2012 @@ -228,6 +228,7 @@ #define CLRBREAK 9 #define STILL_ACTIVE 0x103 #define FIND_FIRST_EX_CASE_SENSITIVE 1 +#define FIND_FIRST_EX_LARGE_FETCH 2 #define SCS_32BIT_BINARY 0 #define SCS_64BIT_BINARY 6 #define SCS_DOS_BINARY 1 @@ -923,6 +924,7 @@
typedef enum _FINDEX_INFO_LEVELS { FindExInfoStandard, + FindExInfoBasic, FindExInfoMaxInfoLevel } FINDEX_INFO_LEVELS;