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