Author: hbelusca
Date: Thu Sep 27 22:07:06 2012
New Revision: 57407
URL:
http://svn.reactos.org/svn/reactos?rev=57407&view=rev
Log:
[KERNEL32]
- Reworking the Find* APIs in kernel32. Fixes some kernel32_winetest:file failures.
- The FindExInfoBasic information level for FindFirstFileEx, is also implemented.
- Update ndk and psdk headers regarding to this work.
CORE-6623 #comment Committed in rev.57407. #resolve
Modified:
trunk/reactos/dll/win32/kernel32/client/file/find.c
trunk/reactos/include/ndk/iotypes.h
trunk/reactos/include/psdk/winbase.h
Modified: trunk/reactos/dll/win32/kernel32/client/file/find.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/file/find.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/file/find.c [iso-8859-1] Thu Sep 27 22:07:06
2012
@@ -1,452 +1,256 @@
-/* $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(a)xs4all.nl)
+ * PROGRAMMERS: Ariadne (ariadne(a)xs4all.nl)
* Pierre Schweitzer (pierre.schweitzer(a)reactos.org)
- * UPDATE HISTORY:
- * Created 01/11/98
+ * Hermes BELUSCA - MAITO (hermes.belusca(a)sfr.fr)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES *******************************************************************/
#include <k32.h>
#define NDEBUG
#include <debug.h>
DEBUG_CHANNEL(kernel32file);
-/* TYPES ********************************************************************/
-
-#define FIND_DATA_SIZE 0x4000
-
-#define FIND_DEVICE_HANDLE ((HANDLE)0x1)
-
-typedef struct _KERNEL32_FIND_FILE_DATA
-{
- HANDLE DirectoryHandle;
- RTL_CRITICAL_SECTION Lock;
- PFILE_BOTH_DIR_INFORMATION pFileInfo;
- BOOLEAN DirectoryOnly;
- BOOLEAN HasMoreData;
- BOOLEAN HasData;
- BOOLEAN LockInitialized;
-} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
-
-typedef struct _KERNEL32_FIND_STREAM_DATA
+
+/* TYPES **********************************************************************/
+
+#define FIND_DATA_SIZE 0x4000
+#define FIND_DEVICE_HANDLE ((HANDLE)0x1)
+
+typedef enum _FIND_DATA_TYPE
+{
+ 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
+{
+ PVOID DirInfo;
+ PFILE_FULL_DIR_INFORMATION FullDirInfo;
+ PFILE_BOTH_DIR_INFORMATION BothDirInfo;
+} DIR_INFORMATION;
+
+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
{
STREAM_INFO_LEVELS InfoLevel;
- PFILE_STREAM_INFORMATION pFileStreamInfo;
- PFILE_STREAM_INFORMATION pCurrent;
-} KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA;
-
-typedef enum _KERNEL32_FIND_DATA_TYPE
-{
- FileFind,
- StreamFind
-} KERNEL32_FIND_DATA_TYPE;
-
-typedef struct _KERNEL32_FIND_DATA_HEADER
-{
- KERNEL32_FIND_DATA_TYPE Type;
-} KERNEL32_FIND_DATA_HEADER, *PKERNEL32_FIND_DATA_HEADER;
-
-
-/* FUNCTIONS ****************************************************************/
+ PFILE_STREAM_INFORMATION FileStreamInfo;
+ PFILE_STREAM_INFORMATION CurrentInfo;
+} FIND_STREAM_DATA, *PFIND_STREAM_DATA;
+
+typedef struct _FIND_DATA_HANDLE
+{
+ 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;
+
+
+/* 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));
-
- /* Return the data */
- RtlZeroMemory(lpFindFileData,
- sizeof(*lpFindFileData));
- lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
- RtlCopyMemory(lpFindFileData->cFileName,
- DeviceName.Buffer,
- DeviceName.Length);
+ _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;
}
static VOID
-InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
- PFILE_BOTH_DIR_INFORMATION lpFileInfo)
-{
- lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes;
-
- 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;
-
- memcpy (lpFindFileData->cFileName, lpFileInfo->FileName,
lpFileInfo->FileNameLength);
- lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
-
- memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName,
lpFileInfo->ShortNameLength);
- lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)]
= 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)
- {
- SetLastError (ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- 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;
- }
-
- do
- {
- if (IData->HasData)
- {
- if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY))
- {
- FoundFile = IData->pFileInfo;
- }
-
- 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)
- {
- _SEH2_TRY
- {
- InternalCopyFindDataW(lpFindFileData,
- FoundFile);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- }
- _SEH2_END;
- }
-
- if (Locked)
- RtlLeaveCriticalSection(&IData->Lock);
- }
-
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError (Status);
- return FALSE;
- }
- else if (FoundFile == NULL)
- {
- SetLastError (ERROR_NO_MORE_FILES);
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- * @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;
-}
-
+CopyFindData(OUT LPWIN32_FIND_DATAW lpFindFileData,
+ IN FINDEX_INFO_LEVELS fInfoLevelId,
+ IN DIR_INFORMATION DirInfo)
+{
+#define ULARGE_INTEGER_2_FILETIME(ft, ul) \
+do { \
+ (ft).dwHighDateTime = (ul).u.HighPart; \
+ (ft).dwLowDateTime = (ul).u.LowPart ; \
+} while(0)
+
+ _SEH2_TRY
+ {
+ RtlZeroMemory(lpFindFileData, sizeof(*lpFindFileData));
+
+ lpFindFileData->dwFileAttributes = DirInfo.FullDirInfo->FileAttributes;
+
+ 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;
+
+ /* 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;
+
+ /* Unused dwReserved1 field */
+ lpFindFileData->dwReserved1 = 0;
+
+ if (fInfoLevelId == FindExInfoStandard)
+ {
+ 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;
+
+ lpFindFileData->cAlternateFileName[0] = UNICODE_NULL;
+ }
+ else
+ {
+ /* Invalid InfoLevelId */
+ ASSERT(FALSE);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+
+ return;
+}
+
+static VOID
+CopyStreamData(IN OUT PFIND_STREAM_DATA FindStreamData,
+ OUT PWIN32_FIND_STREAM_DATA lpFindStreamData)
+{
+ _SEH2_TRY
+ {
+ ASSERT(FindStreamData->CurrentInfo);
+
+ switch (FindStreamData->InfoLevel)
+ {
+ case FindStreamInfoStandard:
+ {
+ ULONG StreamNameLen =
min(FindStreamData->CurrentInfo->StreamNameLength,
+ sizeof(lpFindStreamData->cStreamName) -
sizeof(WCHAR));
+
+ RtlZeroMemory(lpFindStreamData, sizeof(*lpFindStreamData));
+
+ lpFindStreamData->StreamSize.QuadPart =
FindStreamData->CurrentInfo->StreamSize.QuadPart;
+ RtlCopyMemory(lpFindStreamData->cStreamName,
+ FindStreamData->CurrentInfo->StreamName,
+ StreamNameLen);
+ lpFindStreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] =
UNICODE_NULL;
+
+ break;
+ }
+
+ default:
+ {
+ /* Invalid InfoLevel */
+ ASSERT(FALSE);
+ break;
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+
+ return;
+}
+
+
+/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
@@ -464,27 +268,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;
- }
-
- memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA,
cFileName));
+ if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
+
+ 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 +296,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))
{
@@ -506,6 +306,22 @@
}
return hSearch;
+}
+
+
+/*
+ * @implemented
+ */
+HANDLE
+WINAPI
+FindFirstFileW(IN LPCWSTR lpFileName,
+ OUT LPWIN32_FIND_DATAW lpFindFileData)
+{
+ return FindFirstFileExW(lpFileName,
+ FindExInfoStandard,
+ lpFindFileData,
+ FindExSearchNameMatch,
+ NULL, 0);
}
@@ -523,16 +339,16 @@
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))
{
@@ -543,7 +359,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))
{
@@ -554,79 +370,6 @@
return TRUE;
}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-FindClose (
- HANDLE hFindFile
- )
-{
- 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;
-}
-
-
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-FindFirstFileW(IN LPCWSTR lpFileName,
- OUT LPWIN32_FIND_DATAW lpFindFileData)
-{
- return FindFirstFileExW(lpFileName,
- FindExInfoStandard,
- lpFindFileData,
- FindExSearchNameMatch,
- NULL,
- 0);
-}
/*
* @implemented
@@ -636,9 +379,261 @@
FindNextFileW(IN HANDLE hFindFile,
OUT LPWIN32_FIND_DATAW lpFindFileData)
{
- return InternalFindNextFile(hFindFile,
- NULL,
- lpFindFileData);
+ NTSTATUS Status = STATUS_SUCCESS;
+ DIR_INFORMATION FoundFile = {NULL};
+
+ TRACE("FindNextFileW(%lx, 0x%p)\n", hFindFile, lpFindFileData);
+
+ 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
+FindClose(HANDLE hFindFile)
+{
+ 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;
+ }
+
+ /* Protect with SEH against closing attempts on invalid handles. */
+ _SEH2_TRY
+ {
+ PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindFile;
+
+ switch (FindDataHandle->Type)
+ {
+ 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);
+ }
+ }
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+ _SEH2_YIELD(return TRUE);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BaseSetLastNTError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
+}
+
+
+/*
+ * @unimplemented
+ */
+HANDLE
+WINAPI
+FindFirstFileExA(IN LPCSTR lpFileName,
+ IN FINDEX_INFO_LEVELS fInfoLevelId,
+ OUT LPVOID lpFindFileData,
+ IN FINDEX_SEARCH_OPS fSearchOp,
+ LPVOID lpSearchFilter,
+ IN DWORD dwAdditionalFlags)
+{
+ HANDLE hSearch;
+ NTSTATUS Status;
+ ANSI_STRING Ansi;
+ UNICODE_STRING UTF8;
+ PUNICODE_STRING lpFileNameW;
+ WIN32_FIND_DATAW FindFileDataW;
+ LPWIN32_FIND_DATAA lpFindFileDataA = (LPWIN32_FIND_DATAA)lpFindFileData;
+
+ if ((fInfoLevelId != FindExInfoStandard && fInfoLevelId != FindExInfoBasic)
||
+ fSearchOp == FindExSearchLimitToDevices ||
+ dwAdditionalFlags & ~FIND_FIRST_EX_CASE_SENSITIVE /* only supported flag for
now */)
+ {
+ SetLastError(fSearchOp == FindExSearchLimitToDevices
+ ? ERROR_NOT_SUPPORTED
+ : ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName);
+ if (!lpFileNameW) return INVALID_HANDLE_VALUE;
+
+ hSearch = FindFirstFileExW(lpFileNameW->Buffer,
+ fInfoLevelId,
+ &FindFileDataW,
+ fSearchOp,
+ lpSearchFilter,
+ dwAdditionalFlags);
+ if (hSearch == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
+
+ RtlCopyMemory(lpFindFileDataA,
+ &FindFileDataW,
+ FIELD_OFFSET(WIN32_FIND_DATAA, cFileName));
+
+ RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName);
+ Ansi.Buffer = lpFindFileDataA->cFileName;
+ Ansi.Length = 0;
+ Ansi.MaximumLength = sizeof(lpFindFileDataA->cFileName);
+ Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ FindClose(hSearch);
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (fInfoLevelId != FindExInfoBasic)
+ {
+ 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;
}
@@ -654,123 +649,241 @@
LPVOID lpSearchFilter,
IN DWORD dwAdditionalFlags)
{
- if (fInfoLevelId != FindExInfoStandard)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
+ TRACE("FindFirstFileExW(lpFileName %S)\n", lpFileName);
+
+ 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;
}
- if (fSearchOp == FindExSearchNameMatch || fSearchOp ==
FindExSearchLimitToDirectories)
- {
+ 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)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
- return InternalFindFirstFile (lpFileName,
- fSearchOp == FindExSearchLimitToDirectories,
- lpFindFileData);
- }
-
- SetLastError(ERROR_INVALID_PARAMETER);
- return INVALID_HANDLE_VALUE;
-}
-
-/*
- * @unimplemented
- */
-HANDLE
-WINAPI
-FindFirstFileExA(IN LPCSTR lpFileName,
- IN FINDEX_INFO_LEVELS fInfoLevelId,
- OUT LPVOID lpFindFileData,
- IN FINDEX_SEARCH_OPS fSearchOp,
- LPVOID lpSearchFilter,
- IN DWORD dwAdditionalFlags)
-{
- HANDLE hSearch;
- NTSTATUS Status;
- ANSI_STRING Ansi;
- UNICODE_STRING UTF8;
- PUNICODE_STRING lpFileNameW;
- WIN32_FIND_DATAW FindFileDataW;
-
- lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName);
- if (!lpFileNameW)
- {
+ 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;
- }
-
- hSearch = FindFirstFileExW(lpFileNameW->Buffer,
- fInfoLevelId,
- &FindFileDataW,
- fSearchOp,
- lpSearchFilter,
- dwAdditionalFlags);
- if (hSearch == INVALID_HANDLE_VALUE)
- {
- return INVALID_HANDLE_VALUE;
- }
-
- memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA,
cFileName));
-
- RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName);
- Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cFileName;
- Ansi.Length = 0;
- Ansi.MaximumLength = MAX_PATH;
- Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE);
- if (!NT_SUCCESS(Status))
- {
- FindClose(hSearch);
- BaseSetLastNTError(Status);
- return INVALID_HANDLE_VALUE;
- }
-
- RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName);
- Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cAlternateFileName;
- Ansi.Length = 0;
- Ansi.MaximumLength = 14;
- Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE);
- if (!NT_SUCCESS(Status))
- {
- FindClose(hSearch);
- BaseSetLastNTError(Status);
- return INVALID_HANDLE_VALUE;
- }
-
- return hSearch;
-}
-
-
-static VOID
-InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData,
- OUT LPVOID lpFindStreamData)
-{
- ASSERT(IData->pCurrent);
-
- switch (IData->InfoLevel)
- {
- case FindStreamInfoStandard:
- {
- 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;
- }
-
- default:
- ASSERT(FALSE);
- break;
}
}
@@ -785,11 +898,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 +914,18 @@
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);
@@ -822,47 +934,52 @@
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;
- }
-
- /* create the search context */
- IHeader = RtlAllocateHeap(RtlGetProcessHeap(),
- 0,
- sizeof(KERNEL32_FIND_DATA_HEADER) +
- sizeof(KERNEL32_FIND_STREAM_DATA));
- if (IHeader == NULL)
+ 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;
}
- 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;
-
+ 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))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+ goto Cleanup;
+ }
+
+ /* Capture all information about the streams */
do
{
BufferSize += 0x1000;
- if (IData->pFileStreamInfo == NULL)
- {
- IData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(),
- 0,
- BufferSize);
- if (IData->pFileStreamInfo == NULL)
+ if (FindStreamData->FileStreamInfo == NULL)
+ {
+ FindStreamData->FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ BufferSize);
+ if (FindStreamData->FileStreamInfo == NULL)
{
Status = STATUS_NO_MEMORY;
break;
@@ -873,8 +990,8 @@
PFILE_STREAM_INFORMATION pfsi;
pfsi = RtlReAllocateHeap(RtlGetProcessHeap(),
- 0,
- IData->pFileStreamInfo,
+ 0, // HEAP_ZERO_MEMORY,
+ FindStreamData->FileStreamInfo,
BufferSize);
if (pfsi == NULL)
{
@@ -882,12 +999,12 @@
break;
}
- IData->pFileStreamInfo = pfsi;
+ FindStreamData->FileStreamInfo = pfsi;
}
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
- IData->pFileStreamInfo,
+ FindStreamData->FileStreamInfo,
BufferSize,
FileStreamInformation);
@@ -895,49 +1012,37 @@
if (NT_SUCCESS(Status))
{
- NtClose(FileHandle);
- FileHandle = NULL;
-
- /* select the first stream and return the information */
- IData->pCurrent = IData->pFileStreamInfo;
- InternalCopyStreamInfo(IData,
- lpFindStreamData);
-
- /* all done */
+ /* Select the first stream and return the information */
+ FindStreamData->CurrentInfo = FindStreamData->FileStreamInfo;
+ CopyStreamData(FindStreamData, lpFindStreamData);
+
+ /* All done */
Status = STATUS_SUCCESS;
}
+ else
+ {
+ if (FindStreamData->FileStreamInfo)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindStreamData->FileStreamInfo);
+ }
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+ }
Cleanup:
- if (FileHandle != NULL)
- {
- NtClose(FileHandle);
- }
-
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- NtPathU.Buffer);
-
- if (!NT_SUCCESS(Status))
- {
- if (IHeader != NULL)
- {
- if (IData->pFileStreamInfo != NULL)
- {
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- IData->pFileStreamInfo);
- }
-
- RtlFreeHeap(RtlGetProcessHeap(),
- 0,
- IHeader);
- }
-
+ if (FileHandle) NtClose(FileHandle);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtFilePath.Buffer);
+
+ if (NT_SUCCESS(Status))
+ {
+ return (HANDLE)FindDataHandle;
+ }
+ else
+ {
BaseSetLastNTError(Status);
return INVALID_HANDLE_VALUE;
}
-
- return (HANDLE)IHeader;
}
@@ -949,37 +1054,39 @@
FindNextStreamW(IN HANDLE hFindStream,
OUT LPVOID lpFindStreamData)
{
- PKERNEL32_FIND_DATA_HEADER IHeader;
- PKERNEL32_FIND_STREAM_DATA IData;
-
- IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream;
+ PFIND_DATA_HANDLE FindDataHandle = (PFIND_DATA_HANDLE)hFindStream;
+ PFIND_STREAM_DATA FindStreamData;
+
if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE ||
- IHeader->Type != StreamFind)
- {
- SetLastError (ERROR_INVALID_HANDLE);
+ FindDataHandle->Type != FindStream)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
- IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
-
- /* select next stream if possible */
- if (IData->pCurrent->NextEntryOffset != 0)
- {
- IData->pCurrent =
(PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo +
-
IData->pCurrent->NextEntryOffset);
+ RtlEnterCriticalSection(&FindDataHandle->Lock);
+
+ FindStreamData = FindDataHandle->u.FindStreamData;
+
+ /* Select next stream if possible */
+ if (FindStreamData->CurrentInfo->NextEntryOffset != 0)
+ {
+ 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 */
Modified: trunk/reactos/include/ndk/iotypes.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/iotypes.h?rev=…
==============================================================================
--- trunk/reactos/include/ndk/iotypes.h [iso-8859-1] (original)
+++ trunk/reactos/include/ndk/iotypes.h [iso-8859-1] Thu Sep 27 22:07:06 2012
@@ -523,6 +523,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
{
Modified: trunk/reactos/include/psdk/winbase.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/psdk/winbase.h?rev…
==============================================================================
--- trunk/reactos/include/psdk/winbase.h [iso-8859-1] (original)
+++ trunk/reactos/include/psdk/winbase.h [iso-8859-1] Thu Sep 27 22:07:06 2012
@@ -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;