Index: dll/win32/kernel32/client/file/find.c =================================================================== --- dll/win32/kernel32/client/file/find.c (révision 57391) +++ dll/win32/kernel32/client/file/find.c (copie de travail) @@ -1,453 +1,233 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries - * FILE: lib/kernel32/file/find.c + * FILE: kernel32/file/find.c * PURPOSE: Find functions - * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) + * PROGRAMMERS: Ariadne (ariadne@xs4all.nl) * Pierre Schweitzer (pierre.schweitzer@reactos.org) + * Hermes BELUSCA - MAITO * UPDATE HISTORY: * Created 01/11/98 + * 26/09/2012 : Reworking (hbelusca) */ -/* INCLUDES *****************************************************************/ +/* INCLUDES *******************************************************************/ #include #define NDEBUG #include DEBUG_CHANNEL(kernel32file); -/* TYPES ********************************************************************/ +/* TYPES **********************************************************************/ -#define FIND_DATA_SIZE 0x4000 +#define FIND_DATA_SIZE 0x4000 +#define FIND_DEVICE_HANDLE ((HANDLE)0x1) -#define FIND_DEVICE_HANDLE ((HANDLE)0x1) +typedef enum _FIND_DATA_TYPE +{ + FindFile = 1, + FindStream = 2 +} FIND_DATA_TYPE; -typedef struct _KERNEL32_FIND_FILE_DATA +/* + * FILE_FULL_DIR_INFORMATION and FILE_BOTH_DIR_INFORMATION structures layout. + * + * + * struct FILE_FULL_DIR_INFORMATION | struct FILE_BOTH_DIR_INFORMATION + * { | + * ULONG NextEntryOffset; | ULONG NextEntryOffset; + * ULONG FileIndex; | ULONG FileIndex; + * LARGE_INTEGER CreationTime; | LARGE_INTEGER CreationTime; + * LARGE_INTEGER LastAccessTime; | LARGE_INTEGER LastAccessTime; + * LARGE_INTEGER LastWriteTime; | LARGE_INTEGER LastWriteTime; + * LARGE_INTEGER ChangeTime; | LARGE_INTEGER ChangeTime; + * LARGE_INTEGER EndOfFile; | LARGE_INTEGER EndOfFile; + * LARGE_INTEGER AllocationSize; | LARGE_INTEGER AllocationSize; + * ULONG FileAttributes; | ULONG FileAttributes; + * ULONG FileNameLength; | ULONG FileNameLength; + * ULONG EaSize; | ULONG EaSize; + * ------------------------------------+---------------------------------------- + * WCHAR FileName[1]; | CCHAR ShortNameLength; + * | WCHAR ShortName[12]; + * | WCHAR FileName[1]; + * }; + * + */ +typedef union _DIR_INFORMATION { - HANDLE DirectoryHandle; - RTL_CRITICAL_SECTION Lock; - PFILE_BOTH_DIR_INFORMATION pFileInfo; - BOOLEAN DirectoryOnly; - BOOLEAN HasMoreData; - BOOLEAN HasData; - BOOLEAN LockInitialized; -} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA; + PVOID DirInfo; + PFILE_FULL_DIR_INFORMATION FullDirInfo; + PFILE_BOTH_DIR_INFORMATION BothDirInfo; +} DIR_INFORMATION; -typedef struct _KERNEL32_FIND_STREAM_DATA +typedef struct _FIND_FILE_DATA { - STREAM_INFO_LEVELS InfoLevel; - PFILE_STREAM_INFORMATION pFileStreamInfo; - PFILE_STREAM_INFORMATION pCurrent; -} KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA; + HANDLE Handle; + FINDEX_INFO_LEVELS InfoLevel; + FINDEX_SEARCH_OPS SearchOp; -typedef enum _KERNEL32_FIND_DATA_TYPE + BOOLEAN HasMoreData; + + /* + * "Pointer" to the next file info structure in the buffer. + * The type is defined by the 'InfoLevel' parameter. + */ + DIR_INFORMATION NextDirInfo; + + BYTE Buffer[FIND_DATA_SIZE]; +} FIND_FILE_DATA, *PFIND_FILE_DATA; + +typedef struct _FIND_STREAM_DATA { - FileFind, - StreamFind -} KERNEL32_FIND_DATA_TYPE; + STREAM_INFO_LEVELS InfoLevel; + PFILE_STREAM_INFORMATION FileStreamInfo; + PFILE_STREAM_INFORMATION CurrentInfo; +} FIND_STREAM_DATA, *PFIND_STREAM_DATA; -typedef struct _KERNEL32_FIND_DATA_HEADER +typedef struct _FIND_DATA_HANDLE { - KERNEL32_FIND_DATA_TYPE Type; -} KERNEL32_FIND_DATA_HEADER, *PKERNEL32_FIND_DATA_HEADER; + FIND_DATA_TYPE Type; + RTL_CRITICAL_SECTION Lock; + /* + * Pointer to the following finding data, located at + * (this + 1). The type is defined by the 'Type' parameter. + */ + union + { + PFIND_FILE_DATA FindFileData; + PFIND_STREAM_DATA FindStreamData; + } u; -/* FUNCTIONS ****************************************************************/ +} FIND_DATA_HANDLE, *PFIND_DATA_HANDLE; + +/* PRIVATE FUNCTIONS **********************************************************/ + static VOID -InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData, - LPCWSTR lpFileName, - ULONG DeviceNameInfo) +CopyDeviceFindData(OUT LPWIN32_FIND_DATAW lpFindFileData, + IN LPCWSTR lpFileName, + IN ULONG DeviceNameInfo) { UNICODE_STRING DeviceName; + /* DeviceNameInfo == { USHORT Offset; USHORT Length } */ DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF); - DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + (DeviceNameInfo >> 16)); + DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + ((DeviceNameInfo >> 16) & 0xFFFF)); /* Return the data */ - RtlZeroMemory(lpFindFileData, - sizeof(*lpFindFileData)); + RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData)); lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; RtlCopyMemory(lpFindFileData->cFileName, DeviceName.Buffer, DeviceName.Length); + + return; } static VOID -InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData, - PFILE_BOTH_DIR_INFORMATION lpFileInfo) +CopyFindData(OUT LPWIN32_FIND_DATAW lpFindFileData, + IN FINDEX_INFO_LEVELS fInfoLevelId, + IN DIR_INFORMATION DirInfo) { - lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes; +#define ULARGE_INTEGER_2_FILETIME(ft, ul) \ +do { \ + (ft).dwHighDateTime = (ul).u.HighPart; \ + (ft).dwLowDateTime = (ul).u.LowPart ; \ +} while(0) - lpFindFileData->ftCreationTime.dwHighDateTime = lpFileInfo->CreationTime.u.HighPart; - lpFindFileData->ftCreationTime.dwLowDateTime = lpFileInfo->CreationTime.u.LowPart; + _SEH2_TRY + { + RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData)); - lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart; - lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart; + lpFindFileData->dwFileAttributes = DirInfo.FullDirInfo->FileAttributes; - lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart; - lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart; + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftCreationTime, DirInfo.FullDirInfo->CreationTime); + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastAccessTime, DirInfo.FullDirInfo->LastAccessTime); + ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastWriteTime, DirInfo.FullDirInfo->LastWriteTime); - lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart; - lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart; + lpFindFileData->nFileSizeHigh = DirInfo.FullDirInfo->EndOfFile.u.HighPart; + lpFindFileData->nFileSizeLow = DirInfo.FullDirInfo->EndOfFile.u.LowPart; - memcpy (lpFindFileData->cFileName, lpFileInfo->FileName, lpFileInfo->FileNameLength); - lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0; + /* dwReserved0 contains the NTFS reparse point tag, if any. */ + if (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + lpFindFileData->dwReserved0 = DirInfo.FullDirInfo->EaSize; + else + lpFindFileData->dwReserved0 = 0; - memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName, lpFileInfo->ShortNameLength); - lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0; -} + /* Unused dwReserved1 field */ + lpFindFileData->dwReserved1 = 0; - -/* - * @implemented - */ -BOOL -WINAPI -InternalFindNextFile ( - HANDLE hFindFile, - PUNICODE_STRING SearchPattern, - PVOID lpFindFileData - ) -{ - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_FILE_DATA IData; - IO_STATUS_BLOCK IoStatusBlock; - BOOLEAN Locked = FALSE; - PFILE_BOTH_DIR_INFORMATION Buffer, FoundFile = NULL; - NTSTATUS Status = STATUS_SUCCESS; - - TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile, SearchPattern); - - if (hFindFile != FIND_DEVICE_HANDLE) - { - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; - if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE || - IHeader->Type != FileFind) + if (fInfoLevelId == FindExInfoStandard) { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + RtlCopyMemory(lpFindFileData->cFileName, + DirInfo.BothDirInfo->FileName, + DirInfo.BothDirInfo->FileNameLength); + lpFindFileData->cFileName[DirInfo.BothDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; - IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); - - if (SearchPattern == NULL) - { - RtlEnterCriticalSection(&IData->Lock); - Locked = TRUE; + RtlCopyMemory(lpFindFileData->cAlternateFileName, + DirInfo.BothDirInfo->ShortName, + DirInfo.BothDirInfo->ShortNameLength); + lpFindFileData->cAlternateFileName[DirInfo.BothDirInfo->ShortNameLength / sizeof(WCHAR)] = UNICODE_NULL; } - - do + else if (fInfoLevelId == FindExInfoBasic) { - if (IData->HasData) - { - if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - FoundFile = IData->pFileInfo; - } + RtlCopyMemory(lpFindFileData->cFileName, + DirInfo.FullDirInfo->FileName, + DirInfo.FullDirInfo->FileNameLength); + lpFindFileData->cFileName[DirInfo.FullDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; - if (IData->pFileInfo->NextEntryOffset != 0) - { - ULONG_PTR BufferEnd; - - IData->pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset); - - /* Be paranoid and make sure that the next entry is completely there */ - BufferEnd = (ULONG_PTR)Buffer + FIND_DATA_SIZE; - if (BufferEnd < (ULONG_PTR)IData->pFileInfo || - BufferEnd < (ULONG_PTR)&IData->pFileInfo->FileNameLength + sizeof(IData->pFileInfo->FileNameLength) || - BufferEnd <= (ULONG_PTR)&IData->pFileInfo->FileName[IData->pFileInfo->FileNameLength]) - { - goto NeedMoreData; - } - } - else - { -NeedMoreData: - IData->HasData = FALSE; - - if (!IData->HasMoreData) - break; - } - } - else - { - IData->pFileInfo = Buffer; - IData->pFileInfo->NextEntryOffset = 0; - Status = NtQueryDirectoryFile (IData->DirectoryHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - (PVOID)IData->pFileInfo, - FIND_DATA_SIZE, - FileBothDirectoryInformation, - FALSE, - SearchPattern, - SearchPattern != NULL); - - if (Status == STATUS_BUFFER_OVERFLOW) - { - IData->HasMoreData = TRUE; - Status = STATUS_SUCCESS; - } - else - { - if (!NT_SUCCESS(Status)) - break; - - IData->HasMoreData = FALSE; - } - - IData->HasData = TRUE; - SearchPattern = NULL; - } - - } while (FoundFile == NULL); - - if (FoundFile != NULL) + lpFindFileData->cAlternateFileName[0] = UNICODE_NULL; + } + else { - _SEH2_TRY - { - InternalCopyFindDataW(lpFindFileData, - FoundFile); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - } - _SEH2_END; + /* Invalid InfoLevelId */ + ASSERT(FALSE); } - - if (Locked) - RtlLeaveCriticalSection(&IData->Lock); } - - if (!NT_SUCCESS(Status)) + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - BaseSetLastNTError (Status); - return FALSE; } - else if (FoundFile == NULL) - { - SetLastError (ERROR_NO_MORE_FILES); - return FALSE; - } + _SEH2_END; - return TRUE; + return; } - -/* - * @implemented - */ -HANDLE -WINAPI -InternalFindFirstFile ( - LPCWSTR lpFileName, - BOOLEAN DirectoryOnly, - PVOID lpFindFileData - ) +static VOID +CopyStreamInfo(IN OUT PFIND_STREAM_DATA FindStreamData, + OUT PWIN32_FIND_STREAM_DATA lpFindStreamData) { - OBJECT_ATTRIBUTES ObjectAttributes; - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_FILE_DATA IData; - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING NtPathU, FileName, PathFileName; - NTSTATUS Status; - PWSTR NtPathBuffer; - BOOLEAN RemovedLastChar = FALSE; - BOOL bResult; - RTL_RELATIVE_NAME_U DirInfo; - ULONG DeviceNameInfo; - HANDLE hDirectory = NULL; + ASSERT(FindStreamData->CurrentInfo); - TRACE("FindFirstFileW(lpFileName %S)\n", - lpFileName); + switch (FindStreamData->InfoLevel) + { + case FindStreamInfoStandard: + { + ULONG StreamNameLen = min(FindStreamData->CurrentInfo->StreamNameLength, + sizeof(lpFindStreamData->cStreamName) - sizeof(WCHAR)); - RtlZeroMemory(&PathFileName, - sizeof(PathFileName)); - RtlInitUnicodeString(&FileName, - lpFileName); + RtlZeroMemory(lpFindStreamData, sizeof(*lpFindStreamData)); - bResult = RtlDosPathNameToNtPathName_U (lpFileName, - &NtPathU, - (PCWSTR *)((ULONG_PTR)&PathFileName.Buffer), - &DirInfo); - if (FALSE == bResult) - { - SetLastError(ERROR_PATH_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } + lpFindStreamData->StreamSize.QuadPart = FindStreamData->CurrentInfo->StreamSize.QuadPart; + RtlCopyMemory(lpFindStreamData->cStreamName, + FindStreamData->CurrentInfo->StreamName, + StreamNameLen); + lpFindStreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = UNICODE_NULL; - /* Save the buffer pointer for later, we need to free it! */ - NtPathBuffer = NtPathU.Buffer; + break; + } - /* If there is a file name/pattern then determine it's length */ - if (PathFileName.Buffer != NULL) - { - PathFileName.Length = NtPathU.Length - - (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer); - } - PathFileName.MaximumLength = PathFileName.Length; + default: + ASSERT(FALSE); + break; + } - if (DirInfo.RelativeName.Length != 0 && DirInfo.RelativeName.Buffer != PathFileName.Buffer) - { - if (PathFileName.Buffer != NULL) - { - /* This is a relative path to DirInfo.ContainingDirectory, adjust NtPathU! */ - NtPathU.Length = NtPathU.MaximumLength = - (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)DirInfo.RelativeName.Buffer); - NtPathU.Buffer = DirInfo.RelativeName.Buffer; - } - } - else - { - /* This is an absolute path, NtPathU receives the full path */ - DirInfo.ContainingDirectory = NULL; - if (PathFileName.Buffer != NULL) - { - NtPathU.Length = NtPathU.MaximumLength = - (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer); - } - } + return; +} - /* Remove the last character of the path (Unless the path is a drive and - ends with ":\"). If the caller however supplies a path to a device, such - as "C:\NUL" then the last character gets cut off, which later results in - NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers - a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a - real device with a name eg. "NU" in the system, FindFirstFile will succeed, - rendering the fake DOS device check useless... Why would they invent such a - stupid and broken behavior?! */ - if (NtPathU.Length >= 2 * sizeof(WCHAR) && - NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] != L'\\' && - NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':') - { - NtPathU.Length -= sizeof(WCHAR); - RemovedLastChar = TRUE; - } - TRACE("lpFileName: \"%ws\"\n", lpFileName); - TRACE("NtPathU: \"%wZ\"\n", &NtPathU); - TRACE("PathFileName: \"%wZ\"\n", &PathFileName); - TRACE("RelativeTo: 0x%p\n", DirInfo.ContainingDirectory); +/* PUBLIC FUNCTIONS ***********************************************************/ - InitializeObjectAttributes (&ObjectAttributes, - &NtPathU, - OBJ_CASE_INSENSITIVE, - DirInfo.ContainingDirectory, - NULL); - - Status = NtOpenFile (&hDirectory, - FILE_LIST_DIRECTORY | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - - if (Status == STATUS_NOT_A_DIRECTORY && RemovedLastChar) - { - /* Try again, this time with the last character ... */ - NtPathU.Length += sizeof(WCHAR); - - Status = NtOpenFile (&hDirectory, - FILE_LIST_DIRECTORY | SYNCHRONIZE, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); - - NtPathU.Length += sizeof(WCHAR); - } - - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - - /* See if the application tries to look for a DOS device */ - DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName)); - if (DeviceNameInfo != 0) - { - InternalCopyDeviceFindDataW(lpFindFileData, - lpFileName, - DeviceNameInfo); - - return FIND_DEVICE_HANDLE; - } - - BaseSetLastNTError (Status); - return INVALID_HANDLE_VALUE; - } - - if (PathFileName.Length == 0) - { - /* No file part?! */ - NtClose(hDirectory); - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - SetLastError(ERROR_FILE_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } - - IHeader = RtlAllocateHeap (RtlGetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(KERNEL32_FIND_DATA_HEADER) + - sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE); - if (NULL == IHeader) - { - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - NtClose(hDirectory); - - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return INVALID_HANDLE_VALUE; - } - - IHeader->Type = FileFind; - IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - IData->DirectoryHandle = hDirectory; - IData->HasMoreData = TRUE; - - /* change pattern: "*.*" --> "*" */ - if (PathFileName.Length == 6 && - RtlCompareMemory(PathFileName.Buffer, - L"*.*", - 6) == 6) - { - PathFileName.Length = 2; - } - - IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); - IData->pFileInfo->FileIndex = 0; - IData->DirectoryOnly = DirectoryOnly; - - bResult = InternalFindNextFile((HANDLE)IHeader, - &PathFileName, - lpFindFileData); - - RtlFreeHeap (RtlGetProcessHeap(), - 0, - NtPathBuffer); - - if (!bResult) - { - FindClose((HANDLE)IHeader); - return INVALID_HANDLE_VALUE; - } - - RtlInitializeCriticalSection(&IData->Lock); - IData->LockInitialized = TRUE; - - return (HANDLE)IHeader; -} - - /* * @implemented */ @@ -464,27 +244,23 @@ WIN32_FIND_DATAW FindFileDataW; lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); - if (!lpFileNameW) - { - return INVALID_HANDLE_VALUE; - } + if (!lpFileNameW) return INVALID_HANDLE_VALUE; hSearch = FindFirstFileExW(lpFileNameW->Buffer, FindExInfoStandard, &FindFileDataW, FindExSearchNameMatch, NULL, 0); - if (hSearch == INVALID_HANDLE_VALUE) - { - return INVALID_HANDLE_VALUE; - } + if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileData, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName)); RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); Ansi.Buffer = lpFindFileData->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileData->cFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -496,7 +272,7 @@ RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); Ansi.Buffer = lpFindFileData->cAlternateFileName; Ansi.Length = 0; - Ansi.MaximumLength = 14; + Ansi.MaximumLength = sizeof(lpFindFileData->cAlternateFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -512,6 +288,22 @@ /* * @implemented */ +HANDLE +WINAPI +FindFirstFileW(IN LPCWSTR lpFileName, + OUT LPWIN32_FIND_DATAW lpFindFileData) +{ + return FindFirstFileExW(lpFileName, + FindExInfoStandard, + lpFindFileData, + FindExSearchNameMatch, + NULL, 0); +} + + +/* + * @implemented + */ BOOL WINAPI FindNextFileA(IN HANDLE hFindFile, @@ -522,17 +314,16 @@ UNICODE_STRING UTF8; WIN32_FIND_DATAW FindFileDataW; - if (!FindNextFileW(hFindFile, &FindFileDataW)) - { - return FALSE; - } + if (!FindNextFileW(hFindFile, &FindFileDataW)) return FALSE; - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileData, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName)); RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); Ansi.Buffer = lpFindFileData->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileData->cFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -543,7 +334,7 @@ RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); Ansi.Buffer = lpFindFileData->cAlternateFileName; Ansi.Length = 0; - Ansi.MaximumLength = 14; + Ansi.MaximumLength = sizeof(lpFindFileData->cAlternateFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -560,123 +351,202 @@ */ BOOL WINAPI -FindClose ( - HANDLE hFindFile - ) +FindNextFileW(IN HANDLE hFindFile, + OUT LPWIN32_FIND_DATAW lpFindFileData) { - PKERNEL32_FIND_DATA_HEADER IHeader; + NTSTATUS Status = STATUS_SUCCESS; + DIR_INFORMATION FoundFile = {NULL}; - TRACE("FindClose(hFindFile %x)\n",hFindFile); + TRACE("FindNextFileW(%lx, 0x%p)\n", hFindFile, lpFindFileData); - if (hFindFile == FIND_DEVICE_HANDLE) - return TRUE; + if (hFindFile != FIND_DEVICE_HANDLE) + { + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile; + PFIND_FILE_DATA FindFileData; + FINDEX_INFO_LEVELS InfoLevel; + FILE_INFORMATION_CLASS FileInfoClass; + IO_STATUS_BLOCK IoStatusBlock; + DIR_INFORMATION DirInfo = {NULL}, NextDirInfo = {NULL}; - if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) - { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE || + FindDataHandle->Type != FindFile) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; + FindFileData = FindDataHandle->u.FindFileData; + InfoLevel = FindFileData->InfoLevel; + FileInfoClass = (InfoLevel == FindExInfoStandard + ? FileBothDirectoryInformation + : FileFullDirectoryInformation); - switch (IHeader->Type) - { - case FileFind: - { - PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); - CloseHandle (IData->DirectoryHandle); - if (IData->LockInitialized) - RtlDeleteCriticalSection(&IData->Lock); - IData->LockInitialized = FALSE; - break; - } + _SEH2_TRY + { + RtlEnterCriticalSection(&FindDataHandle->Lock); - case StreamFind: - { - PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap (RtlGetProcessHeap(), 0, IData->pFileStreamInfo); - } - break; - } + do + { + if (FindFileData->NextDirInfo.DirInfo == NULL) + { + Status = NtQueryDirectoryFile(FindFileData->Handle, + NULL, NULL, NULL, + &IoStatusBlock, + &FindFileData->Buffer, + sizeof(FindFileData->Buffer), + FileInfoClass, + FALSE, + NULL, /* Use the file pattern from the first call */ + FALSE); + if (Status == STATUS_BUFFER_OVERFLOW) + { + FindFileData->HasMoreData = TRUE; + Status = STATUS_SUCCESS; + } + else + { + if (!NT_SUCCESS(Status)) break; + FindFileData->HasMoreData = FALSE; + } - default: - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; - } + FindFileData->NextDirInfo.DirInfo = &FindFileData->Buffer; + } - RtlFreeHeap (RtlGetProcessHeap(), 0, IHeader); + DirInfo = FindFileData->NextDirInfo; - return TRUE; -} + if (DirInfo.FullDirInfo->NextEntryOffset != 0) + { + ULONG_PTR BufferEnd = (ULONG_PTR)&FindFileData->Buffer + sizeof(FindFileData->Buffer); + PWSTR pFileName; + FindFileData->NextDirInfo.DirInfo = (PVOID)((ULONG_PTR)DirInfo.DirInfo + + DirInfo.FullDirInfo->NextEntryOffset); + NextDirInfo = FindFileData->NextDirInfo; -/* - * @implemented - */ -HANDLE -WINAPI -FindFirstFileW(IN LPCWSTR lpFileName, - OUT LPWIN32_FIND_DATAW lpFindFileData) -{ - return FindFirstFileExW(lpFileName, - FindExInfoStandard, - lpFindFileData, - FindExSearchNameMatch, - NULL, - 0); + pFileName = (InfoLevel == FindExInfoStandard + ? NextDirInfo.BothDirInfo->FileName + : NextDirInfo.FullDirInfo->FileName); + + /* Be paranoid and make sure that the next entry is completely there */ + if (BufferEnd < (ULONG_PTR)NextDirInfo.DirInfo || + BufferEnd < (ULONG_PTR)&NextDirInfo.FullDirInfo->FileNameLength + sizeof(NextDirInfo.FullDirInfo->FileNameLength) || + BufferEnd <= (ULONG_PTR)((ULONG_PTR)pFileName + NextDirInfo.FullDirInfo->FileNameLength)) + { + FindFileData->NextDirInfo.DirInfo = NULL; + } + } + else + { + FindFileData->NextDirInfo.DirInfo = NULL; + } + + if ((FindFileData->SearchOp != FindExSearchLimitToDirectories) || + (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + FoundFile = DirInfo; + } + + } while ( FoundFile.DirInfo == NULL && (FindFileData->NextDirInfo.DirInfo || FindFileData->HasMoreData) ); + + if (FoundFile.DirInfo != NULL) + { + CopyFindData(lpFindFileData, InfoLevel, FoundFile); + } + + RtlLeaveCriticalSection(&FindDataHandle->Lock); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; + } + + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + else if (FoundFile.DirInfo == NULL) + { + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; + } + + return TRUE; } + /* * @implemented */ BOOL WINAPI -FindNextFileW(IN HANDLE hFindFile, - OUT LPWIN32_FIND_DATAW lpFindFileData) +FindClose(HANDLE hFindFile) { - return InternalFindNextFile(hFindFile, - NULL, - lpFindFileData); -} + BOOL bRet = FALSE; + TRACE("FindClose(hFindFile %x)\n", hFindFile); -/* - * @unimplemented - */ -HANDLE -WINAPI -FindFirstFileExW(IN LPCWSTR lpFileName, - IN FINDEX_INFO_LEVELS fInfoLevelId, - OUT LPVOID lpFindFileData, - IN FINDEX_SEARCH_OPS fSearchOp, - LPVOID lpSearchFilter, - IN DWORD dwAdditionalFlags) -{ - if (fInfoLevelId != FindExInfoStandard) + if (hFindFile == FIND_DEVICE_HANDLE) + return TRUE; + + if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) { - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; } - if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories) + /* Protect with SEH against closing attempts on invalid handles. */ + _SEH2_TRY { - if (lpSearchFilter) + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile; + + switch (FindDataHandle->Type) { - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + case FindFile: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + NtClose(FindDataHandle->u.FindFileData->Handle); + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + bRet = TRUE; + break; + } + + case FindStream: + { + RtlEnterCriticalSection(&FindDataHandle->Lock); + if (FindDataHandle->u.FindStreamData->FileStreamInfo != NULL) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, + FindDataHandle->u.FindStreamData->FileStreamInfo); + } + RtlLeaveCriticalSection(&FindDataHandle->Lock); + RtlDeleteCriticalSection(&FindDataHandle->Lock); + + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + bRet = TRUE; + break; + } + + default: + SetLastError(ERROR_INVALID_HANDLE); + break; } - - return InternalFindFirstFile (lpFileName, - fSearchOp == FindExSearchLimitToDirectories, - lpFindFileData); } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + BaseSetLastNTError(_SEH2_GetExceptionCode()); + bRet = FALSE; + } + _SEH2_END; - SetLastError(ERROR_INVALID_PARAMETER); - return INVALID_HANDLE_VALUE; + return bRet; } + /* * @unimplemented */ @@ -695,30 +565,37 @@ UNICODE_STRING UTF8; PUNICODE_STRING lpFileNameW; WIN32_FIND_DATAW FindFileDataW; + LPWIN32_FIND_DATAA lpFindFileDataA = (LPWIN32_FIND_DATAA)lpFindFileData; - lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); - if (!lpFileNameW) + if ((fInfoLevelId != FindExInfoStandard && fInfoLevelId != FindExInfoBasic) || + fSearchOp == FindExSearchLimitToDevices || + dwAdditionalFlags & ~FIND_FIRST_EX_CASE_SENSITIVE /* only supported flag for now */) { + SetLastError(fSearchOp == FindExSearchLimitToDevices + ? ERROR_NOT_SUPPORTED + : ERROR_INVALID_PARAMETER); return INVALID_HANDLE_VALUE; } + lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); + if (!lpFileNameW) return INVALID_HANDLE_VALUE; + hSearch = FindFirstFileExW(lpFileNameW->Buffer, fInfoLevelId, &FindFileDataW, fSearchOp, lpSearchFilter, dwAdditionalFlags); - if (hSearch == INVALID_HANDLE_VALUE) - { - return INVALID_HANDLE_VALUE; - } + if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; - memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); + RtlCopyMemory(lpFindFileDataA, + &FindFileDataW, + FIELD_OFFSET(WIN32_FIND_DATAA, cFileName)); RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); - Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cFileName; + Ansi.Buffer = lpFindFileDataA->cFileName; Ansi.Length = 0; - Ansi.MaximumLength = MAX_PATH; + Ansi.MaximumLength = sizeof(lpFindFileDataA->cFileName); Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); if (!NT_SUCCESS(Status)) { @@ -727,51 +604,291 @@ return INVALID_HANDLE_VALUE; } - RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); - Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cAlternateFileName; - Ansi.Length = 0; - Ansi.MaximumLength = 14; - Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); - if (!NT_SUCCESS(Status)) + if (fInfoLevelId != FindExInfoBasic) { - FindClose(hSearch); - BaseSetLastNTError(Status); - return INVALID_HANDLE_VALUE; + RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); + Ansi.Buffer = lpFindFileDataA->cAlternateFileName; + Ansi.Length = 0; + Ansi.MaximumLength = sizeof(lpFindFileDataA->cAlternateFileName); + Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); + if (!NT_SUCCESS(Status)) + { + FindClose(hSearch); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } } + else + { + lpFindFileDataA->cAlternateFileName[0] = ANSI_NULL; + } return hSearch; } -static VOID -InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData, - OUT LPVOID lpFindStreamData) +/* + * @unimplemented + */ +HANDLE +WINAPI +FindFirstFileExW(IN LPCWSTR lpFileName, + IN FINDEX_INFO_LEVELS fInfoLevelId, + OUT LPVOID lpFindFileData, + IN FINDEX_SEARCH_OPS fSearchOp, + LPVOID lpSearchFilter, + IN DWORD dwAdditionalFlags) { - ASSERT(IData->pCurrent); + TRACE("FindFirstFileExW(lpFileName %S)\n", lpFileName); - switch (IData->InfoLevel) + if ((fInfoLevelId != FindExInfoStandard && fInfoLevelId != FindExInfoBasic) || + fSearchOp == FindExSearchLimitToDevices || + dwAdditionalFlags & ~FIND_FIRST_EX_CASE_SENSITIVE /* only supported flag for now */) { - case FindStreamInfoStandard: + SetLastError(fSearchOp == FindExSearchLimitToDevices + ? ERROR_NOT_SUPPORTED + : ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } + + if (fSearchOp == FindExSearchNameMatch || + fSearchOp == FindExSearchLimitToDirectories) + { + LPWIN32_FIND_DATAW Win32FindData = (LPWIN32_FIND_DATAW)lpFindFileData; + PFIND_DATA_HANDLE FindDataHandle; + PFIND_FILE_DATA FindFileData; + + UNICODE_STRING NtPath, FilePattern; + PWSTR NtPathBuffer; + RTL_RELATIVE_NAME_U RelativePath; + ULONG DeviceNameInfo = 0; + + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE hDirectory = NULL; + + /* + * Can represent many FILE_BOTH_DIR_INFORMATION + * or many FILE_FULL_DIR_INFORMATION structures. + */ + BYTE DirectoryInfo[FIND_DATA_SIZE]; + DIR_INFORMATION DirInfo = {&DirectoryInfo}; + + /* The search filter is always unused */ + if (lpSearchFilter) { - ULONG StreamNameLen; - WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData; + SetLastError(ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } - StreamNameLen = IData->pCurrent->StreamNameLength; - if (StreamNameLen > sizeof(StreamData->cStreamName) - sizeof(WCHAR)) - StreamNameLen = sizeof(StreamData->cStreamName) - sizeof(WCHAR); + if (!RtlDosPathNameToNtPathName_U(lpFileName, + &NtPath, + (PCWSTR*)&FilePattern.Buffer, + &RelativePath)) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } +/* + DPRINT1("lpFileName = '%S'\n", lpFileName); + DPRINT1("NtPath.Buffer = '%S'\n", NtPath.Buffer); + DPRINT1("FilePattern.Buffer = '%S'\n", FilePattern.Buffer); + DPRINT1("RelativePath.RelativeName = '%wZ'\n", &RelativePath.RelativeName); + DPRINT1("NtPath - Before : \"%wZ\"\n", &NtPath); +*/ - StreamData->StreamSize.QuadPart = IData->pCurrent->StreamSize.QuadPart; - RtlCopyMemory(StreamData->cStreamName, - IData->pCurrent->StreamName, - StreamNameLen); - StreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = L'\0'; - break; + /* Save the buffer pointer for later, we need to free it! */ + NtPathBuffer = NtPath.Buffer; + + /* + * Contrary to what Windows does, check NOW whether or not + * lpFileName is a DOS driver. Therefore we don't have to + * write broken code to check that. + */ + if (!FilePattern.Buffer || !*FilePattern.Buffer) + { + /* No file pattern specified, or DOS device */ + + DeviceNameInfo = RtlIsDosDeviceName_U(lpFileName); + if (DeviceNameInfo != 0) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + /* OK, it's really a DOS device */ + CopyDeviceFindData(Win32FindData, lpFileName, DeviceNameInfo); + return FIND_DEVICE_HANDLE; + } } - default: - ASSERT(FALSE); - break; + /* A file pattern was specified, or it was not a DOS device */ + + /* If there is a file pattern then determine its length */ + if (FilePattern.Buffer != NULL) + { + FilePattern.Length = NtPath.Length - + (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer); + } + else + { + FilePattern.Length = 0; + } + FilePattern.MaximumLength = FilePattern.Length; + + if (RelativePath.RelativeName.Length != 0 && + RelativePath.RelativeName.Buffer != FilePattern.Buffer) + { + if (FilePattern.Buffer != NULL) + { + /* This is a relative path to RelativePath.ContainingDirectory, adjust NtPath! */ + NtPath.Length = NtPath.MaximumLength = + (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)RelativePath.RelativeName.Buffer); + NtPath.Buffer = RelativePath.RelativeName.Buffer; + } + } + else + { + /* This is an absolute path, NtPath receives the full path */ + RelativePath.ContainingDirectory = NULL; + if (FilePattern.Buffer != NULL) + { + NtPath.Length = NtPath.MaximumLength = + (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer); + } + } + +/* + DPRINT1("NtPath - After : \"%wZ\"\n", &NtPath); + TRACE("lpFileName: \"%S\"\n", lpFileName); + // TRACE("NtPath: \"%wZ\"\n", &NtPath); + TRACE("FilePattern: \"%wZ\"\n", &FilePattern); + TRACE("RelativeTo: 0x%p\n", RelativePath.ContainingDirectory); +*/ + + InitializeObjectAttributes(&ObjectAttributes, + &NtPath, + (dwAdditionalFlags & FIND_FIRST_EX_CASE_SENSITIVE) ? 0 : OBJ_CASE_INSENSITIVE, + RelativePath.ContainingDirectory, + NULL); + + Status = NtOpenFile(&hDirectory, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + /* Adjust the last error codes */ + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + Status = STATUS_OBJECT_PATH_NOT_FOUND; + else if (Status == STATUS_OBJECT_TYPE_MISMATCH) + Status = STATUS_OBJECT_PATH_NOT_FOUND; + + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + /* + * Fail if there is not any file pattern, + * since we are not looking for a device. + */ + if (FilePattern.Length == 0) + { + NtClose(hDirectory); + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + SetLastError(ERROR_FILE_NOT_FOUND); + return INVALID_HANDLE_VALUE; + } + + /* Change pattern: "*.*" --> "*" */ + if (FilePattern.Length == 6 && + RtlCompareMemory(FilePattern.Buffer, L"*.*", 6) == 6) + { + FilePattern.Length = 2; + } + + Status = NtQueryDirectoryFile(hDirectory, + NULL, NULL, NULL, + &IoStatusBlock, + DirInfo.DirInfo, // == &DirectoryInfo + sizeof(DirectoryInfo), + (fInfoLevelId == FindExInfoStandard + ? FileBothDirectoryInformation + : FileFullDirectoryInformation), + TRUE, /* Return a single entry */ + &FilePattern, + TRUE); + + RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer); + + if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW)) + { + NtClose(hDirectory); + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + ASSERT(DirInfo.FullDirInfo->NextEntryOffset == 0); + + if ((fSearchOp != FindExSearchLimitToDirectories) || + (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + CopyFindData(Win32FindData, fInfoLevelId, DirInfo); + } + else + { + NtClose(hDirectory); + SetLastError(ERROR_NO_MORE_FILES); + return INVALID_HANDLE_VALUE; + } + + /* + * Initialization of the "Find File Handle". + */ + FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(FIND_DATA_HANDLE) + + sizeof(FIND_FILE_DATA)); + if (!FindDataHandle) + { + NtClose(hDirectory); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + FindDataHandle->Type = FindFile; + FindDataHandle->u.FindFileData = (PFIND_FILE_DATA)(FindDataHandle + 1); + FindFileData = FindDataHandle->u.FindFileData; + + FindFileData->Handle = hDirectory; + FindFileData->InfoLevel = fInfoLevelId; + FindFileData->SearchOp = fSearchOp; + FindFileData->HasMoreData = FALSE; + FindFileData->NextDirInfo.DirInfo = NULL; + + /* The critical section must always be initialized */ + Status = RtlInitializeCriticalSection(&FindDataHandle->Lock); + if (!NT_SUCCESS(Status)) + { + NtClose(hDirectory); + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); + + BaseSetLastNTError(Status); + return INVALID_HANDLE_VALUE; + } + + return (HANDLE)FindDataHandle; } + else + { + SetLastError(ERROR_NOT_SUPPORTED); + return INVALID_HANDLE_VALUE; + } } @@ -785,11 +902,11 @@ OUT LPVOID lpFindStreamData, IN DWORD dwFlags) { - PKERNEL32_FIND_DATA_HEADER IHeader = NULL; - PKERNEL32_FIND_STREAM_DATA IData = NULL; + PFIND_DATA_HANDLE FindDataHandle = NULL; + PFIND_STREAM_DATA FindStreamData; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING NtPathU; + UNICODE_STRING NtFilePath; HANDLE FileHandle = NULL; NTSTATUS Status; ULONG BufferSize = 0; @@ -801,19 +918,18 @@ return INVALID_HANDLE_VALUE; } - /* validate & translate the filename */ + /* Validate & translate the filename */ if (!RtlDosPathNameToNtPathName_U(lpFileName, - &NtPathU, - NULL, - NULL)) + &NtFilePath, + NULL, NULL)) { SetLastError(ERROR_PATH_NOT_FOUND); return INVALID_HANDLE_VALUE; } - /* open the file */ + /* Open the file */ InitializeObjectAttributes(&ObjectAttributes, - &NtPathU, + &NtFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); @@ -822,47 +938,42 @@ 0, &ObjectAttributes, &IoStatusBlock, - NULL, - 0, + NULL, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, - 0, - NULL, - 0); - if (!NT_SUCCESS(Status)) - { - goto Cleanup; - } + 0, NULL, 0); + if (!NT_SUCCESS(Status)) goto Cleanup; - /* create the search context */ - IHeader = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - sizeof(KERNEL32_FIND_DATA_HEADER) + - sizeof(KERNEL32_FIND_STREAM_DATA)); - if (IHeader == NULL) + /* Create the search context */ + FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(FIND_DATA_HANDLE) + + sizeof(FIND_STREAM_DATA)); + if (!FindDataHandle) { Status = STATUS_NO_MEMORY; goto Cleanup; } - IHeader->Type = StreamFind; - IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); + /* Capture all information about the streams */ + FindDataHandle->Type = FindStream; + FindDataHandle->u.FindStreamData = (PFIND_STREAM_DATA)(FindDataHandle + 1); + FindStreamData = FindDataHandle->u.FindStreamData; - /* capture all information about the streams */ - IData->InfoLevel = InfoLevel; - IData->pCurrent = NULL; - IData->pFileStreamInfo = NULL; + FindStreamData->InfoLevel = InfoLevel; + FindStreamData->FileStreamInfo = NULL; + FindStreamData->CurrentInfo = NULL; do { BufferSize += 0x1000; - if (IData->pFileStreamInfo == NULL) + if (FindStreamData->FileStreamInfo == NULL) { - IData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - BufferSize); - if (IData->pFileStreamInfo == NULL) + FindStreamData->FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + BufferSize); + if (FindStreamData->FileStreamInfo == NULL) { Status = STATUS_NO_MEMORY; break; @@ -873,8 +984,8 @@ PFILE_STREAM_INFORMATION pfsi; pfsi = RtlReAllocateHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo, + 0, // HEAP_ZERO_MEMORY, + FindStreamData->FileStreamInfo, BufferSize); if (pfsi == NULL) { @@ -882,12 +993,12 @@ break; } - IData->pFileStreamInfo = pfsi; + FindStreamData->FileStreamInfo = pfsi; } Status = NtQueryInformationFile(FileHandle, &IoStatusBlock, - IData->pFileStreamInfo, + FindStreamData->FileStreamInfo, BufferSize, FileStreamInformation); @@ -895,49 +1006,37 @@ if (NT_SUCCESS(Status)) { - NtClose(FileHandle); - FileHandle = NULL; + /* Select the first stream and return the information */ + FindStreamData->CurrentInfo = FindStreamData->FileStreamInfo; + CopyStreamInfo(FindStreamData, lpFindStreamData); - /* select the first stream and return the information */ - IData->pCurrent = IData->pFileStreamInfo; - InternalCopyStreamInfo(IData, - lpFindStreamData); - - /* all done */ + /* All done */ Status = STATUS_SUCCESS; } + else + { + if (FindStreamData->FileStreamInfo) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, FindStreamData->FileStreamInfo); + } -Cleanup: - if (FileHandle != NULL) - { - NtClose(FileHandle); + RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle); } - RtlFreeHeap(RtlGetProcessHeap(), - 0, - NtPathU.Buffer); +Cleanup: + if (FileHandle) NtClose(FileHandle); - if (!NT_SUCCESS(Status)) + RtlFreeHeap(RtlGetProcessHeap(), 0, NtFilePath.Buffer); + + if (NT_SUCCESS(Status)) { - if (IHeader != NULL) - { - if (IData->pFileStreamInfo != NULL) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IData->pFileStreamInfo); - } - - RtlFreeHeap(RtlGetProcessHeap(), - 0, - IHeader); - } - + return (HANDLE)FindDataHandle; + } + else + { BaseSetLastNTError(Status); return INVALID_HANDLE_VALUE; } - - return (HANDLE)IHeader; } @@ -949,37 +1048,33 @@ FindNextStreamW(IN HANDLE hFindStream, OUT LPVOID lpFindStreamData) { - PKERNEL32_FIND_DATA_HEADER IHeader; - PKERNEL32_FIND_STREAM_DATA IData; + PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindStream; + PFIND_STREAM_DATA FindStreamData; - IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream; if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE || - IHeader->Type != StreamFind) + FindDataHandle->Type != FindStream) { - SetLastError (ERROR_INVALID_HANDLE); + SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); + FindStreamData = FindDataHandle->u.FindStreamData; - /* select next stream if possible */ - if (IData->pCurrent->NextEntryOffset != 0) + /* Select next stream if possible */ + if (FindStreamData->CurrentInfo->NextEntryOffset != 0) { - IData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo + - IData->pCurrent->NextEntryOffset); + FindStreamData->CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)FindStreamData->FileStreamInfo + + FindStreamData->CurrentInfo->NextEntryOffset); + + /* Return the information */ + CopyStreamInfo(FindStreamData, lpFindStreamData); + return TRUE; } else { SetLastError(ERROR_HANDLE_EOF); return FALSE; } - - /* return the information */ - InternalCopyStreamInfo(IData, - lpFindStreamData); - - return TRUE; } - /* EOF */ Index: include/ndk/iotypes.h =================================================================== --- include/ndk/iotypes.h (révision 57391) +++ include/ndk/iotypes.h (copie de travail) @@ -524,6 +524,22 @@ PLARGE_INTEGER ReadTimeout; } FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION; +typedef struct _FILE_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; + typedef struct _FILE_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; Index: include/psdk/winbase.h =================================================================== --- include/psdk/winbase.h (révision 57391) +++ include/psdk/winbase.h (copie de travail) @@ -228,6 +228,7 @@ #define CLRBREAK 9 #define STILL_ACTIVE 0x103 #define FIND_FIRST_EX_CASE_SENSITIVE 1 +/// #define FIND_FIRST_EX_LARGE_FETCH 2 #define SCS_32BIT_BINARY 0 #define SCS_64BIT_BINARY 6 #define SCS_DOS_BINARY 1 @@ -923,6 +924,7 @@ typedef enum _FINDEX_INFO_LEVELS { FindExInfoStandard, + FindExInfoBasic, FindExInfoMaxInfoLevel } FINDEX_INFO_LEVELS; Index: lib/rtl/path.c =================================================================== --- lib/rtl/path.c (révision 57313) +++ 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 */