2005-01-06 13:58:04 +00:00
|
|
|
/* $Id$
|
1999-08-29 06:59:11 +00:00
|
|
|
*
|
1999-01-16 02:11:45 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
|
|
|
* FILE: lib/kernel32/file/find.c
|
|
|
|
* PURPOSE: Find functions
|
2005-07-30 13:49:41 +00:00
|
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
1999-01-16 02:11:45 +00:00
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 01/11/98
|
|
|
|
*/
|
1999-01-16 21:03:00 +00:00
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2003-01-15 21:24:36 +00:00
|
|
|
#include <k32.h>
|
[KERNEL32]: While working on the CMAKE branch, Amine and myself discovered a rather serious issue in kernel32 (and perhaps other libraries as well). Unlike rbuild, CMake does not allow you to export non-existant DLL functions (try it: add "poopyhead" in kernel32's exports under RBuild, and will it export "poopyhead", God knowing what that will actually link to).
As an additional feature on top of the "allow non-existing functions to be exported" "feature", because rbuild generates and links STDCALL function names without the proper decoration (vs. enforcing decoration at linking, but only removing it at export-time), this allows the definition (as an export) of a STDCALL function that is completely different from the actual function itself.
For example, the 5-parameter Foo function is normally Foo@20, while the 3-parameter Foo function woudl be Foo@12. Linking one against the other would fail (say, 2 parameters were added to Foo in a newer version). However, under RBUILD, both of these would appear as "Foo", and the linker/compiler would happilly connect the caller of Foo@3 (that has pushed 3 parameters) to the receiving side of Foo@5 (that is about to pop 5 parameters).
Even -if- decorations WERE to be applied, Foo@12 would STILL succeed, because of the first feature, which would enable the export of Foo@12 even though no such function exist.
In a further, bizare, twist of fate, the behavior of this RBUILD "feature", when the target function is not found, is to link the exported DLL TO ITSELF.
Therefore, one can see how, previously to this patch, kernel32.dll would import a dozen functions from itself (all the non-existing functions).
To really seal the deal, the behavior of exported functions used by kernel32, but that are actually forwarded to another DLL deserves a special mention.
GetLastError, for example, merely forwards to RtlGetLastWin32Error, so it is normal behavior to use a #define in the C code so that all internal calls to the function are routed correctly.
This did not happen, so instead, kernel32 tried importing/linking/exporting GetLastError, but this symbol is not found in the binary, because it is only a forwarder.
This caused kernel32 to import from itself (the behavior when an exported symbol is not found). When importing from itself, the loader would now find the _forwarded_ for GetLastError, and correctly link with ntdll.
What should be a one-liner of assembly (inline TEB access) thus became a triple-call indirection (GetLastError@0->StubLastError@0->__impGetLastError@0->__impRtlGetLastWin32Error->RtlGetLastWin32Error.
While analyzing these issues, we also realized a strange macro SetLastErrorByStatus that manually tried to perform what there already exists a function for: RtlSetLastNtStatusFromWin32Error.
And, in an exciting coda, we also realized that our Server 2003 Kernel32 exports more than a dozen Windows 95 APIs, through an auto-stub generation mechanism within winebuild, that gets linked as an object behind the scenes.
[KERNEL32]: Removed all Win95 exports, cleaned up exports.
[KERNEL32]: Fixed up set/get error macros by making them inline and/or calling the correct ntdll function.
[KERNEL32]: Removed bizare calls to Wine-internal/specific APIs from our core Win32 DLL.
[KERNEL32]: Wrote stubs for all functions which should be exported, and set the correct number of parameters for them.
[KERNEL32]: Kernel32 is smaller, loads faster, does not export Windows 95 functions, does not export non-existing functions, and does not import from itself anymore.
Note: This is one of the many failings of RBUILD the CMAKE system has helped us discover. I believe these issues are serious enough to warrant an immediate sync with trunk, but rest assured, there are many more completely broken, infinitely-regressing things that we discovered while switching to CMAKE.
svn path=/trunk/; revision=48475
2010-08-07 05:02:58 +00:00
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
2010-09-21 17:14:22 +00:00
|
|
|
DEBUG_CHANNEL(kernel32file);
|
2000-03-15 23:13:29 +00:00
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
/* TYPES ********************************************************************/
|
1999-01-16 02:11:45 +00:00
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
#define FIND_DATA_SIZE 0x4000
|
2002-09-13 19:03:40 +00:00
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
#define FIND_DEVICE_HANDLE ((HANDLE)0x1)
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
typedef struct _KERNEL32_FIND_FILE_DATA
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-01-16 21:03:00 +00:00
|
|
|
HANDLE DirectoryHandle;
|
2007-07-14 22:29:42 +00:00
|
|
|
RTL_CRITICAL_SECTION Lock;
|
2005-06-20 01:52:47 +00:00
|
|
|
PFILE_BOTH_DIR_INFORMATION pFileInfo;
|
2007-07-14 22:29:42 +00:00
|
|
|
BOOLEAN DirectoryOnly;
|
|
|
|
BOOLEAN HasMoreData;
|
|
|
|
BOOLEAN HasData;
|
|
|
|
BOOLEAN LockInitialized;
|
1999-01-16 21:03:00 +00:00
|
|
|
} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
|
1999-01-16 02:11:45 +00:00
|
|
|
|
2006-01-15 03:11:31 +00:00
|
|
|
typedef struct _KERNEL32_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;
|
|
|
|
|
2000-03-15 23:13:29 +00:00
|
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
1999-01-16 02:11:45 +00:00
|
|
|
|
2010-05-30 21:19:26 +00:00
|
|
|
static VOID
|
2007-07-13 19:43:09 +00:00
|
|
|
InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
|
|
|
|
LPCWSTR lpFileName,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-05-30 21:19:26 +00:00
|
|
|
static VOID
|
2007-07-13 19:43:09 +00:00
|
|
|
InternalCopyDeviceFindDataA(LPWIN32_FIND_DATAA lpFindFileData,
|
|
|
|
PUNICODE_STRING FileName,
|
|
|
|
ULONG DeviceNameInfo)
|
|
|
|
{
|
|
|
|
UNICODE_STRING DeviceName;
|
|
|
|
ANSI_STRING BufferA;
|
|
|
|
CHAR Buffer[MAX_PATH];
|
|
|
|
|
|
|
|
DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF);
|
|
|
|
DeviceName.Buffer = (LPWSTR)((ULONG_PTR)FileName->Buffer + (DeviceNameInfo >> 16));
|
|
|
|
|
|
|
|
BufferA.MaximumLength = sizeof(Buffer) - sizeof(Buffer[0]);
|
|
|
|
BufferA.Buffer = Buffer;
|
|
|
|
if (bIsFileApiAnsi)
|
|
|
|
RtlUnicodeStringToAnsiString (&BufferA, &DeviceName, FALSE);
|
|
|
|
else
|
|
|
|
RtlUnicodeStringToOemString (&BufferA, &DeviceName, FALSE);
|
|
|
|
|
|
|
|
/* Return the data */
|
|
|
|
RtlZeroMemory(lpFindFileData,
|
|
|
|
sizeof(*lpFindFileData));
|
|
|
|
lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE;
|
|
|
|
RtlCopyMemory(lpFindFileData->cFileName,
|
|
|
|
BufferA.Buffer,
|
|
|
|
BufferA.Length);
|
|
|
|
}
|
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
static VOID
|
2005-08-11 19:02:31 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
static VOID
|
2005-08-11 19:02:31 +00:00
|
|
|
InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData,
|
|
|
|
PFILE_BOTH_DIR_INFORMATION lpFileInfo)
|
|
|
|
{
|
|
|
|
UNICODE_STRING FileNameU;
|
|
|
|
ANSI_STRING FileNameA;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2007-01-26 07:22:19 +00:00
|
|
|
FileNameU.Length = FileNameU.MaximumLength = (USHORT)lpFileInfo->FileNameLength;
|
2005-08-11 19:02:31 +00:00
|
|
|
FileNameU.Buffer = lpFileInfo->FileName;
|
|
|
|
|
|
|
|
FileNameA.MaximumLength = sizeof(lpFindFileData->cFileName) - sizeof(CHAR);
|
|
|
|
FileNameA.Buffer = lpFindFileData->cFileName;
|
|
|
|
|
|
|
|
/* convert unicode string to ansi (or oem) */
|
|
|
|
if (bIsFileApiAnsi)
|
|
|
|
RtlUnicodeStringToAnsiString (&FileNameA, &FileNameU, FALSE);
|
|
|
|
else
|
|
|
|
RtlUnicodeStringToOemString (&FileNameA, &FileNameU, FALSE);
|
|
|
|
|
|
|
|
FileNameA.Buffer[FileNameA.Length] = 0;
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("lpFileInfo->ShortNameLength %d\n", lpFileInfo->ShortNameLength);
|
2005-08-11 19:02:31 +00:00
|
|
|
|
|
|
|
FileNameU.Length = FileNameU.MaximumLength = lpFileInfo->ShortNameLength;
|
|
|
|
FileNameU.Buffer = lpFileInfo->ShortName;
|
|
|
|
|
|
|
|
FileNameA.MaximumLength = sizeof(lpFindFileData->cAlternateFileName) - sizeof(CHAR);
|
|
|
|
FileNameA.Buffer = lpFindFileData->cAlternateFileName;
|
|
|
|
|
|
|
|
/* convert unicode string to ansi (or oem) */
|
|
|
|
if (bIsFileApiAnsi)
|
|
|
|
RtlUnicodeStringToAnsiString (&FileNameA, &FileNameU, FALSE);
|
|
|
|
else
|
|
|
|
RtlUnicodeStringToOemString (&FileNameA, &FileNameU, FALSE);
|
|
|
|
|
|
|
|
FileNameA.Buffer[FileNameA.Length] = 0;
|
|
|
|
}
|
2000-03-15 12:25:47 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2004-01-23 16:37:11 +00:00
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2000-03-15 12:25:47 +00:00
|
|
|
InternalFindNextFile (
|
2007-07-14 22:29:42 +00:00
|
|
|
HANDLE hFindFile,
|
|
|
|
PUNICODE_STRING SearchPattern,
|
|
|
|
PVOID lpFindFileData,
|
|
|
|
BOOL bUnicode
|
|
|
|
)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
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;
|
2000-03-15 12:25:47 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile, SearchPattern);
|
2004-05-13 20:32:18 +00:00
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
if (hFindFile != FIND_DEVICE_HANDLE)
|
2007-07-13 19:43:09 +00:00
|
|
|
{
|
2006-01-15 03:11:31 +00:00
|
|
|
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);
|
2007-07-14 22:29:42 +00:00
|
|
|
Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
|
2000-03-15 12:25:47 +00:00
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
if (SearchPattern == NULL)
|
2005-08-11 19:02:31 +00:00
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-08-11 19:02:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
IData->pFileInfo = Buffer;
|
|
|
|
IData->pFileInfo->NextEntryOffset = 0;
|
|
|
|
Status = NtQueryDirectoryFile (IData->DirectoryHandle,
|
|
|
|
NULL,
|
2005-08-11 19:02:31 +00:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&IoStatusBlock,
|
|
|
|
(PVOID)IData->pFileInfo,
|
|
|
|
FIND_DATA_SIZE,
|
|
|
|
FileBothDirectoryInformation,
|
2007-07-14 22:29:42 +00:00
|
|
|
FALSE,
|
2005-08-11 19:02:31 +00:00
|
|
|
SearchPattern,
|
2007-07-14 22:29:42 +00:00
|
|
|
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;
|
2005-08-11 19:02:31 +00:00
|
|
|
SearchPattern = NULL;
|
2007-07-14 22:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} while (FoundFile == NULL);
|
|
|
|
|
|
|
|
if (FoundFile != NULL)
|
|
|
|
{
|
2008-11-30 19:28:11 +00:00
|
|
|
_SEH2_TRY
|
2007-07-14 22:29:42 +00:00
|
|
|
{
|
|
|
|
if (bUnicode)
|
|
|
|
{
|
|
|
|
InternalCopyFindDataW(lpFindFileData,
|
|
|
|
FoundFile);
|
|
|
|
}
|
|
|
|
else
|
2005-08-11 19:02:31 +00:00
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
InternalCopyFindDataA(lpFindFileData,
|
|
|
|
FoundFile);
|
|
|
|
}
|
2005-08-11 19:02:31 +00:00
|
|
|
}
|
2008-11-30 19:28:11 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2005-08-11 19:02:31 +00:00
|
|
|
{
|
|
|
|
}
|
2008-11-30 19:28:11 +00:00
|
|
|
_SEH2_END;
|
2005-08-11 19:02:31 +00:00
|
|
|
}
|
2007-07-14 22:29:42 +00:00
|
|
|
|
|
|
|
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;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
2000-08-05 18:01:58 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
2005-07-20 04:43:12 +00:00
|
|
|
* @implemented
|
2003-07-10 18:50:51 +00:00
|
|
|
*/
|
2000-08-05 18:01:58 +00:00
|
|
|
HANDLE
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
InternalFindFirstFile (
|
2007-07-13 19:43:09 +00:00
|
|
|
LPCWSTR lpFileName,
|
|
|
|
BOOLEAN DirectoryOnly,
|
2007-07-14 22:29:42 +00:00
|
|
|
PVOID lpFindFileData,
|
|
|
|
BOOL bUnicode
|
2000-08-05 18:01:58 +00:00
|
|
|
)
|
|
|
|
{
|
2005-07-29 21:59:06 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
2006-01-15 03:11:31 +00:00
|
|
|
PKERNEL32_FIND_DATA_HEADER IHeader;
|
2005-07-20 04:43:12 +00:00
|
|
|
PKERNEL32_FIND_FILE_DATA IData;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
2007-07-13 19:43:09 +00:00
|
|
|
UNICODE_STRING NtPathU, FileName, PathFileName;
|
2005-07-29 21:59:06 +00:00
|
|
|
NTSTATUS Status;
|
2007-07-13 19:43:09 +00:00
|
|
|
PWSTR NtPathBuffer;
|
2007-07-15 08:33:49 +00:00
|
|
|
BOOLEAN RemovedLastChar = FALSE;
|
2007-01-26 07:22:19 +00:00
|
|
|
BOOL bResult;
|
2007-07-13 19:43:09 +00:00
|
|
|
CURDIR DirInfo;
|
2007-07-14 22:29:42 +00:00
|
|
|
ULONG DeviceNameInfo;
|
|
|
|
HANDLE hDirectory = NULL;
|
2005-07-20 04:43:12 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("FindFirstFileW(lpFileName %S)\n",
|
2005-07-30 13:49:41 +00:00
|
|
|
lpFileName);
|
2005-07-20 04:43:12 +00:00
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
RtlZeroMemory(&PathFileName,
|
|
|
|
sizeof(PathFileName));
|
|
|
|
RtlInitUnicodeString(&FileName,
|
|
|
|
lpFileName);
|
|
|
|
|
|
|
|
bResult = RtlDosPathNameToNtPathName_U (lpFileName,
|
|
|
|
&NtPathU,
|
|
|
|
(PCWSTR *)((ULONG_PTR)&PathFileName.Buffer),
|
|
|
|
&DirInfo);
|
|
|
|
if (FALSE == bResult)
|
2005-07-20 04:43:12 +00:00
|
|
|
{
|
2007-07-13 19:43:09 +00:00
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
2007-07-14 22:49:47 +00:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-07-20 04:43:12 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
/* Save the buffer pointer for later, we need to free it! */
|
|
|
|
NtPathBuffer = NtPathU.Buffer;
|
2005-07-20 04:43:12 +00:00
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
/* If there is a file name/pattern then determine it's length */
|
|
|
|
if (PathFileName.Buffer != NULL)
|
2005-07-20 04:43:12 +00:00
|
|
|
{
|
2007-07-13 19:43:09 +00:00
|
|
|
PathFileName.Length = NtPathU.Length -
|
|
|
|
(USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer);
|
2005-07-20 04:43:12 +00:00
|
|
|
}
|
2007-07-13 19:43:09 +00:00
|
|
|
PathFileName.MaximumLength = PathFileName.Length;
|
2005-07-20 04:43:12 +00:00
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
if (DirInfo.DosPath.Length != 0 && DirInfo.DosPath.Buffer != PathFileName.Buffer)
|
2005-07-20 04:43:12 +00:00
|
|
|
{
|
2007-07-13 19:43:09 +00:00
|
|
|
if (PathFileName.Buffer != NULL)
|
|
|
|
{
|
|
|
|
/* This is a relative path to DirInfo.Handle, adjust NtPathU! */
|
|
|
|
NtPathU.Length = NtPathU.MaximumLength =
|
|
|
|
(USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)DirInfo.DosPath.Buffer);
|
|
|
|
NtPathU.Buffer = DirInfo.DosPath.Buffer;
|
|
|
|
}
|
2005-07-20 04:43:12 +00:00
|
|
|
}
|
2007-07-13 19:43:09 +00:00
|
|
|
else
|
2005-07-20 04:43:12 +00:00
|
|
|
{
|
2007-07-13 19:43:09 +00:00
|
|
|
/* This is an absolute path, NtPathU receives the full path */
|
|
|
|
DirInfo.Handle = NULL;
|
|
|
|
if (PathFileName.Buffer != NULL)
|
|
|
|
{
|
|
|
|
NtPathU.Length = NtPathU.MaximumLength =
|
|
|
|
(USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer);
|
|
|
|
}
|
2005-07-20 04:43:12 +00:00
|
|
|
}
|
|
|
|
|
2007-07-15 08:33:49 +00:00
|
|
|
/* 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'\\' &&
|
2007-07-14 22:29:42 +00:00
|
|
|
NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':')
|
2005-07-20 04:43:12 +00:00
|
|
|
{
|
2007-07-13 19:43:09 +00:00
|
|
|
NtPathU.Length -= sizeof(WCHAR);
|
2007-07-15 08:33:49 +00:00
|
|
|
RemovedLastChar = TRUE;
|
2005-07-20 04:43:12 +00:00
|
|
|
}
|
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("lpFileName: \"%ws\"\n", lpFileName);
|
|
|
|
TRACE("NtPathU: \"%wZ\"\n", &NtPathU);
|
|
|
|
TRACE("PathFileName: \"%wZ\"\n", &PathFileName);
|
|
|
|
TRACE("RelativeTo: 0x%p\n", DirInfo.Handle);
|
2005-07-29 21:59:06 +00:00
|
|
|
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
|
|
&NtPathU,
|
2007-07-13 19:43:09 +00:00
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
DirInfo.Handle,
|
2005-07-29 21:59:06 +00:00
|
|
|
NULL);
|
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
Status = NtOpenFile (&hDirectory,
|
2007-07-14 22:29:42 +00:00
|
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
2005-07-29 21:59:06 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
2007-07-14 22:29:42 +00:00
|
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
2005-07-29 21:59:06 +00:00
|
|
|
|
2007-07-15 08:33:49 +00:00
|
|
|
if (Status == STATUS_NOT_A_DIRECTORY && RemovedLastChar)
|
2007-07-13 19:43:09 +00:00
|
|
|
{
|
2007-07-15 08:33:49 +00:00
|
|
|
/* Try again, this time with the last character ... */
|
|
|
|
NtPathU.Length += sizeof(WCHAR);
|
2007-07-13 19:43:09 +00:00
|
|
|
|
|
|
|
Status = NtOpenFile (&hDirectory,
|
2007-07-14 22:29:42 +00:00
|
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
2007-07-13 19:43:09 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
2007-07-14 22:29:42 +00:00
|
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
|
2007-07-15 08:33:49 +00:00
|
|
|
|
|
|
|
NtPathU.Length += sizeof(WCHAR);
|
2007-07-13 19:43:09 +00:00
|
|
|
}
|
2005-07-20 04:43:12 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
RtlFreeHeap (hProcessHeap,
|
|
|
|
0,
|
|
|
|
NtPathBuffer);
|
2007-07-13 19:43:09 +00:00
|
|
|
|
|
|
|
/* See if the application tries to look for a DOS device */
|
2007-07-14 22:29:42 +00:00
|
|
|
DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName));
|
|
|
|
if (DeviceNameInfo != 0)
|
|
|
|
{
|
|
|
|
if (bUnicode)
|
|
|
|
{
|
|
|
|
InternalCopyDeviceFindDataW(lpFindFileData,
|
|
|
|
lpFileName,
|
|
|
|
DeviceNameInfo);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
InternalCopyDeviceFindDataA(lpFindFileData,
|
|
|
|
&FileName,
|
|
|
|
DeviceNameInfo);
|
|
|
|
}
|
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
return FIND_DEVICE_HANDLE;
|
2007-07-14 22:29:42 +00:00
|
|
|
}
|
2007-07-13 19:43:09 +00:00
|
|
|
|
2005-07-29 21:59:06 +00:00
|
|
|
SetLastErrorByStatus (Status);
|
2007-07-14 22:49:47 +00:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-07-20 04:43:12 +00:00
|
|
|
}
|
2007-07-13 19:43:09 +00:00
|
|
|
|
|
|
|
if (PathFileName.Length == 0)
|
|
|
|
{
|
|
|
|
/* No file part?! */
|
|
|
|
NtClose(hDirectory);
|
|
|
|
RtlFreeHeap (hProcessHeap,
|
|
|
|
0,
|
|
|
|
NtPathBuffer);
|
|
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
2007-07-14 22:49:47 +00:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2007-07-13 19:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
IHeader = RtlAllocateHeap (hProcessHeap,
|
|
|
|
HEAP_ZERO_MEMORY,
|
|
|
|
sizeof(KERNEL32_FIND_DATA_HEADER) +
|
|
|
|
sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
|
|
|
|
if (NULL == IHeader)
|
|
|
|
{
|
|
|
|
RtlFreeHeap (hProcessHeap,
|
|
|
|
0,
|
|
|
|
NtPathBuffer);
|
|
|
|
NtClose(hDirectory);
|
|
|
|
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
2007-07-14 22:49:47 +00:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2007-07-13 19:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
IHeader->Type = FileFind;
|
|
|
|
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
|
|
|
|
IData->DirectoryHandle = hDirectory;
|
2007-07-14 22:29:42 +00:00
|
|
|
IData->HasMoreData = TRUE;
|
2007-07-13 19:43:09 +00:00
|
|
|
|
|
|
|
/* change pattern: "*.*" --> "*" */
|
|
|
|
if (PathFileName.Length == 6 &&
|
|
|
|
RtlCompareMemory(PathFileName.Buffer,
|
|
|
|
L"*.*",
|
|
|
|
6) == 6)
|
|
|
|
{
|
|
|
|
PathFileName.Length = 2;
|
|
|
|
}
|
|
|
|
|
2005-07-20 04:43:12 +00:00
|
|
|
IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
|
|
|
|
IData->pFileInfo->FileIndex = 0;
|
2007-07-13 19:43:09 +00:00
|
|
|
IData->DirectoryOnly = DirectoryOnly;
|
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
bResult = InternalFindNextFile((HANDLE)IHeader,
|
|
|
|
&PathFileName,
|
|
|
|
lpFindFileData,
|
|
|
|
bUnicode);
|
2007-07-13 19:43:09 +00:00
|
|
|
|
|
|
|
RtlFreeHeap (hProcessHeap,
|
|
|
|
0,
|
|
|
|
NtPathBuffer);
|
2005-07-20 04:43:12 +00:00
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
if (!bResult)
|
2005-07-29 21:59:06 +00:00
|
|
|
{
|
2007-07-13 19:43:09 +00:00
|
|
|
FindClose((HANDLE)IHeader);
|
2007-07-14 22:49:47 +00:00
|
|
|
return INVALID_HANDLE_VALUE;
|
2005-07-29 21:59:06 +00:00
|
|
|
}
|
2005-08-11 19:02:31 +00:00
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
RtlInitializeCriticalSection(&IData->Lock);
|
|
|
|
IData->LockInitialized = TRUE;
|
|
|
|
|
2006-01-15 03:11:31 +00:00
|
|
|
return (HANDLE)IHeader;
|
2000-08-05 18:01:58 +00:00
|
|
|
}
|
2002-09-13 19:03:40 +00:00
|
|
|
|
2000-08-05 18:01:58 +00:00
|
|
|
|
2003-07-10 18:50:51 +00:00
|
|
|
/*
|
2005-07-20 04:43:12 +00:00
|
|
|
* @implemented
|
2003-07-10 18:50:51 +00:00
|
|
|
*/
|
2000-08-05 18:01:58 +00:00
|
|
|
HANDLE
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
FindFirstFileA (
|
|
|
|
LPCSTR lpFileName,
|
|
|
|
LPWIN32_FIND_DATAA lpFindFileData
|
2000-08-05 18:01:58 +00:00
|
|
|
)
|
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
return FindFirstFileExA (lpFileName,
|
|
|
|
FindExInfoStandard,
|
|
|
|
(LPVOID)lpFindFileData,
|
|
|
|
FindExSearchNameMatch,
|
|
|
|
NULL,
|
|
|
|
0);
|
2005-07-30 13:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
FindNextFileA (
|
|
|
|
HANDLE hFindFile,
|
|
|
|
LPWIN32_FIND_DATAA lpFindFileData)
|
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
return InternalFindNextFile (hFindFile,
|
|
|
|
NULL,
|
|
|
|
lpFindFileData,
|
|
|
|
FALSE);
|
2005-07-30 13:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
FindClose (
|
|
|
|
HANDLE hFindFile
|
|
|
|
)
|
|
|
|
{
|
2006-01-15 03:11:31 +00:00
|
|
|
PKERNEL32_FIND_DATA_HEADER IHeader;
|
2005-07-30 13:49:41 +00:00
|
|
|
|
2008-05-12 12:01:51 +00:00
|
|
|
TRACE("FindClose(hFindFile %x)\n",hFindFile);
|
2005-07-30 13:49:41 +00:00
|
|
|
|
2007-07-13 19:43:09 +00:00
|
|
|
if (hFindFile == FIND_DEVICE_HANDLE)
|
|
|
|
return TRUE;
|
|
|
|
|
2005-07-30 13:49:41 +00:00
|
|
|
if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2006-01-15 03:11:31 +00:00
|
|
|
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);
|
2007-07-14 22:29:42 +00:00
|
|
|
if (IData->LockInitialized)
|
|
|
|
RtlDeleteCriticalSection(&IData->Lock);
|
2007-11-13 16:50:44 +00:00
|
|
|
IData->LockInitialized = FALSE;
|
2006-01-15 03:11:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case StreamFind:
|
|
|
|
{
|
|
|
|
PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
|
|
|
|
if (IData->pFileStreamInfo != NULL)
|
|
|
|
{
|
|
|
|
RtlFreeHeap (hProcessHeap, 0, IData->pFileStreamInfo);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-07-30 13:49:41 +00:00
|
|
|
|
2006-01-15 03:11:31 +00:00
|
|
|
RtlFreeHeap (hProcessHeap, 0, IHeader);
|
2005-07-30 13:49:41 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
HANDLE
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
FindFirstFileW (
|
|
|
|
LPCWSTR lpFileName,
|
|
|
|
LPWIN32_FIND_DATAW lpFindFileData
|
|
|
|
)
|
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
return FindFirstFileExW (lpFileName,
|
|
|
|
FindExInfoStandard,
|
|
|
|
(LPVOID)lpFindFileData,
|
|
|
|
FindExSearchNameMatch,
|
|
|
|
NULL,
|
|
|
|
0);
|
2005-07-30 13:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
FindNextFileW (
|
|
|
|
HANDLE hFindFile,
|
|
|
|
LPWIN32_FIND_DATAW lpFindFileData
|
|
|
|
)
|
|
|
|
{
|
2007-07-14 22:29:42 +00:00
|
|
|
return InternalFindNextFile (hFindFile,
|
|
|
|
NULL,
|
|
|
|
lpFindFileData,
|
|
|
|
TRUE);
|
2005-07-30 13:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
HANDLE
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-08-11 19:02:31 +00:00
|
|
|
FindFirstFileExW (LPCWSTR lpFileName,
|
|
|
|
FINDEX_INFO_LEVELS fInfoLevelId,
|
|
|
|
LPVOID lpFindFileData,
|
|
|
|
FINDEX_SEARCH_OPS fSearchOp,
|
|
|
|
LPVOID lpSearchFilter,
|
|
|
|
DWORD dwAdditionalFlags)
|
2005-07-30 13:49:41 +00:00
|
|
|
{
|
2005-08-11 19:02:31 +00:00
|
|
|
if (fInfoLevelId != FindExInfoStandard)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
2007-07-14 22:29:42 +00:00
|
|
|
|
2005-08-11 19:02:31 +00:00
|
|
|
if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories)
|
|
|
|
{
|
|
|
|
if (lpSearchFilter)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
2007-07-14 22:49:47 +00:00
|
|
|
return InternalFindFirstFile (lpFileName,
|
|
|
|
fSearchOp == FindExSearchLimitToDirectories,
|
|
|
|
lpFindFileData,
|
|
|
|
TRUE);
|
2005-08-11 19:02:31 +00:00
|
|
|
}
|
2007-07-14 22:29:42 +00:00
|
|
|
|
2005-08-11 19:02:31 +00:00
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
2005-07-30 13:49:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @unimplemented
|
|
|
|
*/
|
|
|
|
HANDLE
|
2008-11-30 11:42:05 +00:00
|
|
|
WINAPI
|
2005-07-30 13:49:41 +00:00
|
|
|
FindFirstFileExA (
|
|
|
|
LPCSTR lpFileName,
|
|
|
|
FINDEX_INFO_LEVELS fInfoLevelId,
|
|
|
|
LPVOID lpFindFileData,
|
|
|
|
FINDEX_SEARCH_OPS fSearchOp,
|
|
|
|
LPVOID lpSearchFilter,
|
|
|
|
DWORD dwAdditionalFlags
|
|
|
|
)
|
|
|
|
{
|
2005-08-11 19:02:31 +00:00
|
|
|
UNICODE_STRING FileNameU;
|
|
|
|
ANSI_STRING FileNameA;
|
2007-07-14 22:29:42 +00:00
|
|
|
HANDLE Handle;
|
2005-08-11 19:02:31 +00:00
|
|
|
|
|
|
|
if (fInfoLevelId != FindExInfoStandard)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories)
|
|
|
|
{
|
|
|
|
if (lpSearchFilter)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
2007-07-14 22:29:42 +00:00
|
|
|
|
2005-08-11 19:02:31 +00:00
|
|
|
RtlInitAnsiString (&FileNameA, (LPSTR)lpFileName);
|
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
/* convert ansi (or oem) string to unicode */
|
|
|
|
if (bIsFileApiAnsi)
|
2005-08-11 19:02:31 +00:00
|
|
|
RtlAnsiStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
|
2007-07-14 22:29:42 +00:00
|
|
|
else
|
2005-08-11 19:02:31 +00:00
|
|
|
RtlOemStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
|
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
Handle = InternalFindFirstFile (FileNameU.Buffer,
|
|
|
|
fSearchOp == FindExSearchLimitToDirectories,
|
|
|
|
lpFindFileData,
|
|
|
|
FALSE);
|
2007-07-13 19:43:09 +00:00
|
|
|
|
2007-07-14 22:29:42 +00:00
|
|
|
RtlFreeUnicodeString (&FileNameU);
|
|
|
|
return Handle;
|
2005-08-11 19:02:31 +00:00
|
|
|
}
|
2007-07-14 22:29:42 +00:00
|
|
|
|
2005-08-11 19:02:31 +00:00
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
2000-08-05 18:01:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-15 03:11:31 +00:00
|
|
|
static VOID
|
|
|
|
InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData,
|
|
|
|
OUT LPVOID lpFindStreamData)
|
|
|
|
{
|
2007-01-26 07:22:19 +00:00
|
|
|
ASSERT(IData->pCurrent);
|
2006-01-15 03:11:31 +00:00
|
|
|
|
|
|
|
switch (IData->InfoLevel)
|
|
|
|
{
|
|
|
|
case FindStreamInfoStandard:
|
|
|
|
{
|
|
|
|
ULONG StreamNameLen;
|
2006-12-12 23:57:24 +00:00
|
|
|
WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData;
|
2006-01-15 03:11:31 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
HANDLE
|
|
|
|
WINAPI
|
|
|
|
FindFirstStreamW(IN LPCWSTR lpFileName,
|
|
|
|
IN STREAM_INFO_LEVELS InfoLevel,
|
|
|
|
OUT LPVOID lpFindStreamData,
|
|
|
|
IN DWORD dwFlags)
|
|
|
|
{
|
|
|
|
PKERNEL32_FIND_DATA_HEADER IHeader = NULL;
|
|
|
|
PKERNEL32_FIND_STREAM_DATA IData = NULL;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
UNICODE_STRING NtPathU;
|
|
|
|
HANDLE FileHandle = NULL;
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG BufferSize = 0;
|
|
|
|
|
|
|
|
if (dwFlags != 0 || InfoLevel != FindStreamInfoStandard ||
|
|
|
|
lpFindStreamData == NULL)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validate & translate the filename */
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(lpFileName,
|
|
|
|
&NtPathU,
|
|
|
|
NULL,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* open the file */
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&NtPathU,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = NtCreateFile(&FileHandle,
|
|
|
|
0,
|
|
|
|
&ObjectAttributes,
|
|
|
|
&IoStatusBlock,
|
|
|
|
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(hProcessHeap,
|
|
|
|
0,
|
|
|
|
sizeof(KERNEL32_FIND_DATA_HEADER) +
|
|
|
|
sizeof(KERNEL32_FIND_STREAM_DATA));
|
|
|
|
if (IHeader == NULL)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
BufferSize += 0x1000;
|
|
|
|
|
|
|
|
if (IData->pFileStreamInfo == NULL)
|
|
|
|
{
|
|
|
|
IData->pFileStreamInfo = RtlAllocateHeap(hProcessHeap,
|
|
|
|
0,
|
|
|
|
BufferSize);
|
|
|
|
if (IData->pFileStreamInfo == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PFILE_STREAM_INFORMATION pfsi;
|
|
|
|
|
|
|
|
pfsi = RtlReAllocateHeap(hProcessHeap,
|
|
|
|
0,
|
|
|
|
IData->pFileStreamInfo,
|
|
|
|
BufferSize);
|
|
|
|
if (pfsi == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
IData->pFileStreamInfo = pfsi;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = NtQueryInformationFile(FileHandle,
|
|
|
|
&IoStatusBlock,
|
|
|
|
IData->pFileStreamInfo,
|
|
|
|
BufferSize,
|
|
|
|
FileStreamInformation);
|
|
|
|
|
|
|
|
} while (Status == STATUS_BUFFER_TOO_SMALL);
|
|
|
|
|
|
|
|
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 */
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (FileHandle != NULL)
|
|
|
|
{
|
|
|
|
NtClose(FileHandle);
|
|
|
|
}
|
|
|
|
|
2006-01-22 13:41:39 +00:00
|
|
|
RtlFreeHeap(RtlGetProcessHeap(),
|
|
|
|
0,
|
|
|
|
NtPathU.Buffer);
|
2006-01-15 03:11:31 +00:00
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (IHeader != NULL)
|
|
|
|
{
|
|
|
|
if (IData->pFileStreamInfo != NULL)
|
|
|
|
{
|
|
|
|
RtlFreeHeap(hProcessHeap,
|
|
|
|
0,
|
|
|
|
IData->pFileStreamInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlFreeHeap(hProcessHeap,
|
|
|
|
0,
|
|
|
|
IHeader);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetLastErrorByStatus(Status);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (HANDLE)IHeader;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
FindNextStreamW(IN HANDLE hFindStream,
|
|
|
|
OUT LPVOID lpFindStreamData)
|
|
|
|
{
|
|
|
|
PKERNEL32_FIND_DATA_HEADER IHeader;
|
|
|
|
PKERNEL32_FIND_STREAM_DATA IData;
|
|
|
|
|
|
|
|
IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream;
|
|
|
|
if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE ||
|
|
|
|
IHeader->Type != StreamFind)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_HANDLE_EOF);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return the information */
|
|
|
|
InternalCopyStreamInfo(IData,
|
|
|
|
lpFindStreamData);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-08-29 06:59:11 +00:00
|
|
|
/* EOF */
|