Dmitry Philippov <shedon@mail.ru>:

 - Implemented FindFirstFileExW() and have removed InternalFindFirstFile() in /lib/kernel32/file/find.c, now FindFirstFileA (), FindFirstFileExA () and FindFirstFileW called FindFirstFileExW ()

NOTE: Filip has asked revision "16661" (the next one) to be done by him... sorry if this sounds silly, but please respect his wish :)
Modified: trunk/reactos/lib/kernel32/file/find.c

Modified: trunk/reactos/lib/kernel32/file/find.c
--- trunk/reactos/lib/kernel32/file/find.c	2005-07-20 03:50:50 UTC (rev 16659)
+++ trunk/reactos/lib/kernel32/file/find.c	2005-07-20 04:43:12 UTC (rev 16660)
@@ -4,9 +4,11 @@
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/file/find.c
  * PURPOSE:         Find functions
- * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
+ * PROGRAMMERS:     Ariadne ( ariadne@xs4all.nl)
+					Dmitry Philippov ( shedon@mail.ru )
  * UPDATE HISTORY:
  *                  Created 01/11/98
+ *					DP (18/06/2005) remove InternalFindFirstFile, implemented FindFirstFileExW
  */
 
 /* INCLUDES *****************************************************************/
@@ -80,332 +82,9 @@
 	return TRUE;
 }
 
-
 /*
  * @implemented
  */
