Reverted back to 16420, because it contains too many bugs.
[reactos.git] / reactos / lib / 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 #ifndef offsetof
23 #define offsetof(TYPE, MEMBER) ((size_t) &( ((TYPE *) 0)->MEMBER ))
24 #endif
25
26 #define FIND_DATA_SIZE (16*1024)
27
28 typedef struct _KERNEL32_FIND_FILE_DATA
29 {
30 HANDLE DirectoryHandle;
31 PFILE_BOTH_DIR_INFORMATION pFileInfo;
32 } KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
33
34
35 /* FUNCTIONS ****************************************************************/
36
37
38 /*
39 * @implemented
40 */
41 BOOL
42 STDCALL
43 InternalFindNextFile (
44 HANDLE hFindFile
45 )
46 {
47 PKERNEL32_FIND_FILE_DATA IData;
48 IO_STATUS_BLOCK IoStatusBlock;
49 NTSTATUS Status;
50
51 DPRINT("InternalFindNextFile(%lx)\n", hFindFile);
52
53 IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
54
55 if (IData->pFileInfo->NextEntryOffset != 0)
56 {
57 IData->pFileInfo = (PVOID)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset);
58 DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
59 return TRUE;
60 }
61 IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
62 IData->pFileInfo->FileIndex = 0;
63 Status = NtQueryDirectoryFile (IData->DirectoryHandle,
64 NULL,
65 NULL,
66 NULL,
67 &IoStatusBlock,
68 (PVOID)IData->pFileInfo,
69 FIND_DATA_SIZE,
70 FileBothDirectoryInformation,
71 FALSE,
72 NULL,
73 FALSE);
74 if (!NT_SUCCESS(Status))
75 {
76 SetLastErrorByStatus (Status);
77 return FALSE;
78 }
79 DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
80 return TRUE;
81 }
82
83
84 /*
85 * @implemented
86 */
87 HANDLE
88 STDCALL
89 InternalFindFirstFile (
90 LPCWSTR lpFileName
91 )
92 {
93 OBJECT_ATTRIBUTES ObjectAttributes;
94 PKERNEL32_FIND_FILE_DATA IData;
95 IO_STATUS_BLOCK IoStatusBlock;
96 UNICODE_STRING NtPathU;
97 UNICODE_STRING PatternStr = RTL_CONSTANT_STRING(L"*");
98 NTSTATUS Status;
99 PWSTR e1, e2;
100 WCHAR CurrentDir[256];
101 PWCHAR SlashlessFileName;
102 PWSTR SearchPath;
103 PWCHAR SearchPattern;
104 ULONG Length;
105 BOOLEAN bResult;
106
107 DPRINT("FindFirstFileW(lpFileName %S)\n",
108 lpFileName);
109
110 Length = wcslen(lpFileName);
111 if (L'\\' == lpFileName[Length - 1])
112 {
113 SlashlessFileName = RtlAllocateHeap(hProcessHeap,
114 0,
115 Length * sizeof(WCHAR));
116 if (NULL == SlashlessFileName)
117 {
118 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
119 return NULL;
120 }
121 memcpy(SlashlessFileName, lpFileName, (Length - 1) * sizeof(WCHAR));
122 SlashlessFileName[Length - 1] = L'\0';
123 lpFileName = SlashlessFileName;
124 }
125 else
126 {
127 SlashlessFileName = NULL;
128 }
129
130 e1 = wcsrchr(lpFileName, L'/');
131 e2 = wcsrchr(lpFileName, L'\\');
132 SearchPattern = max(e1, e2);
133 SearchPath = CurrentDir;
134
135 if (NULL == SearchPattern)
136 {
137 CHECKPOINT;
138 SearchPattern = (PWCHAR)lpFileName;
139 Length = GetCurrentDirectoryW(sizeof(CurrentDir) / sizeof(WCHAR), SearchPath);
140 if (0 == Length)
141 {
142 if (NULL != SlashlessFileName)
143 {
144 RtlFreeHeap(hProcessHeap,
145 0,
146 SlashlessFileName);
147 }
148 return NULL;
149 }
150 if (Length > sizeof(CurrentDir) / sizeof(WCHAR))
151 {
152 SearchPath = RtlAllocateHeap(hProcessHeap,
153 HEAP_ZERO_MEMORY,
154 Length * sizeof(WCHAR));
155 if (NULL == SearchPath)
156 {
157 if (NULL != SlashlessFileName)
158 {
159 RtlFreeHeap(hProcessHeap,
160 0,
161 SlashlessFileName);
162 }
163 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
164 return NULL;
165 }
166 GetCurrentDirectoryW(Length, SearchPath);
167 }
168 }
169 else
170 {
171 CHECKPOINT;
172 SearchPattern++;
173 Length = SearchPattern - lpFileName;
174 if (Length + 1 > sizeof(CurrentDir) / sizeof(WCHAR))
175 {
176 SearchPath = RtlAllocateHeap(hProcessHeap,
177 HEAP_ZERO_MEMORY,
178 (Length + 1) * sizeof(WCHAR));
179 if (NULL == SearchPath)
180 {
181 if (NULL != SlashlessFileName)
182 {
183 RtlFreeHeap(hProcessHeap,
184 0,
185 SlashlessFileName);
186 }
187 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
188 return NULL;
189 }
190 }
191 memcpy(SearchPath, lpFileName, Length * sizeof(WCHAR));
192 SearchPath[Length] = 0;
193 }
194
195 bResult = RtlDosPathNameToNtPathName_U ((LPWSTR)SearchPath,
196 &NtPathU,
197 NULL,
198 NULL);
199 if (SearchPath != CurrentDir)
200 {
201 RtlFreeHeap(hProcessHeap,
202 0,
203 SearchPath);
204 }
205 if (FALSE == bResult)
206 {
207 if (NULL != SlashlessFileName)
208 {
209 RtlFreeHeap(hProcessHeap,
210 0,
211 SlashlessFileName);
212 }
213 return NULL;
214 }
215
216 DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
217
218 IData = RtlAllocateHeap (hProcessHeap,
219 HEAP_ZERO_MEMORY,
220 sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
221 if (NULL == IData)
222 {
223 RtlFreeHeap (hProcessHeap,
224 0,
225 NtPathU.Buffer);
226 if (NULL != SlashlessFileName)
227 {
228 RtlFreeHeap(hProcessHeap,
229 0,
230 SlashlessFileName);
231 }
232 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
233 return NULL;
234 }
235
236 /* change pattern: "*.*" --> "*" */
237 if (wcscmp (SearchPattern, L"*.*"))
238 {
239 RtlInitUnicodeString(&PatternStr, SearchPattern);
240 }
241
242 DPRINT("NtPathU \'%S\' Pattern \'%S\'\n",
243 NtPathU.Buffer, PatternStr.Buffer);
244
245 InitializeObjectAttributes (&ObjectAttributes,
246 &NtPathU,
247 0,
248 NULL,
249 NULL);
250
251 Status = NtOpenFile (&IData->DirectoryHandle,
252 FILE_LIST_DIRECTORY,
253 &ObjectAttributes,
254 &IoStatusBlock,
255 FILE_SHARE_READ|FILE_SHARE_WRITE,
256 FILE_DIRECTORY_FILE);
257
258 RtlFreeHeap (hProcessHeap,
259 0,
260 NtPathU.Buffer);
261
262 if (!NT_SUCCESS(Status))
263 {
264 RtlFreeHeap (hProcessHeap, 0, IData);
265 if (NULL != SlashlessFileName)
266 {
267 RtlFreeHeap(hProcessHeap,
268 0,
269 SlashlessFileName);
270 }
271 SetLastErrorByStatus (Status);
272 return(NULL);
273 }
274 IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
275 IData->pFileInfo->FileIndex = 0;
276
277 Status = NtQueryDirectoryFile (IData->DirectoryHandle,
278 NULL,
279 NULL,
280 NULL,
281 &IoStatusBlock,
282 (PVOID)IData->pFileInfo,
283 FIND_DATA_SIZE,
284 FileBothDirectoryInformation,
285 TRUE,
286 &PatternStr,
287 TRUE);
288 if (NULL != SlashlessFileName)
289 {
290 RtlFreeHeap(hProcessHeap,
291 0,
292 SlashlessFileName);
293 }
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT("Status %lx\n", Status);
297 CloseHandle (IData->DirectoryHandle);
298 RtlFreeHeap (hProcessHeap, 0, IData);
299 SetLastErrorByStatus (Status);
300 return NULL;
301 }
302 DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
303
304 return IData;
305 }
306
307
308 /*
309 * @implemented
310 */
311 HANDLE
312 STDCALL
313 FindFirstFileA (
314 LPCSTR lpFileName,
315 LPWIN32_FIND_DATAA lpFindFileData
316 )
317 {
318 PKERNEL32_FIND_FILE_DATA IData;
319 UNICODE_STRING FileNameU;
320 ANSI_STRING FileName;
321
322 RtlInitAnsiString (&FileName,
323 (LPSTR)lpFileName);
324
325 /* convert ansi (or oem) string to unicode */
326 if (bIsFileApiAnsi)
327 RtlAnsiStringToUnicodeString (&FileNameU,
328 &FileName,
329 TRUE);
330 else
331 RtlOemStringToUnicodeString (&FileNameU,
332 &FileName,
333 TRUE);
334
335 IData = InternalFindFirstFile (FileNameU.Buffer);
336
337 RtlFreeUnicodeString (&FileNameU);
338
339 if (IData == NULL)
340 {
341 DPRINT("Failing request\n");
342 return INVALID_HANDLE_VALUE;
343 }
344
345 DPRINT("IData->pFileInfo->FileNameLength %d\n",
346 IData->pFileInfo->FileNameLength);
347
348 /* copy data into WIN32_FIND_DATA structure */
349 lpFindFileData->dwFileAttributes = IData->pFileInfo->FileAttributes;
350
351 lpFindFileData->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
352 lpFindFileData->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
353
354 lpFindFileData->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
355 lpFindFileData->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
356
357 lpFindFileData->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
358 lpFindFileData->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
359
360 lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
361 lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
362
363 FileNameU.Length = IData->pFileInfo->FileNameLength;
364 FileNameU.MaximumLength = FileNameU.Length + sizeof(WCHAR);
365 FileNameU.Buffer = IData->pFileInfo->FileName;
366
367 FileName.Length = 0;
368 FileName.MaximumLength = MAX_PATH;
369 FileName.Buffer = lpFindFileData->cFileName;
370
371 /* convert unicode string to ansi (or oem) */
372 if (bIsFileApiAnsi)
373 RtlUnicodeStringToAnsiString (&FileName,
374 &FileNameU,
375 FALSE);
376 else
377 RtlUnicodeStringToOemString (&FileName,
378 &FileNameU,
379 FALSE);
380
381 DPRINT("IData->pFileInfo->ShortNameLength %d\n",
382 IData->pFileInfo->ShortNameLength);
383
384 FileNameU.Length = IData->pFileInfo->ShortNameLength;
385 FileNameU.MaximumLength = FileNameU.Length + sizeof(WCHAR);
386 FileNameU.Buffer = IData->pFileInfo->ShortName;
387
388 FileName.Length = 0;
389 FileName.MaximumLength = 14;
390 FileName.Buffer = lpFindFileData->cAlternateFileName;
391
392 /* convert unicode string to ansi (or oem) */
393 if (bIsFileApiAnsi)
394 RtlUnicodeStringToAnsiString (&FileName,
395 &FileNameU,
396 FALSE);
397 else
398 RtlUnicodeStringToOemString (&FileName,
399 &FileNameU,
400 FALSE);
401
402 return (HANDLE)IData;
403 }
404
405
406 /*
407 * @implemented
408 */
409 BOOL
410 STDCALL
411 FindNextFileA (
412 HANDLE hFindFile,
413 LPWIN32_FIND_DATAA lpFindFileData)
414 {
415 PKERNEL32_FIND_FILE_DATA IData;
416 UNICODE_STRING FileNameU;
417 ANSI_STRING FileName;
418
419 if (hFindFile == INVALID_HANDLE_VALUE)
420 {
421 SetLastError (ERROR_INVALID_HANDLE);
422 DPRINT("Failing request\n");
423 return FALSE;
424 }
425
426 IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
427 if (!InternalFindNextFile (hFindFile))
428 {
429 DPRINT("InternalFindNextFile() failed\n");
430 return FALSE;
431 }
432
433 DPRINT("IData->pFileInfo->FileNameLength %d\n",
434 IData->pFileInfo->FileNameLength);
435
436 /* copy data into WIN32_FIND_DATA structure */
437 lpFindFileData->dwFileAttributes = IData->pFileInfo->FileAttributes;
438
439 lpFindFileData->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
440 lpFindFileData->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
441
442 lpFindFileData->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
443 lpFindFileData->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
444
445 lpFindFileData->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
446 lpFindFileData->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
447
448 lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
449 lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
450
451 FileNameU.Length = IData->pFileInfo->FileNameLength;
452 FileNameU.MaximumLength = FileNameU.Length + sizeof(WCHAR);
453 FileNameU.Buffer = IData->pFileInfo->FileName;
454
455 FileName.Length = 0;
456 FileName.MaximumLength = MAX_PATH;
457 FileName.Buffer = lpFindFileData->cFileName;
458
459 /* convert unicode string to ansi (or oem) */
460 if (bIsFileApiAnsi)
461 RtlUnicodeStringToAnsiString (&FileName,
462 &FileNameU,
463 FALSE);
464 else
465 RtlUnicodeStringToOemString (&FileName,
466 &FileNameU,
467 FALSE);
468
469 DPRINT("IData->pFileInfo->ShortNameLength %d\n",
470 IData->pFileInfo->ShortNameLength);
471
472 FileNameU.Length = IData->pFileInfo->ShortNameLength;
473 FileNameU.MaximumLength = FileNameU.Length + sizeof(WCHAR);
474 FileNameU.Buffer = IData->pFileInfo->ShortName;
475
476 FileName.Length = 0;
477 FileName.MaximumLength = 14;
478 FileName.Buffer = lpFindFileData->cAlternateFileName;
479
480 /* convert unicode string to ansi (or oem) */
481 if (bIsFileApiAnsi)
482 RtlUnicodeStringToAnsiString (&FileName,
483 &FileNameU,
484 FALSE);
485 else
486 RtlUnicodeStringToOemString (&FileName,
487 &FileNameU,
488 FALSE);
489
490 return TRUE;
491 }
492
493
494 /*
495 * @implemented
496 */
497 BOOL
498 STDCALL
499 FindClose (
500 HANDLE hFindFile
501 )
502 {
503 PKERNEL32_FIND_FILE_DATA IData;
504
505 DPRINT("FindClose(hFindFile %x)\n",hFindFile);
506
507 if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE)
508 {
509 SetLastError (ERROR_INVALID_HANDLE);
510 return FALSE;
511 }
512
513 IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
514
515 CloseHandle (IData->DirectoryHandle);
516 RtlFreeHeap (hProcessHeap, 0, IData);
517
518 return TRUE;
519 }
520
521
522 /*
523 * @implemented
524 */
525 HANDLE
526 STDCALL
527 FindFirstFileW (
528 LPCWSTR lpFileName,
529 LPWIN32_FIND_DATAW lpFindFileData
530 )
531 {
532 PKERNEL32_FIND_FILE_DATA IData;
533
534 IData = InternalFindFirstFile (lpFileName);
535 if (IData == NULL)
536 {
537 DPRINT("Failing request\n");
538 return INVALID_HANDLE_VALUE;
539 }
540
541 /* copy data into WIN32_FIND_DATA structure */
542 lpFindFileData->dwFileAttributes = IData->pFileInfo->FileAttributes;
543
544 lpFindFileData->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
545 lpFindFileData->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
546
547 lpFindFileData->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
548 lpFindFileData->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
549
550 lpFindFileData->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
551 lpFindFileData->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
552
553 lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
554 lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
555
556 memcpy (lpFindFileData->cFileName,
557 IData->pFileInfo->FileName,
558 IData->pFileInfo->FileNameLength);
559 lpFindFileData->cFileName[IData->pFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
560 memcpy (lpFindFileData->cAlternateFileName,
561 IData->pFileInfo->ShortName,
562 IData->pFileInfo->ShortNameLength);
563 lpFindFileData->cAlternateFileName[IData->pFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
564 return IData;
565 }
566
567
568 /*
569 * @implemented
570 */
571 BOOL
572 STDCALL
573 FindNextFileW (
574 HANDLE hFindFile,
575 LPWIN32_FIND_DATAW lpFindFileData
576 )
577 {
578 PKERNEL32_FIND_FILE_DATA IData;
579
580 if (hFindFile == INVALID_HANDLE_VALUE)
581 {
582 SetLastError (ERROR_INVALID_HANDLE);
583 DPRINT("Failing request\n");
584 return FALSE;
585 }
586
587 IData = (PKERNEL32_FIND_FILE_DATA)hFindFile;
588 if (!InternalFindNextFile(hFindFile))
589 {
590 DPRINT("Failing request\n");
591 return FALSE;
592 }
593
594 /* copy data into WIN32_FIND_DATA structure */
595 lpFindFileData->dwFileAttributes = IData->pFileInfo->FileAttributes;
596
597 lpFindFileData->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
598 lpFindFileData->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
599
600 lpFindFileData->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
601 lpFindFileData->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
602
603 lpFindFileData->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
604 lpFindFileData->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
605
606 lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
607 lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
608
609 lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
610 lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
611
612 memcpy (lpFindFileData->cFileName,
613 IData->pFileInfo->FileName,
614 IData->pFileInfo->FileNameLength);
615 lpFindFileData->cFileName[IData->pFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
616 memcpy (lpFindFileData->cAlternateFileName,
617 IData->pFileInfo->ShortName,
618 IData->pFileInfo->ShortNameLength);
619 lpFindFileData->cAlternateFileName[IData->pFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
620 return TRUE;
621 }
622
623
624 /*
625 * @unimplemented
626 */
627 HANDLE
628 STDCALL
629 FindFirstFileExW (
630 LPCWSTR lpFileName,
631 FINDEX_INFO_LEVELS fInfoLevelId,
632 LPVOID lpFindFileData,
633 FINDEX_SEARCH_OPS fSearchOp,
634 LPVOID lpSearchFilter,
635 DWORD dwAdditionalFlags
636 )
637 {
638 /* FIXME */
639 return (HANDLE) 0;
640 }
641
642
643 /*
644 * @unimplemented
645 */
646 HANDLE
647 STDCALL
648 FindFirstFileExA (
649 LPCSTR lpFileName,
650 FINDEX_INFO_LEVELS fInfoLevelId,
651 LPVOID lpFindFileData,
652 FINDEX_SEARCH_OPS fSearchOp,
653 LPVOID lpSearchFilter,
654 DWORD dwAdditionalFlags
655 )
656 {
657 /* FIXME */
658 return (HANDLE) 0;
659 }
660
661
662 /* EOF */