move from branch
[reactos.git] / reactos / dll / win32 / kernel32 / file / find.c
1 /* $Id$
2 *
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 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <k32.h>
15
16 #define NDEBUG
17 #include "../include/debug.h"
18
19
20 /* TYPES ********************************************************************/
21
22 #define FIND_DATA_SIZE (16*1024)
23
24 typedef struct _KERNEL32_FIND_FILE_DATA
25 {
26 HANDLE DirectoryHandle;
27 BOOLEAN DirectoryOnly;
28 PFILE_BOTH_DIR_INFORMATION pFileInfo;
29 } KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
30
31 typedef struct _KERNEL32_FIND_STREAM_DATA
32 {
33 STREAM_INFO_LEVELS InfoLevel;
34 PFILE_STREAM_INFORMATION pFileStreamInfo;
35 PFILE_STREAM_INFORMATION pCurrent;
36 } KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA;
37
38 typedef enum _KERNEL32_FIND_DATA_TYPE
39 {
40 FileFind,
41 StreamFind
42 } KERNEL32_FIND_DATA_TYPE;
43
44 typedef struct _KERNEL32_FIND_DATA_HEADER
45 {
46 KERNEL32_FIND_DATA_TYPE Type;
47 } KERNEL32_FIND_DATA_HEADER, *PKERNEL32_FIND_DATA_HEADER;
48
49
50 /* FUNCTIONS ****************************************************************/
51
52 VOID
53 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
54 PFILE_BOTH_DIR_INFORMATION lpFileInfo)
55 {
56 lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes;
57
58 lpFindFileData->ftCreationTime.dwHighDateTime = lpFileInfo->CreationTime.u.HighPart;
59 lpFindFileData->ftCreationTime.dwLowDateTime = lpFileInfo->CreationTime.u.LowPart;
60
61 lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart;
62 lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart;
63
64 lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart;
65 lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart;
66
67 lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart;
68 lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart;
69
70 memcpy (lpFindFileData->cFileName, lpFileInfo->FileName, lpFileInfo->FileNameLength);
71 lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
72
73 memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName, lpFileInfo->ShortNameLength);
74 lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
75 }
76
77 VOID
78 InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData,
79 PFILE_BOTH_DIR_INFORMATION lpFileInfo)
80 {
81 UNICODE_STRING FileNameU;
82 ANSI_STRING FileNameA;
83
84 lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes;
85
86 lpFindFileData->ftCreationTime.dwHighDateTime = lpFileInfo->CreationTime.u.HighPart;
87 lpFindFileData->ftCreationTime.dwLowDateTime = lpFileInfo->CreationTime.u.LowPart;
88
89 lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart;
90 lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart;
91
92 lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart;
93 lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart;
94
95 lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart;
96 lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart;
97
98 FileNameU.Length = FileNameU.MaximumLength = (USHORT)lpFileInfo->FileNameLength;
99 FileNameU.Buffer = lpFileInfo->FileName;
100
101 FileNameA.MaximumLength = sizeof(lpFindFileData->cFileName) - sizeof(CHAR);
102 FileNameA.Buffer = lpFindFileData->cFileName;
103
104 /* convert unicode string to ansi (or oem) */
105 if (bIsFileApiAnsi)
106 RtlUnicodeStringToAnsiString (&FileNameA, &FileNameU, FALSE);
107 else
108 RtlUnicodeStringToOemString (&FileNameA, &FileNameU, FALSE);
109
110 FileNameA.Buffer[FileNameA.Length] = 0;
111
112 DPRINT("lpFileInfo->ShortNameLength %d\n", lpFileInfo->ShortNameLength);
113
114 FileNameU.Length = FileNameU.MaximumLength = lpFileInfo->ShortNameLength;
115 FileNameU.Buffer = lpFileInfo->ShortName;
116
117 FileNameA.MaximumLength = sizeof(lpFindFileData->cAlternateFileName) - sizeof(CHAR);
118 FileNameA.Buffer = lpFindFileData->cAlternateFileName;
119
120 /* convert unicode string to ansi (or oem) */
121 if (bIsFileApiAnsi)
122 RtlUnicodeStringToAnsiString (&FileNameA, &FileNameU, FALSE);
123 else
124 RtlUnicodeStringToOemString (&FileNameA, &FileNameU, FALSE);
125
126 FileNameA.Buffer[FileNameA.Length] = 0;
127 }
128
129 /*
130 * @implemented
131 */
132 BOOL
133 STDCALL
134 InternalFindNextFile (
135 HANDLE hFindFile,
136 PUNICODE_STRING SearchPattern
137 )
138 {
139 PKERNEL32_FIND_DATA_HEADER IHeader;
140 PKERNEL32_FIND_FILE_DATA IData;
141 IO_STATUS_BLOCK IoStatusBlock;
142 NTSTATUS Status;
143
144 DPRINT("InternalFindNextFile(%lx)\n", hFindFile);
145
146 IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile;
147 if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE ||
148 IHeader->Type != FileFind)
149 {
150 SetLastError (ERROR_INVALID_HANDLE);
151 return FALSE;
152 }
153
154 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
155
156 while (1)
157 {
158 if (IData->pFileInfo->NextEntryOffset != 0)
159 {
160 IData->pFileInfo = (PVOID)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset);
161 }
162 else
163 {
164 IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
165 IData->pFileInfo->FileIndex = 0;
166 Status = NtQueryDirectoryFile (IData->DirectoryHandle,
167 NULL,
168 NULL,
169 NULL,
170 &IoStatusBlock,
171 (PVOID)IData->pFileInfo,
172 FIND_DATA_SIZE,
173 FileBothDirectoryInformation,
174 SearchPattern ? TRUE : FALSE,
175 SearchPattern,
176 SearchPattern ? TRUE : FALSE);
177 SearchPattern = NULL;
178 if (!NT_SUCCESS(Status))
179 {
180 SetLastErrorByStatus (Status);
181 return FALSE;
182 }
183 }
184 if (!IData->DirectoryOnly || IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
185 {
186 DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
187 return TRUE;
188 }
189 }
190 }
191
192
193 /*
194 * @implemented
195 */
196 HANDLE
197 STDCALL
198 InternalFindFirstFile (
199 LPCWSTR lpFileName,
200 BOOLEAN DirectoryOnly
201 )
202 {
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"*");
209 NTSTATUS Status;
210 PWSTR e1, e2;
211 WCHAR CurrentDir[256];
212 PWCHAR SlashlessFileName;
213 PWSTR SearchPath;
214 PWCHAR SearchPattern;
215 ULONG Length;
216 BOOL bResult;
217
218 DPRINT("FindFirstFileW(lpFileName %S)\n",
219 lpFileName);
220
221 Length = wcslen(lpFileName);
222 if (L'\\' == lpFileName[Length - 1])
223 {
224 SlashlessFileName = RtlAllocateHeap(hProcessHeap,
225 0,
226 Length * sizeof(WCHAR));
227 if (NULL == SlashlessFileName)
228 {
229 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
230 return NULL;
231 }
232 memcpy(SlashlessFileName, lpFileName, (Length - 1) * sizeof(WCHAR));
233 SlashlessFileName[Length - 1] = L'\0';
234 lpFileName = SlashlessFileName;
235 }
236 else
237 {
238 SlashlessFileName = NULL;
239 }
240
241 e1 = wcsrchr(lpFileName, L'/');
242 e2 = wcsrchr(lpFileName, L'\\');
243 SearchPattern = max(e1, e2);
244 SearchPath = CurrentDir;
245
246 if (NULL == SearchPattern)
247 {
248 CHECKPOINT;
249 SearchPattern = (PWCHAR)lpFileName;
250 Length = GetCurrentDirectoryW(sizeof(CurrentDir) / sizeof(WCHAR), SearchPath);
251 if (0 == Length)
252 {
253 if (NULL != SlashlessFileName)
254 {
255 RtlFreeHeap(hProcessHeap,
256 0,
257 SlashlessFileName);
258 }
259 return NULL;
260 }
261 if (Length > sizeof(CurrentDir) / sizeof(WCHAR))
262 {
263 SearchPath = RtlAllocateHeap(hProcessHeap,
264 HEAP_ZERO_MEMORY,
265 Length * sizeof(WCHAR));
266 if (NULL == SearchPath)
267 {
268 if (NULL != SlashlessFileName)
269 {
270 RtlFreeHeap(hProcessHeap,
271 0,
272 SlashlessFileName);
273 }
274 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
275 return NULL;
276 }
277 GetCurrentDirectoryW(Length, SearchPath);
278 }
279 }
280 else
281 {
282 CHECKPOINT;
283 SearchPattern++;
284 Length = SearchPattern - lpFileName;
285 if (Length + 1 > sizeof(CurrentDir) / sizeof(WCHAR))
286 {
287 SearchPath = RtlAllocateHeap(hProcessHeap,
288 HEAP_ZERO_MEMORY,
289 (Length + 1) * sizeof(WCHAR));
290 if (NULL == SearchPath)
291 {
292 if (NULL != SlashlessFileName)
293 {
294 RtlFreeHeap(hProcessHeap,
295 0,
296 SlashlessFileName);
297 }
298 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
299 return NULL;
300 }
301 }
302 memcpy(SearchPath, lpFileName, Length * sizeof(WCHAR));
303 SearchPath[Length] = 0;
304 }
305
306 bResult = RtlDosPathNameToNtPathName_U (SearchPath,
307 &NtPathU,
308 NULL,
309 NULL);
310 if (SearchPath != CurrentDir)
311 {
312 RtlFreeHeap(hProcessHeap,
313 0,
314 SearchPath);
315 }
316 if (FALSE == bResult)
317 {
318 if (NULL != SlashlessFileName)
319 {
320 RtlFreeHeap(hProcessHeap,
321 0,
322 SlashlessFileName);
323 }
324 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
325 return NULL;
326 }
327
328 DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
329
330 IHeader = RtlAllocateHeap (hProcessHeap,
331 HEAP_ZERO_MEMORY,
332 sizeof(KERNEL32_FIND_DATA_HEADER) +
333 sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
334 if (NULL == IHeader)
335 {
336 RtlFreeHeap (hProcessHeap,
337 0,
338 NtPathU.Buffer);
339 if (NULL != SlashlessFileName)
340 {
341 RtlFreeHeap(hProcessHeap,
342 0,
343 SlashlessFileName);
344 }
345 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
346 return NULL;
347 }
348
349 IHeader->Type = FileFind;
350 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
351
352 /* change pattern: "*.*" --> "*" */
353 if (wcscmp (SearchPattern, L"*.*"))
354 {
355 RtlInitUnicodeString(&PatternStr, SearchPattern);
356 }
357
358 DPRINT("NtPathU \'%S\' Pattern \'%S\'\n",
359 NtPathU.Buffer, PatternStr.Buffer);
360
361 InitializeObjectAttributes (&ObjectAttributes,
362 &NtPathU,
363 0,
364 NULL,
365 NULL);
366
367 Status = NtOpenFile (&IData->DirectoryHandle,
368 FILE_LIST_DIRECTORY,
369 &ObjectAttributes,
370 &IoStatusBlock,
371 FILE_SHARE_READ|FILE_SHARE_WRITE,
372 FILE_DIRECTORY_FILE);
373
374 RtlFreeHeap (hProcessHeap,
375 0,
376 NtPathU.Buffer);
377
378 if (!NT_SUCCESS(Status))
379 {
380 RtlFreeHeap (hProcessHeap, 0, IHeader);
381 if (NULL != SlashlessFileName)
382 {
383 RtlFreeHeap(hProcessHeap,
384 0,
385 SlashlessFileName);
386 }
387 SetLastErrorByStatus (Status);
388 return(NULL);
389 }
390 IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
391 IData->pFileInfo->FileIndex = 0;
392 IData->DirectoryOnly = DirectoryOnly;
393
394 bResult = InternalFindNextFile((HANDLE)IHeader, &PatternStr);
395 if (NULL != SlashlessFileName)
396 {
397 RtlFreeHeap(hProcessHeap,
398 0,
399 SlashlessFileName);
400 }
401
402 if (!bResult)
403 {
404 FindClose((HANDLE)IHeader);
405 return NULL;
406 }
407
408 return (HANDLE)IHeader;
409 }
410
411
412 /*
413 * @implemented
414 */
415 HANDLE
416 STDCALL
417 FindFirstFileA (
418 LPCSTR lpFileName,
419 LPWIN32_FIND_DATAA lpFindFileData
420 )
421 {
422 PKERNEL32_FIND_DATA_HEADER IHeader;
423 PKERNEL32_FIND_FILE_DATA IData;
424 UNICODE_STRING FileNameU;
425 ANSI_STRING FileName;
426
427 RtlInitAnsiString (&FileName,
428 (LPSTR)lpFileName);
429
430 /* convert ansi (or oem) string to unicode */
431 if (bIsFileApiAnsi)
432 RtlAnsiStringToUnicodeString (&FileNameU,
433 &FileName,
434 TRUE);
435 else
436 RtlOemStringToUnicodeString (&FileNameU,
437 &FileName,
438 TRUE);
439
440 IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE);
441
442 RtlFreeUnicodeString (&FileNameU);
443
444 if (IHeader == NULL)
445 {
446 DPRINT("Failing request\n");
447 return INVALID_HANDLE_VALUE;
448 }
449
450 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
451
452 DPRINT("IData->pFileInfo->FileNameLength %d\n",
453 IData->pFileInfo->FileNameLength);
454
455 /* copy data into WIN32_FIND_DATA structure */
456 InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
457
458
459 return (HANDLE)IHeader;
460 }
461
462
463 /*
464 * @implemented
465 */
466 BOOL
467 STDCALL
468 FindNextFileA (
469 HANDLE hFindFile,
470 LPWIN32_FIND_DATAA lpFindFileData)
471 {
472 PKERNEL32_FIND_FILE_DATA IData;
473
474 if (!InternalFindNextFile (hFindFile, NULL))
475 {
476 DPRINT("InternalFindNextFile() failed\n");
477 return FALSE;
478 }
479
480 IData = (PKERNEL32_FIND_FILE_DATA)((PKERNEL32_FIND_DATA_HEADER)hFindFile + 1);
481
482 DPRINT("IData->pFileInfo->FileNameLength %d\n",
483 IData->pFileInfo->FileNameLength);
484
485 /* copy data into WIN32_FIND_DATA structure */
486 InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
487
488 return TRUE;
489 }
490
491
492 /*
493 * @implemented
494 */
495 BOOL
496 STDCALL
497 FindClose (
498 HANDLE hFindFile
499 )
500 {
501 PKERNEL32_FIND_DATA_HEADER IHeader;
502
503 DPRINT("FindClose(hFindFile %x)\n",hFindFile);
504
505 if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE)
506 {
507 SetLastError (ERROR_INVALID_HANDLE);
508 return FALSE;
509 }
510
511 IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile;
512
513 switch (IHeader->Type)
514 {
515 case FileFind:
516 {
517 PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
518 CloseHandle (IData->DirectoryHandle);
519 break;
520 }
521
522 case StreamFind:
523 {
524 PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
525 if (IData->pFileStreamInfo != NULL)
526 {
527 RtlFreeHeap (hProcessHeap, 0, IData->pFileStreamInfo);
528 }
529 break;
530 }
531
532 default:
533 SetLastError (ERROR_INVALID_HANDLE);
534 return FALSE;
535 }
536
537 RtlFreeHeap (hProcessHeap, 0, IHeader);
538
539 return TRUE;
540 }
541
542
543 /*
544 * @implemented
545 */
546 HANDLE
547 STDCALL
548 FindFirstFileW (
549 LPCWSTR lpFileName,
550 LPWIN32_FIND_DATAW lpFindFileData
551 )
552 {
553
554 return FindFirstFileExW (lpFileName,
555 FindExInfoStandard,
556 (LPVOID)lpFindFileData,
557 FindExSearchNameMatch,
558 NULL,
559 0);
560 }
561
562 /*
563 * @implemented
564 */
565 BOOL
566 STDCALL
567 FindNextFileW (
568 HANDLE hFindFile,
569 LPWIN32_FIND_DATAW lpFindFileData
570 )
571 {
572 PKERNEL32_FIND_FILE_DATA IData;
573
574 if (!InternalFindNextFile(hFindFile, NULL))
575 {
576 DPRINT("Failing request\n");
577 return FALSE;
578 }
579
580 IData = (PKERNEL32_FIND_FILE_DATA)((PKERNEL32_FIND_DATA_HEADER)hFindFile + 1);
581
582 /* copy data into WIN32_FIND_DATA structure */
583 InternalCopyFindDataW(lpFindFileData, IData->pFileInfo);
584
585 return TRUE;
586 }
587
588
589 /*
590 * @unimplemented
591 */
592 HANDLE
593 STDCALL
594 FindFirstFileExW (LPCWSTR lpFileName,
595 FINDEX_INFO_LEVELS fInfoLevelId,
596 LPVOID lpFindFileData,
597 FINDEX_SEARCH_OPS fSearchOp,
598 LPVOID lpSearchFilter,
599 DWORD dwAdditionalFlags)
600 {
601 PKERNEL32_FIND_DATA_HEADER IHeader;
602 PKERNEL32_FIND_FILE_DATA IData;
603
604 if (fInfoLevelId != FindExInfoStandard)
605 {
606 SetLastError(ERROR_INVALID_PARAMETER);
607 return INVALID_HANDLE_VALUE;
608 }
609 if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories)
610 {
611 if (lpSearchFilter)
612 {
613 SetLastError(ERROR_INVALID_PARAMETER);
614 return INVALID_HANDLE_VALUE;
615 }
616
617 IHeader = InternalFindFirstFile (lpFileName, fSearchOp == FindExSearchLimitToDirectories ? TRUE : FALSE);
618 if (IHeader == NULL)
619 {
620 DPRINT("Failing request\n");
621 return INVALID_HANDLE_VALUE;
622 }
623
624 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
625
626 /* copy data into WIN32_FIND_DATA structure */
627 InternalCopyFindDataW((LPWIN32_FIND_DATAW)lpFindFileData, IData->pFileInfo);
628
629 return (HANDLE)IHeader;
630 }
631 SetLastError(ERROR_INVALID_PARAMETER);
632 return INVALID_HANDLE_VALUE;
633 }
634
635 /*
636 * @unimplemented
637 */
638 HANDLE
639 STDCALL
640 FindFirstFileExA (
641 LPCSTR lpFileName,
642 FINDEX_INFO_LEVELS fInfoLevelId,
643 LPVOID lpFindFileData,
644 FINDEX_SEARCH_OPS fSearchOp,
645 LPVOID lpSearchFilter,
646 DWORD dwAdditionalFlags
647 )
648 {
649 PKERNEL32_FIND_DATA_HEADER IHeader;
650 PKERNEL32_FIND_FILE_DATA IData;
651 UNICODE_STRING FileNameU;
652 ANSI_STRING FileNameA;
653
654 if (fInfoLevelId != FindExInfoStandard)
655 {
656 SetLastError(ERROR_INVALID_PARAMETER);
657 return INVALID_HANDLE_VALUE;
658 }
659 if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories)
660 {
661 if (lpSearchFilter)
662 {
663 SetLastError(ERROR_INVALID_PARAMETER);
664 return INVALID_HANDLE_VALUE;
665 }
666
667 RtlInitAnsiString (&FileNameA, (LPSTR)lpFileName);
668
669 /* convert ansi (or oem) string to unicode */
670 if (bIsFileApiAnsi)
671 RtlAnsiStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
672 else
673 RtlOemStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
674
675 IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE);
676
677 RtlFreeUnicodeString (&FileNameU);
678
679 if (IHeader == NULL)
680 {
681 DPRINT("Failing request\n");
682 return INVALID_HANDLE_VALUE;
683 }
684
685 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
686
687 /* copy data into WIN32_FIND_DATA structure */
688 InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
689
690 return (HANDLE)IHeader;
691 }
692 SetLastError(ERROR_INVALID_PARAMETER);
693 return INVALID_HANDLE_VALUE;
694 }
695
696
697 static VOID
698 InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData,
699 OUT LPVOID lpFindStreamData)
700 {
701 ASSERT(IData->pCurrent);
702
703 switch (IData->InfoLevel)
704 {
705 case FindStreamInfoStandard:
706 {
707 ULONG StreamNameLen;
708 WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData;
709
710 StreamNameLen = IData->pCurrent->StreamNameLength;
711 if (StreamNameLen > sizeof(StreamData->cStreamName) - sizeof(WCHAR))
712 StreamNameLen = sizeof(StreamData->cStreamName) - sizeof(WCHAR);
713
714 StreamData->StreamSize.QuadPart = IData->pCurrent->StreamSize.QuadPart;
715 RtlCopyMemory(StreamData->cStreamName,
716 IData->pCurrent->StreamName,
717 StreamNameLen);
718 StreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = L'\0';
719 break;
720 }
721
722 default:
723 ASSERT(FALSE);
724 break;
725 }
726 }
727
728
729 /*
730 * @implemented
731 */
732 HANDLE
733 WINAPI
734 FindFirstStreamW(IN LPCWSTR lpFileName,
735 IN STREAM_INFO_LEVELS InfoLevel,
736 OUT LPVOID lpFindStreamData,
737 IN DWORD dwFlags)
738 {
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;
745 NTSTATUS Status;
746 ULONG BufferSize = 0;
747
748 if (dwFlags != 0 || InfoLevel != FindStreamInfoStandard ||
749 lpFindStreamData == NULL)
750 {
751 SetLastError(ERROR_INVALID_PARAMETER);
752 return INVALID_HANDLE_VALUE;
753 }
754
755 /* validate & translate the filename */
756 if (!RtlDosPathNameToNtPathName_U(lpFileName,
757 &NtPathU,
758 NULL,
759 NULL))
760 {
761 SetLastError(ERROR_PATH_NOT_FOUND);
762 return INVALID_HANDLE_VALUE;
763 }
764
765 /* open the file */
766 InitializeObjectAttributes(&ObjectAttributes,
767 &NtPathU,
768 OBJ_CASE_INSENSITIVE,
769 NULL,
770 NULL);
771
772 Status = NtCreateFile(&FileHandle,
773 0,
774 &ObjectAttributes,
775 &IoStatusBlock,
776 NULL,
777 0,
778 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
779 FILE_OPEN,
780 0,
781 NULL,
782 0);
783 if (!NT_SUCCESS(Status))
784 {
785 goto Cleanup;
786 }
787
788 /* create the search context */
789 IHeader = RtlAllocateHeap(hProcessHeap,
790 0,
791 sizeof(KERNEL32_FIND_DATA_HEADER) +
792 sizeof(KERNEL32_FIND_STREAM_DATA));
793 if (IHeader == NULL)
794 {
795 Status = STATUS_NO_MEMORY;
796 goto Cleanup;
797 }
798
799 IHeader->Type = StreamFind;
800 IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
801
802 /* capture all information about the streams */
803 IData->InfoLevel = InfoLevel;
804 IData->pCurrent = NULL;
805 IData->pFileStreamInfo = NULL;
806
807 do
808 {
809 BufferSize += 0x1000;
810
811 if (IData->pFileStreamInfo == NULL)
812 {
813 IData->pFileStreamInfo = RtlAllocateHeap(hProcessHeap,
814 0,
815 BufferSize);
816 if (IData->pFileStreamInfo == NULL)
817 {
818 Status = STATUS_NO_MEMORY;
819 break;
820 }
821 }
822 else
823 {
824 PFILE_STREAM_INFORMATION pfsi;
825
826 pfsi = RtlReAllocateHeap(hProcessHeap,
827 0,
828 IData->pFileStreamInfo,
829 BufferSize);
830 if (pfsi == NULL)
831 {
832 Status = STATUS_NO_MEMORY;
833 break;
834 }
835
836 IData->pFileStreamInfo = pfsi;
837 }
838
839 Status = NtQueryInformationFile(FileHandle,
840 &IoStatusBlock,
841 IData->pFileStreamInfo,
842 BufferSize,
843 FileStreamInformation);
844
845 } while (Status == STATUS_BUFFER_TOO_SMALL);
846
847 if (NT_SUCCESS(Status))
848 {
849 NtClose(FileHandle);
850 FileHandle = NULL;
851
852 /* select the first stream and return the information */
853 IData->pCurrent = IData->pFileStreamInfo;
854 InternalCopyStreamInfo(IData,
855 lpFindStreamData);
856
857 /* all done */
858 Status = STATUS_SUCCESS;
859 }
860
861 Cleanup:
862 if (FileHandle != NULL)
863 {
864 NtClose(FileHandle);
865 }
866
867 RtlFreeHeap(RtlGetProcessHeap(),
868 0,
869 NtPathU.Buffer);
870
871 if (!NT_SUCCESS(Status))
872 {
873 if (IHeader != NULL)
874 {
875 if (IData->pFileStreamInfo != NULL)
876 {
877 RtlFreeHeap(hProcessHeap,
878 0,
879 IData->pFileStreamInfo);
880 }
881
882 RtlFreeHeap(hProcessHeap,
883 0,
884 IHeader);
885 }
886
887 SetLastErrorByStatus(Status);
888 return INVALID_HANDLE_VALUE;
889 }
890
891 return (HANDLE)IHeader;
892 }
893
894
895 /*
896 * @implemented
897 */
898 BOOL
899 WINAPI
900 FindNextStreamW(IN HANDLE hFindStream,
901 OUT LPVOID lpFindStreamData)
902 {
903 PKERNEL32_FIND_DATA_HEADER IHeader;
904 PKERNEL32_FIND_STREAM_DATA IData;
905
906 IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream;
907 if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE ||
908 IHeader->Type != StreamFind)
909 {
910 SetLastError (ERROR_INVALID_HANDLE);
911 return FALSE;
912 }
913
914 IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1);
915
916 /* select next stream if possible */
917 if (IData->pCurrent->NextEntryOffset != 0)
918 {
919 IData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo +
920 IData->pCurrent->NextEntryOffset);
921 }
922 else
923 {
924 SetLastError(ERROR_HANDLE_EOF);
925 return FALSE;
926 }
927
928 /* return the information */
929 InternalCopyStreamInfo(IData,
930 lpFindStreamData);
931
932 return TRUE;
933 }
934
935
936 /* EOF */