-HANDLE
-STDCALL
-InternalFindFirstFile (
-	LPCWSTR	lpFileName
-	)
-{
-	OBJECT_ATTRIBUTES ObjectAttributes;
-	PKERNEL32_FIND_FILE_DATA IData;
-	IO_STATUS_BLOCK IoStatusBlock;
-	UNICODE_STRING NtPathU;
-	UNICODE_STRING PatternStr = RTL_CONSTANT_STRING(L"*");
-	NTSTATUS Status;
-	PWSTR e1, e2;
-	WCHAR CurrentDir[256];
-	PWCHAR SlashlessFileName;
-	PWSTR SearchPath;
-	PWCHAR SearchPattern;
-	ULONG Length;
-	BOOLEAN bResult;
-
-	DPRINT("FindFirstFileW(lpFileName %S)\n",
-	       lpFileName);
-
-	Length = wcslen(lpFileName);
-	if (L'\\' == lpFileName[Length - 1])
-	{
-	    SlashlessFileName = RtlAllocateHeap(hProcessHeap,
-	                                        0,
-					        Length * sizeof(WCHAR));
-	    if (NULL == SlashlessFileName)
-	    {
-	        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-	        return NULL;
-	    }
-	    memcpy(SlashlessFileName, lpFileName, (Length - 1) * sizeof(WCHAR));
-	    SlashlessFileName[Length - 1] = L'\0';
-	    lpFileName = SlashlessFileName;
-	}
-	else
-	{
-	    SlashlessFileName = NULL;
-	}
-
-	e1 = wcsrchr(lpFileName, L'/');
-	e2 = wcsrchr(lpFileName, L'\\');
-	SearchPattern = max(e1, e2);
-	SearchPath = CurrentDir;
-
-	if (NULL == SearchPattern)
-	{
-	   CHECKPOINT;
-	   SearchPattern = (PWCHAR)lpFileName;
-           Length = GetCurrentDirectoryW(sizeof(CurrentDir) / sizeof(WCHAR), SearchPath);
-	   if (0 == Length)
-	   {
-	      if (NULL != SlashlessFileName)
-	      {
-	         RtlFreeHeap(hProcessHeap,
-	                     0,
-	                     SlashlessFileName);
-	      }
-	      return NULL;
-	   }
-	   if (Length > sizeof(CurrentDir) / sizeof(WCHAR))
-	   {
-	      SearchPath = RtlAllocateHeap(hProcessHeap,
-	                                   HEAP_ZERO_MEMORY,
-					   Length * sizeof(WCHAR));
-	      if (NULL == SearchPath)
-	      {
-	         if (NULL != SlashlessFileName)
-	         {
-	            RtlFreeHeap(hProcessHeap,
-	                        0,
-	                        SlashlessFileName);
-	         }
-	         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-	         return NULL;
-	      }
-	      GetCurrentDirectoryW(Length, SearchPath);
-	   }
-	}
-	else
-	{
-	   CHECKPOINT;
-	   SearchPattern++;
-	   Length = SearchPattern - lpFileName;
-	   if (Length + 1 > sizeof(CurrentDir) / sizeof(WCHAR))
-	   {
-              SearchPath = RtlAllocateHeap(hProcessHeap,
-	                                   HEAP_ZERO_MEMORY,
-					   (Length + 1) * sizeof(WCHAR));
-	      if (NULL == SearchPath)
-	      {
-	         if (NULL != SlashlessFileName)
-	         {
-	            RtlFreeHeap(hProcessHeap,
-	                        0,
-	                        SlashlessFileName);
-	         }
-	         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-	         return NULL;
-	      }
-	   }
-           memcpy(SearchPath, lpFileName, Length * sizeof(WCHAR));
-	   SearchPath[Length] = 0;
-	}
-
-	bResult = RtlDosPathNameToNtPathName_U ((LPWSTR)SearchPath,
-	                                        &NtPathU,
-	                                        NULL,
-	                                        NULL);
-        if (SearchPath != CurrentDir)
-	{
-	   RtlFreeHeap(hProcessHeap,
-	               0,
-		       SearchPath);
-	}
-	if (FALSE == bResult)
-	{
-	   if (NULL != SlashlessFileName)
-	   {
-	      RtlFreeHeap(hProcessHeap,
-	                  0,
-	                  SlashlessFileName);
-	   }
-	   return NULL;
-	}
-
-	DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
-
-	IData = RtlAllocateHeap (hProcessHeap,
-	                         HEAP_ZERO_MEMORY,
-	                         sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
-	if (NULL == IData)
-	{
-	   RtlFreeHeap (hProcessHeap,
-	                0,
-	                NtPathU.Buffer);
-	   if (NULL != SlashlessFileName)
-	   {
-	      RtlFreeHeap(hProcessHeap,
-	                  0,
-	                  SlashlessFileName);
-	   }
-	   SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-	   return NULL;
-	}
-
-	/* change pattern: "*.*" --> "*" */
-	if (wcscmp (SearchPattern, L"*.*"))
-	{
-	    RtlInitUnicodeString(&PatternStr, SearchPattern);
-	}
-
-	DPRINT("NtPathU \'%S\' Pattern \'%S\'\n",
-	       NtPathU.Buffer, PatternStr.Buffer);
-
-	InitializeObjectAttributes (&ObjectAttributes,
-	                            &NtPathU,
-	                            0,
-	                            NULL,
-	                            NULL);
-
-	Status = NtOpenFile (&IData->DirectoryHandle,
-	                     FILE_LIST_DIRECTORY,
-	                     &ObjectAttributes,
-	                     &IoStatusBlock,
-	                     FILE_SHARE_READ|FILE_SHARE_WRITE,
-	                     FILE_DIRECTORY_FILE);
-
-	RtlFreeHeap (hProcessHeap,
-	             0,
-	             NtPathU.Buffer);
-
-	if (!NT_SUCCESS(Status))
-	{
-	   RtlFreeHeap (hProcessHeap, 0, IData);
-	   if (NULL != SlashlessFileName)
-	   {
-	      RtlFreeHeap(hProcessHeap,
-	                  0,
-	                  SlashlessFileName);
-	   }
-	   SetLastErrorByStatus (Status);
-	   return(NULL);
-	}
-	IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
-	IData->pFileInfo->FileIndex = 0;
-
-	Status = NtQueryDirectoryFile (IData->DirectoryHandle,
-	                               NULL,
-	                               NULL,
-	                               NULL,
-	                               &IoStatusBlock,
-	                               (PVOID)IData->pFileInfo,
-	                               FIND_DATA_SIZE,
-	                               FileBothDirectoryInformation,
-	                               TRUE,
-	                               &PatternStr,
-	                               TRUE);
-	if (NULL != SlashlessFileName)
-	{
-	   RtlFreeHeap(hProcessHeap,
-	               0,
-	               SlashlessFileName);
-	}
-	if (!NT_SUCCESS(Status))
-	{
-	   DPRINT("Status %lx\n", Status);
-	   CloseHandle (IData->DirectoryHandle);
-	   RtlFreeHeap (hProcessHeap, 0, IData);
-	   SetLastErrorByStatus (Status);
-	   return NULL;
-	}
-	DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
-
-	return IData;
-}
-
-
-/*
- * @implemented
- */
-HANDLE
-STDCALL
-FindFirstFileA (
-	LPCSTR			lpFileName,
-	LPWIN32_FIND_DATAA	lpFindFileData
-	)
-{
-	PKERNEL32_FIND_FILE_DATA IData;
-	UNICODE_STRING FileNameU;
-	ANSI_STRING FileName;
-
-	RtlInitAnsiString (&FileName,
-	                   (LPSTR)lpFileName);
-
-	/* convert ansi (or oem) string to unicode */
-	if (bIsFileApiAnsi)
-		RtlAnsiStringToUnicodeString (&FileNameU,
-		                              &FileName,
-		                              TRUE);
-	else
-		RtlOemStringToUnicodeString (&FileNameU,
-		                             &FileName,
-		                             TRUE);
-
-	IData = InternalFindFirstFile (FileNameU.Buffer);
-
-	RtlFreeUnicodeString (&FileNameU);
-
-	if (IData == NULL)
-	{
-		DPRINT("Failing request\n");
-		return INVALID_HANDLE_VALUE;
-	}
-
-	DPRINT("IData->pFileInfo->FileNameLength %d\n",
-	       IData->pFileInfo->FileNameLength);
-
-	/* copy data into WIN32_FIND_DATA structure */
-	lpFindFileData->dwFileAttributes = IData->pFileInfo->FileAttributes;
-
-	lpFindFileData->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
-	lpFindFileData->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
-
-	lpFindFileData->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
-	lpFindFileData->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
-
-	lpFindFileData->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
-	lpFindFileData->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
-
-	lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
-	lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
-
-	FileNameU.Length = IData->pFileInfo->FileNameLength;
-	FileNameU.MaximumLength = FileNameU.Length + sizeof(WCHAR);
-	FileNameU.Buffer = IData->pFileInfo->FileName;
-
-	FileName.Length = 0;
-	FileName.MaximumLength = MAX_PATH;
-	FileName.Buffer = lpFindFileData->cFileName;
-
-	/* convert unicode string to ansi (or oem) */
-	if (bIsFileApiAnsi)
-		RtlUnicodeStringToAnsiString (&FileName,
-		                              &FileNameU,
-		                              FALSE);
-	else
-		RtlUnicodeStringToOemString (&FileName,
-		                             &FileNameU,
-		                             FALSE);
-
-	DPRINT("IData->pFileInfo->ShortNameLength %d\n",
-	       IData->pFileInfo->ShortNameLength);
-
-	FileNameU.Length = IData->pFileInfo->ShortNameLength;
-	FileNameU.MaximumLength = FileNameU.Length + sizeof(WCHAR);
-	FileNameU.Buffer = IData->pFileInfo->ShortName;
-
-	FileName.Length = 0;
-	FileName.MaximumLength = 14;
-	FileName.Buffer = lpFindFileData->cAlternateFileName;
-
-	/* convert unicode string to ansi (or oem) */
-	if (bIsFileApiAnsi)
-		RtlUnicodeStringToAnsiString (&FileName,
-		                              &FileNameU,
-		                              FALSE);
-	else
-		RtlUnicodeStringToOemString (&FileName,
-		                             &FileNameU,
-		                             FALSE);
-
-	return (HANDLE)IData;
-}
-
-
-/*
- * @implemented
- */
 BOOL
 STDCALL
 FindNextFileA (
@@ -518,53 +197,86 @@
 	return TRUE;
 }
 
-
 /*
  * @implemented
  */
 HANDLE
 STDCALL
-FindFirstFileW (
-	LPCWSTR			lpFileName,
-	LPWIN32_FIND_DATAW	lpFindFileData
+FindFirstFileA (
+	LPCSTR			lpFileName,
+	LPWIN32_FIND_DATAA	lpFindFileData
 	)
 {
 	PKERNEL32_FIND_FILE_DATA IData;
+	UNICODE_STRING FileNameU;
+	ANSI_STRING FileName;
+	WIN32_FIND_DATAW FindFileData;
 
-	IData = InternalFindFirstFile (lpFileName);
-	if (IData == NULL)
-	{
-		DPRINT("Failing request\n");
-		return INVALID_HANDLE_VALUE;
-	}
+	RtlInitAnsiString (&FileName,
+	                   (LPSTR)lpFileName);
 
-	/* copy data into WIN32_FIND_DATA structure */
-	lpFindFileData->dwFileAttributes = IData->pFileInfo->FileAttributes;
+	/* convert ansi (or oem) string to unicode */
+	if (bIsFileApiAnsi)
+		RtlAnsiStringToUnicodeString (&FileNameU,
+		                              &FileName,
+		                              TRUE);
+	else
+		RtlOemStringToUnicodeString (&FileNameU,
+		                             &FileName,
+		                             TRUE);
 
-	lpFindFileData->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
-	lpFindFileData->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
+	IData = FindFirstFileExW(FileNameU.Buffer,
+							FindExInfoStandard,
+							&FindFileData,
+							FindExSearchNameMatch,
+							NULL,
+							0);
 
-	lpFindFileData->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
-	lpFindFileData->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
+	RtlFreeUnicodeString(&FileNameU);
 
-	lpFindFileData->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
-	lpFindFileData->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
+	if(INVALID_HANDLE_VALUE != IData)
+	{
+		RtlInitUnicodeString(&FileNameU, (PWSTR)FindFileData.cFileName);
+		FileName.Buffer = lpFindFileData->cFileName;
+		FileName.MaximumLength = MAX_PATH;
+		if (bIsFileApiAnsi)	{
+			RtlUnicodeStringToAnsiString (&FileName,
+										&FileNameU,
+										FALSE);
+		}
+		else
+		{
+			RtlUnicodeStringToOemString (&FileName,
+										&FileNameU,
+										FALSE);
+		}
+	}
 
-	lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
-	lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
 
-	memcpy (lpFindFileData->cFileName,
-	        IData->pFileInfo->FileName,
-	        IData->pFileInfo->FileNameLength);
-	lpFindFileData->cFileName[IData->pFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
-	memcpy (lpFindFileData->cAlternateFileName,
-	        IData->pFileInfo->ShortName,
-	        IData->pFileInfo->ShortNameLength);
-	lpFindFileData->cAlternateFileName[IData->pFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
-	return IData;
+	return (HANDLE)IData;
 }
 
+/*
+ * @implemented
+ */
+HANDLE
+STDCALL
+FindFirstFileW (
+	LPCWSTR			lpFileName,
+	LPWIN32_FIND_DATAW	lpFindFileData
+	)
+{
+	return FindFirstFileExW(
+				lpFileName,
+				FindExInfoStandard,
+				lpFindFileData,
+				FindExSearchNameMatch,
+                NULL,
+                0
+                );
+}
 
+
 /*
  * @implemented
  */
@@ -609,7 +321,7 @@
 	lpFindFileData->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
 	lpFindFileData->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
 
-        memcpy (lpFindFileData->cFileName,
+	memcpy (lpFindFileData->cFileName,
 	        IData->pFileInfo->FileName,
 	        IData->pFileInfo->FileNameLength);
 	lpFindFileData->cFileName[IData->pFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
@@ -622,40 +334,326 @@
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 HANDLE
 STDCALL
 FindFirstFileExW (
-	LPCWSTR			lpFileName,
-	FINDEX_INFO_LEVELS	fInfoLevelId,
-	LPVOID			lpFindFileData,
-	FINDEX_SEARCH_OPS	fSearchOp,
-	LPVOID			lpSearchFilter,
-	DWORD			dwAdditionalFlags
+	LPCWSTR lpFileName,
+	FINDEX_INFO_LEVELS fInfoLevelId,
+	LPVOID lpFindFileData,
+	FINDEX_SEARCH_OPS fSearchOp,
+	LPVOID lpSearchFilter,
+	DWORD dwAdditionalFlags
 	)
 {
-	/* FIXME */
-	return (HANDLE) 0;
+	PKERNEL32_FIND_FILE_DATA IData;
+	IO_STATUS_BLOCK IoStatusBlock;
+    NTSTATUS Status;
+	OBJECT_ATTRIBUTES ObjectAttributes;
+	UNICODE_STRING DosFilePath;
+    UNICODE_STRING NtName;
+	UNICODE_STRING FileNameU;
+	UNICODE_STRING NtFilePath;
+	PWSTR e1, e2;
+	WCHAR CurrentDir[256];
+	PWCHAR SlashlessFileName;
+	PWSTR SearchPath;
+	PWCHAR SearchPattern;
+	ULONG Length;
+
+/*
+.....
+.....
+.....
+*/
+	DPRINT("FindFirstFileExW(%S, %p, %p, %X, %p %d)\n",
+		lpFileName,
+		fInfoLevelId,
+		lpFindFileData,
+		fSearchOp,
+		lpSearchFilter,
+		dwAdditionalFlags);
+
+	RtlInitUnicodeString(&FileNameU, lpFileName);
+
+	Length = wcslen(lpFileName);
+	if (L'\\' == lpFileName[Length - 1])
+	{
+	    SlashlessFileName = RtlAllocateHeap(hProcessHeap, 0, Length * sizeof(WCHAR));
+	    if (NULL == SlashlessFileName)
+	    {
+	        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+	        return (INVALID_HANDLE_VALUE);
+	    }
+	    memcpy(SlashlessFileName, lpFileName, (Length - 1) * sizeof(WCHAR));
+	    SlashlessFileName[Length - 1] = L'\0';
+	    lpFileName = SlashlessFileName;
+	}
+	else
+	{
+	    SlashlessFileName = NULL;
+	}
+
+	e1 = wcsrchr(lpFileName, L'/');
+	e2 = wcsrchr(lpFileName, L'\\');
+	SearchPattern = max(e1, e2);
+	SearchPath = CurrentDir;
+
+	if (NULL == SearchPattern)
+	{
+		CHECKPOINT;
+		SearchPattern = (PWCHAR)lpFileName;
+		Length = GetCurrentDirectoryW(sizeof(CurrentDir) / sizeof(WCHAR), SearchPath);
+		if (0 == Length)
+		{
+			if (NULL != SlashlessFileName)	{
+				RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+			}
+			return (INVALID_HANDLE_VALUE);
+	   }
+	   if (Length > sizeof(CurrentDir) / sizeof(WCHAR))
+	   {
+			SearchPath = RtlAllocateHeap(hProcessHeap, HEAP_ZERO_MEMORY, Length * sizeof(WCHAR));
+			if (NULL == SearchPath)
+			{
+				if (NULL != SlashlessFileName) {
+					RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+				}
+				SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+				return (INVALID_HANDLE_VALUE);
+	      }
+	      GetCurrentDirectoryW(Length, SearchPath);
+	   }
+	}
+	else
+	{
+		CHECKPOINT;
+		SearchPattern++;
+		Length = SearchPattern - lpFileName;
+		if (Length + 1 > sizeof(CurrentDir) / sizeof(WCHAR))
+		{
+			SearchPath = RtlAllocateHeap(hProcessHeap, HEAP_ZERO_MEMORY, (Length + 1) * sizeof(WCHAR));
+			if (NULL == SearchPath)		{
+				if (NULL != SlashlessFileName)	{
+					RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+				}
+				SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+				return (INVALID_HANDLE_VALUE);
+			}
+		}
+		memcpy(SearchPath, lpFileName, Length * sizeof(WCHAR));
+		SearchPath[Length] = 0;
+	}
+
+	if( FALSE == RtlDosPathNameToNtPathName_U(
+											(PWSTR)SearchPath,
+											&NtName,
+											&DosFilePath.Buffer,
+											(PCURDIR)&NtFilePath
+											) )
+	{
+		RtlFreeHeap(hProcessHeap, 0, SearchPath);
+		if (NULL != SlashlessFileName) {
+			RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+		}
+		SetLastError(ERROR_PATH_NOT_FOUND);
+        return (INVALID_HANDLE_VALUE);
+	}
+
+
+	if (SearchPath != CurrentDir) {
+		RtlFreeHeap(hProcessHeap, 0, SearchPath);
+	}
+
+	DPRINT("NtName \'%S\'\n", NtName.Buffer);
+
+	IData = RtlAllocateHeap (hProcessHeap,
+	                         HEAP_ZERO_MEMORY,
+	                         sizeof(KERNEL32_FIND_FILE_DATA) + FIND_DATA_SIZE);
+	if (NULL == IData)
+	{
+	   RtlFreeHeap (hProcessHeap, 0, NtName.Buffer);
+	   if (NULL != SlashlessFileName)  {
+			RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+	   }
+	   SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+	   return (INVALID_HANDLE_VALUE);
+	}
+
+	/* change pattern: "*.*" --> "*" */
+	if (!wcscmp (SearchPattern, L"*.*")) {
+		RtlInitUnicodeString(&DosFilePath, L"*");
+	} else	{
+	    RtlInitUnicodeString(&DosFilePath, SearchPattern);
+	}
+
+	DPRINT("NtName \'%S\' DosFilePath \'%S\'\n",
+	       NtName.Buffer, DosFilePath.Buffer);
+
+	InitializeObjectAttributes( &ObjectAttributes,
+								&NtName,
+								dwAdditionalFlags,
+								NtFilePath.Buffer,
+								NULL );
+
+	Status =
+		NtOpenFile(
+					&IData->DirectoryHandle,
+					SYNCHRONIZE | FILE_LIST_DIRECTORY,
+					&ObjectAttributes,
+					&IoStatusBlock,
+					FILE_SHARE_READ | FILE_SHARE_WRITE,
+					FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT
+					);
+
+	if( !NT_SUCCESS(Status) )
+	{
+		DPRINT1("NtOpenFile() - failed (Status %lx)\n", Status);
+		SetLastError( Status );
+		return (INVALID_HANDLE_VALUE);
+	}
+
+	RtlFreeHeap(hProcessHeap, 0, NtName.Buffer);
+
+	if (!NT_SUCCESS(Status))
+	{
+		RtlFreeHeap (hProcessHeap, 0, IData);
+		if (NULL != SlashlessFileName)	{
+			RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+		}
+		SetLastErrorByStatus (Status);
+		return (INVALID_HANDLE_VALUE);
+	}
+	
+	if ( 0 == DosFilePath.Length ) {
+		DPRINT1("0 == DosFilePath.Length\n");
+		NtClose(IData->DirectoryHandle);
+		SetLastError(ERROR_FILE_NOT_FOUND);
+        return INVALID_HANDLE_VALUE;
+	}
+
+	IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
+	IData->pFileInfo->FileIndex = 0;
+	
+	Status =
+		NtQueryDirectoryFile(
+					IData->DirectoryHandle,
+					NULL,
+					NULL,
+					NULL,
+					&IoStatusBlock,
+					(PVOID)IData->pFileInfo,
+					FIND_DATA_SIZE,
+					FileBothDirectoryInformation,
+					TRUE,
+					&DosFilePath,
+					FALSE
+					);
+
+	if (NULL != SlashlessFileName)	{
+	   RtlFreeHeap(hProcessHeap, 0, SlashlessFileName);
+	}
+
+	if( !NT_SUCCESS(Status) ) {
+		DPRINT1("NtQueryDirectoryFile() - failed (Status %lx)\n", Status);
+		RtlFreeHeap(hProcessHeap, 0, IData);
+		NtClose(IData->DirectoryHandle);
+		SetLastError(Status);
+		return (INVALID_HANDLE_VALUE);
+	}
+
+	DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
+
+	/* copy data into WIN32_FIND_DATA structure */
+	((LPWIN32_FIND_DATAW)lpFindFileData)->dwFileAttributes = IData->pFileInfo->FileAttributes;
+
+	((LPWIN32_FIND_DATAW)lpFindFileData)->ftCreationTime.dwHighDateTime = IData->pFileInfo->CreationTime.u.HighPart;
+	((LPWIN32_FIND_DATAW)lpFindFileData)->ftCreationTime.dwLowDateTime = IData->pFileInfo->CreationTime.u.LowPart;
+
+	((LPWIN32_FIND_DATAW)lpFindFileData)->ftLastAccessTime.dwHighDateTime = IData->pFileInfo->LastAccessTime.u.HighPart;
+	((LPWIN32_FIND_DATAW)lpFindFileData)->ftLastAccessTime.dwLowDateTime = IData->pFileInfo->LastAccessTime.u.LowPart;
+
+	((LPWIN32_FIND_DATAW)lpFindFileData)->ftLastWriteTime.dwHighDateTime = IData->pFileInfo->LastWriteTime.u.HighPart;
+	((LPWIN32_FIND_DATAW)lpFindFileData)->ftLastWriteTime.dwLowDateTime = IData->pFileInfo->LastWriteTime.u.LowPart;
+
+	((LPWIN32_FIND_DATAW)lpFindFileData)->nFileSizeHigh = IData->pFileInfo->EndOfFile.u.HighPart;
+	((LPWIN32_FIND_DATAW)lpFindFileData)->nFileSizeLow = IData->pFileInfo->EndOfFile.u.LowPart;
+
+	memcpy (((LPWIN32_FIND_DATAW)lpFindFileData)->cFileName,
+	        IData->pFileInfo->FileName,
+	        IData->pFileInfo->FileNameLength);
+	((LPWIN32_FIND_DATAW)lpFindFileData)->cFileName[IData->pFileInfo->FileNameLength / sizeof(WCHAR)] = 0;
+	memcpy (((LPWIN32_FIND_DATAW)lpFindFileData)->cAlternateFileName,
+	        IData->pFileInfo->ShortName,
+	        IData->pFileInfo->ShortNameLength);
+	((LPWIN32_FIND_DATAW)lpFindFileData)->cAlternateFileName[IData->pFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
+
+
+    return (HANDLE)IData;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 HANDLE
 STDCALL
 FindFirstFileExA (
-	LPCSTR			lpFileName,
-	FINDEX_INFO_LEVELS	fInfoLevelId,
-	LPVOID			lpFindFileData,
-	FINDEX_SEARCH_OPS	fSearchOp,
-	LPVOID			lpSearchFilter,
-	DWORD			dwAdditionalFlags
+	LPCSTR lpFileName,
+	FINDEX_INFO_LEVELS fInfoLevelId,
+	LPVOID lpFindFileData,
+	FINDEX_SEARCH_OPS fSearchOp,
+	LPVOID lpSearchFilter,
+	DWORD dwAdditionalFlags
 	)
 {
-	/* FIXME */
-	return (HANDLE) 0;
+	PKERNEL32_FIND_FILE_DATA IData;
+	UNICODE_STRING FileNameU;
+	ANSI_STRING FileNameA;
+
+	RtlInitAnsiString (&FileNameA,
+	                   (LPSTR)lpFileName);
+
+	/* convert ansi (or oem) string to unicode */
+	if (bIsFileApiAnsi)
+		RtlAnsiStringToUnicodeString (&FileNameU,
+		                              &FileNameA,
+		                              TRUE);
+	else
+		RtlOemStringToUnicodeString (&FileNameU,
+		                             &FileNameA,
+		                             TRUE);
+
+	IData = FindFirstFileExW(
+				(LPCWSTR)FileNameU.Buffer, 
+				fInfoLevelId,
+				lpFindFileData,
+				fSearchOp,
+				lpSearchFilter,
+				dwAdditionalFlags
+				);
+
+	RtlFreeUnicodeString(&FileNameU);
+
+	if(INVALID_HANDLE_VALUE != IData)
+	{
+		RtlInitUnicodeString(&FileNameU, (PWSTR)((LPWIN32_FIND_DATAW)lpFindFileData)->cFileName);
+			FileNameU.Buffer = ((LPWIN32_FIND_DATAW)lpFindFileData)->cFileName;
+			FileNameU.MaximumLength = MAX_PATH;
+
+		/* convert unicode string to ansi (or oem) */
+		if (bIsFileApiAnsi)
+			RtlUnicodeStringToAnsiString (&FileNameA,
+				                          &FileNameU,
+					                      FALSE);
+		else
+			RtlUnicodeStringToOemString (&FileNameA,
+				                         &FileNameU,
+					                     FALSE);
+	}
+
+	return (HANDLE)IData;
 }