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)
8 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
13 /* INCLUDES *****************************************************************/
18 DEBUG_CHANNEL(kernel32file
);
20 /* TYPES ********************************************************************/
22 #define FIND_DATA_SIZE 0x4000
24 #define FIND_DEVICE_HANDLE ((HANDLE)0x1)
26 typedef struct _KERNEL32_FIND_FILE_DATA
28 HANDLE DirectoryHandle
;
29 RTL_CRITICAL_SECTION Lock
;
30 PFILE_BOTH_DIR_INFORMATION pFileInfo
;
31 BOOLEAN DirectoryOnly
;
34 BOOLEAN LockInitialized
;
35 } KERNEL32_FIND_FILE_DATA
, *PKERNEL32_FIND_FILE_DATA
;
37 typedef struct _KERNEL32_FIND_STREAM_DATA
39 STREAM_INFO_LEVELS InfoLevel
;
40 PFILE_STREAM_INFORMATION pFileStreamInfo
;
41 PFILE_STREAM_INFORMATION pCurrent
;
42 } KERNEL32_FIND_STREAM_DATA
, *PKERNEL32_FIND_STREAM_DATA
;
44 typedef enum _KERNEL32_FIND_DATA_TYPE
48 } KERNEL32_FIND_DATA_TYPE
;
50 typedef struct _KERNEL32_FIND_DATA_HEADER
52 KERNEL32_FIND_DATA_TYPE Type
;
53 } KERNEL32_FIND_DATA_HEADER
, *PKERNEL32_FIND_DATA_HEADER
;
56 /* FUNCTIONS ****************************************************************/
59 InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
63 UNICODE_STRING DeviceName
;
65 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)(DeviceNameInfo
& 0xFFFF);
66 DeviceName
.Buffer
= (LPWSTR
)((ULONG_PTR
)lpFileName
+ (DeviceNameInfo
>> 16));
69 RtlZeroMemory(lpFindFileData
,
70 sizeof(*lpFindFileData
));
71 lpFindFileData
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
72 RtlCopyMemory(lpFindFileData
->cFileName
,
78 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
79 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
81 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
83 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
84 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
86 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
87 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
89 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
90 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
92 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
93 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
95 memcpy (lpFindFileData
->cFileName
, lpFileInfo
->FileName
, lpFileInfo
->FileNameLength
);
96 lpFindFileData
->cFileName
[lpFileInfo
->FileNameLength
/ sizeof(WCHAR
)] = 0;
98 memcpy (lpFindFileData
->cAlternateFileName
, lpFileInfo
->ShortName
, lpFileInfo
->ShortNameLength
);
99 lpFindFileData
->cAlternateFileName
[lpFileInfo
->ShortNameLength
/ sizeof(WCHAR
)] = 0;
108 InternalFindNextFile (
110 PUNICODE_STRING SearchPattern
,
114 PKERNEL32_FIND_DATA_HEADER IHeader
;
115 PKERNEL32_FIND_FILE_DATA IData
;
116 IO_STATUS_BLOCK IoStatusBlock
;
117 BOOLEAN Locked
= FALSE
;
118 PFILE_BOTH_DIR_INFORMATION Buffer
, FoundFile
= NULL
;
119 NTSTATUS Status
= STATUS_SUCCESS
;
121 TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile
, SearchPattern
);
123 if (hFindFile
!= FIND_DEVICE_HANDLE
)
125 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
126 if (hFindFile
== NULL
|| hFindFile
== INVALID_HANDLE_VALUE
||
127 IHeader
->Type
!= FileFind
)
129 SetLastError (ERROR_INVALID_HANDLE
);
133 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
134 Buffer
= (PFILE_BOTH_DIR_INFORMATION
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
136 if (SearchPattern
== NULL
)
138 RtlEnterCriticalSection(&IData
->Lock
);
146 if (!IData
->DirectoryOnly
|| (IData
->pFileInfo
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
148 FoundFile
= IData
->pFileInfo
;
151 if (IData
->pFileInfo
->NextEntryOffset
!= 0)
155 IData
->pFileInfo
= (PFILE_BOTH_DIR_INFORMATION
)((ULONG_PTR
)IData
->pFileInfo
+ IData
->pFileInfo
->NextEntryOffset
);
157 /* Be paranoid and make sure that the next entry is completely there */
158 BufferEnd
= (ULONG_PTR
)Buffer
+ FIND_DATA_SIZE
;
159 if (BufferEnd
< (ULONG_PTR
)IData
->pFileInfo
||
160 BufferEnd
< (ULONG_PTR
)&IData
->pFileInfo
->FileNameLength
+ sizeof(IData
->pFileInfo
->FileNameLength
) ||
161 BufferEnd
<= (ULONG_PTR
)&IData
->pFileInfo
->FileName
[IData
->pFileInfo
->FileNameLength
])
169 IData
->HasData
= FALSE
;
171 if (!IData
->HasMoreData
)
177 IData
->pFileInfo
= Buffer
;
178 IData
->pFileInfo
->NextEntryOffset
= 0;
179 Status
= NtQueryDirectoryFile (IData
->DirectoryHandle
,
184 (PVOID
)IData
->pFileInfo
,
186 FileBothDirectoryInformation
,
189 SearchPattern
!= NULL
);
191 if (Status
== STATUS_BUFFER_OVERFLOW
)
193 IData
->HasMoreData
= TRUE
;
194 Status
= STATUS_SUCCESS
;
198 if (!NT_SUCCESS(Status
))
201 IData
->HasMoreData
= FALSE
;
204 IData
->HasData
= TRUE
;
205 SearchPattern
= NULL
;
208 } while (FoundFile
== NULL
);
210 if (FoundFile
!= NULL
)
214 InternalCopyFindDataW(lpFindFileData
,
217 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
224 RtlLeaveCriticalSection(&IData
->Lock
);
227 if (!NT_SUCCESS(Status
))
229 SetLastErrorByStatus (Status
);
232 else if (FoundFile
== NULL
)
234 SetLastError (ERROR_NO_MORE_FILES
);
247 InternalFindFirstFile (
249 BOOLEAN DirectoryOnly
,
253 OBJECT_ATTRIBUTES ObjectAttributes
;
254 PKERNEL32_FIND_DATA_HEADER IHeader
;
255 PKERNEL32_FIND_FILE_DATA IData
;
256 IO_STATUS_BLOCK IoStatusBlock
;
257 UNICODE_STRING NtPathU
, FileName
, PathFileName
;
260 BOOLEAN RemovedLastChar
= FALSE
;
262 RTL_RELATIVE_NAME_U DirInfo
;
263 ULONG DeviceNameInfo
;
264 HANDLE hDirectory
= NULL
;
266 TRACE("FindFirstFileW(lpFileName %S)\n",
269 RtlZeroMemory(&PathFileName
,
270 sizeof(PathFileName
));
271 RtlInitUnicodeString(&FileName
,
274 bResult
= RtlDosPathNameToNtPathName_U (lpFileName
,
276 (PCWSTR
*)((ULONG_PTR
)&PathFileName
.Buffer
),
278 if (FALSE
== bResult
)
280 SetLastError(ERROR_PATH_NOT_FOUND
);
281 return INVALID_HANDLE_VALUE
;
284 /* Save the buffer pointer for later, we need to free it! */
285 NtPathBuffer
= NtPathU
.Buffer
;
287 /* If there is a file name/pattern then determine it's length */
288 if (PathFileName
.Buffer
!= NULL
)
290 PathFileName
.Length
= NtPathU
.Length
-
291 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)NtPathU
.Buffer
);
293 PathFileName
.MaximumLength
= PathFileName
.Length
;
295 if (DirInfo
.RelativeName
.Length
!= 0 && DirInfo
.RelativeName
.Buffer
!= PathFileName
.Buffer
)
297 if (PathFileName
.Buffer
!= NULL
)
299 /* This is a relative path to DirInfo.ContainingDirectory, adjust NtPathU! */
300 NtPathU
.Length
= NtPathU
.MaximumLength
=
301 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)DirInfo
.RelativeName
.Buffer
);
302 NtPathU
.Buffer
= DirInfo
.RelativeName
.Buffer
;
307 /* This is an absolute path, NtPathU receives the full path */
308 DirInfo
.ContainingDirectory
= NULL
;
309 if (PathFileName
.Buffer
!= NULL
)
311 NtPathU
.Length
= NtPathU
.MaximumLength
=
312 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)NtPathU
.Buffer
);
316 /* Remove the last character of the path (Unless the path is a drive and
317 ends with ":\"). If the caller however supplies a path to a device, such
318 as "C:\NUL" then the last character gets cut off, which later results in
319 NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers
320 a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a
321 real device with a name eg. "NU" in the system, FindFirstFile will succeed,
322 rendering the fake DOS device check useless... Why would they invent such a
323 stupid and broken behavior?! */
324 if (NtPathU
.Length
>= 2 * sizeof(WCHAR
) &&
325 NtPathU
.Buffer
[(NtPathU
.Length
/ sizeof(WCHAR
)) - 1] != L
'\\' &&
326 NtPathU
.Buffer
[(NtPathU
.Length
/ sizeof(WCHAR
)) - 2] != L
':')
328 NtPathU
.Length
-= sizeof(WCHAR
);
329 RemovedLastChar
= TRUE
;
332 TRACE("lpFileName: \"%ws\"\n", lpFileName
);
333 TRACE("NtPathU: \"%wZ\"\n", &NtPathU
);
334 TRACE("PathFileName: \"%wZ\"\n", &PathFileName
);
335 TRACE("RelativeTo: 0x%p\n", DirInfo
.ContainingDirectory
);
337 InitializeObjectAttributes (&ObjectAttributes
,
339 OBJ_CASE_INSENSITIVE
,
340 DirInfo
.ContainingDirectory
,
343 Status
= NtOpenFile (&hDirectory
,
344 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
347 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
348 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
350 if (Status
== STATUS_NOT_A_DIRECTORY
&& RemovedLastChar
)
352 /* Try again, this time with the last character ... */
353 NtPathU
.Length
+= sizeof(WCHAR
);
355 Status
= NtOpenFile (&hDirectory
,
356 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
359 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
360 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
362 NtPathU
.Length
+= sizeof(WCHAR
);
365 if (!NT_SUCCESS(Status
))
367 RtlFreeHeap (hProcessHeap
,
371 /* See if the application tries to look for a DOS device */
372 DeviceNameInfo
= RtlIsDosDeviceName_U((PWSTR
)((ULONG_PTR
)lpFileName
));
373 if (DeviceNameInfo
!= 0)
375 InternalCopyDeviceFindDataW(lpFindFileData
,
379 return FIND_DEVICE_HANDLE
;
382 SetLastErrorByStatus (Status
);
383 return INVALID_HANDLE_VALUE
;
386 if (PathFileName
.Length
== 0)
390 RtlFreeHeap (hProcessHeap
,
393 SetLastError(ERROR_FILE_NOT_FOUND
);
394 return INVALID_HANDLE_VALUE
;
397 IHeader
= RtlAllocateHeap (hProcessHeap
,
399 sizeof(KERNEL32_FIND_DATA_HEADER
) +
400 sizeof(KERNEL32_FIND_FILE_DATA
) + FIND_DATA_SIZE
);
403 RtlFreeHeap (hProcessHeap
,
408 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
409 return INVALID_HANDLE_VALUE
;
412 IHeader
->Type
= FileFind
;
413 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
414 IData
->DirectoryHandle
= hDirectory
;
415 IData
->HasMoreData
= TRUE
;
417 /* change pattern: "*.*" --> "*" */
418 if (PathFileName
.Length
== 6 &&
419 RtlCompareMemory(PathFileName
.Buffer
,
423 PathFileName
.Length
= 2;
426 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
427 IData
->pFileInfo
->FileIndex
= 0;
428 IData
->DirectoryOnly
= DirectoryOnly
;
430 bResult
= InternalFindNextFile((HANDLE
)IHeader
,
434 RtlFreeHeap (hProcessHeap
,
440 FindClose((HANDLE
)IHeader
);
441 return INVALID_HANDLE_VALUE
;
444 RtlInitializeCriticalSection(&IData
->Lock
);
445 IData
->LockInitialized
= TRUE
;
447 return (HANDLE
)IHeader
;
456 FindFirstFileA(IN LPCSTR lpFileName
,
457 OUT LPWIN32_FIND_DATAA lpFindFileData
)
463 PUNICODE_STRING lpFileNameW
;
464 WIN32_FIND_DATAW FindFileDataW
;
466 lpFileNameW
= Basep8BitStringToStaticUnicodeString(lpFileName
);
469 return INVALID_HANDLE_VALUE
;
472 hSearch
= FindFirstFileExW(lpFileNameW
->Buffer
,
475 FindExSearchNameMatch
,
477 if (hSearch
== INVALID_HANDLE_VALUE
)
479 return INVALID_HANDLE_VALUE
;
482 memcpy(lpFindFileData
, &FindFileDataW
, FIELD_OFFSET(WIN32_FIND_DATA
, cFileName
));
484 RtlInitUnicodeString(&UTF8
, FindFileDataW
.cFileName
);
485 Ansi
.Buffer
= lpFindFileData
->cFileName
;
487 Ansi
.MaximumLength
= MAX_PATH
;
488 Status
= BasepUnicodeStringTo8BitString(&Ansi
, &UTF8
, FALSE
);
489 if (!NT_SUCCESS(Status
))
492 BaseSetLastNTError(Status
);
493 return INVALID_HANDLE_VALUE
;
496 RtlInitUnicodeString(&UTF8
, FindFileDataW
.cAlternateFileName
);
497 Ansi
.Buffer
= lpFindFileData
->cAlternateFileName
;
499 Ansi
.MaximumLength
= 14;
500 Status
= BasepUnicodeStringTo8BitString(&Ansi
, &UTF8
, FALSE
);
501 if (!NT_SUCCESS(Status
))
504 BaseSetLastNTError(Status
);
505 return INVALID_HANDLE_VALUE
;
517 FindNextFileA(IN HANDLE hFindFile
,
518 OUT LPWIN32_FIND_DATAA lpFindFileData
)
523 WIN32_FIND_DATAW FindFileDataW
;
525 if (!FindNextFileW(hFindFile
, &FindFileDataW
))
530 memcpy(lpFindFileData
, &FindFileDataW
, FIELD_OFFSET(WIN32_FIND_DATA
, cFileName
));
532 RtlInitUnicodeString(&UTF8
, FindFileDataW
.cFileName
);
533 Ansi
.Buffer
= lpFindFileData
->cFileName
;
535 Ansi
.MaximumLength
= MAX_PATH
;
536 Status
= BasepUnicodeStringTo8BitString(&Ansi
, &UTF8
, FALSE
);
537 if (!NT_SUCCESS(Status
))
539 BaseSetLastNTError(Status
);
543 RtlInitUnicodeString(&UTF8
, FindFileDataW
.cAlternateFileName
);
544 Ansi
.Buffer
= lpFindFileData
->cAlternateFileName
;
546 Ansi
.MaximumLength
= 14;
547 Status
= BasepUnicodeStringTo8BitString(&Ansi
, &UTF8
, FALSE
);
548 if (!NT_SUCCESS(Status
))
550 BaseSetLastNTError(Status
);
567 PKERNEL32_FIND_DATA_HEADER IHeader
;
569 TRACE("FindClose(hFindFile %x)\n",hFindFile
);
571 if (hFindFile
== FIND_DEVICE_HANDLE
)
574 if (!hFindFile
|| hFindFile
== INVALID_HANDLE_VALUE
)
576 SetLastError (ERROR_INVALID_HANDLE
);
580 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
582 switch (IHeader
->Type
)
586 PKERNEL32_FIND_FILE_DATA IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
587 CloseHandle (IData
->DirectoryHandle
);
588 if (IData
->LockInitialized
)
589 RtlDeleteCriticalSection(&IData
->Lock
);
590 IData
->LockInitialized
= FALSE
;
596 PKERNEL32_FIND_STREAM_DATA IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
597 if (IData
->pFileStreamInfo
!= NULL
)
599 RtlFreeHeap (hProcessHeap
, 0, IData
->pFileStreamInfo
);
605 SetLastError (ERROR_INVALID_HANDLE
);
609 RtlFreeHeap (hProcessHeap
, 0, IHeader
);
620 FindFirstFileW(IN LPCWSTR lpFileName
,
621 OUT LPWIN32_FIND_DATAW lpFindFileData
)
623 return FindFirstFileExW(lpFileName
,
626 FindExSearchNameMatch
,
636 FindNextFileW(IN HANDLE hFindFile
,
637 OUT LPWIN32_FIND_DATAW lpFindFileData
)
639 return InternalFindNextFile(hFindFile
,
650 FindFirstFileExW(IN LPCWSTR lpFileName
,
651 IN FINDEX_INFO_LEVELS fInfoLevelId
,
652 OUT LPVOID lpFindFileData
,
653 IN FINDEX_SEARCH_OPS fSearchOp
,
654 LPVOID lpSearchFilter
,
655 IN DWORD dwAdditionalFlags
)
657 if (fInfoLevelId
!= FindExInfoStandard
)
659 SetLastError(ERROR_INVALID_PARAMETER
);
660 return INVALID_HANDLE_VALUE
;
663 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
667 SetLastError(ERROR_INVALID_PARAMETER
);
668 return INVALID_HANDLE_VALUE
;
671 return InternalFindFirstFile (lpFileName
,
672 fSearchOp
== FindExSearchLimitToDirectories
,
676 SetLastError(ERROR_INVALID_PARAMETER
);
677 return INVALID_HANDLE_VALUE
;
685 FindFirstFileExA(IN LPCSTR lpFileName
,
686 IN FINDEX_INFO_LEVELS fInfoLevelId
,
687 OUT LPVOID lpFindFileData
,
688 IN FINDEX_SEARCH_OPS fSearchOp
,
689 LPVOID lpSearchFilter
,
690 IN DWORD dwAdditionalFlags
)
696 PUNICODE_STRING lpFileNameW
;
697 WIN32_FIND_DATAW FindFileDataW
;
699 lpFileNameW
= Basep8BitStringToStaticUnicodeString(lpFileName
);
702 return INVALID_HANDLE_VALUE
;
705 hSearch
= FindFirstFileExW(lpFileNameW
->Buffer
,
711 if (hSearch
== INVALID_HANDLE_VALUE
)
713 return INVALID_HANDLE_VALUE
;
716 memcpy(lpFindFileData
, &FindFileDataW
, FIELD_OFFSET(WIN32_FIND_DATA
, cFileName
));
718 RtlInitUnicodeString(&UTF8
, FindFileDataW
.cFileName
);
719 Ansi
.Buffer
= ((LPWIN32_FIND_DATAA
)lpFindFileData
)->cFileName
;
721 Ansi
.MaximumLength
= MAX_PATH
;
722 Status
= BasepUnicodeStringTo8BitString(&Ansi
, &UTF8
, FALSE
);
723 if (!NT_SUCCESS(Status
))
726 BaseSetLastNTError(Status
);
727 return INVALID_HANDLE_VALUE
;
730 RtlInitUnicodeString(&UTF8
, FindFileDataW
.cAlternateFileName
);
731 Ansi
.Buffer
= ((LPWIN32_FIND_DATAA
)lpFindFileData
)->cAlternateFileName
;
733 Ansi
.MaximumLength
= 14;
734 Status
= BasepUnicodeStringTo8BitString(&Ansi
, &UTF8
, FALSE
);
735 if (!NT_SUCCESS(Status
))
738 BaseSetLastNTError(Status
);
739 return INVALID_HANDLE_VALUE
;
747 InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData
,
748 OUT LPVOID lpFindStreamData
)
750 ASSERT(IData
->pCurrent
);
752 switch (IData
->InfoLevel
)
754 case FindStreamInfoStandard
:
757 WIN32_FIND_STREAM_DATA
*StreamData
= (WIN32_FIND_STREAM_DATA
*)lpFindStreamData
;
759 StreamNameLen
= IData
->pCurrent
->StreamNameLength
;
760 if (StreamNameLen
> sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
))
761 StreamNameLen
= sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
);
763 StreamData
->StreamSize
.QuadPart
= IData
->pCurrent
->StreamSize
.QuadPart
;
764 RtlCopyMemory(StreamData
->cStreamName
,
765 IData
->pCurrent
->StreamName
,
767 StreamData
->cStreamName
[StreamNameLen
/ sizeof(WCHAR
)] = L
'\0';
783 FindFirstStreamW(IN LPCWSTR lpFileName
,
784 IN STREAM_INFO_LEVELS InfoLevel
,
785 OUT LPVOID lpFindStreamData
,
788 PKERNEL32_FIND_DATA_HEADER IHeader
= NULL
;
789 PKERNEL32_FIND_STREAM_DATA IData
= NULL
;
790 OBJECT_ATTRIBUTES ObjectAttributes
;
791 IO_STATUS_BLOCK IoStatusBlock
;
792 UNICODE_STRING NtPathU
;
793 HANDLE FileHandle
= NULL
;
795 ULONG BufferSize
= 0;
797 if (dwFlags
!= 0 || InfoLevel
!= FindStreamInfoStandard
||
798 lpFindStreamData
== NULL
)
800 SetLastError(ERROR_INVALID_PARAMETER
);
801 return INVALID_HANDLE_VALUE
;
804 /* validate & translate the filename */
805 if (!RtlDosPathNameToNtPathName_U(lpFileName
,
810 SetLastError(ERROR_PATH_NOT_FOUND
);
811 return INVALID_HANDLE_VALUE
;
815 InitializeObjectAttributes(&ObjectAttributes
,
817 OBJ_CASE_INSENSITIVE
,
821 Status
= NtCreateFile(&FileHandle
,
827 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
832 if (!NT_SUCCESS(Status
))
837 /* create the search context */
838 IHeader
= RtlAllocateHeap(hProcessHeap
,
840 sizeof(KERNEL32_FIND_DATA_HEADER
) +
841 sizeof(KERNEL32_FIND_STREAM_DATA
));
844 Status
= STATUS_NO_MEMORY
;
848 IHeader
->Type
= StreamFind
;
849 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
851 /* capture all information about the streams */
852 IData
->InfoLevel
= InfoLevel
;
853 IData
->pCurrent
= NULL
;
854 IData
->pFileStreamInfo
= NULL
;
858 BufferSize
+= 0x1000;
860 if (IData
->pFileStreamInfo
== NULL
)
862 IData
->pFileStreamInfo
= RtlAllocateHeap(hProcessHeap
,
865 if (IData
->pFileStreamInfo
== NULL
)
867 Status
= STATUS_NO_MEMORY
;
873 PFILE_STREAM_INFORMATION pfsi
;
875 pfsi
= RtlReAllocateHeap(hProcessHeap
,
877 IData
->pFileStreamInfo
,
881 Status
= STATUS_NO_MEMORY
;
885 IData
->pFileStreamInfo
= pfsi
;
888 Status
= NtQueryInformationFile(FileHandle
,
890 IData
->pFileStreamInfo
,
892 FileStreamInformation
);
894 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
896 if (NT_SUCCESS(Status
))
901 /* select the first stream and return the information */
902 IData
->pCurrent
= IData
->pFileStreamInfo
;
903 InternalCopyStreamInfo(IData
,
907 Status
= STATUS_SUCCESS
;
911 if (FileHandle
!= NULL
)
916 RtlFreeHeap(RtlGetProcessHeap(),
920 if (!NT_SUCCESS(Status
))
924 if (IData
->pFileStreamInfo
!= NULL
)
926 RtlFreeHeap(hProcessHeap
,
928 IData
->pFileStreamInfo
);
931 RtlFreeHeap(hProcessHeap
,
936 SetLastErrorByStatus(Status
);
937 return INVALID_HANDLE_VALUE
;
940 return (HANDLE
)IHeader
;
949 FindNextStreamW(IN HANDLE hFindStream
,
950 OUT LPVOID lpFindStreamData
)
952 PKERNEL32_FIND_DATA_HEADER IHeader
;
953 PKERNEL32_FIND_STREAM_DATA IData
;
955 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindStream
;
956 if (hFindStream
== NULL
|| hFindStream
== INVALID_HANDLE_VALUE
||
957 IHeader
->Type
!= StreamFind
)
959 SetLastError (ERROR_INVALID_HANDLE
);
963 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
965 /* select next stream if possible */
966 if (IData
->pCurrent
->NextEntryOffset
!= 0)
968 IData
->pCurrent
= (PFILE_STREAM_INFORMATION
)((ULONG_PTR
)IData
->pFileStreamInfo
+
969 IData
->pCurrent
->NextEntryOffset
);
973 SetLastError(ERROR_HANDLE_EOF
);
977 /* return the information */
978 InternalCopyStreamInfo(IData
,