Index: dll/win32/kernel32/client/file/find.c =================================================================== --- dll/win32/kernel32/client/file/find.c (révision 57323) +++ dll/win32/kernel32/client/file/find.c (copie de travail) @@ -1,37 +1,43 @@ -/* $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 + * 10/09/2012 : Reworking (hbelusca) */ /* INCLUDES *****************************************************************/ #include -#define NDEBUG +// #define NDEBUG #include DEBUG_CHANNEL(kernel32file); /* 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 _KERNEL32_FIND_DATA_TYPE +{ + FindFile = 1, + FindStream = 2 +} KERNEL32_FIND_DATA_TYPE; 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; + HANDLE DirectoryHandle; + FINDEX_INFO_LEVELS FileInfoLevel; + FINDEX_SEARCH_OPS FileSearchOp; + + BOOLEAN HasMoreData; + PVOID pNextDirInfo; // Ptr to the next file info structure in the buffer. + BYTE Buffer[FIND_DATA_SIZE]; } KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA; typedef struct _KERNEL32_FIND_STREAM_DATA @@ -41,410 +47,141 @@ PFILE_STREAM_INFORMATION pCurrent; } KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA; -typedef enum _KERNEL32_FIND_DATA_TYPE +typedef struct _KERNEL32_FIND_DATA_HANDLE { - 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; + RTL_CRITICAL_SECTION Lock; + union + { + PKERNEL32_FIND_FILE_DATA FindFileData; + PKERNEL32_FIND_STREAM_DATA FindStreamData; + } u; +} KERNEL32_FIND_DATA_HANDLE, *PKERNEL32_FIND_DATA_HANDLE; + + /* FUNCTIONS ****************************************************************/ static VOID -InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData, - LPCWSTR lpFileName, - ULONG DeviceNameInfo) +InternalCopyDeviceFindDataW(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) +InternalCopyFindDataW(OUT LPWIN32_FIND_DATAW lpFindFileData, + IN FINDEX_INFO_LEVELS fInfoLevelId, + IN PVOID lpFileInfo) { - 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 + { + PFILE_FULL_DIR_INFORMATION lpFileFullInfo = (PFILE_FULL_DIR_INFORMATION)lpFileInfo; - lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart; - lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart; + lpFindFileData->dwFileAttributes = lpFileFullInfo->FileAttributes; - lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart; - lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart; + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftCreationTime, lpFileFullInfo->CreationTime); + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastAccessTime, lpFileFullInfo->LastAccessTime); + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastWriteTime, lpFileFullInfo->LastWriteTime); - lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart; - lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart; + lpFindFileData->nFileSizeHigh = lpFileFullInfo->EndOfFile.u.HighPart; + lpFindFileData->nFileSizeLow = lpFileFullInfo->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 (lpFileFullInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + lpFindFileData->dwReserved0 = lpFileFullInfo->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; - } + PFILE_BOTH_DIR_INFORMATION lpFileBothInfo = (PFILE_BOTH_DIR_INFORMATION)lpFileInfo; - IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); + RtlCopyMemory(lpFindFileData->cFileName, + lpFileBothInfo->FileName, + lpFileBothInfo->FileNameLength); + lpFindFileData->cFileName[lpFileBothInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; - if (SearchPattern == NULL) - { - RtlEnterCriticalSection(&IData->Lock); - Locked = TRUE; + RtlCopyMemory(lpFindFileData->cAlternateFileName, + lpFileBothInfo->ShortName, + lpFileBothInfo->ShortNameLength); + lpFindFileData->cAlternateFileName[lpFileBothInfo->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, + lpFileFullInfo->FileName, + lpFileFullInfo->FileNameLength); + lpFindFileData->cFileName[lpFileFullInfo->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 +InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_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->pCurrent); - TRACE("FindFirstFileW(lpFileName %S)\n", - lpFileName); + switch (FindStreamData->InfoLevel) + { + case FindStreamInfoStandard: + { + ULONG StreamNameLen = min(FindStreamData->pCurrent->StreamNameLength, + sizeof(lpFindStreamData->cStreamName) - sizeof(WCHAR)); - RtlZeroMemory(&PathFileName, - sizeof(PathFileName)); - RtlInitUnicodeString(&FileName, - lpFileName); + lpFindStreamData->StreamSize.QuadPart = FindStreamData->pCurrent->StreamSize.QuadPart; + RtlCopyMemory(lpFindStreamData->cStreamName, + FindStreamData->pCurrent->StreamName, + StreamNameLen); + lpFindStreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = UNICODE_NULL; - bResult = RtlDosPathNameToNtPathName_U (lpFileName, - &NtPathU, - (PCWSTR *)((ULONG_PTR)&PathFileName.Buffer), - &DirInfo); - if (FALSE == bResult) - { - SetLastError(ERROR_PATH_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } + break; + } - /* Save the buffer pointer for later, we need to free it! */ - NtPathBuffer = NtPathU.Buffer; + default: + ASSERT(FALSE); + 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; - - 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; + return; } @@ -463,6 +200,8 @@ PUNICODE_STRING lpFileNameW; WIN32_FIND_DATAW FindFileDataW; + TRACE("FindFirstFileA called, lpFileName = %s, lpFindFileData = 0x%p\n", lpFileName, lpFindFileData); + lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); if (!lpFileNameW) { @@ -479,15 +218,18 @@ return INVALID_HANDLE_VALUE; } - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileData, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); Ansi.Buffer = lpFindFileData->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileData->cFileName); // MAX_PATH Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { + DPRINT1("FindFirstFileA - 1\n"); FindClose(hSearch); BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; @@ -496,10 +238,11 @@ RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); Ansi.Buffer = lpFindFileData->cAlternateFileName; Ansi.Length = 0; - Ansi.MaximumLength = 14; + Ansi.MaximumLength = sizeof(lpFindFileData->cAlternateFileName); // 14 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { + DPRINT1("FindFirstFileA - 2\n"); FindClose(hSearch); BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; @@ -512,6 +255,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, @@ -527,15 +286,18 @@ return FALSE; } - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileData, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); Ansi.Buffer = lpFindFileData->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileData->cFileName); // MAX_PATH Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { + DPRINT1("FindNextFileA - 1\n"); BaseSetLastNTError(Status); return FALSE; } @@ -543,10 +305,11 @@ RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); Ansi.Buffer = lpFindFileData->cAlternateFileName; Ansi.Length = 0; - Ansi.MaximumLength = 14; + Ansi.MaximumLength = sizeof(lpFindFileData->cAlternateFileName); // 14 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { + DPRINT1("FindNextFileA - 2\n"); BaseSetLastNTError(Status); return FALSE; } @@ -560,123 +323,208 @@ */ BOOL WINAPI -FindClose ( - HANDLE hFindFile - ) +FindNextFileW(IN HANDLE hFindFile, + OUT LPWIN32_FIND_DATAW lpFindFileData) { - PKERNEL32_FIND_DATA_HEADER IHeader; + NTSTATUS Status = STATUS_SUCCESS; + PVOID 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) + { + PKERNEL32_FIND_DATA_HANDLE FindDataHandle = (PKERNEL32_FIND_DATA_HANDLE)hFindFile; + PKERNEL32_FIND_FILE_DATA FindFileData; + FINDEX_INFO_LEVELS FileInfoLevel; + FILE_INFORMATION_CLASS FileInformationClass; + IO_STATUS_BLOCK IoStatusBlock; + PFILE_FULL_DIR_INFORMATION pDirInfo = NULL, pNextDirInfo; - 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; + FileInfoLevel = FindFileData->FileInfoLevel; + FileInformationClass = (FileInfoLevel == 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; - } + 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->pNextDirInfo == NULL) + { + Status = NtQueryDirectoryFile(FindFileData->DirectoryHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + &FindFileData->Buffer, + sizeof(FindFileData->Buffer), + FileInformationClass, + FALSE, + NULL, /* Use the file pattern from the first call */ + FALSE); + if (Status == STATUS_BUFFER_OVERFLOW) + { + FindFileData->HasMoreData = TRUE; + Status = STATUS_SUCCESS; + } + else + { + DPRINT1("Status = 0x%p\n", Status); + if (!NT_SUCCESS(Status)) break; + FindFileData->HasMoreData = FALSE; + } - default: - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + FindFileData->pNextDirInfo = &FindFileData->Buffer; + } - RtlFreeHeap (RtlGetProcessHeap(), 0, IHeader); + pDirInfo = FindFileData->pNextDirInfo; - return TRUE; -} + if (pDirInfo->NextEntryOffset != 0) + { + ULONG_PTR BufferEnd = (ULONG_PTR)&FindFileData->Buffer + sizeof(FindFileData->Buffer); + PWSTR pFileName; + FindFileData->pNextDirInfo = (PVOID)((ULONG_PTR)pDirInfo + + pDirInfo->NextEntryOffset); + pNextDirInfo = (PFILE_FULL_DIR_INFORMATION)FindFileData->pNextDirInfo; + pFileName = (FileInfoLevel == FindExInfoStandard + ? ((PFILE_BOTH_DIR_INFORMATION)pNextDirInfo)->FileName + : ((PFILE_FULL_DIR_INFORMATION)pNextDirInfo)->FileName); + + /* Be paranoid and make sure that the next entry is completely there */ + if (BufferEnd < (ULONG_PTR)pNextDirInfo || + BufferEnd < (ULONG_PTR)&pNextDirInfo->FileNameLength + sizeof(pNextDirInfo->FileNameLength) || + BufferEnd <= (ULONG_PTR)((ULONG_PTR)pFileName + pNextDirInfo->FileNameLength)) + { + FindFileData->pNextDirInfo = NULL; + } + } + else + { + FindFileData->pNextDirInfo = NULL; + } + /* - * @implemented - */ -HANDLE -WINAPI -FindFirstFileW(IN LPCWSTR lpFileName, - OUT LPWIN32_FIND_DATAW lpFindFileData) -{ - return FindFirstFileExW(lpFileName, - FindExInfoStandard, - lpFindFileData, - FindExSearchNameMatch, - NULL, - 0); + /\* Don't return '.' and '..' in the root of the drive *\/ + if (FindFileData->IsRootDir) + { + if ( (pDirInfo->FileNameLength == sizeof(WCHAR) && pDirInfo->FileName[0] == L'.') || + (pDirInfo->FileNameLength == 2 * sizeof(WCHAR) && pDirInfo->FileName[0] == L'.' && + pDirInfo->FileName[1] == L'.') ) + { + continue; + } + } +*/ + if ((FindFileData->FileSearchOp != FindExSearchLimitToDirectories) || + (pDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + FoundFile = pDirInfo; + } + } while ( FoundFile == NULL && (FindFileData->pNextDirInfo || FindFileData->HasMoreData) ); + + if (FoundFile != NULL) + { + InternalCopyFindDataW(lpFindFileData, + FileInfoLevel, + FoundFile); + } + + RtlLeaveCriticalSection(&FindDataHandle->Lock); + } + + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + else if (FoundFile == 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); -} + ERR("FindClose(hFindFile %x)\n",hFindFile); + if (hFindFile == FIND_DEVICE_HANDLE) + return TRUE; -/* - * @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 || 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) + PKERNEL32_FIND_DATA_HANDLE FindDataHandle = (PKERNEL32_FIND_DATA_HANDLE)hFindFile; + + switch (FindDataHandle->Type) { - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + case FindFile: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + NtClose(FindDataHandle->u.FindFileData->DirectoryHandle); + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + break; + } + + case FindStream: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + if (FindDataHandle->u.FindStreamData->pFileStreamInfo != NULL) + { + RtlFreeHeap(RtlGetProcessHeap(), + 0, + FindDataHandle->u.FindStreamData->pFileStreamInfo); + } + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + break; + } + + default: + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; } - return InternalFindFirstFile (lpFileName, - fSearchOp == FindExSearchLimitToDirectories, - lpFindFileData); + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + return TRUE; } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + BaseSetLastNTError(_SEH2_GetExceptionCode()); + return FALSE; + } + _SEH2_END; - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + return FALSE; } + /* * @unimplemented */ @@ -695,7 +543,17 @@ 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) { @@ -713,65 +571,300 @@ return INVALID_HANDLE_VALUE; } - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileDataA, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATA, 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); // MAX_PATH Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { + DPRINT1("FindFirstFileExA - 1\n"); 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)) + 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); // 14 + Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("FindFirstFileExA - 2\n"); + 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); + ERR("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; + PKERNEL32_FIND_DATA_HANDLE FindDataHandle; + PKERNEL32_FIND_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]; + + /* 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); + ERR("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); + // RtlFreeUnicodeString(&NtPath); + + /* OK, it's really a DOS device */ + InternalCopyDeviceFindDataW(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); + } + } + + ERR("NtPath - After : \"%wZ\"\n", &NtPath); + ERR("lpFileName: \"%ws\"\n", lpFileName); + //ERR("NtPath: \"%wZ\"\n", &NtPath); + ERR("FilePattern: \"%wZ\"\n", &FilePattern); + ERR("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); + // RtlFreeUnicodeString(&NtPath); + + /* 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); + // RtlFreeUnicodeString(&NtPath); + 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, + &DirectoryInfo, + sizeof(DirectoryInfo), + (fInfoLevelId == FindExInfoStandard + ? FileBothDirectoryInformation + : FileFullDirectoryInformation), + TRUE, // Return a single entry. + &FilePattern, + TRUE /*FALSE*/); + + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + // RtlFreeUnicodeString(&NtPath); + + if (!NT_SUCCESS(Status)) + { + NtClose(hDirectory); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + InternalCopyFindDataW(Win32FindData, + fInfoLevelId, + &DirectoryInfo); + + /* + * Initialization of the "Find File Handle". + */ + FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(KERNEL32_FIND_DATA_HANDLE) + + sizeof(KERNEL32_FIND_FILE_DATA)); + if (!FindDataHandle) + { + NtClose(hDirectory); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + FindDataHandle->Type = FindFile; + FindDataHandle->u.FindFileData = (PKERNEL32_FIND_FILE_DATA)(FindDataHandle + 1); + FindFileData = FindDataHandle->u.FindFileData; + + FindFileData->DirectoryHandle = hDirectory; + FindFileData->FileInfoLevel = fInfoLevelId; + FindFileData->FileSearchOp = fSearchOp; + FindFileData->HasMoreData = FALSE; + FindFileData->pNextDirInfo = NULL; + + /* The critical section must always be initialized */ + Status = RtlInitializeCriticalSection(&FindDataHandle->Lock); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + NtClose(hDirectory); + + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + return (HANDLE)FindDataHandle; } + else + { + SetLastError(ERROR_NOT_SUPPORTED); + return INVALID_HANDLE_VALUE; + } } @@ -785,25 +878,26 @@ OUT LPVOID lpFindStreamData, IN DWORD dwFlags) { - PKERNEL32_FIND_DATA_HEADER IHeader = NULL; - PKERNEL32_FIND_STREAM_DATA IData = NULL; + PKERNEL32_FIND_DATA_HANDLE FindDataHandle = NULL; + PKERNEL32_FIND_STREAM_DATA FindStreamData; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING NtPathU; + UNICODE_STRING NtFilePath; HANDLE FileHandle = NULL; NTSTATUS Status; ULONG BufferSize = 0; - if (dwFlags != 0 || InfoLevel != FindStreamInfoStandard || + if (dwFlags != 0 || + InfoLevel != FindStreamInfoStandard || lpFindStreamData == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } - /* validate & translate the filename */ + /* Validate & translate the filename */ if (!RtlDosPathNameToNtPathName_U(lpFileName, - &NtPathU, + &NtFilePath, NULL, NULL)) { @@ -811,9 +905,9 @@ return INVALID_HANDLE_VALUE; } - /* open the file */ + /* Open the file */ InitializeObjectAttributes(&ObjectAttributes, - &NtPathU, + &NtFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); @@ -834,35 +928,36 @@ 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(KERNEL32_FIND_DATA_HANDLE) + + sizeof(KERNEL32_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 = (PKERNEL32_FIND_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->pFileStreamInfo = NULL; + FindStreamData->pCurrent = NULL; do { BufferSize += 0x1000; - if (IData->pFileStreamInfo == NULL) + if (FindStreamData->pFileStreamInfo == NULL) { - IData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - BufferSize); - if (IData->pFileStreamInfo == NULL) + FindStreamData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + BufferSize); + if (FindStreamData->pFileStreamInfo == NULL) { Status = STATUS_NO_MEMORY; break; @@ -873,8 +968,8 @@ PFILE_STREAM_INFORMATION pfsi; pfsi = RtlReAllocateHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo, + 0, // HEAP_ZERO_MEMORY + FindStreamData->pFileStreamInfo, BufferSize); if (pfsi == NULL) { @@ -882,12 +977,12 @@ break; } - IData->pFileStreamInfo = pfsi; + FindStreamData->pFileStreamInfo = pfsi; } Status = NtQueryInformationFile(FileHandle, &IoStatusBlock, - IData->pFileStreamInfo, + FindStreamData->pFileStreamInfo, BufferSize, FileStreamInformation); @@ -895,49 +990,40 @@ if (NT_SUCCESS(Status)) { - NtClose(FileHandle); - FileHandle = NULL; + /* Select the first stream and return the information */ + FindStreamData->pCurrent = FindStreamData->pFileStreamInfo; + InternalCopyStreamInfo(FindStreamData, lpFindStreamData); - /* select the first stream and return the information */ - IData->pCurrent = IData->pFileStreamInfo; - InternalCopyStreamInfo(IData, - lpFindStreamData); - - /* all done */ + /* All done */ Status = STATUS_SUCCESS; } - -Cleanup: - if (FileHandle != NULL) + else { - NtClose(FileHandle); - } - - RtlFreeHeap(RtlGetProcessHeap(), - 0, - NtPathU.Buffer); - - if (!NT_SUCCESS(Status)) - { - if (IHeader != NULL) + if (FindStreamData->pFileStreamInfo) { - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo); - } - RtlFreeHeap(RtlGetProcessHeap(), 0, - IHeader); + FindStreamData->pFileStreamInfo); } + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + } + +Cleanup: + if (FileHandle) NtClose(FileHandle); + + RtlFreeHeap(RtlGetProcessHeap(), 0, NtFilePath.Buffer); + // RtlFreeUnicodeString(&NtFilePath); + + if (NT_SUCCESS(Status)) + { + return (HANDLE)FindDataHandle; + } + else + { BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; } - - return (HANDLE)IHeader; } @@ -949,37 +1035,34 @@ FindNextStreamW(IN HANDLE hFindStream, OUT LPVOID lpFindStreamData) { - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_STREAM_DATA IData; + PKERNEL32_FIND_DATA_HANDLE FindDataHandle = (PKERNEL32_FIND_DATA_HANDLE)hFindStream; + PKERNEL32_FIND_STREAM_DATA FindStreamData; - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream; - if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE || - IHeader->Type != StreamFind) + if (hFindStream == NULL || + hFindStream == INVALID_HANDLE_VALUE || + 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->pCurrent->NextEntryOffset != 0) { - IData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo + - IData->pCurrent->NextEntryOffset); + FindStreamData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)FindStreamData->pFileStreamInfo + + FindStreamData->pCurrent->NextEntryOffset); + + /* Return the information */ + InternalCopyStreamInfo(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 57323) +++ 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 57323) +++ 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;