ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

find.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.