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; Index: lib/rtl/path.c =================================================================== --- lib/rtl/path.c (révision 57323) +++ lib/rtl/path.c (copie de travail) @@ -35,9 +35,9 @@ const UNICODE_STRING DeviceRootString = RTL_CONSTANT_STRING(L"\\\\.\\"); const UNICODE_STRING RtlpDosDevicesUncPrefix = RTL_CONSTANT_STRING(L"\\??\\UNC\\"); -const UNICODE_STRING RtlpWin32NtRootSlash = RTL_CONSTANT_STRING(L"\\\\?\\"); -const UNICODE_STRING RtlpDosSlashCONDevice = RTL_CONSTANT_STRING(L"\\\\.\\CON"); -const UNICODE_STRING RtlpDosDevicesPrefix = RTL_CONSTANT_STRING(L"\\??\\"); +const UNICODE_STRING RtlpWin32NtRootSlash = RTL_CONSTANT_STRING(L"\\\\?\\"); +const UNICODE_STRING RtlpDosSlashCONDevice = RTL_CONSTANT_STRING(L"\\\\.\\CON"); +const UNICODE_STRING RtlpDosDevicesPrefix = RTL_CONSTANT_STRING(L"\\??\\"); const UNICODE_STRING RtlpDosLPTDevice = RTL_CONSTANT_STRING(L"LPT"); const UNICODE_STRING RtlpDosCOMDevice = RTL_CONSTANT_STRING(L"COM"); @@ -141,7 +141,7 @@ { /* Stop if we hit something else than a space or period */ c = PathCopy.Buffer[PathChars - 1]; - if ((c != '.') && (c != ' ')) break; + if ((c != L'.') && (c != L' ')) break; /* Fixup the lengths */ PathCopy.Length -= sizeof(WCHAR); @@ -160,15 +160,15 @@ { /* Check if the character is a path or drive separator */ c = *End; - if ((c == '\\') || (c == '/') || ((c == ':') && (End == PathCopy.Buffer + 1))) + if ((c == L'\\') || (c == L'/') || ((c == L':') && (End == PathCopy.Buffer + 1))) { /* Get the next lower case character */ End++; - c = *End | ' '; // ' ' == ('z' - 'Z') + c = towlower(*End); /* Check if it's a DOS device (LPT, COM, PRN, AUX, or NUL) */ if ((End < &PathCopy.Buffer[OriginalLength / sizeof(WCHAR)]) && - ((c == 'l') || (c == 'c') || (c == 'p') || (c == 'a') || (c == 'n'))) + ((c == L'l') || (c == L'c') || (c == L'p') || (c == L'a') || (c == L'n'))) { /* Calculate the offset */ ReturnOffset = (USHORT)((PCHAR)End - (PCHAR)PathCopy.Buffer); @@ -190,8 +190,8 @@ } /* Get the next lower case character and check if it's a DOS device */ - c = *PathCopy.Buffer | ' '; // ' ' == ('z' - 'Z') - if ((c != 'l') && (c != 'c') && (c != 'p') && (c != 'a') && (c != 'n')) + c = towlower(*PathCopy.Buffer); + if ((c != L'l') && (c != L'c') && (c != L'p') && (c != L'a') && (c != L'n')) { /* Not LPT, COM, PRN, AUX, or NUL */ return 0; @@ -204,12 +204,12 @@ while (Start < End) { c = *Start; - if ((c == '.') || (c == ':')) break; + if ((c == L'.') || (c == L':')) break; Start++; } /* And then go backwards to get rid of spaces */ - while ((Start > PathCopy.Buffer) && (Start[-1] == ' ')) --Start; + while ((Start > PathCopy.Buffer) && (Start[-1] == L' ')) --Start; /* Finally see how many characters are left, and that's our size */ PathChars = (USHORT)(Start - PathCopy.Buffer); @@ -217,7 +217,7 @@ /* Check if this is a COM or LPT port, which has a digit after it */ if ((PathChars == 4) && - (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != '0'))) + (iswdigit(PathCopy.Buffer[3]) && (PathCopy.Buffer[3] != L'0'))) { /* Don't compare the number part, just check for LPT or COM */ PathCopy.Length -= sizeof(WCHAR); @@ -422,7 +422,7 @@ { /* Loop from the back until we find a path separator */ p = &NewBuffer[(DosLength - 1) / sizeof (WCHAR)]; - while (p > NewBuffer) if (*p-- == '\\') break; + while (p > NewBuffer) if (*p-- == L'\\') break; /* Was one found? */ if (p > NewBuffer) @@ -468,7 +468,7 @@ PCURDIR CurrentDirectory; /* Assume MAX_PATH for now */ - DPRINT("Relative: %lx DosName: %wZ NtName: %wZ, PartName: %p, RelativeName: %p\n", + DPRINT("Relative: %lx DosName: %wZ NtName: %p, PartName: %p, RelativeName: %p\n", HaveRelative, DosName, NtName, PartName, RelativeName); MaxLength = sizeof(BigBuffer); @@ -478,7 +478,7 @@ /* Capture input string */ CapturedDosName = *DosName; - /* Check for \\?\\ form */ + /* Check for \\?\ form */ if ((CapturedDosName.Length <= RtlpWin32NtRootSlash.Length) || (CapturedDosName.Buffer[0] != RtlpWin32NtRootSlash.Buffer[0]) || (CapturedDosName.Buffer[1] != RtlpWin32NtRootSlash.Buffer[1]) || @@ -494,7 +494,7 @@ /* Allocate a buffer to hold the path */ NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MaxLength); - DPRINT("Length: %lx\n", MaxLength); + DPRINT("MaxLength: %lx\n", MaxLength); if (!NewBuffer) return STATUS_NO_MEMORY; } else @@ -574,11 +574,11 @@ /* Now copy the prefix and the buffer */ RtlCopyMemory(NewBuffer, PrefixBuffer, PrefixLength); RtlCopyMemory((PCHAR)NewBuffer + PrefixLength, - &Buffer[PrefixCut], + Buffer + PrefixCut, PathLength - (PrefixCut * sizeof(WCHAR))); /* Compute the length */ - Length = PathLength - PrefixCut * sizeof(WCHAR) + PrefixLength; + Length = PathLength + PrefixLength - PrefixCut * sizeof(WCHAR); LengthChars = Length / sizeof(WCHAR); /* Setup the actual NT path string and terminate it */ @@ -642,12 +642,12 @@ if (RtlEqualUnicodeString(&FullPath, &CurrentDirectory->DosPath, TRUE)) { /* Make relative name string */ - RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + FullPath.Length - PrefixCut); + RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)NewBuffer + PrefixLength + FullPath.Length - PrefixCut * sizeof(WCHAR)); RelativeName->RelativeName.Length = (USHORT)(PathLength - FullPath.Length); /* If relative name starts with \, skip it */ if (RelativeName->RelativeName.Buffer[0] == L'\\') { - RelativeName->RelativeName.Buffer = (PWSTR)((ULONG_PTR)RelativeName->RelativeName.Buffer + sizeof(WCHAR)); + RelativeName->RelativeName.Buffer++; RelativeName->RelativeName.Length -= sizeof(WCHAR); } RelativeName->RelativeName.MaximumLength = RelativeName->RelativeName.Length; @@ -1198,11 +1198,11 @@ WCHAR *p, *next; /* convert every / into a \ */ - for (p = path; *p; p++) if (*p == '/') *p = '\\'; + for (p = path; *p; p++) if (*p == L'/') *p = L'\\'; /* collapse duplicate backslashes */ next = path + max( 1, mark ); - for (p = next; *p; p++) if (*p != '\\' || next[-1] != '\\') *next++ = *p; + for (p = next; *p; p++) if (*p != L'\\' || next[-1] != L'\\') *next++ = *p; *next = 0; p = path + mark; @@ -1212,7 +1212,7 @@ { switch(p[1]) { - case '\\': /* .\ component */ + case L'\\': /* .\ component */ next = p + 2; memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); continue; @@ -1220,14 +1220,14 @@ if (p > path + mark) p--; *p = 0; continue; - case '.': - if (p[2] == '\\') /* ..\ component */ + case L'.': + if (p[2] == L'\\') /* ..\ component */ { next = p + 3; if (p > path + mark) { p--; - while (p > path + mark && p[-1] != '\\') p--; + while (p > path + mark && p[-1] != L'\\') p--; } memmove( p, next, (wcslen(next) + 1) * sizeof(WCHAR) ); continue; @@ -1237,7 +1237,7 @@ if (p > path + mark) { p--; - while (p > path + mark && p[-1] != '\\') p--; + while (p > path + mark && p[-1] != L'\\') p--; if (p > path + mark) p--; } *p = 0; @@ -1247,17 +1247,17 @@ } } /* skip to the next component */ - while (*p && *p != '\\') p++; - if (*p == '\\') + while (*p && *p != L'\\') p++; + if (*p == L'\\') { /* remove last dot in previous dir name */ - if (p > path + mark && p[-1] == '.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) ); + if (p > path + mark && p[-1] == L'.') memmove( p-1, p, (wcslen(p) + 1) * sizeof(WCHAR) ); else p++; } } /* remove trailing spaces and dots (yes, Windows really does that, don't ask) */ - while (p > path + mark && (p[-1] == ' ' || p[-1] == '.')) p--; + while (p > path + mark && (p[-1] == L' ' || p[-1] == L'.')) p--; *p = 0; } @@ -1297,7 +1297,7 @@ WCHAR tmp[4]; /* return error if name only consists of spaces */ - for (ptr = name; *ptr; ptr++) if (*ptr != ' ') break; + for (ptr = name; *ptr; ptr++) if (*ptr != L' ') break; if (!*ptr) return 0; RtlAcquirePebLock(); @@ -1326,14 +1326,14 @@ case RtlPathTypeDriveRelative: /* c:foo */ dep = 2; - if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != ':') + if (towupper(name[0]) != towupper(cd->Buffer[0]) || cd->Buffer[1] != L':') { UNICODE_STRING var, val; - tmp[0] = '='; + tmp[0] = L'='; tmp[1] = name[0]; - tmp[2] = ':'; - tmp[3] = '\0'; + tmp[2] = L':'; + tmp[3] = L'\0'; var.Length = 3 * sizeof(WCHAR); var.MaximumLength = 4 * sizeof(WCHAR); var.Buffer = tmp; @@ -1357,14 +1357,14 @@ /* fall thru */ case STATUS_BUFFER_TOO_SMALL: reqsize = val.Length + sizeof(WCHAR); /* append trailing '\\' */ - val.Buffer[val.Length / sizeof(WCHAR)] = '\\'; + val.Buffer[val.Length / sizeof(WCHAR)] = L'\\'; ins_str = val.Buffer; break; case STATUS_VARIABLE_NOT_FOUND: reqsize = 3 * sizeof(WCHAR); tmp[0] = name[0]; - tmp[1] = ':'; - tmp[2] = '\\'; + tmp[1] = L':'; + tmp[2] = L'\\'; ins_str = tmp; RtlFreeHeap(RtlGetProcessHeap(), 0, val.Buffer); break; @@ -1381,7 +1381,7 @@ case RtlPathTypeRelative: /* foo */ reqsize = cd->Length; ins_str = cd->Buffer; - if (cd->Buffer[1] != ':') + if (cd->Buffer[1] != L':') { ptr = skip_unc_prefix( cd->Buffer ); mark = ptr - cd->Buffer; @@ -1391,16 +1391,16 @@ case RtlPathTypeRooted: /* \xxx */ #ifdef __WINE__ - if (name[0] == '/') /* may be a Unix path */ + if (name[0] == L'/') /* may be a Unix path */ { const WCHAR *ptr = name; int drive = find_drive_root( &ptr ); if (drive != -1) { reqsize = 3 * sizeof(WCHAR); - tmp[0] = 'A' + drive; - tmp[1] = ':'; - tmp[2] = '\\'; + tmp[0] = L'A' + drive; + tmp[1] = L':'; + tmp[2] = L'\\'; ins_str = tmp; mark = 3; dep = ptr - name; @@ -1408,11 +1408,11 @@ } } #endif - if (cd->Buffer[1] == ':') + if (cd->Buffer[1] == L':') { reqsize = 2 * sizeof(WCHAR); tmp[0] = cd->Buffer[0]; - tmp[1] = ':'; + tmp[1] = L':'; ins_str = tmp; mark = 3; } @@ -1428,10 +1428,10 @@ case RtlPathTypeRootLocalDevice: /* \\. */ reqsize = 4 * sizeof(WCHAR); dep = 3; - tmp[0] = '\\'; - tmp[1] = '\\'; - tmp[2] = '.'; - tmp[3] = '\\'; + tmp[0] = L'\\'; + tmp[1] = L'\\'; + tmp[2] = L'.'; + tmp[3] = L'\\'; ins_str = tmp; mark = 4; break; @@ -1503,7 +1503,7 @@ if (8 + sz + 2 > size) return sz + 10; wcscpy(buffer, DeviceRootW); memmove(buffer + 4, name + offset, sz); - buffer[4 + sz / sizeof(WCHAR)] = '\0'; + buffer[4 + sz / sizeof(WCHAR)] = L'\0'; /* file_part isn't set in this case */ return sz + 8; } @@ -1525,7 +1525,7 @@ } /* find file part */ - if (file_part && (ptr = wcsrchr(buffer, '\\')) != NULL && ptr >= buffer + 2 && *++ptr) + if (file_part && (ptr = wcsrchr(buffer, L'\\')) != NULL && ptr >= buffer + 2 && *++ptr) *file_part = ptr; return reqsize; } @@ -1654,7 +1654,7 @@ while (*p) { /* Looking for an extension */ - if (*p == '.') + if (*p == L'.') { /* No extension string needed -- it's part of the filename */ Extension = NULL; @@ -1712,7 +1712,7 @@ if (*Path) { /* Loop as long as there's no semicolon */ - while (*Path != ';') + while (*Path != L';') { /* Copy the next character */ *BufferStart++ = *Path++; @@ -1720,13 +1720,13 @@ } /* We found a semi-colon, to stop path processing on this loop */ - if (*Path == ';') ++Path; + if (*Path == L';') ++Path; } /* Add a terminating slash if needed */ - if ((BufferStart != NewBuffer) && (BufferStart[-1] != '\\')) + if ((BufferStart != NewBuffer) && (BufferStart[-1] != L'\\')) { - *BufferStart++ = '\\'; + *BufferStart++ = L'\\'; } /* Bail out if we reached the end */