Index: dll/win32/kernel32/client/file/find.c =================================================================== --- dll/win32/kernel32/client/file/find.c (révision 57391) +++ dll/win32/kernel32/client/file/find.c (copie de travail) @@ -1,453 +1,233 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries - * FILE: lib/kernel32/file/find.c + * FILE: kernel32/file/find.c * PURPOSE: Find functions - * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) + * PROGRAMMERS: Ariadne (ariadne@xs4all.nl) * Pierre Schweitzer (pierre.schweitzer@reactos.org) + * Hermes BELUSCA - MAITO * UPDATE HISTORY: * Created 01/11/98 + * 26/09/2012 : Reworking (hbelusca) */ -/* INCLUDES *****************************************************************/ +/* INCLUDES *******************************************************************/ #include #define NDEBUG #include DEBUG_CHANNEL(kernel32file); -/* TYPES ********************************************************************/ +/* TYPES **********************************************************************/ -#define FIND_DATA_SIZE 0x4000 +#define FIND_DATA_SIZE 0x4000 +#define FIND_DEVICE_HANDLE ((HANDLE)0x1) -#define FIND_DEVICE_HANDLE ((HANDLE)0x1) +typedef enum _FIND_DATA_TYPE +{ + FindFile = 1, + FindStream = 2 +} FIND_DATA_TYPE; -typedef struct _KERNEL32_FIND_FILE_DATA +/* + * 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]; + * }; + * + */ +typedef union _DIR_INFORMATION { - 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; + PVOID DirInfo; + PFILE_FULL_DIR_INFORMATION FullDirInfo; + PFILE_BOTH_DIR_INFORMATION BothDirInfo; +} DIR_INFORMATION; -typedef struct _KERNEL32_FIND_STREAM_DATA +typedef struct _FIND_FILE_DATA { - STREAM_INFO_LEVELS InfoLevel; - PFILE_STREAM_INFORMATION pFileStreamInfo; - PFILE_STREAM_INFORMATION pCurrent; -} KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA; + HANDLE Handle; + FINDEX_INFO_LEVELS InfoLevel; + FINDEX_SEARCH_OPS SearchOp; -typedef enum _KERNEL32_FIND_DATA_TYPE + 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 { - FileFind, - StreamFind -} KERNEL32_FIND_DATA_TYPE; + STREAM_INFO_LEVELS InfoLevel; + PFILE_STREAM_INFORMATION FileStreamInfo; + PFILE_STREAM_INFORMATION CurrentInfo; +} FIND_STREAM_DATA, *PFIND_STREAM_DATA; -typedef struct _KERNEL32_FIND_DATA_HEADER +typedef struct _FIND_DATA_HANDLE { - KERNEL32_FIND_DATA_TYPE Type; -} KERNEL32_FIND_DATA_HEADER, *PKERNEL32_FIND_DATA_HEADER; + 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; -/* FUNCTIONS ****************************************************************/ +} 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; + /* DeviceNameInfo == { USHORT Offset; USHORT Length } */ DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF); - DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + (DeviceNameInfo >> 16)); + DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + ((DeviceNameInfo >> 16) & 0xFFFF)); /* Return the data */ - RtlZeroMemory(lpFindFileData, - sizeof(*lpFindFileData)); + RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData)); lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; RtlCopyMemory(lpFindFileData->cFileName, DeviceName.Buffer, DeviceName.Length); + + return; } static VOID -InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData, - PFILE_BOTH_DIR_INFORMATION lpFileInfo) +CopyFindData(OUT LPWIN32_FIND_DATAW lpFindFileData, + IN FINDEX_INFO_LEVELS fInfoLevelId, + IN DIR_INFORMATION DirInfo) { - lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes; +#define ULARGE_INTEGER_2_FILETIME(ft, ul) \ +do { \ + (ft).dwHighDateTime = (ul).u.HighPart; \ + (ft).dwLowDateTime = (ul).u.LowPart ; \ +} while(0) - lpFindFileData->ftCreationTime.dwHighDateTime = lpFileInfo->CreationTime.u.HighPart; - lpFindFileData->ftCreationTime.dwLowDateTime = lpFileInfo->CreationTime.u.LowPart; + _SEH2_TRY + { + RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData)); - lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart; - lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart; + lpFindFileData->dwFileAttributes = DirInfo.FullDirInfo->FileAttributes; - lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart; - lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart; + 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 = lpFileInfo->EndOfFile.u.HighPart; - lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart; + lpFindFileData->nFileSizeHigh = DirInfo.FullDirInfo->EndOfFile.u.HighPart; + lpFindFileData->nFileSizeLow = DirInfo.FullDirInfo->EndOfFile.u.LowPart; - memcpy (lpFindFileData->cFileName, lpFileInfo->FileName, lpFileInfo->FileNameLength); - lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0; + /* 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; - memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName, lpFileInfo->ShortNameLength); - lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0; -} + /* Unused dwReserved1 field */ + lpFindFileData->dwReserved1 = 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) + if (fInfoLevelId == FindExInfoStandard) { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + RtlCopyMemory(lpFindFileData->cFileName, + DirInfo.BothDirInfo->FileName, + DirInfo.BothDirInfo->FileNameLength); + lpFindFileData->cFileName[DirInfo.BothDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; - 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; + RtlCopyMemory(lpFindFileData->cAlternateFileName, + DirInfo.BothDirInfo->ShortName, + DirInfo.BothDirInfo->ShortNameLength); + lpFindFileData->cAlternateFileName[DirInfo.BothDirInfo->ShortNameLength / sizeof(WCHAR)] = UNICODE_NULL; } - - do + else if (fInfoLevelId == FindExInfoBasic) { - if (IData->HasData) - { - if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - FoundFile = IData->pFileInfo; - } + RtlCopyMemory(lpFindFileData->cFileName, + DirInfo.FullDirInfo->FileName, + DirInfo.FullDirInfo->FileNameLength); + lpFindFileData->cFileName[DirInfo.FullDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; - 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) + lpFindFileData->cAlternateFileName[0] = UNICODE_NULL; + } + else { - _SEH2_TRY - { - InternalCopyFindDataW(lpFindFileData, - FoundFile); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - } - _SEH2_END; + /* Invalid InfoLevelId */ + ASSERT(FALSE); } - - if (Locked) - RtlLeaveCriticalSection(&IData->Lock); } - - if (!NT_SUCCESS(Status)) + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - BaseSetLastNTError (Status); - return FALSE; } - else if (FoundFile == NULL) - { - SetLastError (ERROR_NO_MORE_FILES); - return FALSE; - } + _SEH2_END; - return TRUE; + return; } - -/* - * @implemented - */ -HANDLE -WINAPI -InternalFindFirstFile ( - LPCWSTR lpFileName, - BOOLEAN DirectoryOnly, - PVOID lpFindFileData - ) +static VOID +CopyStreamInfo(IN OUT PFIND_STREAM_DATA FindStreamData, + OUT PWIN32_FIND_STREAM_DATA lpFindStreamData) { - 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; + ASSERT(FindStreamData->CurrentInfo); - TRACE("FindFirstFileW(lpFileName %S)\n", - lpFileName); + switch (FindStreamData->InfoLevel) + { + case FindStreamInfoStandard: + { + ULONG StreamNameLen = min(FindStreamData->CurrentInfo->StreamNameLength, + sizeof(lpFindStreamData->cStreamName) - sizeof(WCHAR)); - RtlZeroMemory(&PathFileName, - sizeof(PathFileName)); - RtlInitUnicodeString(&FileName, - lpFileName); + RtlZeroMemory(lpFindStreamData, sizeof(*lpFindStreamData)); - bResult = RtlDosPathNameToNtPathName_U (lpFileName, - &NtPathU, - (PCWSTR *)((ULONG_PTR)&PathFileName.Buffer), - &DirInfo); - if (FALSE == bResult) - { - SetLastError(ERROR_PATH_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } + lpFindStreamData->StreamSize.QuadPart = FindStreamData->CurrentInfo->StreamSize.QuadPart; + RtlCopyMemory(lpFindStreamData->cStreamName, + FindStreamData->CurrentInfo->StreamName, + StreamNameLen); + lpFindStreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = UNICODE_NULL; - /* Save the buffer pointer for later, we need to free it! */ - NtPathBuffer = NtPathU.Buffer; + break; + } - /* 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; + default: + ASSERT(FALSE); + break; + } - 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); - } - } + return; +} - /* 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); +/* PUBLIC FUNCTIONS ***********************************************************/ - 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; -} - - /* * @implemented */ @@ -464,27 +244,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; - } + if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; - 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)) { @@ -496,7 +272,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)) { @@ -512,6 +288,22 @@ /* * @implemented */ +HANDLE +WINAPI +FindFirstFileW(IN LPCWSTR lpFileName, + OUT LPWIN32_FIND_DATAW lpFindFileData) +{ + return FindFirstFileExW(lpFileName, + FindExInfoStandard, + lpFindFileData, + FindExSearchNameMatch, + NULL, 0); +} + + +/* + * @implemented + */ BOOL WINAPI FindNextFileA(IN HANDLE hFindFile, @@ -522,17 +314,16 @@ UNICODE_STRING UTF8; WIN32_FIND_DATAW FindFileDataW; - if (!FindNextFileW(hFindFile, &FindFileDataW)) - { - return FALSE; - } + 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 +334,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)) { @@ -560,123 +351,202 @@ */ BOOL WINAPI -FindClose ( - HANDLE hFindFile - ) +FindNextFileW(IN HANDLE hFindFile, + OUT LPWIN32_FIND_DATAW lpFindFileData) { - PKERNEL32_FIND_DATA_HEADER IHeader; + NTSTATUS Status = STATUS_SUCCESS; + DIR_INFORMATION FoundFile = {NULL}; - TRACE("FindClose(hFindFile %x)\n",hFindFile); + TRACE("FindNextFileW(%lx, 0x%p)\n", hFindFile, lpFindFileData); - if (hFindFile == FIND_DEVICE_HANDLE) - return TRUE; + if (hFindFile != FIND_DEVICE_HANDLE) + { + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile; + PFIND_FILE_DATA FindFileData; + FINDEX_INFO_LEVELS InfoLevel; + FILE_INFORMATION_CLASS FileInfoClass; + IO_STATUS_BLOCK IoStatusBlock; + DIR_INFORMATION DirInfo = {NULL}, NextDirInfo = {NULL}; - if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) - { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE || + FindDataHandle->Type != FindFile) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; + FindFileData = FindDataHandle->u.FindFileData; + InfoLevel = FindFileData->InfoLevel; + FileInfoClass = (InfoLevel == FindExInfoStandard + ? FileBothDirectoryInformation + : FileFullDirectoryInformation); - 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; - } + _SEH2_TRY + { + RtlEnterCriticalSection(&FindDataHandle->Lock); - case StreamFind: - { - PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap (RtlGetProcessHeap(), 0, IData->pFileStreamInfo); - } - break; - } + do + { + if (FindFileData->NextDirInfo.DirInfo == NULL) + { + Status = NtQueryDirectoryFile(FindFileData->Handle, + NULL, NULL, NULL, + &IoStatusBlock, + &FindFileData->Buffer, + sizeof(FindFileData->Buffer), + FileInfoClass, + 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; + } - default: - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + FindFileData->NextDirInfo.DirInfo = &FindFileData->Buffer; + } - RtlFreeHeap (RtlGetProcessHeap(), 0, IHeader); + DirInfo = FindFileData->NextDirInfo; - return TRUE; -} + if (DirInfo.FullDirInfo->NextEntryOffset != 0) + { + ULONG_PTR BufferEnd = (ULONG_PTR)&FindFileData->Buffer + sizeof(FindFileData->Buffer); + PWSTR pFileName; + FindFileData->NextDirInfo.DirInfo = (PVOID)((ULONG_PTR)DirInfo.DirInfo + + DirInfo.FullDirInfo->NextEntryOffset); + NextDirInfo = FindFileData->NextDirInfo; -/* - * @implemented - */ -HANDLE -WINAPI -FindFirstFileW(IN LPCWSTR lpFileName, - OUT LPWIN32_FIND_DATAW lpFindFileData) -{ - return FindFirstFileExW(lpFileName, - FindExInfoStandard, - lpFindFileData, - FindExSearchNameMatch, - NULL, - 0); + 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) + { + CopyFindData(lpFindFileData, InfoLevel, FoundFile); + } + + RtlLeaveCriticalSection(&FindDataHandle->Lock); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + } + + 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 -FindNextFileW(IN HANDLE hFindFile, - OUT LPWIN32_FIND_DATAW lpFindFileData) +FindClose(HANDLE hFindFile) { - return InternalFindNextFile(hFindFile, - NULL, - lpFindFileData); -} + BOOL bRet = FALSE; + TRACE("FindClose(hFindFile %x)\n", hFindFile); -/* - * @unimplemented - */ -HANDLE -WINAPI -FindFirstFileExW(IN LPCWSTR lpFileName, - IN FINDEX_INFO_LEVELS fInfoLevelId, - OUT LPVOID lpFindFileData, - IN FINDEX_SEARCH_OPS fSearchOp, - LPVOID lpSearchFilter, - IN DWORD dwAdditionalFlags) -{ - if (fInfoLevelId != FindExInfoStandard) + if (hFindFile == FIND_DEVICE_HANDLE) + return TRUE; + + if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) { - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; } - if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories) + /* Protect with SEH against closing attempts on invalid handles. */ + _SEH2_TRY { - if (lpSearchFilter) + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile; + + switch (FindDataHandle->Type) { - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + case FindFile: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + NtClose(FindDataHandle->u.FindFileData->Handle); + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + bRet = TRUE; + 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); + + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + bRet = TRUE; + break; + } + + default: + SetLastError(ERROR_INVALID_HANDLE); + break; } - - return InternalFindFirstFile (lpFileName, - fSearchOp == FindExSearchLimitToDirectories, - lpFindFileData); } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + BaseSetLastNTError(_SEH2_GetExceptionCode()); + bRet = FALSE; + } + _SEH2_END; - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + return bRet; } + /* * @unimplemented */ @@ -695,30 +565,37 @@ UNICODE_STRING UTF8; PUNICODE_STRING lpFileNameW; WIN32_FIND_DATAW FindFileDataW; + LPWIN32_FIND_DATAA lpFindFileDataA = (LPWIN32_FIND_DATAA)lpFindFileData; - lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); - if (!lpFileNameW) + 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; - } + if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileDataA, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName)); RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); - Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cFileName; + Ansi.Buffer = lpFindFileDataA->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileDataA->cFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -727,51 +604,291 @@ 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)) + if (fInfoLevelId != FindExInfoBasic) { - FindClose(hSearch); - BaseSetLastNTError(Status); - return INVALID_HANDLE_VALUE; + 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; } -static VOID -InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData, - OUT LPVOID lpFindStreamData) +/* + * @unimplemented + */ +HANDLE +WINAPI +FindFirstFileExW(IN LPCWSTR lpFileName, + IN FINDEX_INFO_LEVELS fInfoLevelId, + OUT LPVOID lpFindFileData, + IN FINDEX_SEARCH_OPS fSearchOp, + LPVOID lpSearchFilter, + IN DWORD dwAdditionalFlags) { - ASSERT(IData->pCurrent); + TRACE("FindFirstFileExW(lpFileName %S)\n", lpFileName); - switch (IData->InfoLevel) + if ((fInfoLevelId != FindExInfoStandard && fInfoLevelId != FindExInfoBasic) || + fSearchOp == FindExSearchLimitToDevices || + dwAdditionalFlags & ~FIND_FIRST_EX_CASE_SENSITIVE /* only supported flag for now */) { - case FindStreamInfoStandard: + SetLastError(fSearchOp == FindExSearchLimitToDevices + ? ERROR_NOT_SUPPORTED + : ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } + + 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; + + /* + * Can 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) { - ULONG StreamNameLen; - WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData; + SetLastError(ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } - StreamNameLen = IData->pCurrent->StreamNameLength; - if (StreamNameLen > sizeof(StreamData->cStreamName) - sizeof(WCHAR)) - StreamNameLen = sizeof(StreamData->cStreamName) - sizeof(WCHAR); + if (!RtlDosPathNameToNtPathName_U(lpFileName, + &NtPath, + (PCWSTR*)&FilePattern.Buffer, + &RelativePath)) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } +/* + DPRINT1("lpFileName = '%S'\n", lpFileName); + DPRINT1("NtPath.Buffer = '%S'\n", NtPath.Buffer); + DPRINT1("FilePattern.Buffer = '%S'\n", FilePattern.Buffer); + DPRINT1("RelativePath.RelativeName = '%wZ'\n", &RelativePath.RelativeName); + DPRINT1("NtPath - Before : \"%wZ\"\n", &NtPath); +*/ - StreamData->StreamSize.QuadPart = IData->pCurrent->StreamSize.QuadPart; - RtlCopyMemory(StreamData->cStreamName, - IData->pCurrent->StreamName, - StreamNameLen); - StreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = L'\0'; - break; + /* 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; + } } - default: - ASSERT(FALSE); - break; + /* 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); + } + } + +/* + DPRINT1("NtPath - After : \"%wZ\"\n", &NtPath); + TRACE("lpFileName: \"%S\"\n", lpFileName); + // TRACE("NtPath: \"%wZ\"\n", &NtPath); + TRACE("FilePattern: \"%wZ\"\n", &FilePattern); + TRACE("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) && (Status != STATUS_BUFFER_OVERFLOW)) + { + NtClose(hDirectory); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + ASSERT(DirInfo.FullDirInfo->NextEntryOffset == 0); + + if ((fSearchOp != FindExSearchLimitToDirectories) || + (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + CopyFindData(Win32FindData, fInfoLevelId, DirInfo); + } + else + { + NtClose(hDirectory); + SetLastError(ERROR_NO_MORE_FILES); + return INVALID_HANDLE_VALUE; + } + + /* + * Initialization of the "Find File 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; + } } @@ -785,11 +902,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 +918,18 @@ return INVALID_HANDLE_VALUE; } - /* validate & translate the filename */ + /* Validate & 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 +938,42 @@ 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; - } + 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) + /* Create the search context */ + 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 */ + FindDataHandle->Type = FindStream; + FindDataHandle->u.FindStreamData = (PFIND_STREAM_DATA)(FindDataHandle + 1); + FindStreamData = FindDataHandle->u.FindStreamData; - /* capture all information about the streams */ - IData->InfoLevel = InfoLevel; - IData->pCurrent = NULL; - IData->pFileStreamInfo = NULL; + FindStreamData->InfoLevel = InfoLevel; + FindStreamData->FileStreamInfo = NULL; + FindStreamData->CurrentInfo = NULL; do { BufferSize += 0x1000; - if (IData->pFileStreamInfo == NULL) + if (FindStreamData->FileStreamInfo == NULL) { - IData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - BufferSize); - if (IData->pFileStreamInfo == NULL) + FindStreamData->FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + BufferSize); + if (FindStreamData->FileStreamInfo == NULL) { Status = STATUS_NO_MEMORY; break; @@ -873,8 +984,8 @@ PFILE_STREAM_INFORMATION pfsi; pfsi = RtlReAllocateHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo, + 0, // HEAP_ZERO_MEMORY, + FindStreamData->FileStreamInfo, BufferSize); if (pfsi == NULL) { @@ -882,12 +993,12 @@ break; } - IData->pFileStreamInfo = pfsi; + FindStreamData->FileStreamInfo = pfsi; } Status = NtQueryInformationFile(FileHandle, &IoStatusBlock, - IData->pFileStreamInfo, + FindStreamData->FileStreamInfo, BufferSize, FileStreamInformation); @@ -895,49 +1006,37 @@ if (NT_SUCCESS(Status)) { - NtClose(FileHandle); - FileHandle = NULL; + /* Select the first stream and return the information */ + FindStreamData->CurrentInfo = FindStreamData->FileStreamInfo; + CopyStreamInfo(FindStreamData, lpFindStreamData); - /* select the first stream and return the information */ - IData->pCurrent = IData->pFileStreamInfo; - InternalCopyStreamInfo(IData, - lpFindStreamData); - - /* all done */ + /* All done */ Status = STATUS_SUCCESS; } + else + { + if (FindStreamData->FileStreamInfo) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, FindStreamData->FileStreamInfo); + } -Cleanup: - if (FileHandle != NULL) - { - NtClose(FileHandle); + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); } - RtlFreeHeap(RtlGetProcessHeap(), - 0, - NtPathU.Buffer); +Cleanup: + if (FileHandle) NtClose(FileHandle); - if (!NT_SUCCESS(Status)) + RtlFreeHeap(RtlGetProcessHeap(), 0, NtFilePath.Buffer); + + if (NT_SUCCESS(Status)) { - if (IHeader != NULL) - { - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo); - } - - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IHeader); - } - + return (HANDLE)FindDataHandle; + } + else + { BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; } - - return (HANDLE)IHeader; } @@ -949,37 +1048,33 @@ FindNextStreamW(IN HANDLE hFindStream, OUT LPVOID lpFindStreamData) { - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_STREAM_DATA IData; + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindStream; + PFIND_STREAM_DATA FindStreamData; - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream; if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE || - IHeader->Type != StreamFind) + FindDataHandle->Type != FindStream) { - SetLastError (ERROR_INVALID_HANDLE); + SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); + FindStreamData = FindDataHandle->u.FindStreamData; - /* select next stream if possible */ - if (IData->pCurrent->NextEntryOffset != 0) + /* Select next stream if possible */ + if (FindStreamData->CurrentInfo->NextEntryOffset != 0) { - IData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo + - IData->pCurrent->NextEntryOffset); + FindStreamData->CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)FindStreamData->FileStreamInfo + + FindStreamData->CurrentInfo->NextEntryOffset); + + /* Return the information */ + CopyStreamInfo(FindStreamData, lpFindStreamData); + return TRUE; } else { SetLastError(ERROR_HANDLE_EOF); return FALSE; } - - /* return the information */ - InternalCopyStreamInfo(IData, - lpFindStreamData); - - return TRUE; } - /* EOF */ Index: include/ndk/iotypes.h =================================================================== --- include/ndk/iotypes.h (révision 57391) +++ include/ndk/iotypes.h (copie de travail) @@ -524,6 +524,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 { ULONG NextEntryOffset; Index: include/psdk/winbase.h =================================================================== --- include/psdk/winbase.h (révision 57391) +++ include/psdk/winbase.h (copie de travail) @@ -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;