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