Author: weiden
Date: Sun Jul 15 02:29:42 2007
New Revision: 27667
URL:
http://svn.reactos.org/svn/reactos?rev=27667&view=rev
Log:
- Fix caching of directory queries, FindFirstFile(Ex) should no longer return garbage
occasionally
- These changes re-introduce the problem with searches for fake DOS devices that I claimed
to have fixed in r27634
Modified:
trunk/reactos/dll/win32/kernel32/file/find.c
Modified: trunk/reactos/dll/win32/kernel32/file/find.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/file/fi…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/file/find.c (original)
+++ trunk/reactos/dll/win32/kernel32/file/find.c Sun Jul 15 02:29:42 2007
@@ -19,15 +19,19 @@
/* TYPES ********************************************************************/
-#define FIND_DATA_SIZE (16*1024)
+#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;
- PFILE_BOTH_DIR_INFORMATION pFileInfo;
+ BOOLEAN HasMoreData;
+ BOOLEAN HasData;
+ BOOLEAN LockInitialized;
} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
typedef struct _KERNEL32_FIND_STREAM_DATA
@@ -51,7 +55,7 @@
/* FUNCTIONS ****************************************************************/
-HANDLE
+static HANDLE
InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
LPCWSTR lpFileName,
ULONG DeviceNameInfo)
@@ -72,7 +76,7 @@
return FIND_DEVICE_HANDLE;
}
-HANDLE
+static HANDLE
InternalCopyDeviceFindDataA(LPWIN32_FIND_DATAA lpFindFileData,
PUNICODE_STRING FileName,
ULONG DeviceNameInfo)
@@ -90,10 +94,6 @@
RtlUnicodeStringToAnsiString (&BufferA, &DeviceName, FALSE);
else
RtlUnicodeStringToOemString (&BufferA, &DeviceName, FALSE);
-
- /* NOTE: Free the string before we try to write the results to the caller,
- this way we prevent a memory leak in case of a fault... */
- RtlFreeUnicodeString(FileName);
/* Return the data */
RtlZeroMemory(lpFindFileData,
@@ -106,7 +106,7 @@
return FIND_DEVICE_HANDLE;
}
-VOID
+static VOID
InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
PFILE_BOTH_DIR_INFORMATION lpFileInfo)
{
@@ -131,7 +131,7 @@
lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)]
= 0;
}
-VOID
+static VOID
InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData,
PFILE_BOTH_DIR_INFORMATION lpFileInfo)
{
@@ -189,23 +189,23 @@
BOOL
STDCALL
InternalFindNextFile (
- HANDLE hFindFile,
- PUNICODE_STRING SearchPattern
- )
-{
- PKERNEL32_FIND_DATA_HEADER IHeader;
- PKERNEL32_FIND_FILE_DATA IData;
- IO_STATUS_BLOCK IoStatusBlock;
- NTSTATUS Status;
-
- DPRINT("InternalFindNextFile(%lx)\n", hFindFile);
-
- if (hFindFile == FIND_DEVICE_HANDLE)
- {
- SetLastError (ERROR_NO_MORE_FILES);
- return FALSE;
- }
-
+ HANDLE hFindFile,
+ PUNICODE_STRING SearchPattern,
+ PVOID lpFindFileData,
+ BOOL bUnicode
+ )
+{
+ 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;
+
+ DPRINT("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)
@@ -215,41 +215,119 @@
}
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
- while (1)
- {
- if (IData->pFileInfo->NextEntryOffset != 0)
- {
- IData->pFileInfo = (PVOID)((ULONG_PTR)IData->pFileInfo +
IData->pFileInfo->NextEntryOffset);
+ 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 = (PVOID)((ULONG_PTR)IData +
sizeof(KERNEL32_FIND_FILE_DATA));
- IData->pFileInfo->FileIndex = 0;
- Status = NtQueryDirectoryFile (IData->DirectoryHandle,
- NULL,
+ IData->pFileInfo = Buffer;
+ IData->pFileInfo->NextEntryOffset = 0;
+ Status = NtQueryDirectoryFile (IData->DirectoryHandle,
+ NULL,
NULL,
NULL,
&IoStatusBlock,
(PVOID)IData->pFileInfo,
FIND_DATA_SIZE,
FileBothDirectoryInformation,
- SearchPattern ? TRUE : FALSE,
+ FALSE,
SearchPattern,
- SearchPattern ? TRUE : FALSE);
+ 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;
- if (!NT_SUCCESS(Status))
+ }
+
+ } while (FoundFile == NULL);
+
+ if (FoundFile != NULL)
+ {
+ _SEH_TRY
+ {
+ if (bUnicode)
{
- SetLastErrorByStatus (Status);
- return FALSE;
- }
+ InternalCopyFindDataW(lpFindFileData,
+ FoundFile);
+ }
+ else
+ {
+ InternalCopyFindDataA(lpFindFileData,
+ FoundFile);
+ }
}
- if (!IData->DirectoryOnly || IData->pFileInfo->FileAttributes &
FILE_ATTRIBUTE_DIRECTORY)
+ _SEH_HANDLE
{
- DPRINT("Found
%.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR),
IData->pFileInfo->FileName);
- return TRUE;
}
+ _SEH_END;
}
+
+ if (Locked)
+ RtlLeaveCriticalSection(&IData->Lock);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastErrorByStatus (Status);
+ return FALSE;
+ }
+ else if (FoundFile == NULL)
+ {
+ SetLastError (ERROR_NO_MORE_FILES);
+ return FALSE;
+ }
+
+ return TRUE;
}
@@ -261,7 +339,8 @@
InternalFindFirstFile (
LPCWSTR lpFileName,
BOOLEAN DirectoryOnly,
- PULONG DeviceNameInfo
+ PVOID lpFindFileData,
+ BOOL bUnicode
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
@@ -274,12 +353,12 @@
BOOLEAN RemovedSlash = FALSE;
BOOL bResult;
CURDIR DirInfo;
- HANDLE hDirectory = NULL;
+ ULONG DeviceNameInfo;
+ HANDLE hDirectory = NULL;
DPRINT("FindFirstFileW(lpFileName %S)\n",
lpFileName);
- *DeviceNameInfo = 0;
RtlZeroMemory(&PathFileName,
sizeof(PathFileName));
RtlInitUnicodeString(&FileName,
@@ -329,8 +408,8 @@
/* Remove a trailing backslash from the path, unless it's a DOS drive directly */
if (NtPathU.Length > 3 * sizeof(WCHAR) &&
- NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':' &&
- NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] != L'\\')
+ NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] == L'\\' &&
+ NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':')
{
NtPathU.Length -= sizeof(WCHAR);
RemovedSlash = TRUE;
@@ -348,11 +427,11 @@
NULL);
Status = NtOpenFile (&hDirectory,
- FILE_LIST_DIRECTORY,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_DIRECTORY_FILE);
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status) && RemovedSlash)
{
@@ -360,25 +439,38 @@
NtPathU.Length -= sizeof(WCHAR);
Status = NtOpenFile (&hDirectory,
- FILE_LIST_DIRECTORY,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_DIRECTORY_FILE);
-
- NtPathU.Length -= sizeof(WCHAR);
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
}
if (!NT_SUCCESS(Status))
{
- RtlFreeHeap (hProcessHeap,
- 0,
- NtPathBuffer);
+ RtlFreeHeap (hProcessHeap,
+ 0,
+ NtPathBuffer);
/* See if the application tries to look for a DOS device */
- *DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName));
- if (*DeviceNameInfo != 0)
+ DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName));
+ if (DeviceNameInfo != 0)
+ {
+ if (bUnicode)
+ {
+ InternalCopyDeviceFindDataW(lpFindFileData,
+ lpFileName,
+ DeviceNameInfo);
+ }
+ else
+ {
+ InternalCopyDeviceFindDataA(lpFindFileData,
+ &FileName,
+ DeviceNameInfo);
+ }
+
return FIND_DEVICE_HANDLE;
+ }
SetLastErrorByStatus (Status);
return(NULL);
@@ -413,6 +505,7 @@
IHeader->Type = FileFind;
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
IData->DirectoryHandle = hDirectory;
+ IData->HasMoreData = TRUE;
/* change pattern: "*.*" --> "*" */
if (PathFileName.Length == 6 &&
@@ -427,7 +520,10 @@
IData->pFileInfo->FileIndex = 0;
IData->DirectoryOnly = DirectoryOnly;
- bResult = InternalFindNextFile((HANDLE)IHeader, &PathFileName);
+ bResult = InternalFindNextFile((HANDLE)IHeader,
+ &PathFileName,
+ lpFindFileData,
+ bUnicode);
RtlFreeHeap (hProcessHeap,
0,
@@ -438,6 +534,9 @@
FindClose((HANDLE)IHeader);
return NULL;
}
+
+ RtlInitializeCriticalSection(&IData->Lock);
+ IData->LockInitialized = TRUE;
return (HANDLE)IHeader;
}
@@ -453,52 +552,12 @@
LPWIN32_FIND_DATAA lpFindFileData
)
{
- PKERNEL32_FIND_DATA_HEADER IHeader;
- PKERNEL32_FIND_FILE_DATA IData;
- UNICODE_STRING FileNameU;
- ANSI_STRING FileName;
- ULONG DeviceNameInfo;
-
- RtlInitAnsiString (&FileName,
- (LPSTR)lpFileName);
-
- /* convert ansi (or oem) string to unicode */
- if (bIsFileApiAnsi)
- RtlAnsiStringToUnicodeString (&FileNameU,
- &FileName,
- TRUE);
- else
- RtlOemStringToUnicodeString (&FileNameU,
- &FileName,
- TRUE);
-
- IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE, &DeviceNameInfo);
-
- if (IHeader == NULL)
- {
- RtlFreeUnicodeString (&FileNameU);
- DPRINT("Failing request\n");
- return INVALID_HANDLE_VALUE;
- }
-
- if ((HANDLE)IHeader == FIND_DEVICE_HANDLE)
- {
- /* NOTE: FileNameU will be freed in InternalCopyDeviceFindDataA */
- return InternalCopyDeviceFindDataA(lpFindFileData, &FileNameU, DeviceNameInfo);
- }
-
- RtlFreeUnicodeString (&FileNameU);
-
- IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
- DPRINT("IData->pFileInfo->FileNameLength %d\n",
- IData->pFileInfo->FileNameLength);
-
- /* copy data into WIN32_FIND_DATA structure */
- InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
-
-
- return (HANDLE)IHeader;
+ return FindFirstFileExA (lpFileName,
+ FindExInfoStandard,
+ (LPVOID)lpFindFileData,
+ FindExSearchNameMatch,
+ NULL,
+ 0);
}
@@ -511,23 +570,10 @@
HANDLE hFindFile,
LPWIN32_FIND_DATAA lpFindFileData)
{
- PKERNEL32_FIND_FILE_DATA IData;
-
- if (!InternalFindNextFile (hFindFile, NULL))
- {
- DPRINT("InternalFindNextFile() failed\n");
- return FALSE;
- }
-
- IData = (PKERNEL32_FIND_FILE_DATA)((PKERNEL32_FIND_DATA_HEADER)hFindFile + 1);
-
- DPRINT("IData->pFileInfo->FileNameLength %d\n",
- IData->pFileInfo->FileNameLength);
-
- /* copy data into WIN32_FIND_DATA structure */
- InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
-
- return TRUE;
+ return InternalFindNextFile (hFindFile,
+ NULL,
+ lpFindFileData,
+ FALSE);
}
@@ -561,6 +607,8 @@
{
PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
CloseHandle (IData->DirectoryHandle);
+ if (IData->LockInitialized)
+ RtlDeleteCriticalSection(&IData->Lock);
break;
}
@@ -595,13 +643,12 @@
LPWIN32_FIND_DATAW lpFindFileData
)
{
-
- return FindFirstFileExW (lpFileName,
- FindExInfoStandard,
- (LPVOID)lpFindFileData,
- FindExSearchNameMatch,
- NULL,
- 0);
+ return FindFirstFileExW (lpFileName,
+ FindExInfoStandard,
+ (LPVOID)lpFindFileData,
+ FindExSearchNameMatch,
+ NULL,
+ 0);
}
/*
@@ -614,20 +661,10 @@
LPWIN32_FIND_DATAW lpFindFileData
)
{
- PKERNEL32_FIND_FILE_DATA IData;
-
- if (!InternalFindNextFile(hFindFile, NULL))
- {
- DPRINT("Failing request\n");
- return FALSE;
- }
-
- IData = (PKERNEL32_FIND_FILE_DATA)((PKERNEL32_FIND_DATA_HEADER)hFindFile + 1);
-
- /* copy data into WIN32_FIND_DATA structure */
- InternalCopyFindDataW(lpFindFileData, IData->pFileInfo);
-
- return TRUE;
+ return InternalFindNextFile (hFindFile,
+ NULL,
+ lpFindFileData,
+ TRUE);
}
@@ -643,15 +680,14 @@
LPVOID lpSearchFilter,
DWORD dwAdditionalFlags)
{
- PKERNEL32_FIND_DATA_HEADER IHeader;
- PKERNEL32_FIND_FILE_DATA IData;
- ULONG DeviceNameInfo;
+ HANDLE Handle;
if (fInfoLevelId != FindExInfoStandard)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
+
if (fSearchOp == FindExSearchNameMatch || fSearchOp ==
FindExSearchLimitToDirectories)
{
if (lpSearchFilter)
@@ -660,23 +696,19 @@
return INVALID_HANDLE_VALUE;
}
- IHeader = InternalFindFirstFile (lpFileName, fSearchOp ==
FindExSearchLimitToDirectories ? TRUE : FALSE, &DeviceNameInfo);
- if (IHeader == NULL)
+ Handle = InternalFindFirstFile (lpFileName,
+ fSearchOp == FindExSearchLimitToDirectories,
+ lpFindFileData,
+ TRUE);
+ if (Handle == NULL)
{
DPRINT("Failing request\n");
return INVALID_HANDLE_VALUE;
}
- if ((HANDLE)IHeader == FIND_DEVICE_HANDLE)
- return InternalCopyDeviceFindDataW((LPWIN32_FIND_DATAW)lpFindFileData,
lpFileName, DeviceNameInfo);
-
- IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
- /* copy data into WIN32_FIND_DATA structure */
- InternalCopyFindDataW((LPWIN32_FIND_DATAW)lpFindFileData, IData->pFileInfo);
-
- return (HANDLE)IHeader;
- }
+ return Handle;
+ }
+
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
@@ -695,11 +727,9 @@
DWORD dwAdditionalFlags
)
{
- PKERNEL32_FIND_DATA_HEADER IHeader;
- PKERNEL32_FIND_FILE_DATA IData;
UNICODE_STRING FileNameU;
ANSI_STRING FileNameA;
- ULONG DeviceNameInfo;
+ HANDLE Handle;
if (fInfoLevelId != FindExInfoStandard)
{
@@ -713,39 +743,31 @@
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
-
+
RtlInitAnsiString (&FileNameA, (LPSTR)lpFileName);
- /* convert ansi (or oem) string to unicode */
- if (bIsFileApiAnsi)
+ /* convert ansi (or oem) string to unicode */
+ if (bIsFileApiAnsi)
RtlAnsiStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
- else
+ else
RtlOemStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
- IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE, &DeviceNameInfo);
-
- if (IHeader == NULL)
- {
- RtlFreeUnicodeString (&FileNameU);
- DPRINT("Failing request\n");
- return INVALID_HANDLE_VALUE;
- }
-
- if ((HANDLE)IHeader == FIND_DEVICE_HANDLE)
- {
- /* NOTE: FileNameU will be freed in InternalCopyDeviceFindDataA */
- return InternalCopyDeviceFindDataA(lpFindFileData, &FileNameU, DeviceNameInfo);
- }
-
- RtlFreeUnicodeString (&FileNameU);
-
- IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
- /* copy data into WIN32_FIND_DATA structure */
- InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
-
- return (HANDLE)IHeader;
- }
+ Handle = InternalFindFirstFile (FileNameU.Buffer,
+ fSearchOp == FindExSearchLimitToDirectories,
+ lpFindFileData,
+ FALSE);
+
+ RtlFreeUnicodeString (&FileNameU);
+
+ if (Handle == NULL)
+ {
+ DPRINT("Failing request\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return Handle;
+ }
+
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}