implemented FindFirstStreamW() and FindNextStreamW() (untested!) Modified: trunk/reactos/include/ndk/iotypes.h Modified: trunk/reactos/lib/kernel32/file/find.c Modified: trunk/reactos/lib/kernel32/kernel32.def Modified: trunk/reactos/w32api/include/winbase.h _____
Modified: trunk/reactos/include/ndk/iotypes.h --- trunk/reactos/include/ndk/iotypes.h 2006-01-15 01:24:59 UTC (rev 20881) +++ trunk/reactos/include/ndk/iotypes.h 2006-01-15 03:11:31 UTC (rev 20882) @@ -320,6 +320,15 @@
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; _____
Modified: trunk/reactos/lib/kernel32/file/find.c --- trunk/reactos/lib/kernel32/file/find.c 2006-01-15 01:24:59 UTC (rev 20881) +++ trunk/reactos/lib/kernel32/file/find.c 2006-01-15 03:11:31 UTC (rev 20882) @@ -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 @@ 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,14 +150,23 @@ 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) { if (IData->pFileInfo->NextEntryOffset != 0) @@ -178,6 +215,7 @@ ) { OBJECT_ATTRIBUTES ObjectAttributes; + PKERNEL32_FIND_DATA_HEADER IHeader; PKERNEL32_FIND_FILE_DATA IData; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING NtPathU; @@ -302,10 +340,11 @@
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 @@ return NULL; }
+ IHeader->Type = FileFind; + IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); + /* change pattern: "*.*" --> "*" */ if (wcscmp (SearchPattern, L"*.*")) { @@ -348,7 +390,7 @@
if (!NT_SUCCESS(Status)) { - RtlFreeHeap (hProcessHeap, 0, IData); + RtlFreeHeap (hProcessHeap, 0, IHeader); if (NULL != SlashlessFileName) { RtlFreeHeap(hProcessHeap, @@ -362,7 +404,7 @@ 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 @@
if (!bResult) { - FindClose((HANDLE)IData); + FindClose((HANDLE)IHeader); return NULL; }
- return IData; + return (HANDLE)IHeader; }
@@ -390,6 +432,7 @@ LPWIN32_FIND_DATAA lpFindFileData ) { + PKERNEL32_FIND_DATA_HEADER IHeader; PKERNEL32_FIND_FILE_DATA IData; UNICODE_STRING FileNameU; ANSI_STRING FileName; @@ -407,16 +450,18 @@ &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 @@ InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
- return (HANDLE)IData; + return (HANDLE)IHeader; }
@@ -439,20 +484,14 @@ { 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 @@ HANDLE hFindFile ) { - PKERNEL32_FIND_FILE_DATA IData; + PKERNEL32_FIND_DATA_HEADER IHeader;
DPRINT("FindClose(hFindFile %x)\n",hFindFile);
@@ -482,11 +521,34 @@ 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 @@ { 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 @@ LPVOID lpSearchFilter, DWORD dwAdditionalFlags) { + PKERNEL32_FIND_DATA_HEADER IHeader; PKERNEL32_FIND_FILE_DATA IData;
if (fInfoLevelId != FindExInfoStandard) @@ -570,17 +627,19 @@ 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 @@ DWORD dwAdditionalFlags ) { + PKERNEL32_FIND_DATA_HEADER IHeader; PKERNEL32_FIND_FILE_DATA IData; UNICODE_STRING FileNameU; ANSI_STRING FileNameA; @@ -625,22 +685,263 @@ 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 */ _____
Modified: trunk/reactos/lib/kernel32/kernel32.def --- trunk/reactos/lib/kernel32/kernel32.def 2006-01-15 01:24:59 UTC (rev 20881) +++ trunk/reactos/lib/kernel32/kernel32.def 2006-01-15 03:11:31 UTC (rev 20882) @@ -243,9 +243,11 @@
FindFirstFileExA@24 FindFirstFileExW@24 FindFirstFileW@8 +FindFirstStreamW@16 FindNextChangeNotification@4 FindNextFileA@8 FindNextFileW@8 +FindNextStreamW@8 FindFirstVolumeA@8 FindFirstVolumeMountPointA@12 FindFirstVolumeMountPointW@12 _____
Modified: trunk/reactos/w32api/include/winbase.h --- trunk/reactos/w32api/include/winbase.h 2006-01-15 01:24:59 UTC (rev 20881) +++ trunk/reactos/w32api/include/winbase.h 2006-01-15 03:11:31 UTC (rev 20882) @@ -809,6 +809,15 @@
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 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,PVOI D,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 @@ 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 @@ #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;