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 static ULONG gDebugChannel
= kernel32file
;
19 /* TYPES ********************************************************************/
21 #define FIND_DATA_SIZE 0x4000
23 #define FIND_DEVICE_HANDLE ((HANDLE)0x1)
25 typedef struct _KERNEL32_FIND_FILE_DATA
27 HANDLE DirectoryHandle
;
28 RTL_CRITICAL_SECTION Lock
;
29 PFILE_BOTH_DIR_INFORMATION pFileInfo
;
30 BOOLEAN DirectoryOnly
;
33 BOOLEAN LockInitialized
;
34 } KERNEL32_FIND_FILE_DATA
, *PKERNEL32_FIND_FILE_DATA
;
36 typedef struct _KERNEL32_FIND_STREAM_DATA
38 STREAM_INFO_LEVELS InfoLevel
;
39 PFILE_STREAM_INFORMATION pFileStreamInfo
;
40 PFILE_STREAM_INFORMATION pCurrent
;
41 } KERNEL32_FIND_STREAM_DATA
, *PKERNEL32_FIND_STREAM_DATA
;
43 typedef enum _KERNEL32_FIND_DATA_TYPE
47 } KERNEL32_FIND_DATA_TYPE
;
49 typedef struct _KERNEL32_FIND_DATA_HEADER
51 KERNEL32_FIND_DATA_TYPE Type
;
52 } KERNEL32_FIND_DATA_HEADER
, *PKERNEL32_FIND_DATA_HEADER
;
55 /* FUNCTIONS ****************************************************************/
58 InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
62 UNICODE_STRING DeviceName
;
64 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)(DeviceNameInfo
& 0xFFFF);
65 DeviceName
.Buffer
= (LPWSTR
)((ULONG_PTR
)lpFileName
+ (DeviceNameInfo
>> 16));
68 RtlZeroMemory(lpFindFileData
,
69 sizeof(*lpFindFileData
));
70 lpFindFileData
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
71 RtlCopyMemory(lpFindFileData
->cFileName
,
77 InternalCopyDeviceFindDataA(LPWIN32_FIND_DATAA lpFindFileData
,
78 PUNICODE_STRING FileName
,
81 UNICODE_STRING DeviceName
;
83 CHAR Buffer
[MAX_PATH
];
85 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)(DeviceNameInfo
& 0xFFFF);
86 DeviceName
.Buffer
= (LPWSTR
)((ULONG_PTR
)FileName
->Buffer
+ (DeviceNameInfo
>> 16));
88 BufferA
.MaximumLength
= sizeof(Buffer
) - sizeof(Buffer
[0]);
89 BufferA
.Buffer
= Buffer
;
91 RtlUnicodeStringToAnsiString (&BufferA
, &DeviceName
, FALSE
);
93 RtlUnicodeStringToOemString (&BufferA
, &DeviceName
, FALSE
);
96 RtlZeroMemory(lpFindFileData
,
97 sizeof(*lpFindFileData
));
98 lpFindFileData
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
99 RtlCopyMemory(lpFindFileData
->cFileName
,
105 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
106 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
108 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
110 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
111 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
113 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
114 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
116 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
117 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
119 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
120 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
122 memcpy (lpFindFileData
->cFileName
, lpFileInfo
->FileName
, lpFileInfo
->FileNameLength
);
123 lpFindFileData
->cFileName
[lpFileInfo
->FileNameLength
/ sizeof(WCHAR
)] = 0;
125 memcpy (lpFindFileData
->cAlternateFileName
, lpFileInfo
->ShortName
, lpFileInfo
->ShortNameLength
);
126 lpFindFileData
->cAlternateFileName
[lpFileInfo
->ShortNameLength
/ sizeof(WCHAR
)] = 0;
130 InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData
,
131 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
133 UNICODE_STRING FileNameU
;
134 ANSI_STRING FileNameA
;
136 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
138 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
139 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
141 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
142 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
144 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
145 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
147 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
148 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
150 FileNameU
.Length
= FileNameU
.MaximumLength
= (USHORT
)lpFileInfo
->FileNameLength
;
151 FileNameU
.Buffer
= lpFileInfo
->FileName
;
153 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cFileName
) - sizeof(CHAR
);
154 FileNameA
.Buffer
= lpFindFileData
->cFileName
;
156 /* convert unicode string to ansi (or oem) */
158 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
160 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
162 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
164 TRACE("lpFileInfo->ShortNameLength %d\n", lpFileInfo
->ShortNameLength
);
166 FileNameU
.Length
= FileNameU
.MaximumLength
= lpFileInfo
->ShortNameLength
;
167 FileNameU
.Buffer
= lpFileInfo
->ShortName
;
169 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cAlternateFileName
) - sizeof(CHAR
);
170 FileNameA
.Buffer
= lpFindFileData
->cAlternateFileName
;
172 /* convert unicode string to ansi (or oem) */
174 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
176 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
178 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
186 InternalFindNextFile (
188 PUNICODE_STRING SearchPattern
,
189 PVOID lpFindFileData
,
193 PKERNEL32_FIND_DATA_HEADER IHeader
;
194 PKERNEL32_FIND_FILE_DATA IData
;
195 IO_STATUS_BLOCK IoStatusBlock
;
196 BOOLEAN Locked
= FALSE
;
197 PFILE_BOTH_DIR_INFORMATION Buffer
, FoundFile
= NULL
;
198 NTSTATUS Status
= STATUS_SUCCESS
;
200 TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile
, SearchPattern
);
202 if (hFindFile
!= FIND_DEVICE_HANDLE
)
204 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
205 if (hFindFile
== NULL
|| hFindFile
== INVALID_HANDLE_VALUE
||
206 IHeader
->Type
!= FileFind
)
208 SetLastError (ERROR_INVALID_HANDLE
);
212 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
213 Buffer
= (PFILE_BOTH_DIR_INFORMATION
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
215 if (SearchPattern
== NULL
)
217 RtlEnterCriticalSection(&IData
->Lock
);
225 if (!IData
->DirectoryOnly
|| (IData
->pFileInfo
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
227 FoundFile
= IData
->pFileInfo
;
230 if (IData
->pFileInfo
->NextEntryOffset
!= 0)
234 IData
->pFileInfo
= (PFILE_BOTH_DIR_INFORMATION
)((ULONG_PTR
)IData
->pFileInfo
+ IData
->pFileInfo
->NextEntryOffset
);
236 /* Be paranoid and make sure that the next entry is completely there */
237 BufferEnd
= (ULONG_PTR
)Buffer
+ FIND_DATA_SIZE
;
238 if (BufferEnd
< (ULONG_PTR
)IData
->pFileInfo
||
239 BufferEnd
< (ULONG_PTR
)&IData
->pFileInfo
->FileNameLength
+ sizeof(IData
->pFileInfo
->FileNameLength
) ||
240 BufferEnd
<= (ULONG_PTR
)&IData
->pFileInfo
->FileName
[IData
->pFileInfo
->FileNameLength
])
248 IData
->HasData
= FALSE
;
250 if (!IData
->HasMoreData
)
256 IData
->pFileInfo
= Buffer
;
257 IData
->pFileInfo
->NextEntryOffset
= 0;
258 Status
= NtQueryDirectoryFile (IData
->DirectoryHandle
,
263 (PVOID
)IData
->pFileInfo
,
265 FileBothDirectoryInformation
,
268 SearchPattern
!= NULL
);
270 if (Status
== STATUS_BUFFER_OVERFLOW
)
272 IData
->HasMoreData
= TRUE
;
273 Status
= STATUS_SUCCESS
;
277 if (!NT_SUCCESS(Status
))
280 IData
->HasMoreData
= FALSE
;
283 IData
->HasData
= TRUE
;
284 SearchPattern
= NULL
;
287 } while (FoundFile
== NULL
);
289 if (FoundFile
!= NULL
)
295 InternalCopyFindDataW(lpFindFileData
,
300 InternalCopyFindDataA(lpFindFileData
,
304 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
311 RtlLeaveCriticalSection(&IData
->Lock
);
314 if (!NT_SUCCESS(Status
))
316 SetLastErrorByStatus (Status
);
319 else if (FoundFile
== NULL
)
321 SetLastError (ERROR_NO_MORE_FILES
);
334 InternalFindFirstFile (
336 BOOLEAN DirectoryOnly
,
337 PVOID lpFindFileData
,
341 OBJECT_ATTRIBUTES ObjectAttributes
;
342 PKERNEL32_FIND_DATA_HEADER IHeader
;
343 PKERNEL32_FIND_FILE_DATA IData
;
344 IO_STATUS_BLOCK IoStatusBlock
;
345 UNICODE_STRING NtPathU
, FileName
, PathFileName
;
348 BOOLEAN RemovedLastChar
= FALSE
;
351 ULONG DeviceNameInfo
;
352 HANDLE hDirectory
= NULL
;
354 TRACE("FindFirstFileW(lpFileName %S)\n",
357 RtlZeroMemory(&PathFileName
,
358 sizeof(PathFileName
));
359 RtlInitUnicodeString(&FileName
,
362 bResult
= RtlDosPathNameToNtPathName_U (lpFileName
,
364 (PCWSTR
*)((ULONG_PTR
)&PathFileName
.Buffer
),
366 if (FALSE
== bResult
)
368 SetLastError(ERROR_PATH_NOT_FOUND
);
369 return INVALID_HANDLE_VALUE
;
372 /* Save the buffer pointer for later, we need to free it! */
373 NtPathBuffer
= NtPathU
.Buffer
;
375 /* If there is a file name/pattern then determine it's length */
376 if (PathFileName
.Buffer
!= NULL
)
378 PathFileName
.Length
= NtPathU
.Length
-
379 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)NtPathU
.Buffer
);
381 PathFileName
.MaximumLength
= PathFileName
.Length
;
383 if (DirInfo
.DosPath
.Length
!= 0 && DirInfo
.DosPath
.Buffer
!= PathFileName
.Buffer
)
385 if (PathFileName
.Buffer
!= NULL
)
387 /* This is a relative path to DirInfo.Handle, adjust NtPathU! */
388 NtPathU
.Length
= NtPathU
.MaximumLength
=
389 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)DirInfo
.DosPath
.Buffer
);
390 NtPathU
.Buffer
= DirInfo
.DosPath
.Buffer
;
395 /* This is an absolute path, NtPathU receives the full path */
396 DirInfo
.Handle
= NULL
;
397 if (PathFileName
.Buffer
!= NULL
)
399 NtPathU
.Length
= NtPathU
.MaximumLength
=
400 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)NtPathU
.Buffer
);
404 /* Remove the last character of the path (Unless the path is a drive and
405 ends with ":\"). If the caller however supplies a path to a device, such
406 as "C:\NUL" then the last character gets cut off, which later results in
407 NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers
408 a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a
409 real device with a name eg. "NU" in the system, FindFirstFile will succeed,
410 rendering the fake DOS device check useless... Why would they invent such a
411 stupid and broken behavior?! */
412 if (NtPathU
.Length
>= 2 * sizeof(WCHAR
) &&
413 NtPathU
.Buffer
[(NtPathU
.Length
/ sizeof(WCHAR
)) - 1] != L
'\\' &&
414 NtPathU
.Buffer
[(NtPathU
.Length
/ sizeof(WCHAR
)) - 2] != L
':')
416 NtPathU
.Length
-= sizeof(WCHAR
);
417 RemovedLastChar
= TRUE
;
420 TRACE("lpFileName: \"%ws\"\n", lpFileName
);
421 TRACE("NtPathU: \"%wZ\"\n", &NtPathU
);
422 TRACE("PathFileName: \"%wZ\"\n", &PathFileName
);
423 TRACE("RelativeTo: 0x%p\n", DirInfo
.Handle
);
425 InitializeObjectAttributes (&ObjectAttributes
,
427 OBJ_CASE_INSENSITIVE
,
431 Status
= NtOpenFile (&hDirectory
,
432 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
435 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
436 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
438 if (Status
== STATUS_NOT_A_DIRECTORY
&& RemovedLastChar
)
440 /* Try again, this time with the last character ... */
441 NtPathU
.Length
+= sizeof(WCHAR
);
443 Status
= NtOpenFile (&hDirectory
,
444 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
447 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
448 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
450 NtPathU
.Length
+= sizeof(WCHAR
);
453 if (!NT_SUCCESS(Status
))
455 RtlFreeHeap (hProcessHeap
,
459 /* See if the application tries to look for a DOS device */
460 DeviceNameInfo
= RtlIsDosDeviceName_U((PWSTR
)((ULONG_PTR
)lpFileName
));
461 if (DeviceNameInfo
!= 0)
465 InternalCopyDeviceFindDataW(lpFindFileData
,
471 InternalCopyDeviceFindDataA(lpFindFileData
,
476 return FIND_DEVICE_HANDLE
;
479 SetLastErrorByStatus (Status
);
480 return INVALID_HANDLE_VALUE
;
483 if (PathFileName
.Length
== 0)
487 RtlFreeHeap (hProcessHeap
,
490 SetLastError(ERROR_FILE_NOT_FOUND
);
491 return INVALID_HANDLE_VALUE
;
494 IHeader
= RtlAllocateHeap (hProcessHeap
,
496 sizeof(KERNEL32_FIND_DATA_HEADER
) +
497 sizeof(KERNEL32_FIND_FILE_DATA
) + FIND_DATA_SIZE
);
500 RtlFreeHeap (hProcessHeap
,
505 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
506 return INVALID_HANDLE_VALUE
;
509 IHeader
->Type
= FileFind
;
510 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
511 IData
->DirectoryHandle
= hDirectory
;
512 IData
->HasMoreData
= TRUE
;
514 /* change pattern: "*.*" --> "*" */
515 if (PathFileName
.Length
== 6 &&
516 RtlCompareMemory(PathFileName
.Buffer
,
520 PathFileName
.Length
= 2;
523 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
524 IData
->pFileInfo
->FileIndex
= 0;
525 IData
->DirectoryOnly
= DirectoryOnly
;
527 bResult
= InternalFindNextFile((HANDLE
)IHeader
,
532 RtlFreeHeap (hProcessHeap
,
538 FindClose((HANDLE
)IHeader
);
539 return INVALID_HANDLE_VALUE
;
542 RtlInitializeCriticalSection(&IData
->Lock
);
543 IData
->LockInitialized
= TRUE
;
545 return (HANDLE
)IHeader
;
556 LPWIN32_FIND_DATAA lpFindFileData
559 return FindFirstFileExA (lpFileName
,
561 (LPVOID
)lpFindFileData
,
562 FindExSearchNameMatch
,
575 LPWIN32_FIND_DATAA lpFindFileData
)
577 return InternalFindNextFile (hFindFile
,
593 PKERNEL32_FIND_DATA_HEADER IHeader
;
595 TRACE("FindClose(hFindFile %x)\n",hFindFile
);
597 if (hFindFile
== FIND_DEVICE_HANDLE
)
600 if (!hFindFile
|| hFindFile
== INVALID_HANDLE_VALUE
)
602 SetLastError (ERROR_INVALID_HANDLE
);
606 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
608 switch (IHeader
->Type
)
612 PKERNEL32_FIND_FILE_DATA IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
613 CloseHandle (IData
->DirectoryHandle
);
614 if (IData
->LockInitialized
)
615 RtlDeleteCriticalSection(&IData
->Lock
);
616 IData
->LockInitialized
= FALSE
;
622 PKERNEL32_FIND_STREAM_DATA IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
623 if (IData
->pFileStreamInfo
!= NULL
)
625 RtlFreeHeap (hProcessHeap
, 0, IData
->pFileStreamInfo
);
631 SetLastError (ERROR_INVALID_HANDLE
);
635 RtlFreeHeap (hProcessHeap
, 0, IHeader
);
648 LPWIN32_FIND_DATAW lpFindFileData
651 return FindFirstFileExW (lpFileName
,
653 (LPVOID
)lpFindFileData
,
654 FindExSearchNameMatch
,
666 LPWIN32_FIND_DATAW lpFindFileData
669 return InternalFindNextFile (hFindFile
,
681 FindFirstFileExW (LPCWSTR lpFileName
,
682 FINDEX_INFO_LEVELS fInfoLevelId
,
683 LPVOID lpFindFileData
,
684 FINDEX_SEARCH_OPS fSearchOp
,
685 LPVOID lpSearchFilter
,
686 DWORD dwAdditionalFlags
)
688 if (fInfoLevelId
!= FindExInfoStandard
)
690 SetLastError(ERROR_INVALID_PARAMETER
);
691 return INVALID_HANDLE_VALUE
;
694 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
698 SetLastError(ERROR_INVALID_PARAMETER
);
699 return INVALID_HANDLE_VALUE
;
702 return InternalFindFirstFile (lpFileName
,
703 fSearchOp
== FindExSearchLimitToDirectories
,
708 SetLastError(ERROR_INVALID_PARAMETER
);
709 return INVALID_HANDLE_VALUE
;
719 FINDEX_INFO_LEVELS fInfoLevelId
,
720 LPVOID lpFindFileData
,
721 FINDEX_SEARCH_OPS fSearchOp
,
722 LPVOID lpSearchFilter
,
723 DWORD dwAdditionalFlags
726 UNICODE_STRING FileNameU
;
727 ANSI_STRING FileNameA
;
730 if (fInfoLevelId
!= FindExInfoStandard
)
732 SetLastError(ERROR_INVALID_PARAMETER
);
733 return INVALID_HANDLE_VALUE
;
735 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
739 SetLastError(ERROR_INVALID_PARAMETER
);
740 return INVALID_HANDLE_VALUE
;
743 RtlInitAnsiString (&FileNameA
, (LPSTR
)lpFileName
);
745 /* convert ansi (or oem) string to unicode */
747 RtlAnsiStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
749 RtlOemStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
751 Handle
= InternalFindFirstFile (FileNameU
.Buffer
,
752 fSearchOp
== FindExSearchLimitToDirectories
,
756 RtlFreeUnicodeString (&FileNameU
);
760 SetLastError(ERROR_INVALID_PARAMETER
);
761 return INVALID_HANDLE_VALUE
;
766 InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData
,
767 OUT LPVOID lpFindStreamData
)
769 ASSERT(IData
->pCurrent
);
771 switch (IData
->InfoLevel
)
773 case FindStreamInfoStandard
:
776 WIN32_FIND_STREAM_DATA
*StreamData
= (WIN32_FIND_STREAM_DATA
*)lpFindStreamData
;
778 StreamNameLen
= IData
->pCurrent
->StreamNameLength
;
779 if (StreamNameLen
> sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
))
780 StreamNameLen
= sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
);
782 StreamData
->StreamSize
.QuadPart
= IData
->pCurrent
->StreamSize
.QuadPart
;
783 RtlCopyMemory(StreamData
->cStreamName
,
784 IData
->pCurrent
->StreamName
,
786 StreamData
->cStreamName
[StreamNameLen
/ sizeof(WCHAR
)] = L
'\0';
802 FindFirstStreamW(IN LPCWSTR lpFileName
,
803 IN STREAM_INFO_LEVELS InfoLevel
,
804 OUT LPVOID lpFindStreamData
,
807 PKERNEL32_FIND_DATA_HEADER IHeader
= NULL
;
808 PKERNEL32_FIND_STREAM_DATA IData
= NULL
;
809 OBJECT_ATTRIBUTES ObjectAttributes
;
810 IO_STATUS_BLOCK IoStatusBlock
;
811 UNICODE_STRING NtPathU
;
812 HANDLE FileHandle
= NULL
;
814 ULONG BufferSize
= 0;
816 if (dwFlags
!= 0 || InfoLevel
!= FindStreamInfoStandard
||
817 lpFindStreamData
== NULL
)
819 SetLastError(ERROR_INVALID_PARAMETER
);
820 return INVALID_HANDLE_VALUE
;
823 /* validate & translate the filename */
824 if (!RtlDosPathNameToNtPathName_U(lpFileName
,
829 SetLastError(ERROR_PATH_NOT_FOUND
);
830 return INVALID_HANDLE_VALUE
;
834 InitializeObjectAttributes(&ObjectAttributes
,
836 OBJ_CASE_INSENSITIVE
,
840 Status
= NtCreateFile(&FileHandle
,
846 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
851 if (!NT_SUCCESS(Status
))
856 /* create the search context */
857 IHeader
= RtlAllocateHeap(hProcessHeap
,
859 sizeof(KERNEL32_FIND_DATA_HEADER
) +
860 sizeof(KERNEL32_FIND_STREAM_DATA
));
863 Status
= STATUS_NO_MEMORY
;
867 IHeader
->Type
= StreamFind
;
868 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
870 /* capture all information about the streams */
871 IData
->InfoLevel
= InfoLevel
;
872 IData
->pCurrent
= NULL
;
873 IData
->pFileStreamInfo
= NULL
;
877 BufferSize
+= 0x1000;
879 if (IData
->pFileStreamInfo
== NULL
)
881 IData
->pFileStreamInfo
= RtlAllocateHeap(hProcessHeap
,
884 if (IData
->pFileStreamInfo
== NULL
)
886 Status
= STATUS_NO_MEMORY
;
892 PFILE_STREAM_INFORMATION pfsi
;
894 pfsi
= RtlReAllocateHeap(hProcessHeap
,
896 IData
->pFileStreamInfo
,
900 Status
= STATUS_NO_MEMORY
;
904 IData
->pFileStreamInfo
= pfsi
;
907 Status
= NtQueryInformationFile(FileHandle
,
909 IData
->pFileStreamInfo
,
911 FileStreamInformation
);
913 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
915 if (NT_SUCCESS(Status
))
920 /* select the first stream and return the information */
921 IData
->pCurrent
= IData
->pFileStreamInfo
;
922 InternalCopyStreamInfo(IData
,
926 Status
= STATUS_SUCCESS
;
930 if (FileHandle
!= NULL
)
935 RtlFreeHeap(RtlGetProcessHeap(),
939 if (!NT_SUCCESS(Status
))
943 if (IData
->pFileStreamInfo
!= NULL
)
945 RtlFreeHeap(hProcessHeap
,
947 IData
->pFileStreamInfo
);
950 RtlFreeHeap(hProcessHeap
,
955 SetLastErrorByStatus(Status
);
956 return INVALID_HANDLE_VALUE
;
959 return (HANDLE
)IHeader
;
968 FindNextStreamW(IN HANDLE hFindStream
,
969 OUT LPVOID lpFindStreamData
)
971 PKERNEL32_FIND_DATA_HEADER IHeader
;
972 PKERNEL32_FIND_STREAM_DATA IData
;
974 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindStream
;
975 if (hFindStream
== NULL
|| hFindStream
== INVALID_HANDLE_VALUE
||
976 IHeader
->Type
!= StreamFind
)
978 SetLastError (ERROR_INVALID_HANDLE
);
982 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
984 /* select next stream if possible */
985 if (IData
->pCurrent
->NextEntryOffset
!= 0)
987 IData
->pCurrent
= (PFILE_STREAM_INFORMATION
)((ULONG_PTR
)IData
->pFileStreamInfo
+
988 IData
->pCurrent
->NextEntryOffset
);
992 SetLastError(ERROR_HANDLE_EOF
);
996 /* return the information */
997 InternalCopyStreamInfo(IData
,