-/* $Id: find.c 53068 2011-08-04 22:18:01Z ion $
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
- * FILE: lib/kernel32/file/find.c
+ * FILE: dll/win32/kernel32/client/file/find.c
* PURPOSE: Find functions
- * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
+ * PROGRAMMERS: Ariadne (ariadne@xs4all.nl)
* Pierre Schweitzer (pierre.schweitzer@reactos.org)
- * UPDATE HISTORY:
- * Created 01/11/98
+ * Hermes BELUSCA - MAITO (hermes.belusca@sfr.fr)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES *******************************************************************/
#include <k32.h>
#define NDEBUG
#include <debug.h>
DEBUG_CHANNEL(kernel32file);
-/* TYPES ********************************************************************/
-#define FIND_DATA_SIZE 0x4000
+/* TYPES **********************************************************************/
-#define FIND_DEVICE_HANDLE ((HANDLE)0x1)
+#define FIND_DATA_SIZE 0x4000
+#define FIND_DEVICE_HANDLE ((HANDLE)0x1)
-typedef struct _KERNEL32_FIND_FILE_DATA
+typedef enum _FIND_DATA_TYPE
{
- HANDLE DirectoryHandle;
- RTL_CRITICAL_SECTION Lock;
- PFILE_BOTH_DIR_INFORMATION pFileInfo;
- BOOLEAN DirectoryOnly;
- BOOLEAN HasMoreData;
- BOOLEAN HasData;
- BOOLEAN LockInitialized;
-} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
-
-typedef struct _KERNEL32_FIND_STREAM_DATA
+ FindFile = 1,
+ FindStream = 2
+} FIND_DATA_TYPE;
+
+/*
+ * FILE_FULL_DIR_INFORMATION and FILE_BOTH_DIR_INFORMATION structures layout.
+ *
+ *
+ * struct FILE_FULL_DIR_INFORMATION | struct FILE_BOTH_DIR_INFORMATION
+ * ------------------------------------+---------------------------------------
+ * ULONG NextEntryOffset; | ULONG NextEntryOffset;
+ * ULONG FileIndex; | ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; | LARGE_INTEGER CreationTime;
+ * LARGE_INTEGER LastAccessTime; | LARGE_INTEGER LastAccessTime;
+ * LARGE_INTEGER LastWriteTime; | LARGE_INTEGER LastWriteTime;
+ * LARGE_INTEGER ChangeTime; | LARGE_INTEGER ChangeTime;
+ * LARGE_INTEGER EndOfFile; | LARGE_INTEGER EndOfFile;
+ * LARGE_INTEGER AllocationSize; | LARGE_INTEGER AllocationSize;
+ * ULONG FileAttributes; | ULONG FileAttributes;
+ * ULONG FileNameLength; | ULONG FileNameLength;
+ * ULONG EaSize; | ULONG EaSize;
+ * ------------------------------------+---------------------------------------
+ * WCHAR FileName[1]; | CCHAR ShortNameLength;
+ * | WCHAR ShortName[12];
+ * | WCHAR FileName[1];
+ *
+ * Therefore we can use pointers to FILE_FULL_DIR_INFORMATION when one doesn't
+ * want to refer to the ShortName* fields and FileName (useful for implementing
+ * the FindExInfoBasic functionality for FindFirstFileEx), however a cast to
+ * FILE_BOTH_DIR_INFORMATION is required when one wants to use FileName and
+ * ShortName* fields (needed for the FindExInfoStandard functionality).
+ *
+ */
+typedef union _DIR_INFORMATION
{
- STREAM_INFO_LEVELS InfoLevel;
- PFILE_STREAM_INFORMATION pFileStreamInfo;
- PFILE_STREAM_INFORMATION pCurrent;
-} KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA;
+ PVOID DirInfo;
+ PFILE_FULL_DIR_INFORMATION FullDirInfo;
+ PFILE_BOTH_DIR_INFORMATION BothDirInfo;
+} DIR_INFORMATION;
-typedef enum _KERNEL32_FIND_DATA_TYPE
+typedef struct _FIND_FILE_DATA
+{
+ HANDLE Handle;
+ FINDEX_INFO_LEVELS InfoLevel;
+ FINDEX_SEARCH_OPS SearchOp;
+
+ /*
+ * For handling STATUS_BUFFER_OVERFLOW errors emitted by
+ * NtQueryDirectoryFile in the FildNextFile function.
+ */
+ BOOLEAN HasMoreData;
+
+ /*
+ * "Pointer" to the next file info structure in the buffer.
+ * The type is defined by the 'InfoLevel' parameter.
+ */
+ DIR_INFORMATION NextDirInfo;
+
+ BYTE Buffer[FIND_DATA_SIZE];
+} FIND_FILE_DATA, *PFIND_FILE_DATA;
+
+typedef struct _FIND_STREAM_DATA
{
- 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;
+
+} FIND_DATA_HANDLE, *PFIND_DATA_HANDLE;
-/* FUNCTIONS ****************************************************************/
+/* PRIVATE FUNCTIONS **********************************************************/
static VOID
-InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
- LPCWSTR lpFileName,
- ULONG DeviceNameInfo)
+CopyDeviceFindData(OUT LPWIN32_FIND_DATAW lpFindFileData,
+ IN LPCWSTR lpFileName,
+ IN ULONG DeviceNameInfo)
{
UNICODE_STRING DeviceName;
- DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF);
- DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + (DeviceNameInfo >> 16));
+ _SEH2_TRY
+ {
+ /* DeviceNameInfo == { USHORT Offset; USHORT Length } */
+ DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF);
+ DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + ((DeviceNameInfo >> 16) & 0xFFFF));
+
+ /* Return the data */
+ RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData));
+ lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
+ RtlCopyMemory(lpFindFileData->cFileName,
+ DeviceName.Buffer,
+ DeviceName.Length);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
- /* Return the data */
- 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;
-
- lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart;
- lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart;
-
- lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart;
- lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart;
-
- lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart;
- lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart;
+ _SEH2_TRY
+ {
+ RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData));
- memcpy (lpFindFileData->cFileName, lpFileInfo->FileName, lpFileInfo->FileNameLength);
- lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
+ lpFindFileData->dwFileAttributes = DirInfo.FullDirInfo->FileAttributes;
- memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName, lpFileInfo->ShortNameLength);
- lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
-}
+ ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftCreationTime, DirInfo.FullDirInfo->CreationTime);
+ ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastAccessTime, DirInfo.FullDirInfo->LastAccessTime);
+ ULARGE_INTEGER_2_FILETIME(lpFindFileData->ftLastWriteTime, DirInfo.FullDirInfo->LastWriteTime);
+ lpFindFileData->nFileSizeHigh = DirInfo.FullDirInfo->EndOfFile.u.HighPart;
+ lpFindFileData->nFileSizeLow = DirInfo.FullDirInfo->EndOfFile.u.LowPart;
-/*
- * @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;
+ /* 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;
- TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile, SearchPattern);
+ /* Unused dwReserved1 field */
+ lpFindFileData->dwReserved1 = 0;
- 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;
+
+ RtlCopyMemory(lpFindFileData->cAlternateFileName,
+ DirInfo.BothDirInfo->ShortName,
+ DirInfo.BothDirInfo->ShortNameLength);
+ lpFindFileData->cAlternateFileName[DirInfo.BothDirInfo->ShortNameLength / sizeof(WCHAR)] = UNICODE_NULL;
}
+ else if (fInfoLevelId == FindExInfoBasic)
+ {
+ RtlCopyMemory(lpFindFileData->cFileName,
+ DirInfo.FullDirInfo->FileName,
+ DirInfo.FullDirInfo->FileNameLength);
+ lpFindFileData->cFileName[DirInfo.FullDirInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
- IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
- Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
-
- if (SearchPattern == NULL)
+ lpFindFileData->cAlternateFileName[0] = UNICODE_NULL;
+ }
+ else
{
- RtlEnterCriticalSection(&IData->Lock);
- Locked = TRUE;
+ /* Invalid InfoLevelId */
+ ASSERT(FALSE);
}
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
- do
- {
- if (IData->HasData)
- {
- if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
- {
- FoundFile = IData->pFileInfo;
- }
+ return;
+}
- 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;
+static VOID
+CopyStreamData(IN OUT PFIND_STREAM_DATA FindStreamData,
+ OUT PWIN32_FIND_STREAM_DATA lpFindStreamData)
+{
+ _SEH2_TRY
+ {
+ ASSERT(FindStreamData->CurrentInfo);
- if (!IData->HasMoreData)
- break;
- }
- }
- else
+ switch (FindStreamData->InfoLevel)
+ {
+ case FindStreamInfoStandard:
{
- 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);
+ ULONG StreamNameLen = min(FindStreamData->CurrentInfo->StreamNameLength,
+ sizeof(lpFindStreamData->cStreamName) - sizeof(WCHAR));
- if (Status == STATUS_BUFFER_OVERFLOW)
- {
- IData->HasMoreData = TRUE;
- Status = STATUS_SUCCESS;
- }
- else
- {
- if (!NT_SUCCESS(Status))
- break;
+ RtlZeroMemory(lpFindStreamData, sizeof(*lpFindStreamData));
- IData->HasMoreData = FALSE;
- }
+ lpFindStreamData->StreamSize.QuadPart = FindStreamData->CurrentInfo->StreamSize.QuadPart;
+ RtlCopyMemory(lpFindStreamData->cStreamName,
+ FindStreamData->CurrentInfo->StreamName,
+ StreamNameLen);
+ lpFindStreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = UNICODE_NULL;
- IData->HasData = TRUE;
- SearchPattern = NULL;
+ break;
}
- } while (FoundFile == NULL);
-
- if (FoundFile != NULL)
- {
- _SEH2_TRY
- {
- InternalCopyFindDataW(lpFindFileData,
- FoundFile);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ default:
{
+ /* Invalid InfoLevel */
+ ASSERT(FALSE);
+ break;
}
- _SEH2_END;
}
-
- if (Locked)
- RtlLeaveCriticalSection(&IData->Lock);
}
-
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError (Status);
- return FALSE;
- }
- else if (FoundFile == NULL)
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- SetLastError (ERROR_NO_MORE_FILES);
- return FALSE;
}
+ _SEH2_END;
- return TRUE;
+ return;
}
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-InternalFindFirstFile (
- LPCWSTR lpFileName,
- BOOLEAN DirectoryOnly,
- PVOID lpFindFileData
- )
-{
- OBJECT_ATTRIBUTES ObjectAttributes;
- PKERNEL32_FIND_DATA_HEADER IHeader;
- PKERNEL32_FIND_FILE_DATA IData;
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING NtPathU, FileName, PathFileName;
- NTSTATUS Status;
- PWSTR NtPathBuffer;
- BOOLEAN RemovedLastChar = FALSE;
- BOOL bResult;
- RTL_RELATIVE_NAME_U DirInfo;
- ULONG DeviceNameInfo;
- HANDLE hDirectory = NULL;
-
- TRACE("FindFirstFileW(lpFileName %S)\n",
- lpFileName);
-
- RtlZeroMemory(&PathFileName,
- sizeof(PathFileName));
- RtlInitUnicodeString(&FileName,
- lpFileName);
-
- bResult = RtlDosPathNameToNtPathName_U (lpFileName,
- &NtPathU,
- (PCWSTR *)((ULONG_PTR)&PathFileName.Buffer),
- &DirInfo);
- if (FALSE == bResult)
- {
- SetLastError(ERROR_PATH_NOT_FOUND);
- return INVALID_HANDLE_VALUE;
- }
-
- /* Save the buffer pointer for later, we need to free it! */
- NtPathBuffer = NtPathU.Buffer;
-
- /* If there is a file name/pattern then determine it's length */
- if (PathFileName.Buffer != NULL)
- {
- PathFileName.Length = NtPathU.Length -
- (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer);
- }
- PathFileName.MaximumLength = PathFileName.Length;
-
- if (DirInfo.RelativeName.Length != 0 && DirInfo.RelativeName.Buffer != PathFileName.Buffer)
- {
- if (PathFileName.Buffer != NULL)
- {
- /* This is a relative path to DirInfo.ContainingDirectory, adjust NtPathU! */
- NtPathU.Length = NtPathU.MaximumLength =
- (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)DirInfo.RelativeName.Buffer);
- NtPathU.Buffer = DirInfo.RelativeName.Buffer;
- }
- }
- else
- {
- /* This is an absolute path, NtPathU receives the full path */
- DirInfo.ContainingDirectory = NULL;
- if (PathFileName.Buffer != NULL)
- {
- NtPathU.Length = NtPathU.MaximumLength =
- (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer);
- }
- }
-
- /* Remove the last character of the path (Unless the path is a drive and
- ends with ":\"). If the caller however supplies a path to a device, such
- as "C:\NUL" then the last character gets cut off, which later results in
- NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers
- a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a
- real device with a name eg. "NU" in the system, FindFirstFile will succeed,
- rendering the fake DOS device check useless... Why would they invent such a
- stupid and broken behavior?! */
- if (NtPathU.Length >= 2 * sizeof(WCHAR) &&
- NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] != L'\\' &&
- NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':')
- {
- NtPathU.Length -= sizeof(WCHAR);
- RemovedLastChar = TRUE;
- }
-
- TRACE("lpFileName: \"%ws\"\n", lpFileName);
- TRACE("NtPathU: \"%wZ\"\n", &NtPathU);
- TRACE("PathFileName: \"%wZ\"\n", &PathFileName);
- TRACE("RelativeTo: 0x%p\n", DirInfo.ContainingDirectory);
-
- InitializeObjectAttributes (&ObjectAttributes,
- &NtPathU,
- OBJ_CASE_INSENSITIVE,
- DirInfo.ContainingDirectory,
- NULL);
-
- Status = NtOpenFile (&hDirectory,
- FILE_LIST_DIRECTORY | SYNCHRONIZE,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
-
- if (Status == STATUS_NOT_A_DIRECTORY && RemovedLastChar)
- {
- /* Try again, this time with the last character ... */
- NtPathU.Length += sizeof(WCHAR);
-
- Status = NtOpenFile (&hDirectory,
- FILE_LIST_DIRECTORY | SYNCHRONIZE,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
-
- NtPathU.Length += sizeof(WCHAR);
- }
-
- if (!NT_SUCCESS(Status))
- {
- RtlFreeHeap (RtlGetProcessHeap(),
- 0,
- NtPathBuffer);
-
- /* See if the application tries to look for a DOS device */
- DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName));
- if (DeviceNameInfo != 0)
- {
- InternalCopyDeviceFindDataW(lpFindFileData,
- lpFileName,
- DeviceNameInfo);
-
- return FIND_DEVICE_HANDLE;
- }
-
- BaseSetLastNTError (Status);
- return INVALID_HANDLE_VALUE;
- }
-
- if (PathFileName.Length == 0)
- {
- /* No file part?! */
- NtClose(hDirectory);
- RtlFreeHeap (RtlGetProcessHeap(),
- 0,
- NtPathBuffer);
- SetLastError(ERROR_FILE_NOT_FOUND);
- return INVALID_HANDLE_VALUE;
- }
-
- IHeader = RtlAllocateHeap (RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof(KERNEL32_FIND_DATA_HEADER) +
- sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
- if (NULL == IHeader)
- {
- RtlFreeHeap (RtlGetProcessHeap(),
- 0,
- NtPathBuffer);
- NtClose(hDirectory);
-
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return INVALID_HANDLE_VALUE;
- }
-
- IHeader->Type = FileFind;
- IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
- IData->DirectoryHandle = hDirectory;
- IData->HasMoreData = TRUE;
-
- /* change pattern: "*.*" --> "*" */
- if (PathFileName.Length == 6 &&
- RtlCompareMemory(PathFileName.Buffer,
- L"*.*",
- 6) == 6)
- {
- PathFileName.Length = 2;
- }
-
- IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
- IData->pFileInfo->FileIndex = 0;
- IData->DirectoryOnly = DirectoryOnly;
-
- bResult = InternalFindNextFile((HANDLE)IHeader,
- &PathFileName,
- lpFindFileData);
-
- RtlFreeHeap (RtlGetProcessHeap(),
- 0,
- NtPathBuffer);
-
- if (!bResult)
- {
- FindClose((HANDLE)IHeader);
- return INVALID_HANDLE_VALUE;
- }
-
- RtlInitializeCriticalSection(&IData->Lock);
- IData->LockInitialized = TRUE;
-
- return (HANDLE)IHeader;
-}
-
+/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
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))
{
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))
{
}
+/*
+ * @implemented
+ */
+HANDLE
+WINAPI
+FindFirstFileW(IN LPCWSTR lpFileName,
+ OUT LPWIN32_FIND_DATAW lpFindFileData)
+{
+ return FindFirstFileExW(lpFileName,
+ FindExInfoStandard,
+ lpFindFileData,
+ FindExSearchNameMatch,
+ NULL, 0);
+}
+
+
/*
* @implemented
*/
WIN32_FIND_DATAW FindFileDataW;
if (!FindNextFileW(hFindFile, &FindFileDataW))
- {
return FALSE;
- }
- memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName));
+ RtlCopyMemory(lpFindFileData,
+ &FindFileDataW,
+ FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName);
Ansi.Buffer = lpFindFileData->cFileName;
Ansi.Length = 0;
- Ansi.MaximumLength = MAX_PATH;
+ Ansi.MaximumLength = sizeof(lpFindFileData->cFileName);
Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE);
if (!NT_SUCCESS(Status))
{
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))
{
*/
BOOL
WINAPI
-FindClose (
- HANDLE hFindFile
- )
+FindNextFileW(IN HANDLE hFindFile,
+ OUT LPWIN32_FIND_DATAW lpFindFileData)
{
- PKERNEL32_FIND_DATA_HEADER IHeader;
-
- TRACE("FindClose(hFindFile %x)\n",hFindFile);
-
- if (hFindFile == FIND_DEVICE_HANDLE)
- return TRUE;
-
- if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE)
- {
- SetLastError (ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile;
-
- switch (IHeader->Type)
- {
- case FileFind:
- {
- PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
- CloseHandle (IData->DirectoryHandle);
- if (IData->LockInitialized)
- RtlDeleteCriticalSection(&IData->Lock);
- IData->LockInitialized = FALSE;
- break;
- }
-
- case StreamFind:
- {
- PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
- if (IData->pFileStreamInfo != NULL)
- {
- RtlFreeHeap (RtlGetProcessHeap(), 0, IData->pFileStreamInfo);
- }
- break;
- }
-
- default:
- SetLastError (ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- RtlFreeHeap (RtlGetProcessHeap(), 0, IHeader);
-
- return TRUE;
-}
+ NTSTATUS Status = STATUS_SUCCESS;
+ DIR_INFORMATION FoundFile = {NULL};
+ TRACE("FindNextFileW(%lx, 0x%p)\n", hFindFile, lpFindFileData);
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-FindFirstFileW(IN LPCWSTR lpFileName,
- OUT LPWIN32_FIND_DATAW lpFindFileData)
-{
- return FindFirstFileExW(lpFileName,
- FindExInfoStandard,
- lpFindFileData,
- FindExSearchNameMatch,
- NULL,
- 0);
+ if (hFindFile != FIND_DEVICE_HANDLE)
+ {
+ PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile;
+ PFIND_FILE_DATA FindFileData;
+ FINDEX_INFO_LEVELS InfoLevel;
+ IO_STATUS_BLOCK IoStatusBlock;
+ DIR_INFORMATION DirInfo = {NULL}, NextDirInfo = {NULL};
+
+ if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE ||
+ FindDataHandle->Type != FindFile)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ RtlEnterCriticalSection(&FindDataHandle->Lock);
+
+ FindFileData = FindDataHandle->u.FindFileData;
+ InfoLevel = FindFileData->InfoLevel;
+
+ do
+ {
+ if (FindFileData->NextDirInfo.DirInfo == NULL)
+ {
+ Status = NtQueryDirectoryFile(FindFileData->Handle,
+ NULL, NULL, NULL,
+ &IoStatusBlock,
+ &FindFileData->Buffer,
+ sizeof(FindFileData->Buffer),
+ (InfoLevel == FindExInfoStandard
+ ? FileBothDirectoryInformation
+ : FileFullDirectoryInformation),
+ FALSE,
+ NULL, /* Use the file pattern from the first call */
+ FALSE);
+ if (Status == STATUS_BUFFER_OVERFLOW)
+ {
+ FindFileData->HasMoreData = TRUE;
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ if (!NT_SUCCESS(Status)) break;
+ FindFileData->HasMoreData = FALSE;
+ }
+
+ FindFileData->NextDirInfo.DirInfo = &FindFileData->Buffer;
+ }
+
+ DirInfo = FindFileData->NextDirInfo;
+
+ if (DirInfo.FullDirInfo->NextEntryOffset != 0)
+ {
+ ULONG_PTR BufferEnd = (ULONG_PTR)&FindFileData->Buffer + sizeof(FindFileData->Buffer);
+ PWSTR pFileName;
+
+ NextDirInfo.DirInfo = FindFileData->NextDirInfo.DirInfo =
+ (PVOID)((ULONG_PTR)DirInfo.DirInfo + DirInfo.FullDirInfo->NextEntryOffset);
+
+ pFileName = (InfoLevel == FindExInfoStandard
+ ? NextDirInfo.BothDirInfo->FileName
+ : NextDirInfo.FullDirInfo->FileName);
+
+ /* Be paranoid and make sure that the next entry is completely there */
+ if (BufferEnd < (ULONG_PTR)NextDirInfo.DirInfo ||
+ BufferEnd < (ULONG_PTR)&NextDirInfo.FullDirInfo->FileNameLength + sizeof(NextDirInfo.FullDirInfo->FileNameLength) ||
+ BufferEnd <= (ULONG_PTR)((ULONG_PTR)pFileName + NextDirInfo.FullDirInfo->FileNameLength))
+ {
+ FindFileData->NextDirInfo.DirInfo = NULL;
+ }
+ }
+ else
+ {
+ FindFileData->NextDirInfo.DirInfo = NULL;
+ }
+
+ if ((FindFileData->SearchOp != FindExSearchLimitToDirectories) ||
+ (DirInfo.FullDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ FoundFile = DirInfo;
+ }
+ } while ( FoundFile.DirInfo == NULL && (FindFileData->NextDirInfo.DirInfo || FindFileData->HasMoreData) );
+
+ if (FoundFile.DirInfo != NULL)
+ {
+ /* Return the information */
+ CopyFindData(lpFindFileData, InfoLevel, FoundFile);
+ }
+
+ RtlLeaveCriticalSection(&FindDataHandle->Lock);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
+ else if (FoundFile.DirInfo == NULL)
+ {
+ SetLastError(ERROR_NO_MORE_FILES);
+ return FALSE;
+ }
+
+ return TRUE;
}
+
/*
* @implemented
*/
BOOL
WINAPI
-FindNextFileW(IN HANDLE hFindFile,
- OUT LPWIN32_FIND_DATAW lpFindFileData)
+FindClose(HANDLE hFindFile)
{
- return InternalFindNextFile(hFindFile,
- NULL,
- lpFindFileData);
-}
+ TRACE("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)
+ 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);
+ break;
+ }
+
+ case FindStream:
+ {
+ RtlEnterCriticalSection(&FindDataHandle->Lock);
+ if (FindDataHandle->u.FindStreamData->FileStreamInfo != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0,
+ FindDataHandle->u.FindStreamData->FileStreamInfo);
+ }
+ RtlLeaveCriticalSection(&FindDataHandle->Lock);
+ RtlDeleteCriticalSection(&FindDataHandle->Lock);
+ break;
+ }
+
+ default:
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ _SEH2_YIELD(return FALSE);
+ }
}
- return InternalFindFirstFile (lpFileName,
- fSearchOp == FindExSearchLimitToDirectories,
- lpFindFileData);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+ _SEH2_YIELD(return TRUE);
}
-
- SetLastError(ERROR_INVALID_PARAMETER);
- return INVALID_HANDLE_VALUE;
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BaseSetLastNTError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
}
+
/*
* @unimplemented
*/
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))
{
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;
+
+ /*
+ * May represent many FILE_BOTH_DIR_INFORMATION
+ * or many FILE_FULL_DIR_INFORMATION structures.
+ */
+ BYTE DirectoryInfo[FIND_DATA_SIZE];
+ DIR_INFORMATION DirInfo = {&DirectoryInfo};
+
+ /* The search filter is always unused */
+ if (lpSearchFilter)
{
- ULONG StreamNameLen;
- WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData;
-
- StreamNameLen = IData->pCurrent->StreamNameLength;
- if (StreamNameLen > sizeof(StreamData->cStreamName) - sizeof(WCHAR))
- StreamNameLen = sizeof(StreamData->cStreamName) - sizeof(WCHAR);
-
- StreamData->StreamSize.QuadPart = IData->pCurrent->StreamSize.QuadPart;
- RtlCopyMemory(StreamData->cStreamName,
- IData->pCurrent->StreamName,
- StreamNameLen);
- StreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = L'\0';
- break;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
}
- default:
- ASSERT(FALSE);
- break;
+ if (!RtlDosPathNameToNtPathName_U(lpFileName,
+ &NtPath,
+ (PCWSTR*)&FilePattern.Buffer,
+ &RelativePath))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ DPRINT("lpFileName = '%S'\n", lpFileName);
+ DPRINT("FilePattern.Buffer = '%S'\n", FilePattern.Buffer);
+ DPRINT("RelativePath.RelativeName = '%wZ'\n", &RelativePath.RelativeName);
+ DPRINT("NtPath.Buffer = '%S'\n", NtPath.Buffer);
+ DPRINT("NtPath - Before = '%wZ'\n", &NtPath);
+
+ /* Save the buffer pointer for later, we need to free it! */
+ NtPathBuffer = NtPath.Buffer;
+
+ /*
+ * Contrary to what Windows does, check NOW whether or not
+ * lpFileName is a DOS driver. Therefore we don't have to
+ * write broken code to check that.
+ */
+ if (!FilePattern.Buffer || !*FilePattern.Buffer)
+ {
+ /* No file pattern specified, or DOS device */
+
+ DeviceNameInfo = RtlIsDosDeviceName_U(lpFileName);
+ if (DeviceNameInfo != 0)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ /* OK, it's really a DOS device */
+ CopyDeviceFindData(Win32FindData, lpFileName, DeviceNameInfo);
+ return FIND_DEVICE_HANDLE;
+ }
+ }
+
+ /* A file pattern was specified, or it was not a DOS device */
+
+ /* If there is a file pattern then determine its length */
+ if (FilePattern.Buffer != NULL)
+ {
+ FilePattern.Length = NtPath.Length -
+ (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer);
+ }
+ else
+ {
+ FilePattern.Length = 0;
+ }
+ FilePattern.MaximumLength = FilePattern.Length;
+
+ if (RelativePath.RelativeName.Length != 0 &&
+ RelativePath.RelativeName.Buffer != FilePattern.Buffer)
+ {
+ if (FilePattern.Buffer != NULL)
+ {
+ /* This is a relative path to RelativePath.ContainingDirectory, adjust NtPath! */
+ NtPath.Length = NtPath.MaximumLength =
+ (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)RelativePath.RelativeName.Buffer);
+ NtPath.Buffer = RelativePath.RelativeName.Buffer;
+ }
+ }
+ else
+ {
+ /* This is an absolute path, NtPath receives the full path */
+ RelativePath.ContainingDirectory = NULL;
+ if (FilePattern.Buffer != NULL)
+ {
+ NtPath.Length = NtPath.MaximumLength =
+ (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer);
+ }
+ }
+
+ DPRINT("NtPath - After = '%wZ'\n", &NtPath);
+ DPRINT("FilePattern = '%wZ'\n", &FilePattern);
+ DPRINT("RelativeTo = 0x%p\n", RelativePath.ContainingDirectory);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &NtPath,
+ (dwAdditionalFlags & FIND_FIRST_EX_CASE_SENSITIVE) ? 0 : OBJ_CASE_INSENSITIVE,
+ RelativePath.ContainingDirectory,
+ NULL);
+
+ Status = NtOpenFile(&hDirectory,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ /* Adjust the last error codes */
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ else if (Status == STATUS_OBJECT_TYPE_MISMATCH)
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /*
+ * Fail if there is not any file pattern,
+ * since we are not looking for a device.
+ */
+ if (FilePattern.Length == 0)
+ {
+ NtClose(hDirectory);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /* Change pattern: "*.*" --> "*" */
+ if (FilePattern.Length == 6 &&
+ RtlCompareMemory(FilePattern.Buffer, L"*.*", 6) == 6)
+ {
+ FilePattern.Length = 2;
+ }
+
+ Status = NtQueryDirectoryFile(hDirectory,
+ NULL, NULL, NULL,
+ &IoStatusBlock,
+ DirInfo.DirInfo, // == &DirectoryInfo
+ sizeof(DirectoryInfo),
+ (fInfoLevelId == FindExInfoStandard
+ ? FileBothDirectoryInformation
+ : FileFullDirectoryInformation),
+ TRUE, /* Return a single entry */
+ &FilePattern,
+ TRUE);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ NtClose(hDirectory);
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ ASSERT(DirInfo.FullDirInfo->NextEntryOffset == 0);
+
+ /* Return the information */
+ CopyFindData(Win32FindData, fInfoLevelId, DirInfo);
+
+ /*
+ * Initialization of the search handle.
+ */
+ FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(FIND_DATA_HANDLE) +
+ sizeof(FIND_FILE_DATA));
+ if (!FindDataHandle)
+ {
+ NtClose(hDirectory);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ FindDataHandle->Type = FindFile;
+ FindDataHandle->u.FindFileData = (PFIND_FILE_DATA)(FindDataHandle + 1);
+ FindFileData = FindDataHandle->u.FindFileData;
+
+ FindFileData->Handle = hDirectory;
+ FindFileData->InfoLevel = fInfoLevelId;
+ FindFileData->SearchOp = fSearchOp;
+ FindFileData->HasMoreData = FALSE;
+ FindFileData->NextDirInfo.DirInfo = NULL;
+
+ /* The critical section must always be initialized */
+ Status = RtlInitializeCriticalSection(&FindDataHandle->Lock);
+ if (!NT_SUCCESS(Status))
+ {
+ NtClose(hDirectory);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return (HANDLE)FindDataHandle;
+ }
+ else
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return INVALID_HANDLE_VALUE;
}
}
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;
return INVALID_HANDLE_VALUE;
}
- /* validate & translate the filename */
+ /* Validate and translate the filename */
if (!RtlDosPathNameToNtPathName_U(lpFileName,
- &NtPathU,
- NULL,
- NULL))
+ &NtFilePath,
+ NULL, NULL))
{
SetLastError(ERROR_PATH_NOT_FOUND);
return INVALID_HANDLE_VALUE;
}
- /* open the file */
+ /* Open the file */
InitializeObjectAttributes(&ObjectAttributes,
- &NtPathU,
+ &NtFilePath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
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))
+ 0, NULL, 0);
+ if (!NT_SUCCESS(Status)) goto Cleanup;
+
+ /*
+ * Initialization of the search handle.
+ */
+ FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(FIND_DATA_HANDLE) +
+ sizeof(FIND_STREAM_DATA));
+ if (!FindDataHandle)
{
+ Status = STATUS_NO_MEMORY;
goto Cleanup;
}
- /* create the search context */
- IHeader = RtlAllocateHeap(RtlGetProcessHeap(),
- 0,
- sizeof(KERNEL32_FIND_DATA_HEADER) +
- sizeof(KERNEL32_FIND_STREAM_DATA));
- if (IHeader == NULL)
+ FindDataHandle->Type = FindStream;
+ FindDataHandle->u.FindStreamData = (PFIND_STREAM_DATA)(FindDataHandle + 1);
+ FindStreamData = FindDataHandle->u.FindStreamData;
+
+ FindStreamData->InfoLevel = InfoLevel;
+ FindStreamData->FileStreamInfo = NULL;
+ FindStreamData->CurrentInfo = NULL;
+
+ /* The critical section must always be initialized */
+ Status = RtlInitializeCriticalSection(&FindDataHandle->Lock);
+ if (!NT_SUCCESS(Status))
{
- Status = STATUS_NO_MEMORY;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
goto Cleanup;
}
- IHeader->Type = StreamFind;
- IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
-
- /* capture all information about the streams */
- IData->InfoLevel = InfoLevel;
- IData->pCurrent = NULL;
- IData->pFileStreamInfo = NULL;
-
+ /* Capture all information about the streams */
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;
PFILE_STREAM_INFORMATION pfsi;
pfsi = RtlReAllocateHeap(RtlGetProcessHeap(),
- 0,
- IData->pFileStreamInfo,
+ 0, // HEAP_ZERO_MEMORY,
+ FindStreamData->FileStreamInfo,
BufferSize);
if (pfsi == NULL)
{
break;
}
- IData->pFileStreamInfo = pfsi;
+ FindStreamData->FileStreamInfo = pfsi;
}
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
- IData->pFileStreamInfo,
+ FindStreamData->FileStreamInfo,
BufferSize,
FileStreamInformation);
if (NT_SUCCESS(Status))
{
- NtClose(FileHandle);
- FileHandle = NULL;
-
- /* select the first stream and return the information */
- IData->pCurrent = IData->pFileStreamInfo;
- InternalCopyStreamInfo(IData,
- lpFindStreamData);
+ /* Select the first stream and return the information */
+ FindStreamData->CurrentInfo = FindStreamData->FileStreamInfo;
+ CopyStreamData(FindStreamData, lpFindStreamData);
- /* all done */
+ /* All done */
Status = STATUS_SUCCESS;
}
-
-Cleanup:
- if (FileHandle != NULL)
+ else
{
- NtClose(FileHandle);
- }
+ if (FindStreamData->FileStreamInfo)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindStreamData->FileStreamInfo);
+ }
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- NtPathU.Buffer);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+ }
- if (!NT_SUCCESS(Status))
- {
- if (IHeader != NULL)
- {
- if (IData->pFileStreamInfo != NULL)
- {
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- IData->pFileStreamInfo);
- }
+Cleanup:
+ if (FileHandle) NtClose(FileHandle);
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- IHeader);
- }
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtFilePath.Buffer);
+ if (NT_SUCCESS(Status))
+ {
+ return (HANDLE)FindDataHandle;
+ }
+ else
+ {
BaseSetLastNTError(Status);
return INVALID_HANDLE_VALUE;
}
-
- return (HANDLE)IHeader;
}
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);
+ RtlEnterCriticalSection(&FindDataHandle->Lock);
- /* select next stream if possible */
- if (IData->pCurrent->NextEntryOffset != 0)
+ FindStreamData = FindDataHandle->u.FindStreamData;
+
+ /* 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 */
+ CopyStreamData(FindStreamData, lpFindStreamData);
+
+ RtlLeaveCriticalSection(&FindDataHandle->Lock);
+ return TRUE;
}
else
{
+ RtlLeaveCriticalSection(&FindDataHandle->Lock);
+
SetLastError(ERROR_HANDLE_EOF);
return FALSE;
}
-
- /* return the information */
- InternalCopyStreamInfo(IData,
- lpFindStreamData);
-
- return TRUE;
}
-
/* EOF */