+ if (!RtlDosPathNameToNtPathName_U(lpFileName,
+ &NtPath,
+ (PCWSTR*)&FilePattern.Buffer,
+ &RelativePath))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ DPRINT("lpFileName = '%S'\n", lpFileName);
+ DPRINT("FilePattern.Buffer = '%S'\n", FilePattern.Buffer);
+ DPRINT("RelativePath.RelativeName = '%wZ'\n", &RelativePath.RelativeName);
+ DPRINT("NtPath.Buffer = '%S'\n", NtPath.Buffer);
+ DPRINT("NtPath - Before = '%wZ'\n", &NtPath);
+
+ /* Save the buffer pointer for later, we need to free it! */
+ NtPathBuffer = NtPath.Buffer;
+
+ /*
+ * Contrary to what Windows does, check NOW whether or not
+ * lpFileName is a DOS driver. Therefore we don't have to
+ * write broken code to check that.
+ */
+ if (!FilePattern.Buffer || !*FilePattern.Buffer)
+ {
+ /* No file pattern specified, or DOS device */
+
+ DeviceNameInfo = RtlIsDosDeviceName_U(lpFileName);
+ if (DeviceNameInfo != 0)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ /* OK, it's really a DOS device */
+ CopyDeviceFindData(Win32FindData, lpFileName, DeviceNameInfo);
+ return FIND_DEVICE_HANDLE;
+ }
+ }
+
+ /* A file pattern was specified, or it was not a DOS device */
+
+ /* If there is a file pattern then determine its length */
+ if (FilePattern.Buffer != NULL)
+ {
+ FilePattern.Length = NtPath.Length -
+ (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer);
+ }
+ else
+ {
+ FilePattern.Length = 0;
+ }
+ FilePattern.MaximumLength = FilePattern.Length;
+
+ if (RelativePath.RelativeName.Length != 0 &&
+ RelativePath.RelativeName.Buffer != FilePattern.Buffer)
+ {
+ if (FilePattern.Buffer != NULL)
+ {
+ /* This is a relative path to RelativePath.ContainingDirectory, adjust NtPath! */
+ NtPath.Length = NtPath.MaximumLength =
+ (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)RelativePath.RelativeName.Buffer);
+ NtPath.Buffer = RelativePath.RelativeName.Buffer;
+ }
+ }
+ else
+ {
+ /* This is an absolute path, NtPath receives the full path */
+ RelativePath.ContainingDirectory = NULL;
+ if (FilePattern.Buffer != NULL)
+ {
+ NtPath.Length = NtPath.MaximumLength =
+ (USHORT)((ULONG_PTR)FilePattern.Buffer - (ULONG_PTR)NtPath.Buffer);
+ }
+ }
+
+ DPRINT("NtPath - After = '%wZ'\n", &NtPath);
+ DPRINT("FilePattern = '%wZ'\n", &FilePattern);
+ DPRINT("RelativeTo = 0x%p\n", RelativePath.ContainingDirectory);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &NtPath,
+ (dwAdditionalFlags & FIND_FIRST_EX_CASE_SENSITIVE) ? 0 : OBJ_CASE_INSENSITIVE,
+ RelativePath.ContainingDirectory,
+ NULL);
+
+ Status = NtOpenFile(&hDirectory,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+
+ if (!NT_SUCCESS(Status))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ /* Adjust the last error codes */
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ else if (Status == STATUS_OBJECT_TYPE_MISMATCH)
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /*
+ * Fail if there is not any file pattern,
+ * since we are not looking for a device.
+ */
+ if (FilePattern.Length == 0)
+ {
+ NtClose(hDirectory);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ /* Change pattern: "*.*" --> "*" */
+ if (FilePattern.Length == 6 &&
+ RtlCompareMemory(FilePattern.Buffer, L"*.*", 6) == 6)
+ {
+ FilePattern.Length = 2;
+ }
+
+ Status = NtQueryDirectoryFile(hDirectory,
+ NULL, NULL, NULL,
+ &IoStatusBlock,
+ DirInfo.DirInfo, // == &DirectoryInfo
+ sizeof(DirectoryInfo),
+ (fInfoLevelId == FindExInfoStandard
+ ? FileBothDirectoryInformation
+ : FileFullDirectoryInformation),
+ TRUE, /* Return a single entry */
+ &FilePattern,
+ TRUE);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathBuffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ NtClose(hDirectory);
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ ASSERT(DirInfo.FullDirInfo->NextEntryOffset == 0);
+
+ /* Return the information */
+ CopyFindData(Win32FindData, fInfoLevelId, DirInfo);
+
+ /*
+ * Initialization of the search handle.
+ */
+ FindDataHandle = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(FIND_DATA_HANDLE) +
+ sizeof(FIND_FILE_DATA));
+ if (!FindDataHandle)
+ {
+ NtClose(hDirectory);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ FindDataHandle->Type = FindFile;
+ FindDataHandle->u.FindFileData = (PFIND_FILE_DATA)(FindDataHandle + 1);
+ FindFileData = FindDataHandle->u.FindFileData;
+
+ FindFileData->Handle = hDirectory;
+ FindFileData->InfoLevel = fInfoLevelId;
+ FindFileData->SearchOp = fSearchOp;
+ FindFileData->HasMoreData = FALSE;
+ FindFileData->NextDirInfo.DirInfo = NULL;
+
+ /* The critical section must always be initialized */
+ Status = RtlInitializeCriticalSection(&FindDataHandle->Lock);
+ if (!NT_SUCCESS(Status))
+ {
+ NtClose(hDirectory);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, FindDataHandle);
+
+ BaseSetLastNTError(Status);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return (HANDLE)FindDataHandle;
+ }
+ else
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return INVALID_HANDLE_VALUE;