implemented FindFirstStreamW() and FindNextStreamW() (untested!)

svn path=/trunk/; revision=20882
This commit is contained in:
Thomas Bluemel 2006-01-15 03:11:31 +00:00
parent e592a21cc6
commit ba9679e15b
4 changed files with 372 additions and 42 deletions

View file

@ -320,6 +320,15 @@ typedef struct _FILE_STANDARD_INFORMATION
BOOLEAN Directory;
} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
typedef struct _FILE_STREAM_INFORMATION
{
ULONG NextEntryOffset;
ULONG StreamNameLength;
LARGE_INTEGER StreamSize;
LARGE_INTEGER StreamAllocationSize;
WCHAR StreamName[1];
} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
typedef struct _FILE_NETWORK_OPEN_INFORMATION
{
LARGE_INTEGER CreationTime;

View file

@ -19,10 +19,6 @@
/* TYPES ********************************************************************/
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &( ((TYPE *) 0)->MEMBER ))
#endif
#define FIND_DATA_SIZE (16*1024)
typedef struct _KERNEL32_FIND_FILE_DATA
@ -32,9 +28,41 @@ typedef struct _KERNEL32_FIND_FILE_DATA
PFILE_BOTH_DIR_INFORMATION pFileInfo;
} KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
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;
/* FUNCTIONS ****************************************************************/
static __inline PKERNEL32_FIND_FILE_DATA
HandleToFindData(IN HANDLE Handle)
{
PKERNEL32_FIND_DATA_HEADER FindData = (PKERNEL32_FIND_DATA_HEADER)Handle;
if (Handle != NULL && Handle != INVALID_HANDLE_VALUE &&
FindData->Type == FileFind)
{
return (PKERNEL32_FIND_FILE_DATA)(FindData + 1);
}
return NULL;
}
VOID
InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
PFILE_BOTH_DIR_INFORMATION lpFileInfo)
@ -122,13 +150,22 @@ InternalFindNextFile (
PUNICODE_STRING SearchPattern
)
{
PKERNEL32_FIND_DATA_HEADER IHeader;
PKERNEL32_FIND_FILE_DATA IData;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
DPRINT("InternalFindNextFile(%lx)\n", hFindFile);
IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
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);
while (1)
{
@ -178,6 +215,7 @@ InternalFindFirstFile (
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
PKERNEL32_FIND_DATA_HEADER IHeader;
PKERNEL32_FIND_FILE_DATA IData;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING NtPathU;
@ -302,10 +340,11 @@ InternalFindFirstFile (
DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
IData = RtlAllocateHeap (hProcessHeap,
HEAP_ZERO_MEMORY,
sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
if (NULL == IData)
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,
@ -320,6 +359,9 @@ InternalFindFirstFile (
return NULL;
}
IHeader->Type = FileFind;
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
/* change pattern: "*.*" --> "*" */
if (wcscmp (SearchPattern, L"*.*"))
{
@ -348,7 +390,7 @@ InternalFindFirstFile (
if (!NT_SUCCESS(Status))
{
RtlFreeHeap (hProcessHeap, 0, IData);
RtlFreeHeap (hProcessHeap, 0, IHeader);
if (NULL != SlashlessFileName)
{
RtlFreeHeap(hProcessHeap,
@ -362,7 +404,7 @@ InternalFindFirstFile (
IData->pFileInfo->FileIndex = 0;
IData->DirectoryOnly = DirectoryOnly;
bResult = InternalFindNextFile((HANDLE)IData, &PatternStr);
bResult = InternalFindNextFile((HANDLE)IHeader, &PatternStr);
if (NULL != SlashlessFileName)
{
RtlFreeHeap(hProcessHeap,
@ -372,11 +414,11 @@ InternalFindFirstFile (
if (!bResult)
{
FindClose((HANDLE)IData);
FindClose((HANDLE)IHeader);
return NULL;
}
return IData;
return (HANDLE)IHeader;
}
@ -390,6 +432,7 @@ FindFirstFileA (
LPWIN32_FIND_DATAA lpFindFileData
)
{
PKERNEL32_FIND_DATA_HEADER IHeader;
PKERNEL32_FIND_FILE_DATA IData;
UNICODE_STRING FileNameU;
ANSI_STRING FileName;
@ -407,16 +450,18 @@ FindFirstFileA (
&FileName,
TRUE);
IData = InternalFindFirstFile (FileNameU.Buffer, FALSE);
IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE);
RtlFreeUnicodeString (&FileNameU);
if (IData == NULL)
if (IHeader == NULL)
{
DPRINT("Failing request\n");
return INVALID_HANDLE_VALUE;
}
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
DPRINT("IData->pFileInfo->FileNameLength %d\n",
IData->pFileInfo->FileNameLength);
@ -424,7 +469,7 @@ FindFirstFileA (
InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
return (HANDLE)IData;
return (HANDLE)IHeader;
}
@ -439,20 +484,14 @@ FindNextFileA (
{
PKERNEL32_FIND_FILE_DATA IData;
if (hFindFile == INVALID_HANDLE_VALUE)
{
SetLastError (ERROR_INVALID_HANDLE);
DPRINT("Failing request\n");
return FALSE;
}
IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
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);
@ -472,7 +511,7 @@ FindClose (
HANDLE hFindFile
)
{
PKERNEL32_FIND_FILE_DATA IData;
PKERNEL32_FIND_DATA_HEADER IHeader;
DPRINT("FindClose(hFindFile %x)\n",hFindFile);
@ -482,10 +521,33 @@ FindClose (
return FALSE;
}
IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile;
CloseHandle (IData->DirectoryHandle);
RtlFreeHeap (hProcessHeap, 0, IData);
switch (IHeader->Type)
{
case FileFind:
{
PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
CloseHandle (IData->DirectoryHandle);
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;
}
RtlFreeHeap (hProcessHeap, 0, IHeader);
return TRUE;
}
@ -522,20 +584,14 @@ FindNextFileW (
{
PKERNEL32_FIND_FILE_DATA IData;
if (hFindFile == INVALID_HANDLE_VALUE)
{
SetLastError (ERROR_INVALID_HANDLE);
DPRINT("Failing request\n");
return FALSE;
}
IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
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);
@ -555,6 +611,7 @@ FindFirstFileExW (LPCWSTR lpFileName,
LPVOID lpSearchFilter,
DWORD dwAdditionalFlags)
{
PKERNEL32_FIND_DATA_HEADER IHeader;
PKERNEL32_FIND_FILE_DATA IData;
if (fInfoLevelId != FindExInfoStandard)
@ -570,17 +627,19 @@ FindFirstFileExW (LPCWSTR lpFileName,
return INVALID_HANDLE_VALUE;
}
IData = InternalFindFirstFile (lpFileName, fSearchOp == FindExSearchLimitToDirectories ? TRUE : FALSE);
if (IData == NULL)
IHeader = InternalFindFirstFile (lpFileName, fSearchOp == FindExSearchLimitToDirectories ? TRUE : FALSE);
if (IHeader == NULL)
{
DPRINT("Failing request\n");
return INVALID_HANDLE_VALUE;
}
/* copy data into WIN32_FIND_DATA structure */
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
/* copy data into WIN32_FIND_DATA structure */
InternalCopyFindDataW((LPWIN32_FIND_DATAW)lpFindFileData, IData->pFileInfo);
return (HANDLE)IData;
return (HANDLE)IHeader;
}
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
@ -600,6 +659,7 @@ FindFirstFileExA (
DWORD dwAdditionalFlags
)
{
PKERNEL32_FIND_DATA_HEADER IHeader;
PKERNEL32_FIND_FILE_DATA IData;
UNICODE_STRING FileNameU;
ANSI_STRING FileNameA;
@ -625,22 +685,263 @@ FindFirstFileExA (
else
RtlOemStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
IData = InternalFindFirstFile (FileNameU.Buffer, FALSE);
IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE);
RtlFreeUnicodeString (&FileNameU);
if (IData == NULL)
if (IHeader == NULL)
{
DPRINT("Failing request\n");
return INVALID_HANDLE_VALUE;
}
IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
/* copy data into WIN32_FIND_DATA structure */
InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
return (HANDLE)IHeader;
}
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
static VOID
InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData,
OUT LPVOID lpFindStreamData)
{
ASSERT(IData->pCurrent != NULL);
switch (IData->InfoLevel)
{
case FindStreamInfoStandard:
{
ULONG StreamNameLen;
WIN32_FIND_STREAM_DATAW *StreamData = (WIN32_FIND_STREAM_DATAW*)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;
}
}
/*
* @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);
}
RtlFreeUnicodeString(&NtPathU);
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;
}
/* EOF */

View file

@ -243,9 +243,11 @@ FindFirstFileA@8
FindFirstFileExA@24
FindFirstFileExW@24
FindFirstFileW@8
FindFirstStreamW@16
FindNextChangeNotification@4
FindNextFileA@8
FindNextFileW@8
FindNextStreamW@8
FindFirstVolumeA@8
FindFirstVolumeMountPointA@12
FindFirstVolumeMountPointW@12

View file

@ -809,6 +809,15 @@ typedef struct _WIN32_FIND_DATAW {
WCHAR cFileName[MAX_PATH];
WCHAR cAlternateFileName[14];
} WIN32_FIND_DATAW,*PWIN32_FIND_DATAW,*LPWIN32_FIND_DATAW;
#if (_WIN32_WINNT >= 0x0501)
typedef enum _STREAM_INFO_LEVELS {
FindStreamInfoStandard
} STREAM_INFO_LEVELS;
typedef struct _WIN32_FIND_STREAM_DATAW {
LARGE_INTEGER StreamSize;
WCHAR cStreamName[MAX_PATH + 36];
} WIN32_FIND_STREAM_DATAW, *PWIN32_FIND_STREAM_DATAW, *LPWIN32_FIND_STREAM_DATAW;
#endif
typedef struct _WIN32_STREAM_ID {
DWORD dwStreamId;
DWORD dwStreamAttributes;
@ -1288,6 +1297,9 @@ HANDLE WINAPI FindFirstFileA(LPCSTR,LPWIN32_FIND_DATAA);
HANDLE WINAPI FindFirstFileW(LPCWSTR,LPWIN32_FIND_DATAW);
HANDLE WINAPI FindFirstFileExA(LPCSTR,FINDEX_INFO_LEVELS,PVOID,FINDEX_SEARCH_OPS,PVOID,DWORD);
HANDLE WINAPI FindFirstFileExW(LPCWSTR,FINDEX_INFO_LEVELS,PVOID,FINDEX_SEARCH_OPS,PVOID,DWORD);
#if (_WIN32_WINNT >= 0x0501)
HANDLE WINAPI FindFirstStreamW(LPCWSTR,STREAM_INFO_LEVELS,LPVOID,DWORD);
#endif
BOOL WINAPI FindFirstFreeAce(PACL,PVOID*);
#if (_WIN32_WINNT >= 0x0500)
HANDLE WINAPI FindFirstVolumeA(LPCSTR,DWORD);
@ -1298,6 +1310,9 @@ HANDLE WINAPI FindFirstVolumeMountPointW(LPWSTR,LPWSTR,DWORD);
BOOL WINAPI FindNextChangeNotification(HANDLE);
BOOL WINAPI FindNextFileA(HANDLE,LPWIN32_FIND_DATAA);
BOOL WINAPI FindNextFileW(HANDLE,LPWIN32_FIND_DATAW);
#if (_WIN32_WINNT >= 0x0501)
BOOL WINAPI FindNextStreamW(HANDLE,LPVOID);
#endif
#if (_WIN32_WINNT >= 0x0500)
BOOL WINAPI FindNextVolumeA(HANDLE,LPCSTR,DWORD);
BOOL WINAPI FindNextVolumeW(HANDLE,LPWSTR,DWORD);
@ -1988,6 +2003,9 @@ BOOL WINAPI MapUserPhysicalPagesScatter(PVOID*,ULONG_PTR,PULONG_PTR);
#ifdef UNICODE
typedef STARTUPINFOW STARTUPINFO,*LPSTARTUPINFO;
typedef WIN32_FIND_DATAW WIN32_FIND_DATA,*LPWIN32_FIND_DATA;
#if (_WIN32_WINNT >= 0x0501)
typedef WIN32_FIND_STREAM_DATAW WIN32_FIND_STREAM_DATA,*LPWIN32_FIND_STREAM_DATA;
#endif
typedef HW_PROFILE_INFOW HW_PROFILE_INFO,*LPHW_PROFILE_INFO;
typedef ENUMRESLANGPROCW ENUMRESLANGPROC;
typedef ENUMRESNAMEPROCW ENUMRESNAMEPROC;