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)
12 /* INCLUDES *****************************************************************/
17 #include "../include/debug.h"
20 /* TYPES ********************************************************************/
23 #define offsetof(TYPE, MEMBER) ((size_t) &( ((TYPE *) 0)->MEMBER ))
26 #define FIND_DATA_SIZE (16*1024)
28 typedef struct _KERNEL32_FIND_FILE_DATA
30 HANDLE DirectoryHandle
;
31 BOOLEAN DirectoryOnly
;
32 PFILE_BOTH_DIR_INFORMATION pFileInfo
;
33 } KERNEL32_FIND_FILE_DATA
, *PKERNEL32_FIND_FILE_DATA
;
36 /* FUNCTIONS ****************************************************************/
39 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData
,
40 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
42 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
44 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
45 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
47 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
48 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
50 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
51 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
53 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
54 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
56 memcpy (lpFindFileData
->cFileName
, lpFileInfo
->FileName
, lpFileInfo
->FileNameLength
);
57 lpFindFileData
->cFileName
[lpFileInfo
->FileNameLength
/ sizeof(WCHAR
)] = 0;
59 memcpy (lpFindFileData
->cAlternateFileName
, lpFileInfo
->ShortName
, lpFileInfo
->ShortNameLength
);
60 lpFindFileData
->cAlternateFileName
[lpFileInfo
->ShortNameLength
/ sizeof(WCHAR
)] = 0;
64 InternalCopyFindDataA(LPWIN32_FIND_DATAA lpFindFileData
,
65 PFILE_BOTH_DIR_INFORMATION lpFileInfo
)
67 UNICODE_STRING FileNameU
;
68 ANSI_STRING FileNameA
;
70 lpFindFileData
->dwFileAttributes
= lpFileInfo
->FileAttributes
;
72 lpFindFileData
->ftCreationTime
.dwHighDateTime
= lpFileInfo
->CreationTime
.u
.HighPart
;
73 lpFindFileData
->ftCreationTime
.dwLowDateTime
= lpFileInfo
->CreationTime
.u
.LowPart
;
75 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= lpFileInfo
->LastAccessTime
.u
.HighPart
;
76 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= lpFileInfo
->LastAccessTime
.u
.LowPart
;
78 lpFindFileData
->ftLastWriteTime
.dwHighDateTime
= lpFileInfo
->LastWriteTime
.u
.HighPart
;
79 lpFindFileData
->ftLastWriteTime
.dwLowDateTime
= lpFileInfo
->LastWriteTime
.u
.LowPart
;
81 lpFindFileData
->nFileSizeHigh
= lpFileInfo
->EndOfFile
.u
.HighPart
;
82 lpFindFileData
->nFileSizeLow
= lpFileInfo
->EndOfFile
.u
.LowPart
;
84 FileNameU
.Length
= FileNameU
.MaximumLength
= lpFileInfo
->FileNameLength
;
85 FileNameU
.Buffer
= lpFileInfo
->FileName
;
87 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cFileName
) - sizeof(CHAR
);
88 FileNameA
.Buffer
= lpFindFileData
->cFileName
;
90 /* convert unicode string to ansi (or oem) */
92 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
94 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
96 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
98 DPRINT("lpFileInfo->ShortNameLength %d\n", lpFileInfo
->ShortNameLength
);
100 FileNameU
.Length
= FileNameU
.MaximumLength
= lpFileInfo
->ShortNameLength
;
101 FileNameU
.Buffer
= lpFileInfo
->ShortName
;
103 FileNameA
.MaximumLength
= sizeof(lpFindFileData
->cAlternateFileName
) - sizeof(CHAR
);
104 FileNameA
.Buffer
= lpFindFileData
->cAlternateFileName
;
106 /* convert unicode string to ansi (or oem) */
108 RtlUnicodeStringToAnsiString (&FileNameA
, &FileNameU
, FALSE
);
110 RtlUnicodeStringToOemString (&FileNameA
, &FileNameU
, FALSE
);
112 FileNameA
.Buffer
[FileNameA
.Length
] = 0;
120 InternalFindNextFile (
122 PUNICODE_STRING SearchPattern
125 PKERNEL32_FIND_FILE_DATA IData
;
126 IO_STATUS_BLOCK IoStatusBlock
;
129 DPRINT("InternalFindNextFile(%lx)\n", hFindFile
);
131 IData
= (PKERNEL32_FIND_FILE_DATA
)hFindFile
;
135 if (IData
->pFileInfo
->NextEntryOffset
!= 0)
137 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
->pFileInfo
+ IData
->pFileInfo
->NextEntryOffset
);
141 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
142 IData
->pFileInfo
->FileIndex
= 0;
143 Status
= NtQueryDirectoryFile (IData
->DirectoryHandle
,
148 (PVOID
)IData
->pFileInfo
,
150 FileBothDirectoryInformation
,
151 SearchPattern
? TRUE
: FALSE
,
153 SearchPattern
? TRUE
: FALSE
);
154 SearchPattern
= NULL
;
155 if (!NT_SUCCESS(Status
))
157 SetLastErrorByStatus (Status
);
161 if (!IData
->DirectoryOnly
|| IData
->pFileInfo
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
163 DPRINT("Found %.*S\n",IData
->pFileInfo
->FileNameLength
/sizeof(WCHAR
), IData
->pFileInfo
->FileName
);
175 InternalFindFirstFile (
177 BOOLEAN DirectoryOnly
180 OBJECT_ATTRIBUTES ObjectAttributes
;
181 PKERNEL32_FIND_FILE_DATA IData
;
182 IO_STATUS_BLOCK IoStatusBlock
;
183 UNICODE_STRING NtPathU
;
184 UNICODE_STRING PatternStr
= RTL_CONSTANT_STRING(L
"*");
187 WCHAR CurrentDir
[256];
188 PWCHAR SlashlessFileName
;
190 PWCHAR SearchPattern
;
194 DPRINT("FindFirstFileW(lpFileName %S)\n",
197 Length
= wcslen(lpFileName
);
198 if (L
'\\' == lpFileName
[Length
- 1])
200 SlashlessFileName
= RtlAllocateHeap(hProcessHeap
,
202 Length
* sizeof(WCHAR
));
203 if (NULL
== SlashlessFileName
)
205 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
208 memcpy(SlashlessFileName
, lpFileName
, (Length
- 1) * sizeof(WCHAR
));
209 SlashlessFileName
[Length
- 1] = L
'\0';
210 lpFileName
= SlashlessFileName
;
214 SlashlessFileName
= NULL
;
217 e1
= wcsrchr(lpFileName
, L
'/');
218 e2
= wcsrchr(lpFileName
, L
'\\');
219 SearchPattern
= max(e1
, e2
);
220 SearchPath
= CurrentDir
;
222 if (NULL
== SearchPattern
)
225 SearchPattern
= (PWCHAR
)lpFileName
;
226 Length
= GetCurrentDirectoryW(sizeof(CurrentDir
) / sizeof(WCHAR
), SearchPath
);
229 if (NULL
!= SlashlessFileName
)
231 RtlFreeHeap(hProcessHeap
,
237 if (Length
> sizeof(CurrentDir
) / sizeof(WCHAR
))
239 SearchPath
= RtlAllocateHeap(hProcessHeap
,
241 Length
* sizeof(WCHAR
));
242 if (NULL
== SearchPath
)
244 if (NULL
!= SlashlessFileName
)
246 RtlFreeHeap(hProcessHeap
,
250 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
253 GetCurrentDirectoryW(Length
, SearchPath
);
260 Length
= SearchPattern
- lpFileName
;
261 if (Length
+ 1 > sizeof(CurrentDir
) / sizeof(WCHAR
))
263 SearchPath
= RtlAllocateHeap(hProcessHeap
,
265 (Length
+ 1) * sizeof(WCHAR
));
266 if (NULL
== SearchPath
)
268 if (NULL
!= SlashlessFileName
)
270 RtlFreeHeap(hProcessHeap
,
274 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
278 memcpy(SearchPath
, lpFileName
, Length
* sizeof(WCHAR
));
279 SearchPath
[Length
] = 0;
282 bResult
= RtlDosPathNameToNtPathName_U ((LPWSTR
)SearchPath
,
286 if (SearchPath
!= CurrentDir
)
288 RtlFreeHeap(hProcessHeap
,
292 if (FALSE
== bResult
)
294 if (NULL
!= SlashlessFileName
)
296 RtlFreeHeap(hProcessHeap
,
303 DPRINT("NtPathU \'%S\'\n", NtPathU
.Buffer
);
305 IData
= RtlAllocateHeap (hProcessHeap
,
307 sizeof(KERNEL32_FIND_FILE_DATA
) + FIND_DATA_SIZE
);
310 RtlFreeHeap (hProcessHeap
,
313 if (NULL
!= SlashlessFileName
)
315 RtlFreeHeap(hProcessHeap
,
319 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
323 /* change pattern: "*.*" --> "*" */
324 if (wcscmp (SearchPattern
, L
"*.*"))
326 RtlInitUnicodeString(&PatternStr
, SearchPattern
);
329 DPRINT("NtPathU \'%S\' Pattern \'%S\'\n",
330 NtPathU
.Buffer
, PatternStr
.Buffer
);
332 InitializeObjectAttributes (&ObjectAttributes
,
338 Status
= NtOpenFile (&IData
->DirectoryHandle
,
342 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
343 FILE_DIRECTORY_FILE
);
345 RtlFreeHeap (hProcessHeap
,
349 if (!NT_SUCCESS(Status
))
351 RtlFreeHeap (hProcessHeap
, 0, IData
);
352 if (NULL
!= SlashlessFileName
)
354 RtlFreeHeap(hProcessHeap
,
358 SetLastErrorByStatus (Status
);
361 IData
->pFileInfo
= (PVOID
)((ULONG_PTR
)IData
+ sizeof(KERNEL32_FIND_FILE_DATA
));
362 IData
->pFileInfo
->FileIndex
= 0;
363 IData
->DirectoryOnly
= DirectoryOnly
;
365 bResult
= InternalFindNextFile((HANDLE
)IData
, &PatternStr
);
366 if (NULL
!= SlashlessFileName
)
368 RtlFreeHeap(hProcessHeap
,
375 FindClose((HANDLE
)IData
);
390 LPWIN32_FIND_DATAA lpFindFileData
393 PKERNEL32_FIND_FILE_DATA IData
;
394 UNICODE_STRING FileNameU
;
395 ANSI_STRING FileName
;
397 RtlInitAnsiString (&FileName
,
400 /* convert ansi (or oem) string to unicode */
402 RtlAnsiStringToUnicodeString (&FileNameU
,
406 RtlOemStringToUnicodeString (&FileNameU
,
410 IData
= InternalFindFirstFile (FileNameU
.Buffer
, FALSE
);
412 RtlFreeUnicodeString (&FileNameU
);
416 DPRINT("Failing request\n");
417 return INVALID_HANDLE_VALUE
;
420 DPRINT("IData->pFileInfo->FileNameLength %d\n",
421 IData
->pFileInfo
->FileNameLength
);
423 /* copy data into WIN32_FIND_DATA structure */
424 InternalCopyFindDataA(lpFindFileData
, IData
->pFileInfo
);
427 return (HANDLE
)IData
;
438 LPWIN32_FIND_DATAA lpFindFileData
)
440 PKERNEL32_FIND_FILE_DATA IData
;
442 if (hFindFile
== INVALID_HANDLE_VALUE
)
444 SetLastError (ERROR_INVALID_HANDLE
);
445 DPRINT("Failing request\n");
449 IData
= (PKERNEL32_FIND_FILE_DATA
)hFindFile
;
450 if (!InternalFindNextFile (hFindFile
, NULL
))
452 DPRINT("InternalFindNextFile() failed\n");
456 DPRINT("IData->pFileInfo->FileNameLength %d\n",
457 IData
->pFileInfo
->FileNameLength
);
459 /* copy data into WIN32_FIND_DATA structure */
460 InternalCopyFindDataA(lpFindFileData
, IData
->pFileInfo
);
475 PKERNEL32_FIND_FILE_DATA IData
;
477 DPRINT("FindClose(hFindFile %x)\n",hFindFile
);
479 if (!hFindFile
|| hFindFile
== INVALID_HANDLE_VALUE
)
481 SetLastError (ERROR_INVALID_HANDLE
);
485 IData
= (PKERNEL32_FIND_FILE_DATA
)hFindFile
;
487 CloseHandle (IData
->DirectoryHandle
);
488 RtlFreeHeap (hProcessHeap
, 0, IData
);
501 LPWIN32_FIND_DATAW lpFindFileData
505 return FindFirstFileExW (lpFileName
,
507 (LPVOID
)lpFindFileData
,
508 FindExSearchNameMatch
,
520 LPWIN32_FIND_DATAW lpFindFileData
523 PKERNEL32_FIND_FILE_DATA IData
;
525 if (hFindFile
== INVALID_HANDLE_VALUE
)
527 SetLastError (ERROR_INVALID_HANDLE
);
528 DPRINT("Failing request\n");
532 IData
= (PKERNEL32_FIND_FILE_DATA
)hFindFile
;
533 if (!InternalFindNextFile(hFindFile
, NULL
))
535 DPRINT("Failing request\n");
539 /* copy data into WIN32_FIND_DATA structure */
540 InternalCopyFindDataW(lpFindFileData
, IData
->pFileInfo
);
551 FindFirstFileExW (LPCWSTR lpFileName
,
552 FINDEX_INFO_LEVELS fInfoLevelId
,
553 LPVOID lpFindFileData
,
554 FINDEX_SEARCH_OPS fSearchOp
,
555 LPVOID lpSearchFilter
,
556 DWORD dwAdditionalFlags
)
558 PKERNEL32_FIND_FILE_DATA IData
;
560 if (fInfoLevelId
!= FindExInfoStandard
)
562 SetLastError(ERROR_INVALID_PARAMETER
);
563 return INVALID_HANDLE_VALUE
;
565 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
569 SetLastError(ERROR_INVALID_PARAMETER
);
570 return INVALID_HANDLE_VALUE
;
573 IData
= InternalFindFirstFile (lpFileName
, fSearchOp
== FindExSearchLimitToDirectories
? TRUE
: FALSE
);
576 DPRINT("Failing request\n");
577 return INVALID_HANDLE_VALUE
;
580 /* copy data into WIN32_FIND_DATA structure */
581 InternalCopyFindDataW((LPWIN32_FIND_DATAW
)lpFindFileData
, IData
->pFileInfo
);
583 return (HANDLE
)IData
;
585 SetLastError(ERROR_INVALID_PARAMETER
);
586 return INVALID_HANDLE_VALUE
;
596 FINDEX_INFO_LEVELS fInfoLevelId
,
597 LPVOID lpFindFileData
,
598 FINDEX_SEARCH_OPS fSearchOp
,
599 LPVOID lpSearchFilter
,
600 DWORD dwAdditionalFlags
603 PKERNEL32_FIND_FILE_DATA IData
;
604 UNICODE_STRING FileNameU
;
605 ANSI_STRING FileNameA
;
607 if (fInfoLevelId
!= FindExInfoStandard
)
609 SetLastError(ERROR_INVALID_PARAMETER
);
610 return INVALID_HANDLE_VALUE
;
612 if (fSearchOp
== FindExSearchNameMatch
|| fSearchOp
== FindExSearchLimitToDirectories
)
616 SetLastError(ERROR_INVALID_PARAMETER
);
617 return INVALID_HANDLE_VALUE
;
620 RtlInitAnsiString (&FileNameA
, (LPSTR
)lpFileName
);
622 /* convert ansi (or oem) string to unicode */
624 RtlAnsiStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
626 RtlOemStringToUnicodeString (&FileNameU
, &FileNameA
, TRUE
);
628 IData
= InternalFindFirstFile (FileNameU
.Buffer
, FALSE
);
630 RtlFreeUnicodeString (&FileNameU
);
634 DPRINT("Failing request\n");
635 return INVALID_HANDLE_VALUE
;
638 /* copy data into WIN32_FIND_DATA structure */
639 InternalCopyFindDataA(lpFindFileData
, IData
->pFileInfo
);
641 SetLastError(ERROR_INVALID_PARAMETER
);
642 return INVALID_HANDLE_VALUE
;