3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/find.c
6 * PURPOSE: Find functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
12 /* INCLUDES *****************************************************************/
17 #include "../include/debug.h"
20 /* TYPES ********************************************************************/
22 #define FIND_DATA_SIZE (16*1024)
24 typedef struct _KERNEL32_FIND_FILE_DATA
26 HANDLE DirectoryHandle
;
27 BOOLEAN DirectoryOnly
;
28 PFILE_BOTH_DIR_INFORMATION pFileInfo
;
29 } KERNEL32_FIND_FILE_DATA
, *PKERNEL32_FIND_FILE_DATA
;
31 typedef struct _KERNEL32_FIND_STREAM_DATA
33 STREAM_INFO_LEVELS InfoLevel
;
34 PFILE_STREAM_INFORMATION pFileStreamInfo
;
35 PFILE_STREAM_INFORMATION pCurrent
;
36 } KERNEL32_FIND_STREAM_DATA
, *PKERNEL32_FIND_STREAM_DATA
;
38 typedef enum _KERNEL32_FIND_DATA_TYPE
42 } KERNEL32_FIND_DATA_TYPE
;
44 typedef struct _KERNEL32_FIND_DATA_HEADER
46 KERNEL32_FIND_DATA_TYPE Type
;
47 } KERNEL32_FIND_DATA_HEADER
, *PKERNEL32_FIND_DATA_HEADER
;
50 /* FUNCTIONS ****************************************************************/
53 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
54 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
56 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
58 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
59 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
61 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
62 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
64 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
65 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
67 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
68 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
70 memcpy (lpFindFileData
->cFileName
, lpFileInfo
->FileName
, lpFileInfo
->FileNameLength
);
71 lpFindFileData
->cFileName
[lpFileInfo
->FileNameLength
/ sizeof(WCHAR
)] = 0;
73 memcpy (lpFindFileData
->cAlternateFileName
, lpFileInfo
->ShortName
, lpFileInfo
->ShortNameLength
);
74 lpFindFileData
->cAlternateFileName
[lpFileInfo
->ShortNameLength
/ sizeof(WCHAR
)] = 0;
78 InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData
,
79 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
81 UNICODE_STRING FileNameU
;
82 ANSI_STRING FileNameA
;
84 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
86 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
87 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
89 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
90 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
92 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
93 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
95 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
96 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
98 FileNameU
.Length
= FileNameU
.MaximumLength
= (USHORT
)lpFileInfo
->FileNameLength
;
99 FileNameU
.Buffer
= lpFileInfo
->FileName
;
101 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cFileName
) - sizeof(CHAR
);
102 FileNameA
.Buffer
= lpFindFileData
->cFileName
;
104 /* convert unicode string to ansi (or oem) */
106 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
108 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
110 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
112 DPRINT("lpFileInfo->ShortNameLength %d\n", lpFileInfo
->ShortNameLength
);
114 FileNameU
.Length
= FileNameU
.MaximumLength
= lpFileInfo
->ShortNameLength
;
115 FileNameU
.Buffer
= lpFileInfo
->ShortName
;
117 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cAlternateFileName
) - sizeof(CHAR
);
118 FileNameA
.Buffer
= lpFindFileData
->cAlternateFileName
;
120 /* convert unicode string to ansi (or oem) */
122 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
124 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
126 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
134 InternalFindNextFile (
136 PUNICODE_STRING SearchPattern
139 PKERNEL32_FIND_DATA_HEADER IHeader
;
140 PKERNEL32_FIND_FILE_DATA IData
;
141 IO_STATUS_BLOCK IoStatusBlock
;
144 DPRINT("InternalFindNextFile(%lx)\n", hFindFile
);
146 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
147 if (hFindFile
== NULL
|| hFindFile
== INVALID_HANDLE_VALUE
||
148 IHeader
->Type
!= FileFind
)
150 SetLastError (ERROR_INVALID_HANDLE
);
154 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
158 if (IData
->pFileInfo
->NextEntryOffset
!= 0)
160 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
->pFileInfo
+ IData
->pFileInfo
->NextEntryOffset
);
164 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
165 IData
->pFileInfo
->FileIndex
= 0;
166 Status
= NtQueryDirectoryFile (IData
->DirectoryHandle
,
171 (PVOID
)IData
->pFileInfo
,
173 FileBothDirectoryInformation
,
174 SearchPattern
? TRUE
: FALSE
,
176 SearchPattern
? TRUE
: FALSE
);
177 SearchPattern
= NULL
;
178 if (!NT_SUCCESS(Status
))
180 SetLastErrorByStatus (Status
);
184 if (!IData
->DirectoryOnly
|| IData
->pFileInfo
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
186 DPRINT("Found %.*S\n",IData
->pFileInfo
->FileNameLength
/sizeof(WCHAR
), IData
->pFileInfo
->FileName
);
198 InternalFindFirstFile (
200 BOOLEAN DirectoryOnly
203 OBJECT_ATTRIBUTES ObjectAttributes
;
204 PKERNEL32_FIND_DATA_HEADER IHeader
;
205 PKERNEL32_FIND_FILE_DATA IData
;
206 IO_STATUS_BLOCK IoStatusBlock
;
207 UNICODE_STRING NtPathU
;
208 UNICODE_STRING PatternStr
= RTL_CONSTANT_STRING(L
"*");
211 WCHAR CurrentDir
[256];
212 PWCHAR SlashlessFileName
;
214 PWCHAR SearchPattern
;
218 DPRINT("FindFirstFileW(lpFileName %S)\n",
221 Length
= wcslen(lpFileName
);
222 if (L
'\\' == lpFileName
[Length
- 1])
224 SlashlessFileName
= RtlAllocateHeap(hProcessHeap
,
226 Length
* sizeof(WCHAR
));
227 if (NULL
== SlashlessFileName
)
229 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
232 memcpy(SlashlessFileName
, lpFileName
, (Length
- 1) * sizeof(WCHAR
));
233 SlashlessFileName
[Length
- 1] = L
'\0';
234 lpFileName
= SlashlessFileName
;
238 SlashlessFileName
= NULL
;
241 e1
= wcsrchr(lpFileName
, L
'/');
242 e2
= wcsrchr(lpFileName
, L
'\\');
243 SearchPattern
= max(e1
, e2
);
244 SearchPath
= CurrentDir
;
246 if (NULL
== SearchPattern
)
249 SearchPattern
= (PWCHAR
)lpFileName
;
250 Length
= GetCurrentDirectoryW(sizeof(CurrentDir
) / sizeof(WCHAR
), SearchPath
);
253 if (NULL
!= SlashlessFileName
)
255 RtlFreeHeap(hProcessHeap
,
261 if (Length
> sizeof(CurrentDir
) / sizeof(WCHAR
))
263 SearchPath
= RtlAllocateHeap(hProcessHeap
,
265 Length
* sizeof(WCHAR
));
266 if (NULL
== SearchPath
)
268 if (NULL
!= SlashlessFileName
)
270 RtlFreeHeap(hProcessHeap
,
274 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
277 GetCurrentDirectoryW(Length
, SearchPath
);
284 Length
= SearchPattern
- lpFileName
;
285 if (Length
+ 1 > sizeof(CurrentDir
) / sizeof(WCHAR
))
287 SearchPath
= RtlAllocateHeap(hProcessHeap
,
289 (Length
+ 1) * sizeof(WCHAR
));
290 if (NULL
== SearchPath
)
292 if (NULL
!= SlashlessFileName
)
294 RtlFreeHeap(hProcessHeap
,
298 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
302 memcpy(SearchPath
, lpFileName
, Length
* sizeof(WCHAR
));
303 SearchPath
[Length
] = 0;
306 bResult
= RtlDosPathNameToNtPathName_U (SearchPath
,
310 if (SearchPath
!= CurrentDir
)
312 RtlFreeHeap(hProcessHeap
,
316 if (FALSE
== bResult
)
318 if (NULL
!= SlashlessFileName
)
320 RtlFreeHeap(hProcessHeap
,
324 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
328 DPRINT("NtPathU \'%S\'\n", NtPathU
.Buffer
);
330 IHeader
= RtlAllocateHeap (hProcessHeap
,
332 sizeof(KERNEL32_FIND_DATA_HEADER
) +
333 sizeof(KERNEL32_FIND_FILE_DATA
) + FIND_DATA_SIZE
);
336 RtlFreeHeap (hProcessHeap
,
339 if (NULL
!= SlashlessFileName
)
341 RtlFreeHeap(hProcessHeap
,
345 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
349 IHeader
->Type
= FileFind
;
350 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
352 /* change pattern: "*.*" --> "*" */
353 if (wcscmp (SearchPattern
, L
"*.*"))
355 RtlInitUnicodeString(&PatternStr
, SearchPattern
);
358 DPRINT("NtPathU \'%S\' Pattern \'%S\'\n",
359 NtPathU
.Buffer
, PatternStr
.Buffer
);
361 InitializeObjectAttributes (&ObjectAttributes
,
367 Status
= NtOpenFile (&IData
->DirectoryHandle
,
371 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
372 FILE_DIRECTORY_FILE
);
374 RtlFreeHeap (hProcessHeap
,
378 if (!NT_SUCCESS(Status
))
380 RtlFreeHeap (hProcessHeap
, 0, IHeader
);
381 if (NULL
!= SlashlessFileName
)
383 RtlFreeHeap(hProcessHeap
,
387 SetLastErrorByStatus (Status
);
390 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
391 IData
->pFileInfo
->FileIndex
= 0;
392 IData
->DirectoryOnly
= DirectoryOnly
;
394 bResult
= InternalFindNextFile((HANDLE
)IHeader
, &PatternStr
);
395 if (NULL
!= SlashlessFileName
)
397 RtlFreeHeap(hProcessHeap
,
404 FindClose((HANDLE
)IHeader
);
408 return (HANDLE
)IHeader
;
419 LPWIN32_FIND_DATAA lpFindFileData
422 PKERNEL32_FIND_DATA_HEADER IHeader
;
423 PKERNEL32_FIND_FILE_DATA IData
;
424 UNICODE_STRING FileNameU
;
425 ANSI_STRING FileName
;
427 RtlInitAnsiString (&FileName
,
430 /* convert ansi (or oem) string to unicode */
432 RtlAnsiStringToUnicodeString (&FileNameU
,
436 RtlOemStringToUnicodeString (&FileNameU
,
440 IHeader
= InternalFindFirstFile (FileNameU
.Buffer
, FALSE
);
442 RtlFreeUnicodeString (&FileNameU
);
446 DPRINT("Failing request\n");
447 return INVALID_HANDLE_VALUE
;
450 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
452 DPRINT("IData->pFileInfo->FileNameLength %d\n",
453 IData
->pFileInfo
->FileNameLength
);
455 /* copy data into WIN32_FIND_DATA structure */
456 InternalCopyFindDataA(lpFindFileData
, IData
->pFileInfo
);
459 return (HANDLE
)IHeader
;
470 LPWIN32_FIND_DATAA lpFindFileData
)
472 PKERNEL32_FIND_FILE_DATA IData
;
474 if (!InternalFindNextFile (hFindFile
, NULL
))
476 DPRINT("InternalFindNextFile() failed\n");
480 IData
= (PKERNEL32_FIND_FILE_DATA
)((PKERNEL32_FIND_DATA_HEADER
)hFindFile
+ 1);
482 DPRINT("IData->pFileInfo->FileNameLength %d\n",
483 IData
->pFileInfo
->FileNameLength
);
485 /* copy data into WIN32_FIND_DATA structure */
486 InternalCopyFindDataA(lpFindFileData
, IData
->pFileInfo
);
501 PKERNEL32_FIND_DATA_HEADER IHeader
;
503 DPRINT("FindClose(hFindFile %x)\n",hFindFile
);
505 if (!hFindFile
|| hFindFile
== INVALID_HANDLE_VALUE
)
507 SetLastError (ERROR_INVALID_HANDLE
);
511 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
513 switch (IHeader
->Type
)
517 PKERNEL32_FIND_FILE_DATA IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
518 CloseHandle (IData
->DirectoryHandle
);
524 PKERNEL32_FIND_STREAM_DATA IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
525 if (IData
->pFileStreamInfo
!= NULL
)
527 RtlFreeHeap (hProcessHeap
, 0, IData
->pFileStreamInfo
);
533 SetLastError (ERROR_INVALID_HANDLE
);
537 RtlFreeHeap (hProcessHeap
, 0, IHeader
);
550 LPWIN32_FIND_DATAW lpFindFileData
554 return FindFirstFileExW (lpFileName
,
556 (LPVOID
)lpFindFileData
,
557 FindExSearchNameMatch
,
569 LPWIN32_FIND_DATAW lpFindFileData
572 PKERNEL32_FIND_FILE_DATA IData
;
574 if (!InternalFindNextFile(hFindFile
, NULL
))
576 DPRINT("Failing request\n");
580 IData
= (PKERNEL32_FIND_FILE_DATA
)((PKERNEL32_FIND_DATA_HEADER
)hFindFile
+ 1);
582 /* copy data into WIN32_FIND_DATA structure */
583 InternalCopyFindDataW(lpFindFileData
, IData
->pFileInfo
);
594 FindFirstFileExW (LPCWSTR lpFileName
,
595 FINDEX_INFO_LEVELS fInfoLevelId
,
596 LPVOID lpFindFileData
,
597 FINDEX_SEARCH_OPS fSearchOp
,
598 LPVOID lpSearchFilter
,
599 DWORD dwAdditionalFlags
)
601 PKERNEL32_FIND_DATA_HEADER IHeader
;
602 PKERNEL32_FIND_FILE_DATA IData
;
604 if (fInfoLevelId
!= FindExInfoStandard
)
606 SetLastError(ERROR_INVALID_PARAMETER
);
607 return INVALID_HANDLE_VALUE
;
609 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
613 SetLastError(ERROR_INVALID_PARAMETER
);
614 return INVALID_HANDLE_VALUE
;
617 IHeader
= InternalFindFirstFile (lpFileName
, fSearchOp
== FindExSearchLimitToDirectories
? TRUE
: FALSE
);
620 DPRINT("Failing request\n");
621 return INVALID_HANDLE_VALUE
;
624 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
626 /* copy data into WIN32_FIND_DATA structure */
627 InternalCopyFindDataW((LPWIN32_FIND_DATAW
)lpFindFileData
, IData
->pFileInfo
);
629 return (HANDLE
)IHeader
;
631 SetLastError(ERROR_INVALID_PARAMETER
);
632 return INVALID_HANDLE_VALUE
;
642 FINDEX_INFO_LEVELS fInfoLevelId
,
643 LPVOID lpFindFileData
,
644 FINDEX_SEARCH_OPS fSearchOp
,
645 LPVOID lpSearchFilter
,
646 DWORD dwAdditionalFlags
649 PKERNEL32_FIND_DATA_HEADER IHeader
;
650 PKERNEL32_FIND_FILE_DATA IData
;
651 UNICODE_STRING FileNameU
;
652 ANSI_STRING FileNameA
;
654 if (fInfoLevelId
!= FindExInfoStandard
)
656 SetLastError(ERROR_INVALID_PARAMETER
);
657 return INVALID_HANDLE_VALUE
;
659 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
663 SetLastError(ERROR_INVALID_PARAMETER
);
664 return INVALID_HANDLE_VALUE
;
667 RtlInitAnsiString (&FileNameA
, (LPSTR
)lpFileName
);
669 /* convert ansi (or oem) string to unicode */
671 RtlAnsiStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
673 RtlOemStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
675 IHeader
= InternalFindFirstFile (FileNameU
.Buffer
, FALSE
);
677 RtlFreeUnicodeString (&FileNameU
);
681 DPRINT("Failing request\n");
682 return INVALID_HANDLE_VALUE
;
685 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
687 /* copy data into WIN32_FIND_DATA structure */
688 InternalCopyFindDataA(lpFindFileData
, IData
->pFileInfo
);
690 return (HANDLE
)IHeader
;
692 SetLastError(ERROR_INVALID_PARAMETER
);
693 return INVALID_HANDLE_VALUE
;
698 InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData
,
699 OUT LPVOID lpFindStreamData
)
701 ASSERT(IData
->pCurrent
);
703 switch (IData
->InfoLevel
)
705 case FindStreamInfoStandard
:
708 WIN32_FIND_STREAM_DATA
*StreamData
= (WIN32_FIND_STREAM_DATA
*)lpFindStreamData
;
710 StreamNameLen
= IData
->pCurrent
->StreamNameLength
;
711 if (StreamNameLen
> sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
))
712 StreamNameLen
= sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
);
714 StreamData
->StreamSize
.QuadPart
= IData
->pCurrent
->StreamSize
.QuadPart
;
715 RtlCopyMemory(StreamData
->cStreamName
,
716 IData
->pCurrent
->StreamName
,
718 StreamData
->cStreamName
[StreamNameLen
/ sizeof(WCHAR
)] = L
'\0';
734 FindFirstStreamW(IN LPCWSTR lpFileName
,
735 IN STREAM_INFO_LEVELS InfoLevel
,
736 OUT LPVOID lpFindStreamData
,
739 PKERNEL32_FIND_DATA_HEADER IHeader
= NULL
;
740 PKERNEL32_FIND_STREAM_DATA IData
= NULL
;
741 OBJECT_ATTRIBUTES ObjectAttributes
;
742 IO_STATUS_BLOCK IoStatusBlock
;
743 UNICODE_STRING NtPathU
;
744 HANDLE FileHandle
= NULL
;
746 ULONG BufferSize
= 0;
748 if (dwFlags
!= 0 || InfoLevel
!= FindStreamInfoStandard
||
749 lpFindStreamData
== NULL
)
751 SetLastError(ERROR_INVALID_PARAMETER
);
752 return INVALID_HANDLE_VALUE
;
755 /* validate & translate the filename */
756 if (!RtlDosPathNameToNtPathName_U(lpFileName
,
761 SetLastError(ERROR_PATH_NOT_FOUND
);
762 return INVALID_HANDLE_VALUE
;
766 InitializeObjectAttributes(&ObjectAttributes
,
768 OBJ_CASE_INSENSITIVE
,
772 Status
= NtCreateFile(&FileHandle
,
778 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
783 if (!NT_SUCCESS(Status
))
788 /* create the search context */
789 IHeader
= RtlAllocateHeap(hProcessHeap
,
791 sizeof(KERNEL32_FIND_DATA_HEADER
) +
792 sizeof(KERNEL32_FIND_STREAM_DATA
));
795 Status
= STATUS_NO_MEMORY
;
799 IHeader
->Type
= StreamFind
;
800 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
802 /* capture all information about the streams */
803 IData
->InfoLevel
= InfoLevel
;
804 IData
->pCurrent
= NULL
;
805 IData
->pFileStreamInfo
= NULL
;
809 BufferSize
+= 0x1000;
811 if (IData
->pFileStreamInfo
== NULL
)
813 IData
->pFileStreamInfo
= RtlAllocateHeap(hProcessHeap
,
816 if (IData
->pFileStreamInfo
== NULL
)
818 Status
= STATUS_NO_MEMORY
;
824 PFILE_STREAM_INFORMATION pfsi
;
826 pfsi
= RtlReAllocateHeap(hProcessHeap
,
828 IData
->pFileStreamInfo
,
832 Status
= STATUS_NO_MEMORY
;
836 IData
->pFileStreamInfo
= pfsi
;
839 Status
= NtQueryInformationFile(FileHandle
,
841 IData
->pFileStreamInfo
,
843 FileStreamInformation
);
845 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
847 if (NT_SUCCESS(Status
))
852 /* select the first stream and return the information */
853 IData
->pCurrent
= IData
->pFileStreamInfo
;
854 InternalCopyStreamInfo(IData
,
858 Status
= STATUS_SUCCESS
;
862 if (FileHandle
!= NULL
)
867 RtlFreeHeap(RtlGetProcessHeap(),
871 if (!NT_SUCCESS(Status
))
875 if (IData
->pFileStreamInfo
!= NULL
)
877 RtlFreeHeap(hProcessHeap
,
879 IData
->pFileStreamInfo
);
882 RtlFreeHeap(hProcessHeap
,
887 SetLastErrorByStatus(Status
);
888 return INVALID_HANDLE_VALUE
;
891 return (HANDLE
)IHeader
;
900 FindNextStreamW(IN HANDLE hFindStream
,
901 OUT LPVOID lpFindStreamData
)
903 PKERNEL32_FIND_DATA_HEADER IHeader
;
904 PKERNEL32_FIND_STREAM_DATA IData
;
906 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindStream
;
907 if (hFindStream
== NULL
|| hFindStream
== INVALID_HANDLE_VALUE
||
908 IHeader
->Type
!= StreamFind
)
910 SetLastError (ERROR_INVALID_HANDLE
);
914 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
916 /* select next stream if possible */
917 if (IData
->pCurrent
->NextEntryOffset
!= 0)
919 IData
->pCurrent
= (PFILE_STREAM_INFORMATION
)((ULONG_PTR
)IData
->pFileStreamInfo
+
920 IData
->pCurrent
->NextEntryOffset
);
924 SetLastError(ERROR_HANDLE_EOF
);
928 /* return the information */
929 InternalCopyStreamInfo(IData
,