Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfind.c
Go to the documentation of this file.
00001 /* $Id: find.c 53068 2011-08-04 22:18:01Z ion $ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS system libraries 00005 * FILE: lib/kernel32/file/find.c 00006 * PURPOSE: Find functions 00007 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) 00008 * Pierre Schweitzer (pierre.schweitzer@reactos.org) 00009 * UPDATE HISTORY: 00010 * Created 01/11/98 00011 */ 00012 00013 /* INCLUDES *****************************************************************/ 00014 00015 #include <k32.h> 00016 #define NDEBUG 00017 #include <debug.h> 00018 DEBUG_CHANNEL(kernel32file); 00019 00020 /* TYPES ********************************************************************/ 00021 00022 #define FIND_DATA_SIZE 0x4000 00023 00024 #define FIND_DEVICE_HANDLE ((HANDLE)0x1) 00025 00026 typedef struct _KERNEL32_FIND_FILE_DATA 00027 { 00028 HANDLE DirectoryHandle; 00029 RTL_CRITICAL_SECTION Lock; 00030 PFILE_BOTH_DIR_INFORMATION pFileInfo; 00031 BOOLEAN DirectoryOnly; 00032 BOOLEAN HasMoreData; 00033 BOOLEAN HasData; 00034 BOOLEAN LockInitialized; 00035 } KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA; 00036 00037 typedef struct _KERNEL32_FIND_STREAM_DATA 00038 { 00039 STREAM_INFO_LEVELS InfoLevel; 00040 PFILE_STREAM_INFORMATION pFileStreamInfo; 00041 PFILE_STREAM_INFORMATION pCurrent; 00042 } KERNEL32_FIND_STREAM_DATA, *PKERNEL32_FIND_STREAM_DATA; 00043 00044 typedef enum _KERNEL32_FIND_DATA_TYPE 00045 { 00046 FileFind, 00047 StreamFind 00048 } KERNEL32_FIND_DATA_TYPE; 00049 00050 typedef struct _KERNEL32_FIND_DATA_HEADER 00051 { 00052 KERNEL32_FIND_DATA_TYPE Type; 00053 } KERNEL32_FIND_DATA_HEADER, *PKERNEL32_FIND_DATA_HEADER; 00054 00055 00056 /* FUNCTIONS ****************************************************************/ 00057 00058 static VOID 00059 InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData, 00060 LPCWSTR lpFileName, 00061 ULONG DeviceNameInfo) 00062 { 00063 UNICODE_STRING DeviceName; 00064 00065 DeviceName.Length = DeviceName.MaximumLength = (USHORT)(DeviceNameInfo & 0xFFFF); 00066 DeviceName.Buffer = (LPWSTR)((ULONG_PTR)lpFileName + (DeviceNameInfo >> 16)); 00067 00068 /* Return the data */ 00069 RtlZeroMemory(lpFindFileData, 00070 sizeof(*lpFindFileData)); 00071 lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE; 00072 RtlCopyMemory(lpFindFileData->cFileName, 00073 DeviceName.Buffer, 00074 DeviceName.Length); 00075 } 00076 00077 static VOID 00078 InternalCopyFindDataW(LPWIN32_FIND_DATAW lpFindFileData, 00079 PFILE_BOTH_DIR_INFORMATION lpFileInfo) 00080 { 00081 lpFindFileData->dwFileAttributes = lpFileInfo->FileAttributes; 00082 00083 lpFindFileData->ftCreationTime.dwHighDateTime = lpFileInfo->CreationTime.u.HighPart; 00084 lpFindFileData->ftCreationTime.dwLowDateTime = lpFileInfo->CreationTime.u.LowPart; 00085 00086 lpFindFileData->ftLastAccessTime.dwHighDateTime = lpFileInfo->LastAccessTime.u.HighPart; 00087 lpFindFileData->ftLastAccessTime.dwLowDateTime = lpFileInfo->LastAccessTime.u.LowPart; 00088 00089 lpFindFileData->ftLastWriteTime.dwHighDateTime = lpFileInfo->LastWriteTime.u.HighPart; 00090 lpFindFileData->ftLastWriteTime.dwLowDateTime = lpFileInfo->LastWriteTime.u.LowPart; 00091 00092 lpFindFileData->nFileSizeHigh = lpFileInfo->EndOfFile.u.HighPart; 00093 lpFindFileData->nFileSizeLow = lpFileInfo->EndOfFile.u.LowPart; 00094 00095 memcpy (lpFindFileData->cFileName, lpFileInfo->FileName, lpFileInfo->FileNameLength); 00096 lpFindFileData->cFileName[lpFileInfo->FileNameLength / sizeof(WCHAR)] = 0; 00097 00098 memcpy (lpFindFileData->cAlternateFileName, lpFileInfo->ShortName, lpFileInfo->ShortNameLength); 00099 lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0; 00100 } 00101 00102 00103 /* 00104 * @implemented 00105 */ 00106 BOOL 00107 WINAPI 00108 InternalFindNextFile ( 00109 HANDLE hFindFile, 00110 PUNICODE_STRING SearchPattern, 00111 PVOID lpFindFileData 00112 ) 00113 { 00114 PKERNEL32_FIND_DATA_HEADER IHeader; 00115 PKERNEL32_FIND_FILE_DATA IData; 00116 IO_STATUS_BLOCK IoStatusBlock; 00117 BOOLEAN Locked = FALSE; 00118 PFILE_BOTH_DIR_INFORMATION Buffer, FoundFile = NULL; 00119 NTSTATUS Status = STATUS_SUCCESS; 00120 00121 TRACE("InternalFindNextFile(%lx, %wZ)\n", hFindFile, SearchPattern); 00122 00123 if (hFindFile != FIND_DEVICE_HANDLE) 00124 { 00125 IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; 00126 if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE || 00127 IHeader->Type != FileFind) 00128 { 00129 SetLastError (ERROR_INVALID_HANDLE); 00130 return FALSE; 00131 } 00132 00133 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); 00134 Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); 00135 00136 if (SearchPattern == NULL) 00137 { 00138 RtlEnterCriticalSection(&IData->Lock); 00139 Locked = TRUE; 00140 } 00141 00142 do 00143 { 00144 if (IData->HasData) 00145 { 00146 if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 00147 { 00148 FoundFile = IData->pFileInfo; 00149 } 00150 00151 if (IData->pFileInfo->NextEntryOffset != 0) 00152 { 00153 ULONG_PTR BufferEnd; 00154 00155 IData->pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset); 00156 00157 /* Be paranoid and make sure that the next entry is completely there */ 00158 BufferEnd = (ULONG_PTR)Buffer + FIND_DATA_SIZE; 00159 if (BufferEnd < (ULONG_PTR)IData->pFileInfo || 00160 BufferEnd < (ULONG_PTR)&IData->pFileInfo->FileNameLength + sizeof(IData->pFileInfo->FileNameLength) || 00161 BufferEnd <= (ULONG_PTR)&IData->pFileInfo->FileName[IData->pFileInfo->FileNameLength]) 00162 { 00163 goto NeedMoreData; 00164 } 00165 } 00166 else 00167 { 00168 NeedMoreData: 00169 IData->HasData = FALSE; 00170 00171 if (!IData->HasMoreData) 00172 break; 00173 } 00174 } 00175 else 00176 { 00177 IData->pFileInfo = Buffer; 00178 IData->pFileInfo->NextEntryOffset = 0; 00179 Status = NtQueryDirectoryFile (IData->DirectoryHandle, 00180 NULL, 00181 NULL, 00182 NULL, 00183 &IoStatusBlock, 00184 (PVOID)IData->pFileInfo, 00185 FIND_DATA_SIZE, 00186 FileBothDirectoryInformation, 00187 FALSE, 00188 SearchPattern, 00189 SearchPattern != NULL); 00190 00191 if (Status == STATUS_BUFFER_OVERFLOW) 00192 { 00193 IData->HasMoreData = TRUE; 00194 Status = STATUS_SUCCESS; 00195 } 00196 else 00197 { 00198 if (!NT_SUCCESS(Status)) 00199 break; 00200 00201 IData->HasMoreData = FALSE; 00202 } 00203 00204 IData->HasData = TRUE; 00205 SearchPattern = NULL; 00206 } 00207 00208 } while (FoundFile == NULL); 00209 00210 if (FoundFile != NULL) 00211 { 00212 _SEH2_TRY 00213 { 00214 InternalCopyFindDataW(lpFindFileData, 00215 FoundFile); 00216 } 00217 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00218 { 00219 } 00220 _SEH2_END; 00221 } 00222 00223 if (Locked) 00224 RtlLeaveCriticalSection(&IData->Lock); 00225 } 00226 00227 if (!NT_SUCCESS(Status)) 00228 { 00229 BaseSetLastNTError (Status); 00230 return FALSE; 00231 } 00232 else if (FoundFile == NULL) 00233 { 00234 SetLastError (ERROR_NO_MORE_FILES); 00235 return FALSE; 00236 } 00237 00238 return TRUE; 00239 } 00240 00241 00242 /* 00243 * @implemented 00244 */ 00245 HANDLE 00246 WINAPI 00247 InternalFindFirstFile ( 00248 LPCWSTR lpFileName, 00249 BOOLEAN DirectoryOnly, 00250 PVOID lpFindFileData 00251 ) 00252 { 00253 OBJECT_ATTRIBUTES ObjectAttributes; 00254 PKERNEL32_FIND_DATA_HEADER IHeader; 00255 PKERNEL32_FIND_FILE_DATA IData; 00256 IO_STATUS_BLOCK IoStatusBlock; 00257 UNICODE_STRING NtPathU, FileName, PathFileName; 00258 NTSTATUS Status; 00259 PWSTR NtPathBuffer; 00260 BOOLEAN RemovedLastChar = FALSE; 00261 BOOL bResult; 00262 RTL_RELATIVE_NAME_U DirInfo; 00263 ULONG DeviceNameInfo; 00264 HANDLE hDirectory = NULL; 00265 00266 TRACE("FindFirstFileW(lpFileName %S)\n", 00267 lpFileName); 00268 00269 RtlZeroMemory(&PathFileName, 00270 sizeof(PathFileName)); 00271 RtlInitUnicodeString(&FileName, 00272 lpFileName); 00273 00274 bResult = RtlDosPathNameToNtPathName_U (lpFileName, 00275 &NtPathU, 00276 (PCWSTR *)((ULONG_PTR)&PathFileName.Buffer), 00277 &DirInfo); 00278 if (FALSE == bResult) 00279 { 00280 SetLastError(ERROR_PATH_NOT_FOUND); 00281 return INVALID_HANDLE_VALUE; 00282 } 00283 00284 /* Save the buffer pointer for later, we need to free it! */ 00285 NtPathBuffer = NtPathU.Buffer; 00286 00287 /* If there is a file name/pattern then determine it's length */ 00288 if (PathFileName.Buffer != NULL) 00289 { 00290 PathFileName.Length = NtPathU.Length - 00291 (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer); 00292 } 00293 PathFileName.MaximumLength = PathFileName.Length; 00294 00295 if (DirInfo.RelativeName.Length != 0 && DirInfo.RelativeName.Buffer != PathFileName.Buffer) 00296 { 00297 if (PathFileName.Buffer != NULL) 00298 { 00299 /* This is a relative path to DirInfo.ContainingDirectory, adjust NtPathU! */ 00300 NtPathU.Length = NtPathU.MaximumLength = 00301 (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)DirInfo.RelativeName.Buffer); 00302 NtPathU.Buffer = DirInfo.RelativeName.Buffer; 00303 } 00304 } 00305 else 00306 { 00307 /* This is an absolute path, NtPathU receives the full path */ 00308 DirInfo.ContainingDirectory = NULL; 00309 if (PathFileName.Buffer != NULL) 00310 { 00311 NtPathU.Length = NtPathU.MaximumLength = 00312 (USHORT)((ULONG_PTR)PathFileName.Buffer - (ULONG_PTR)NtPathU.Buffer); 00313 } 00314 } 00315 00316 /* Remove the last character of the path (Unless the path is a drive and 00317 ends with ":\"). If the caller however supplies a path to a device, such 00318 as "C:\NUL" then the last character gets cut off, which later results in 00319 NtOpenFile to return STATUS_OBJECT_NAME_NOT_FOUND, which in turn triggers 00320 a fake DOS device check with RtlIsDosDeviceName_U. However, if there is a 00321 real device with a name eg. "NU" in the system, FindFirstFile will succeed, 00322 rendering the fake DOS device check useless... Why would they invent such a 00323 stupid and broken behavior?! */ 00324 if (NtPathU.Length >= 2 * sizeof(WCHAR) && 00325 NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] != L'\\' && 00326 NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':') 00327 { 00328 NtPathU.Length -= sizeof(WCHAR); 00329 RemovedLastChar = TRUE; 00330 } 00331 00332 TRACE("lpFileName: \"%ws\"\n", lpFileName); 00333 TRACE("NtPathU: \"%wZ\"\n", &NtPathU); 00334 TRACE("PathFileName: \"%wZ\"\n", &PathFileName); 00335 TRACE("RelativeTo: 0x%p\n", DirInfo.ContainingDirectory); 00336 00337 InitializeObjectAttributes (&ObjectAttributes, 00338 &NtPathU, 00339 OBJ_CASE_INSENSITIVE, 00340 DirInfo.ContainingDirectory, 00341 NULL); 00342 00343 Status = NtOpenFile (&hDirectory, 00344 FILE_LIST_DIRECTORY | SYNCHRONIZE, 00345 &ObjectAttributes, 00346 &IoStatusBlock, 00347 FILE_SHARE_READ|FILE_SHARE_WRITE, 00348 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 00349 00350 if (Status == STATUS_NOT_A_DIRECTORY && RemovedLastChar) 00351 { 00352 /* Try again, this time with the last character ... */ 00353 NtPathU.Length += sizeof(WCHAR); 00354 00355 Status = NtOpenFile (&hDirectory, 00356 FILE_LIST_DIRECTORY | SYNCHRONIZE, 00357 &ObjectAttributes, 00358 &IoStatusBlock, 00359 FILE_SHARE_READ|FILE_SHARE_WRITE, 00360 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 00361 00362 NtPathU.Length += sizeof(WCHAR); 00363 } 00364 00365 if (!NT_SUCCESS(Status)) 00366 { 00367 RtlFreeHeap (RtlGetProcessHeap(), 00368 0, 00369 NtPathBuffer); 00370 00371 /* See if the application tries to look for a DOS device */ 00372 DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName)); 00373 if (DeviceNameInfo != 0) 00374 { 00375 InternalCopyDeviceFindDataW(lpFindFileData, 00376 lpFileName, 00377 DeviceNameInfo); 00378 00379 return FIND_DEVICE_HANDLE; 00380 } 00381 00382 BaseSetLastNTError (Status); 00383 return INVALID_HANDLE_VALUE; 00384 } 00385 00386 if (PathFileName.Length == 0) 00387 { 00388 /* No file part?! */ 00389 NtClose(hDirectory); 00390 RtlFreeHeap (RtlGetProcessHeap(), 00391 0, 00392 NtPathBuffer); 00393 SetLastError(ERROR_FILE_NOT_FOUND); 00394 return INVALID_HANDLE_VALUE; 00395 } 00396 00397 IHeader = RtlAllocateHeap (RtlGetProcessHeap(), 00398 HEAP_ZERO_MEMORY, 00399 sizeof(KERNEL32_FIND_DATA_HEADER) + 00400 sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE); 00401 if (NULL == IHeader) 00402 { 00403 RtlFreeHeap (RtlGetProcessHeap(), 00404 0, 00405 NtPathBuffer); 00406 NtClose(hDirectory); 00407 00408 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00409 return INVALID_HANDLE_VALUE; 00410 } 00411 00412 IHeader->Type = FileFind; 00413 IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); 00414 IData->DirectoryHandle = hDirectory; 00415 IData->HasMoreData = TRUE; 00416 00417 /* change pattern: "*.*" --> "*" */ 00418 if (PathFileName.Length == 6 && 00419 RtlCompareMemory(PathFileName.Buffer, 00420 L"*.*", 00421 6) == 6) 00422 { 00423 PathFileName.Length = 2; 00424 } 00425 00426 IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA)); 00427 IData->pFileInfo->FileIndex = 0; 00428 IData->DirectoryOnly = DirectoryOnly; 00429 00430 bResult = InternalFindNextFile((HANDLE)IHeader, 00431 &PathFileName, 00432 lpFindFileData); 00433 00434 RtlFreeHeap (RtlGetProcessHeap(), 00435 0, 00436 NtPathBuffer); 00437 00438 if (!bResult) 00439 { 00440 FindClose((HANDLE)IHeader); 00441 return INVALID_HANDLE_VALUE; 00442 } 00443 00444 RtlInitializeCriticalSection(&IData->Lock); 00445 IData->LockInitialized = TRUE; 00446 00447 return (HANDLE)IHeader; 00448 } 00449 00450 00451 /* 00452 * @implemented 00453 */ 00454 HANDLE 00455 WINAPI 00456 FindFirstFileA(IN LPCSTR lpFileName, 00457 OUT LPWIN32_FIND_DATAA lpFindFileData) 00458 { 00459 HANDLE hSearch; 00460 NTSTATUS Status; 00461 ANSI_STRING Ansi; 00462 UNICODE_STRING UTF8; 00463 PUNICODE_STRING lpFileNameW; 00464 WIN32_FIND_DATAW FindFileDataW; 00465 00466 lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); 00467 if (!lpFileNameW) 00468 { 00469 return INVALID_HANDLE_VALUE; 00470 } 00471 00472 hSearch = FindFirstFileExW(lpFileNameW->Buffer, 00473 FindExInfoStandard, 00474 &FindFileDataW, 00475 FindExSearchNameMatch, 00476 NULL, 0); 00477 if (hSearch == INVALID_HANDLE_VALUE) 00478 { 00479 return INVALID_HANDLE_VALUE; 00480 } 00481 00482 memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); 00483 00484 RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); 00485 Ansi.Buffer = lpFindFileData->cFileName; 00486 Ansi.Length = 0; 00487 Ansi.MaximumLength = MAX_PATH; 00488 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); 00489 if (!NT_SUCCESS(Status)) 00490 { 00491 FindClose(hSearch); 00492 BaseSetLastNTError(Status); 00493 return INVALID_HANDLE_VALUE; 00494 } 00495 00496 RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); 00497 Ansi.Buffer = lpFindFileData->cAlternateFileName; 00498 Ansi.Length = 0; 00499 Ansi.MaximumLength = 14; 00500 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); 00501 if (!NT_SUCCESS(Status)) 00502 { 00503 FindClose(hSearch); 00504 BaseSetLastNTError(Status); 00505 return INVALID_HANDLE_VALUE; 00506 } 00507 00508 return hSearch; 00509 } 00510 00511 00512 /* 00513 * @implemented 00514 */ 00515 BOOL 00516 WINAPI 00517 FindNextFileA(IN HANDLE hFindFile, 00518 OUT LPWIN32_FIND_DATAA lpFindFileData) 00519 { 00520 NTSTATUS Status; 00521 ANSI_STRING Ansi; 00522 UNICODE_STRING UTF8; 00523 WIN32_FIND_DATAW FindFileDataW; 00524 00525 if (!FindNextFileW(hFindFile, &FindFileDataW)) 00526 { 00527 return FALSE; 00528 } 00529 00530 memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); 00531 00532 RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); 00533 Ansi.Buffer = lpFindFileData->cFileName; 00534 Ansi.Length = 0; 00535 Ansi.MaximumLength = MAX_PATH; 00536 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); 00537 if (!NT_SUCCESS(Status)) 00538 { 00539 BaseSetLastNTError(Status); 00540 return FALSE; 00541 } 00542 00543 RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); 00544 Ansi.Buffer = lpFindFileData->cAlternateFileName; 00545 Ansi.Length = 0; 00546 Ansi.MaximumLength = 14; 00547 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); 00548 if (!NT_SUCCESS(Status)) 00549 { 00550 BaseSetLastNTError(Status); 00551 return FALSE; 00552 } 00553 00554 return TRUE; 00555 } 00556 00557 00558 /* 00559 * @implemented 00560 */ 00561 BOOL 00562 WINAPI 00563 FindClose ( 00564 HANDLE hFindFile 00565 ) 00566 { 00567 PKERNEL32_FIND_DATA_HEADER IHeader; 00568 00569 TRACE("FindClose(hFindFile %x)\n",hFindFile); 00570 00571 if (hFindFile == FIND_DEVICE_HANDLE) 00572 return TRUE; 00573 00574 if (!hFindFile || hFindFile == INVALID_HANDLE_VALUE) 00575 { 00576 SetLastError (ERROR_INVALID_HANDLE); 00577 return FALSE; 00578 } 00579 00580 IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile; 00581 00582 switch (IHeader->Type) 00583 { 00584 case FileFind: 00585 { 00586 PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1); 00587 CloseHandle (IData->DirectoryHandle); 00588 if (IData->LockInitialized) 00589 RtlDeleteCriticalSection(&IData->Lock); 00590 IData->LockInitialized = FALSE; 00591 break; 00592 } 00593 00594 case StreamFind: 00595 { 00596 PKERNEL32_FIND_STREAM_DATA IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); 00597 if (IData->pFileStreamInfo != NULL) 00598 { 00599 RtlFreeHeap (RtlGetProcessHeap(), 0, IData->pFileStreamInfo); 00600 } 00601 break; 00602 } 00603 00604 default: 00605 SetLastError (ERROR_INVALID_HANDLE); 00606 return FALSE; 00607 } 00608 00609 RtlFreeHeap (RtlGetProcessHeap(), 0, IHeader); 00610 00611 return TRUE; 00612 } 00613 00614 00615 /* 00616 * @implemented 00617 */ 00618 HANDLE 00619 WINAPI 00620 FindFirstFileW(IN LPCWSTR lpFileName, 00621 OUT LPWIN32_FIND_DATAW lpFindFileData) 00622 { 00623 return FindFirstFileExW(lpFileName, 00624 FindExInfoStandard, 00625 lpFindFileData, 00626 FindExSearchNameMatch, 00627 NULL, 00628 0); 00629 } 00630 00631 /* 00632 * @implemented 00633 */ 00634 BOOL 00635 WINAPI 00636 FindNextFileW(IN HANDLE hFindFile, 00637 OUT LPWIN32_FIND_DATAW lpFindFileData) 00638 { 00639 return InternalFindNextFile(hFindFile, 00640 NULL, 00641 lpFindFileData); 00642 } 00643 00644 00645 /* 00646 * @unimplemented 00647 */ 00648 HANDLE 00649 WINAPI 00650 FindFirstFileExW(IN LPCWSTR lpFileName, 00651 IN FINDEX_INFO_LEVELS fInfoLevelId, 00652 OUT LPVOID lpFindFileData, 00653 IN FINDEX_SEARCH_OPS fSearchOp, 00654 LPVOID lpSearchFilter, 00655 IN DWORD dwAdditionalFlags) 00656 { 00657 if (fInfoLevelId != FindExInfoStandard) 00658 { 00659 SetLastError(ERROR_INVALID_PARAMETER); 00660 return INVALID_HANDLE_VALUE; 00661 } 00662 00663 if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories) 00664 { 00665 if (lpSearchFilter) 00666 { 00667 SetLastError(ERROR_INVALID_PARAMETER); 00668 return INVALID_HANDLE_VALUE; 00669 } 00670 00671 return InternalFindFirstFile (lpFileName, 00672 fSearchOp == FindExSearchLimitToDirectories, 00673 lpFindFileData); 00674 } 00675 00676 SetLastError(ERROR_INVALID_PARAMETER); 00677 return INVALID_HANDLE_VALUE; 00678 } 00679 00680 /* 00681 * @unimplemented 00682 */ 00683 HANDLE 00684 WINAPI 00685 FindFirstFileExA(IN LPCSTR lpFileName, 00686 IN FINDEX_INFO_LEVELS fInfoLevelId, 00687 OUT LPVOID lpFindFileData, 00688 IN FINDEX_SEARCH_OPS fSearchOp, 00689 LPVOID lpSearchFilter, 00690 IN DWORD dwAdditionalFlags) 00691 { 00692 HANDLE hSearch; 00693 NTSTATUS Status; 00694 ANSI_STRING Ansi; 00695 UNICODE_STRING UTF8; 00696 PUNICODE_STRING lpFileNameW; 00697 WIN32_FIND_DATAW FindFileDataW; 00698 00699 lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName); 00700 if (!lpFileNameW) 00701 { 00702 return INVALID_HANDLE_VALUE; 00703 } 00704 00705 hSearch = FindFirstFileExW(lpFileNameW->Buffer, 00706 fInfoLevelId, 00707 &FindFileDataW, 00708 fSearchOp, 00709 lpSearchFilter, 00710 dwAdditionalFlags); 00711 if (hSearch == INVALID_HANDLE_VALUE) 00712 { 00713 return INVALID_HANDLE_VALUE; 00714 } 00715 00716 memcpy(lpFindFileData, &FindFileDataW, FIELD_OFFSET(WIN32_FIND_DATA, cFileName)); 00717 00718 RtlInitUnicodeString(&UTF8, FindFileDataW.cFileName); 00719 Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cFileName; 00720 Ansi.Length = 0; 00721 Ansi.MaximumLength = MAX_PATH; 00722 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); 00723 if (!NT_SUCCESS(Status)) 00724 { 00725 FindClose(hSearch); 00726 BaseSetLastNTError(Status); 00727 return INVALID_HANDLE_VALUE; 00728 } 00729 00730 RtlInitUnicodeString(&UTF8, FindFileDataW.cAlternateFileName); 00731 Ansi.Buffer = ((LPWIN32_FIND_DATAA)lpFindFileData)->cAlternateFileName; 00732 Ansi.Length = 0; 00733 Ansi.MaximumLength = 14; 00734 Status = BasepUnicodeStringTo8BitString(&Ansi, &UTF8, FALSE); 00735 if (!NT_SUCCESS(Status)) 00736 { 00737 FindClose(hSearch); 00738 BaseSetLastNTError(Status); 00739 return INVALID_HANDLE_VALUE; 00740 } 00741 00742 return hSearch; 00743 } 00744 00745 00746 static VOID 00747 InternalCopyStreamInfo(IN OUT PKERNEL32_FIND_STREAM_DATA IData, 00748 OUT LPVOID lpFindStreamData) 00749 { 00750 ASSERT(IData->pCurrent); 00751 00752 switch (IData->InfoLevel) 00753 { 00754 case FindStreamInfoStandard: 00755 { 00756 ULONG StreamNameLen; 00757 WIN32_FIND_STREAM_DATA *StreamData = (WIN32_FIND_STREAM_DATA*)lpFindStreamData; 00758 00759 StreamNameLen = IData->pCurrent->StreamNameLength; 00760 if (StreamNameLen > sizeof(StreamData->cStreamName) - sizeof(WCHAR)) 00761 StreamNameLen = sizeof(StreamData->cStreamName) - sizeof(WCHAR); 00762 00763 StreamData->StreamSize.QuadPart = IData->pCurrent->StreamSize.QuadPart; 00764 RtlCopyMemory(StreamData->cStreamName, 00765 IData->pCurrent->StreamName, 00766 StreamNameLen); 00767 StreamData->cStreamName[StreamNameLen / sizeof(WCHAR)] = L'\0'; 00768 break; 00769 } 00770 00771 default: 00772 ASSERT(FALSE); 00773 break; 00774 } 00775 } 00776 00777 00778 /* 00779 * @implemented 00780 */ 00781 HANDLE 00782 WINAPI 00783 FindFirstStreamW(IN LPCWSTR lpFileName, 00784 IN STREAM_INFO_LEVELS InfoLevel, 00785 OUT LPVOID lpFindStreamData, 00786 IN DWORD dwFlags) 00787 { 00788 PKERNEL32_FIND_DATA_HEADER IHeader = NULL; 00789 PKERNEL32_FIND_STREAM_DATA IData = NULL; 00790 OBJECT_ATTRIBUTES ObjectAttributes; 00791 IO_STATUS_BLOCK IoStatusBlock; 00792 UNICODE_STRING NtPathU; 00793 HANDLE FileHandle = NULL; 00794 NTSTATUS Status; 00795 ULONG BufferSize = 0; 00796 00797 if (dwFlags != 0 || InfoLevel != FindStreamInfoStandard || 00798 lpFindStreamData == NULL) 00799 { 00800 SetLastError(ERROR_INVALID_PARAMETER); 00801 return INVALID_HANDLE_VALUE; 00802 } 00803 00804 /* validate & translate the filename */ 00805 if (!RtlDosPathNameToNtPathName_U(lpFileName, 00806 &NtPathU, 00807 NULL, 00808 NULL)) 00809 { 00810 SetLastError(ERROR_PATH_NOT_FOUND); 00811 return INVALID_HANDLE_VALUE; 00812 } 00813 00814 /* open the file */ 00815 InitializeObjectAttributes(&ObjectAttributes, 00816 &NtPathU, 00817 OBJ_CASE_INSENSITIVE, 00818 NULL, 00819 NULL); 00820 00821 Status = NtCreateFile(&FileHandle, 00822 0, 00823 &ObjectAttributes, 00824 &IoStatusBlock, 00825 NULL, 00826 0, 00827 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 00828 FILE_OPEN, 00829 0, 00830 NULL, 00831 0); 00832 if (!NT_SUCCESS(Status)) 00833 { 00834 goto Cleanup; 00835 } 00836 00837 /* create the search context */ 00838 IHeader = RtlAllocateHeap(RtlGetProcessHeap(), 00839 0, 00840 sizeof(KERNEL32_FIND_DATA_HEADER) + 00841 sizeof(KERNEL32_FIND_STREAM_DATA)); 00842 if (IHeader == NULL) 00843 { 00844 Status = STATUS_NO_MEMORY; 00845 goto Cleanup; 00846 } 00847 00848 IHeader->Type = StreamFind; 00849 IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); 00850 00851 /* capture all information about the streams */ 00852 IData->InfoLevel = InfoLevel; 00853 IData->pCurrent = NULL; 00854 IData->pFileStreamInfo = NULL; 00855 00856 do 00857 { 00858 BufferSize += 0x1000; 00859 00860 if (IData->pFileStreamInfo == NULL) 00861 { 00862 IData->pFileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), 00863 0, 00864 BufferSize); 00865 if (IData->pFileStreamInfo == NULL) 00866 { 00867 Status = STATUS_NO_MEMORY; 00868 break; 00869 } 00870 } 00871 else 00872 { 00873 PFILE_STREAM_INFORMATION pfsi; 00874 00875 pfsi = RtlReAllocateHeap(RtlGetProcessHeap(), 00876 0, 00877 IData->pFileStreamInfo, 00878 BufferSize); 00879 if (pfsi == NULL) 00880 { 00881 Status = STATUS_NO_MEMORY; 00882 break; 00883 } 00884 00885 IData->pFileStreamInfo = pfsi; 00886 } 00887 00888 Status = NtQueryInformationFile(FileHandle, 00889 &IoStatusBlock, 00890 IData->pFileStreamInfo, 00891 BufferSize, 00892 FileStreamInformation); 00893 00894 } while (Status == STATUS_BUFFER_TOO_SMALL); 00895 00896 if (NT_SUCCESS(Status)) 00897 { 00898 NtClose(FileHandle); 00899 FileHandle = NULL; 00900 00901 /* select the first stream and return the information */ 00902 IData->pCurrent = IData->pFileStreamInfo; 00903 InternalCopyStreamInfo(IData, 00904 lpFindStreamData); 00905 00906 /* all done */ 00907 Status = STATUS_SUCCESS; 00908 } 00909 00910 Cleanup: 00911 if (FileHandle != NULL) 00912 { 00913 NtClose(FileHandle); 00914 } 00915 00916 RtlFreeHeap(RtlGetProcessHeap(), 00917 0, 00918 NtPathU.Buffer); 00919 00920 if (!NT_SUCCESS(Status)) 00921 { 00922 if (IHeader != NULL) 00923 { 00924 if (IData->pFileStreamInfo != NULL) 00925 { 00926 RtlFreeHeap(RtlGetProcessHeap(), 00927 0, 00928 IData->pFileStreamInfo); 00929 } 00930 00931 RtlFreeHeap(RtlGetProcessHeap(), 00932 0, 00933 IHeader); 00934 } 00935 00936 BaseSetLastNTError(Status); 00937 return INVALID_HANDLE_VALUE; 00938 } 00939 00940 return (HANDLE)IHeader; 00941 } 00942 00943 00944 /* 00945 * @implemented 00946 */ 00947 BOOL 00948 WINAPI 00949 FindNextStreamW(IN HANDLE hFindStream, 00950 OUT LPVOID lpFindStreamData) 00951 { 00952 PKERNEL32_FIND_DATA_HEADER IHeader; 00953 PKERNEL32_FIND_STREAM_DATA IData; 00954 00955 IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindStream; 00956 if (hFindStream == NULL || hFindStream == INVALID_HANDLE_VALUE || 00957 IHeader->Type != StreamFind) 00958 { 00959 SetLastError (ERROR_INVALID_HANDLE); 00960 return FALSE; 00961 } 00962 00963 IData = (PKERNEL32_FIND_STREAM_DATA)(IHeader + 1); 00964 00965 /* select next stream if possible */ 00966 if (IData->pCurrent->NextEntryOffset != 0) 00967 { 00968 IData->pCurrent = (PFILE_STREAM_INFORMATION)((ULONG_PTR)IData->pFileStreamInfo + 00969 IData->pCurrent->NextEntryOffset); 00970 } 00971 else 00972 { 00973 SetLastError(ERROR_HANDLE_EOF); 00974 return FALSE; 00975 } 00976 00977 /* return the information */ 00978 InternalCopyStreamInfo(IData, 00979 lpFindStreamData); 00980 00981 return TRUE; 00982 } 00983 00984 00985 /* EOF */ Generated on Sun May 27 2012 04:16:31 for ReactOS by
1.7.6.1
|