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 *****************************************************************/
15 #include <wine/debug.h>
17 WINE_DEFAULT_DEBUG_CHANNEL(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
,
75 return FIND_DEVICE_HANDLE
;
79 InternalCopyDeviceFindDataA(LPWIN32_FIND_DATAA lpFindFileData
,
80 PUNICODE_STRING FileName
,
83 UNICODE_STRING DeviceName
;
85 CHAR Buffer
[MAX_PATH
];
87 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)(DeviceNameInfo
& 0xFFFF);
88 DeviceName
.Buffer
= (LPWSTR
)((ULONG_PTR
)FileName
->Buffer
+ (DeviceNameInfo
>> 16));
90 BufferA
.MaximumLength
= sizeof(Buffer
) - sizeof(Buffer
[0]);
91 BufferA
.Buffer
= Buffer
;
93 RtlUnicodeStringToAnsiString (&BufferA
, &DeviceName
, FALSE
);
95 RtlUnicodeStringToOemString (&BufferA
, &DeviceName
, FALSE
);
98 RtlZeroMemory(lpFindFileData
,
99 sizeof(*lpFindFileData
));
100 lpFindFileData
->dwFileAttributes
= FILE_ATTRIBUTE_ARCHIVE
;
101 RtlCopyMemory(lpFindFileData
->cFileName
,
105 return FIND_DEVICE_HANDLE
;
109 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
110 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
112 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
114 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
115 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
117 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
118 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
120 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
121 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
123 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
124 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
126 memcpy (lpFindFileData
->cFileName
, lpFileInfo
->FileName
, lpFileInfo
->FileNameLength
);
127 lpFindFileData
->cFileName
[lpFileInfo
->FileNameLength
/ sizeof(WCHAR
)] = 0;
129 memcpy (lpFindFileData
->cAlternateFileName
, lpFileInfo
->ShortName
, lpFileInfo
->ShortNameLength
);
130 lpFindFileData
->cAlternateFileName
[lpFileInfo
->ShortNameLength
/ sizeof(WCHAR
)] = 0;
134 InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData
,
135 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
137 UNICODE_STRING FileNameU
;
138 ANSI_STRING FileNameA
;
140 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
142 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
143 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
145 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
146 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
148 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
149 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
151 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
152 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
154 FileNameU
.Length
= FileNameU
.MaximumLength
= (USHORT
)lpFileInfo
->FileNameLength
;
155 FileNameU
.Buffer
= lpFileInfo
->FileName
;
157 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cFileName
) - sizeof(CHAR
);
158 FileNameA
.Buffer
= lpFindFileData
->cFileName
;
160 /* convert unicode string to ansi (or oem) */
162 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
164 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
166 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
168 TRACE("lpFileInfo->ShortNameLength %d\n", lpFileInfo
->ShortNameLength
);
170 FileNameU
.Length
= FileNameU
.MaximumLength
= lpFileInfo
->ShortNameLength
;
171 FileNameU
.Buffer
= lpFileInfo
->ShortName
;
173 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cAlternateFileName
) - sizeof(CHAR
);
174 FileNameA
.Buffer
= lpFindFileData
->cAlternateFileName
;
176 /* convert unicode string to ansi (or oem) */
178 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
180 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
182 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
190 InternalFindNextFile (
192 PUNICODE_STRING SearchPattern
,
193 PVOID lpFindFileData
,
197 PKERNEL32_FIND_DATA_HEADER IHeader
;
198 PKERNEL32_FIND_FILE_DATA IData
;
199 IO_STATUS_BLOCK IoStatusBlock
;
200 BOOLEAN Locked
= FALSE
;
201 PFILE_BOTH_DIR_INFORMATION Buffer
, FoundFile
= NULL
;
202 NTSTATUS Status
= STATUS_SUCCESS
;
204 TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile
, SearchPattern
);
206 if (hFindFile
!= FIND_DEVICE_HANDLE
)
208 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
209 if (hFindFile
== NULL
|| hFindFile
== INVALID_HANDLE_VALUE
||
210 IHeader
->Type
!= FileFind
)
212 SetLastError (ERROR_INVALID_HANDLE
);
216 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
217 Buffer
= (PFILE_BOTH_DIR_INFORMATION
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
219 if (SearchPattern
== NULL
)
221 RtlEnterCriticalSection(&IData
->Lock
);
229 if (!IData
->DirectoryOnly
|| (IData
->pFileInfo
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
231 FoundFile
= IData
->pFileInfo
;
234 if (IData
->pFileInfo
->NextEntryOffset
!= 0)
238 IData
->pFileInfo
= (PFILE_BOTH_DIR_INFORMATION
)((ULONG_PTR
)IData
->pFileInfo
+ IData
->pFileInfo
->NextEntryOffset
);
240 /* Be paranoid and make sure that the next entry is completely there */
241 BufferEnd
= (ULONG_PTR
)Buffer
+ FIND_DATA_SIZE
;
242 if (BufferEnd
< (ULONG_PTR
)IData
->pFileInfo
||
243 BufferEnd
< (ULONG_PTR
)&IData
->pFileInfo
->FileNameLength
+ sizeof(IData
->pFileInfo
->FileNameLength
) ||
244 BufferEnd
<= (ULONG_PTR
)&IData
->pFileInfo
->FileName
[IData
->pFileInfo
->FileNameLength
])
252 IData
->HasData
= FALSE
;
254 if (!IData
->HasMoreData
)
260 IData
->pFileInfo
= Buffer
;
261 IData
->pFileInfo
->NextEntryOffset
= 0;
262 Status
= NtQueryDirectoryFile (IData
->DirectoryHandle
,
267 (PVOID
)IData
->pFileInfo
,
269 FileBothDirectoryInformation
,
272 SearchPattern
!= NULL
);
274 if (Status
== STATUS_BUFFER_OVERFLOW
)
276 IData
->HasMoreData
= TRUE
;
277 Status
= STATUS_SUCCESS
;
281 if (!NT_SUCCESS(Status
))
284 IData
->HasMoreData
= FALSE
;
287 IData
->HasData
= TRUE
;
288 SearchPattern
= NULL
;
291 } while (FoundFile
== NULL
);
293 if (FoundFile
!= NULL
)
299 InternalCopyFindDataW(lpFindFileData
,
304 InternalCopyFindDataA(lpFindFileData
,
308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
315 RtlLeaveCriticalSection(&IData
->Lock
);
318 if (!NT_SUCCESS(Status
))
320 SetLastErrorByStatus (Status
);
323 else if (FoundFile
== NULL
)
325 SetLastError (ERROR_NO_MORE_FILES
);
338 InternalFindFirstFile (
340 BOOLEAN DirectoryOnly
,
341 PVOID lpFindFileData
,
345 OBJECT_ATTRIBUTES ObjectAttributes
;
346 PKERNEL32_FIND_DATA_HEADER IHeader
;
347 PKERNEL32_FIND_FILE_DATA IData
;
348 IO_STATUS_BLOCK IoStatusBlock
;
349 UNICODE_STRING NtPathU
, FileName
, PathFileName
;
352 BOOLEAN RemovedLastChar
= FALSE
;
355 ULONG DeviceNameInfo
;
356 HANDLE hDirectory
= NULL
;
358 TRACE("FindFirstFileW(lpFileName %S)\n",
361 RtlZeroMemory(&PathFileName
,
362 sizeof(PathFileName
));
363 RtlInitUnicodeString(&FileName
,
366 bResult
= RtlDosPathNameToNtPathName_U (lpFileName
,
368 (PCWSTR
*)((ULONG_PTR
)&PathFileName
.Buffer
),
370 if (FALSE
== bResult
)
372 SetLastError(ERROR_PATH_NOT_FOUND
);
373 return INVALID_HANDLE_VALUE
;
376 /* Save the buffer pointer for later, we need to free it! */
377 NtPathBuffer
= NtPathU
.Buffer
;
379 /* If there is a file name/pattern then determine it's length */
380 if (PathFileName
.Buffer
!= NULL
)
382 PathFileName
.Length
= NtPathU
.Length
-
383 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)NtPathU
.Buffer
);
385 PathFileName
.MaximumLength
= PathFileName
.Length
;
387 if (DirInfo
.DosPath
.Length
!= 0 && DirInfo
.DosPath
.Buffer
!= PathFileName
.Buffer
)
389 if (PathFileName
.Buffer
!= NULL
)
391 /* This is a relative path to DirInfo.Handle, adjust NtPathU! */
392 NtPathU
.Length
= NtPathU
.MaximumLength
=
393 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)DirInfo
.DosPath
.Buffer
);
394 NtPathU
.Buffer
= DirInfo
.DosPath
.Buffer
;
399 /* This is an absolute path, NtPathU receives the full path */
400 DirInfo
.Handle
= NULL
;
401 if (PathFileName
.Buffer
!= NULL
)
403 NtPathU
.Length
= NtPathU
.MaximumLength
=
404 (USHORT
)((ULONG_PTR
)PathFileName
.Buffer
- (ULONG_PTR
)NtPathU
.Buffer
);
408 /* Remove the last character of the path (Unless the path is a drive and
409 ends with ":\"). If the caller however supplies a path to a device, such
410 as "C:\NUL" then the last character gets cut off, which later results in
411 NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers
412 a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a
413 real device with a name eg. "NU" in the system, FindFirstFile will succeed,
414 rendering the fake DOS device check useless... Why would they invent such a
415 stupid and broken behavior?! */
416 if (NtPathU
.Length
>= 2 * sizeof(WCHAR
) &&
417 NtPathU
.Buffer
[(NtPathU
.Length
/ sizeof(WCHAR
)) - 1] != L
'\\' &&
418 NtPathU
.Buffer
[(NtPathU
.Length
/ sizeof(WCHAR
)) - 2] != L
':')
420 NtPathU
.Length
-= sizeof(WCHAR
);
421 RemovedLastChar
= TRUE
;
424 TRACE("lpFileName: \"%ws\"\n", lpFileName
);
425 TRACE("NtPathU: \"%wZ\"\n", &NtPathU
);
426 TRACE("PathFileName: \"%wZ\"\n", &PathFileName
);
427 TRACE("RelativeTo: 0x%p\n", DirInfo
.Handle
);
429 InitializeObjectAttributes (&ObjectAttributes
,
431 OBJ_CASE_INSENSITIVE
,
435 Status
= NtOpenFile (&hDirectory
,
436 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
439 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
440 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
442 if (Status
== STATUS_NOT_A_DIRECTORY
&& RemovedLastChar
)
444 /* Try again, this time with the last character ... */
445 NtPathU
.Length
+= sizeof(WCHAR
);
447 Status
= NtOpenFile (&hDirectory
,
448 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
451 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
452 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
454 NtPathU
.Length
+= sizeof(WCHAR
);
457 if (!NT_SUCCESS(Status
))
459 RtlFreeHeap (hProcessHeap
,
463 /* See if the application tries to look for a DOS device */
464 DeviceNameInfo
= RtlIsDosDeviceName_U((PWSTR
)((ULONG_PTR
)lpFileName
));
465 if (DeviceNameInfo
!= 0)
469 InternalCopyDeviceFindDataW(lpFindFileData
,
475 InternalCopyDeviceFindDataA(lpFindFileData
,
480 return FIND_DEVICE_HANDLE
;
483 SetLastErrorByStatus (Status
);
484 return INVALID_HANDLE_VALUE
;
487 if (PathFileName
.Length
== 0)
491 RtlFreeHeap (hProcessHeap
,
494 SetLastError(ERROR_FILE_NOT_FOUND
);
495 return INVALID_HANDLE_VALUE
;
498 IHeader
= RtlAllocateHeap (hProcessHeap
,
500 sizeof(KERNEL32_FIND_DATA_HEADER
) +
501 sizeof(KERNEL32_FIND_FILE_DATA
) + FIND_DATA_SIZE
);
504 RtlFreeHeap (hProcessHeap
,
509 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
510 return INVALID_HANDLE_VALUE
;
513 IHeader
->Type
= FileFind
;
514 IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
515 IData
->DirectoryHandle
= hDirectory
;
516 IData
->HasMoreData
= TRUE
;
518 /* change pattern: "*.*" --> "*" */
519 if (PathFileName
.Length
== 6 &&
520 RtlCompareMemory(PathFileName
.Buffer
,
524 PathFileName
.Length
= 2;
527 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
528 IData
->pFileInfo
->FileIndex
= 0;
529 IData
->DirectoryOnly
= DirectoryOnly
;
531 bResult
= InternalFindNextFile((HANDLE
)IHeader
,
536 RtlFreeHeap (hProcessHeap
,
542 FindClose((HANDLE
)IHeader
);
543 return INVALID_HANDLE_VALUE
;
546 RtlInitializeCriticalSection(&IData
->Lock
);
547 IData
->LockInitialized
= TRUE
;
549 return (HANDLE
)IHeader
;
560 LPWIN32_FIND_DATAA lpFindFileData
563 return FindFirstFileExA (lpFileName
,
565 (LPVOID
)lpFindFileData
,
566 FindExSearchNameMatch
,
579 LPWIN32_FIND_DATAA lpFindFileData
)
581 return InternalFindNextFile (hFindFile
,
597 PKERNEL32_FIND_DATA_HEADER IHeader
;
599 TRACE("FindClose(hFindFile %x)\n",hFindFile
);
601 if (hFindFile
== FIND_DEVICE_HANDLE
)
604 if (!hFindFile
|| hFindFile
== INVALID_HANDLE_VALUE
)
606 SetLastError (ERROR_INVALID_HANDLE
);
610 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindFile
;
612 switch (IHeader
->Type
)
616 PKERNEL32_FIND_FILE_DATA IData
= (PKERNEL32_FIND_FILE_DATA
)(IHeader
+ 1);
617 CloseHandle (IData
->DirectoryHandle
);
618 if (IData
->LockInitialized
)
619 RtlDeleteCriticalSection(&IData
->Lock
);
620 IData
->LockInitialized
= FALSE
;
626 PKERNEL32_FIND_STREAM_DATA IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
627 if (IData
->pFileStreamInfo
!= NULL
)
629 RtlFreeHeap (hProcessHeap
, 0, IData
->pFileStreamInfo
);
635 SetLastError (ERROR_INVALID_HANDLE
);
639 RtlFreeHeap (hProcessHeap
, 0, IHeader
);
652 LPWIN32_FIND_DATAW lpFindFileData
655 return FindFirstFileExW (lpFileName
,
657 (LPVOID
)lpFindFileData
,
658 FindExSearchNameMatch
,
670 LPWIN32_FIND_DATAW lpFindFileData
673 return InternalFindNextFile (hFindFile
,
685 FindFirstFileExW (LPCWSTR lpFileName
,
686 FINDEX_INFO_LEVELS fInfoLevelId
,
687 LPVOID lpFindFileData
,
688 FINDEX_SEARCH_OPS fSearchOp
,
689 LPVOID lpSearchFilter
,
690 DWORD dwAdditionalFlags
)
692 if (fInfoLevelId
!= FindExInfoStandard
)
694 SetLastError(ERROR_INVALID_PARAMETER
);
695 return INVALID_HANDLE_VALUE
;
698 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
702 SetLastError(ERROR_INVALID_PARAMETER
);
703 return INVALID_HANDLE_VALUE
;
706 return InternalFindFirstFile (lpFileName
,
707 fSearchOp
== FindExSearchLimitToDirectories
,
712 SetLastError(ERROR_INVALID_PARAMETER
);
713 return INVALID_HANDLE_VALUE
;
723 FINDEX_INFO_LEVELS fInfoLevelId
,
724 LPVOID lpFindFileData
,
725 FINDEX_SEARCH_OPS fSearchOp
,
726 LPVOID lpSearchFilter
,
727 DWORD dwAdditionalFlags
730 UNICODE_STRING FileNameU
;
731 ANSI_STRING FileNameA
;
734 if (fInfoLevelId
!= FindExInfoStandard
)
736 SetLastError(ERROR_INVALID_PARAMETER
);
737 return INVALID_HANDLE_VALUE
;
739 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
743 SetLastError(ERROR_INVALID_PARAMETER
);
744 return INVALID_HANDLE_VALUE
;
747 RtlInitAnsiString (&FileNameA
, (LPSTR
)lpFileName
);
749 /* convert ansi (or oem) string to unicode */
751 RtlAnsiStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
753 RtlOemStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
755 Handle
= InternalFindFirstFile (FileNameU
.Buffer
,
756 fSearchOp
== FindExSearchLimitToDirectories
,
760 RtlFreeUnicodeString (&FileNameU
);
764 SetLastError(ERROR_INVALID_PARAMETER
);
765 return INVALID_HANDLE_VALUE
;
770 InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData
,
771 OUT LPVOID lpFindStreamData
)
773 ASSERT(IData
->pCurrent
);
775 switch (IData
->InfoLevel
)
777 case FindStreamInfoStandard
:
780 WIN32_FIND_STREAM_DATA
*StreamData
= (WIN32_FIND_STREAM_DATA
*)lpFindStreamData
;
782 StreamNameLen
= IData
->pCurrent
->StreamNameLength
;
783 if (StreamNameLen
> sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
))
784 StreamNameLen
= sizeof(StreamData
->cStreamName
) - sizeof(WCHAR
);
786 StreamData
->StreamSize
.QuadPart
= IData
->pCurrent
->StreamSize
.QuadPart
;
787 RtlCopyMemory(StreamData
->cStreamName
,
788 IData
->pCurrent
->StreamName
,
790 StreamData
->cStreamName
[StreamNameLen
/ sizeof(WCHAR
)] = L
'\0';
806 FindFirstStreamW(IN LPCWSTR lpFileName
,
807 IN STREAM_INFO_LEVELS InfoLevel
,
808 OUT LPVOID lpFindStreamData
,
811 PKERNEL32_FIND_DATA_HEADER IHeader
= NULL
;
812 PKERNEL32_FIND_STREAM_DATA IData
= NULL
;
813 OBJECT_ATTRIBUTES ObjectAttributes
;
814 IO_STATUS_BLOCK IoStatusBlock
;
815 UNICODE_STRING NtPathU
;
816 HANDLE FileHandle
= NULL
;
818 ULONG BufferSize
= 0;
820 if (dwFlags
!= 0 || InfoLevel
!= FindStreamInfoStandard
||
821 lpFindStreamData
== NULL
)
823 SetLastError(ERROR_INVALID_PARAMETER
);
824 return INVALID_HANDLE_VALUE
;
827 /* validate & translate the filename */
828 if (!RtlDosPathNameToNtPathName_U(lpFileName
,
833 SetLastError(ERROR_PATH_NOT_FOUND
);
834 return INVALID_HANDLE_VALUE
;
838 InitializeObjectAttributes(&ObjectAttributes
,
840 OBJ_CASE_INSENSITIVE
,
844 Status
= NtCreateFile(&FileHandle
,
850 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
855 if (!NT_SUCCESS(Status
))
860 /* create the search context */
861 IHeader
= RtlAllocateHeap(hProcessHeap
,
863 sizeof(KERNEL32_FIND_DATA_HEADER
) +
864 sizeof(KERNEL32_FIND_STREAM_DATA
));
867 Status
= STATUS_NO_MEMORY
;
871 IHeader
->Type
= StreamFind
;
872 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
874 /* capture all information about the streams */
875 IData
->InfoLevel
= InfoLevel
;
876 IData
->pCurrent
= NULL
;
877 IData
->pFileStreamInfo
= NULL
;
881 BufferSize
+= 0x1000;
883 if (IData
->pFileStreamInfo
== NULL
)
885 IData
->pFileStreamInfo
= RtlAllocateHeap(hProcessHeap
,
888 if (IData
->pFileStreamInfo
== NULL
)
890 Status
= STATUS_NO_MEMORY
;
896 PFILE_STREAM_INFORMATION pfsi
;
898 pfsi
= RtlReAllocateHeap(hProcessHeap
,
900 IData
->pFileStreamInfo
,
904 Status
= STATUS_NO_MEMORY
;
908 IData
->pFileStreamInfo
= pfsi
;
911 Status
= NtQueryInformationFile(FileHandle
,
913 IData
->pFileStreamInfo
,
915 FileStreamInformation
);
917 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
919 if (NT_SUCCESS(Status
))
924 /* select the first stream and return the information */
925 IData
->pCurrent
= IData
->pFileStreamInfo
;
926 InternalCopyStreamInfo(IData
,
930 Status
= STATUS_SUCCESS
;
934 if (FileHandle
!= NULL
)
939 RtlFreeHeap(RtlGetProcessHeap(),
943 if (!NT_SUCCESS(Status
))
947 if (IData
->pFileStreamInfo
!= NULL
)
949 RtlFreeHeap(hProcessHeap
,
951 IData
->pFileStreamInfo
);
954 RtlFreeHeap(hProcessHeap
,
959 SetLastErrorByStatus(Status
);
960 return INVALID_HANDLE_VALUE
;
963 return (HANDLE
)IHeader
;
972 FindNextStreamW(IN HANDLE hFindStream
,
973 OUT LPVOID lpFindStreamData
)
975 PKERNEL32_FIND_DATA_HEADER IHeader
;
976 PKERNEL32_FIND_STREAM_DATA IData
;
978 IHeader
= (PKERNEL32_FIND_DATA_HEADER
)hFindStream
;
979 if (hFindStream
== NULL
|| hFindStream
== INVALID_HANDLE_VALUE
||
980 IHeader
->Type
!= StreamFind
)
982 SetLastError (ERROR_INVALID_HANDLE
);
986 IData
= (PKERNEL32_FIND_STREAM_DATA
)(IHeader
+ 1);
988 /* select next stream if possible */
989 if (IData
->pCurrent
->NextEntryOffset
!= 0)
991 IData
->pCurrent
= (PFILE_STREAM_INFORMATION
)((ULONG_PTR
)IData
->pFileStreamInfo
+
992 IData
->pCurrent
->NextEntryOffset
);
996 SetLastError(ERROR_HANDLE_EOF
);
1000 /* return the information */
1001 InternalCopyStreamInfo(IData
,