* added _DISABLE_TIDENTS macro to disable any ANSI/UNICODE ambiguous elements from...
[reactos.git] / reactos / lib / kernel32 / file / find.c
1 /* $Id: find.c,v 1.38 2003/08/07 04:03:23 royce Exp $
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 */