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/fin... ============================================================================== --- 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; }