[NTFS]
[reactos.git] / reactos / drivers / filesystems / ntfs / dirctl.c
index f2cae37..b16348a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2002,2003 ReactOS Team
+ *  Copyright (C) 2002, 2003, 2014 ReactOS Team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -20,7 +20,9 @@
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/filesystem/ntfs/dirctl.c
  * PURPOSE:          NTFS filesystem driver
- * PROGRAMMER:       Eric Kohl
+ * PROGRAMMERS:      Eric Kohl
+ *                   Pierre Schweitzer (pierre@reactos.org)
+ *                   HervĂ© Poussineau (hpoussin@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
@@ -30,9 +32,6 @@
 #define NDEBUG
 #include <debug.h>
 
-/* GLOBALS *****************************************************************/
-
-
 /* FUNCTIONS ****************************************************************/
 
 #if 0
@@ -123,602 +122,457 @@ CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
 
   return(STATUS_SUCCESS);
 }
+#endif
 
 
 static NTSTATUS
-CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
-            PFCB Fcb,
-            PFCB Parent,
-            PWSTR FileToFind,
-            PULONG pDirIndex,
-            PULONG pDirIndex2)
-/*
- * FUNCTION: Find a file
- */
+NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
+                       PFILE_RECORD_HEADER FileRecord,
+                       PNTFS_ATTR_CONTEXT DataContext,
+                       PFILE_NAMES_INFORMATION Info,
+                       ULONG BufferLength)
 {
-  WCHAR name[256];
-  WCHAR TempStr[2];
-  PVOID Block;
-  NTSTATUS Status;
-  ULONG len;
-  ULONG DirIndex;
-  ULONG Offset;
-  ULONG Read;
-  BOOLEAN IsRoot;
-  PVOID Context = NULL;
-  ULONG DirSize;
-  PUCHAR Ptr;
-  PDIR_RECORD Record;
-  LARGE_INTEGER StreamOffset;
-
-  DPRINT("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n",
-        Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
-  DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",
-        Fcb->PathName, Fcb->ObjectName);
-
-  IsRoot = FALSE;
-  DirIndex = 0;
-  if (wcslen (FileToFind) == 0)
-    {
-      CHECKPOINT;
-      TempStr[0] = (WCHAR) '.';
-      TempStr[1] = 0;
-      FileToFind = (PWSTR)&TempStr;
-    }
-
-  if (Parent)
-    {
-      if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
-       {
-         IsRoot = TRUE;
-       }
-    }
-  else
-    {
-      IsRoot = TRUE;
-    }
-
-  if (IsRoot == TRUE)
-    {
-      StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
-      DirSize = DeviceExt->CdInfo.RootSize;
-
-
-      if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
-         || (FileToFind[0] == '.' && FileToFind[1] == 0))
-       {
-         /* it's root : complete essentials fields then return ok */
-         RtlZeroMemory(Fcb, sizeof(FCB));
-
-         Fcb->PathName[0]='\\';
-         Fcb->ObjectName = &Fcb->PathName[1];
-         Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
-         Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
-         Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;
-
-         if (pDirIndex)
-           *pDirIndex = 0;
-         if (pDirIndex2)
-           *pDirIndex2 = 0;
-         DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
-         return (STATUS_SUCCESS);
-       }
-    }
-  else
-    {
-      StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
-      DirSize = Parent->Entry.DataLengthL;
-    }
-
-  DPRINT("StreamOffset %I64u  DirSize %lu\n", StreamOffset.QuadPart, DirSize);
-
-  if (pDirIndex && (*pDirIndex))
-    DirIndex = *pDirIndex;
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName;
 
-  if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
-               BLOCKSIZE, TRUE, &Context, &Block))
-  {
-    DPRINT("CcMapData() failed\n");
-    return(STATUS_UNSUCCESSFUL);
-  }
+    DPRINT("NtfsGetNameInformation() called\n");
 
-  Ptr = (PUCHAR)Block;
-  while(TRUE)
-    {
-      Record = (PDIR_RECORD)Ptr;
-      if (Record->RecordLength == 0)
-       {
-         DPRINT1("Stopped!\n");
-         break;
-       }
-
-      DPRINT("RecordLength %u  ExtAttrRecordLength %u  NameLength %u\n",
-            Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
-
-      Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset,
-                               DirSize, (PVOID*)&Ptr, name, &DirIndex, pDirIndex2);
-      if (Status == STATUS_NO_MORE_ENTRIES)
-       {
-         break;
-       }
-      else if (Status == STATUS_UNSUCCESSFUL)
-       {
-         /* Note: the directory cache has already been unpinned */
-         return(Status);
-       }
-
-      DPRINT("Name '%S'\n", name);
-
-      if (wstrcmpjoki(name, FileToFind)) /* || wstrcmpjoki (name2, FileToFind)) */
-       {
-         if (Parent && Parent->PathName)
-           {
-             len = wcslen(Parent->PathName);
-             memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
-             Fcb->ObjectName=&Fcb->PathName[len];
-             if (len != 1 || Fcb->PathName[0] != '\\')
-               {
-                 Fcb->ObjectName[0] = '\\';
-                 Fcb->ObjectName = &Fcb->ObjectName[1];
-               }
-           }
-         else
-           {
-             Fcb->ObjectName=Fcb->PathName;
-             Fcb->ObjectName[0]='\\';
-             Fcb->ObjectName=&Fcb->ObjectName[1];
-           }
+    FileName = GetBestFileNameFromRecord(FileRecord);
+    ASSERT(FileName != NULL);
 
-         DPRINT("PathName '%S'  ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
+        return(STATUS_BUFFER_OVERFLOW);
 
-         memcpy(&Fcb->Entry, Ptr, sizeof(DIR_RECORD));
-         wcsncpy(Fcb->ObjectName, name, MAX_PATH);
-         if (pDirIndex)
-           *pDirIndex = DirIndex;
+    Info->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-         DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
-                Fcb->PathName, Fcb->ObjectName, DirIndex);
-
-         CcUnpinData(Context);
-
-         return(STATUS_SUCCESS);
-       }
-
-
-      Ptr = Ptr + Record->RecordLength;
-      DirIndex++;
-
-      if (((ULONG)Ptr - (ULONG)Block) >= DirSize)
-       {
-         DPRINT("Stopped!\n");
-         break;
-       }
-    }
-
-  CcUnpinData(Context);
-
-  if (pDirIndex)
-    *pDirIndex = DirIndex;
-
-  return(STATUS_UNSUCCESSFUL);
+    return(STATUS_SUCCESS);
 }
 
 
 static NTSTATUS
-CdfsGetNameInformation(PFCB Fcb,
-                      PDEVICE_EXTENSION DeviceExt,
-                      PFILE_NAMES_INFORMATION Info,
-                      ULONG BufferLength)
+NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
+                            PFILE_RECORD_HEADER FileRecord,
+                            PNTFS_ATTR_CONTEXT DataContext,
+                            ULONGLONG MFTIndex,
+                            PFILE_DIRECTORY_INFORMATION Info,
+                            ULONG BufferLength)
 {
-  ULONG Length;
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName;
+    PSTANDARD_INFORMATION StdInfo;
 
-  DPRINT("CdfsGetNameInformation() called\n");
+    DPRINT("NtfsGetDirectoryInformation() called\n");
 
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
+    FileName = GetBestFileNameFromRecord(FileRecord);
+    ASSERT(FileName != NULL);
 
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    ASSERT(StdInfo != NULL);
 
-  return(STATUS_SUCCESS);
-}
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
+        return(STATUS_BUFFER_OVERFLOW);
 
+    Info->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-static NTSTATUS
-CdfsGetDirectoryInformation(PFCB Fcb,
-                           PDEVICE_EXTENSION DeviceExt,
-                           PFILE_DIRECTORY_INFORMATION Info,
-                           ULONG BufferLength)
-{
-  ULONG Length;
-
-  DPRINT("CdfsGetDirectoryInformation() called\n");
-
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
-
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    Info->CreationTime.QuadPart = FileName->CreationTime;
+    Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+    Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+    Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
-  /* Convert file times */
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->CreationTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastAccessTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastWriteTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->ChangeTime);
+    /* Convert file flags */
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-  /* Convert file flags */
-  CdfsFileFlagsToAttributes(Fcb,
-                           &Info->FileAttributes);
+    Info->EndOfFile.QuadPart = FileName->AllocatedSize;
+    Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
 
-  Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
+    Info->FileIndex = MFTIndex;
 
-  /* Make AllocSize a rounded up multiple of the sector size */
-  Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
-
-//  Info->FileIndex=;
-
-  return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 
 static NTSTATUS
-CdfsGetFullDirectoryInformation(PFCB Fcb,
-                               PDEVICE_EXTENSION DeviceExt,
-                               PFILE_FULL_DIRECTORY_INFORMATION Info,
-                               ULONG BufferLength)
+NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
+                                PFILE_RECORD_HEADER FileRecord,
+                                PNTFS_ATTR_CONTEXT DataContext,
+                                ULONGLONG MFTIndex,
+                                PFILE_FULL_DIRECTORY_INFORMATION Info,
+                                ULONG BufferLength)
 {
-  ULONG Length;
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName;
+    PSTANDARD_INFORMATION StdInfo;
 
-  DPRINT("CdfsGetFullDirectoryInformation() called\n");
+    DPRINT("NtfsGetFullDirectoryInformation() called\n");
 
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
+    FileName = GetBestFileNameFromRecord(FileRecord);
+    ASSERT(FileName != NULL);
 
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    ASSERT(StdInfo != NULL);
 
-  /* Convert file times */
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->CreationTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastAccessTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastWriteTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->ChangeTime);
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
+        return(STATUS_BUFFER_OVERFLOW);
 
-  /* Convert file flags */
-  CdfsFileFlagsToAttributes(Fcb,
-                           &Info->FileAttributes);
+    Info->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-  Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
+    Info->CreationTime.QuadPart = FileName->CreationTime;
+    Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+    Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+    Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
-  /* Make AllocSize a rounded up multiple of the sector size */
-  Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
+    /* Convert file flags */
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-//  Info->FileIndex=;
-  Info->EaSize = 0;
+    Info->EndOfFile.QuadPart = FileName->AllocatedSize;
+    Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
 
-  return(STATUS_SUCCESS);
+    Info->FileIndex = MFTIndex;
+    Info->EaSize = 0;
+
+    return STATUS_SUCCESS;
 }
 
 
 static NTSTATUS
-CdfsGetBothDirectoryInformation(PFCB Fcb,
-                               PDEVICE_EXTENSION DeviceExt,
-                               PFILE_BOTH_DIRECTORY_INFORMATION Info,
-                               ULONG BufferLength)
+NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
+                                PFILE_RECORD_HEADER FileRecord,
+                                PNTFS_ATTR_CONTEXT DataContext,
+                                ULONGLONG MFTIndex,
+                                PFILE_BOTH_DIR_INFORMATION Info,
+                                ULONG BufferLength)
 {
-  ULONG Length;
-
-  DPRINT("CdfsGetBothDirectoryInformation() called\n");
-
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
-
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName, ShortFileName;
+    PSTANDARD_INFORMATION StdInfo;
 
-  /* Convert file times */
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->CreationTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastAccessTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastWriteTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->ChangeTime);
+    DPRINT("NtfsGetBothDirectoryInformation() called\n");
 
-  /* Convert file flags */
-  CdfsFileFlagsToAttributes(Fcb,
-                           &Info->FileAttributes);
+    FileName = GetBestFileNameFromRecord(FileRecord);
+    ASSERT(FileName != NULL);
+    ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
 
-  Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
+    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    ASSERT(StdInfo != NULL);
 
-  /* Make AllocSize a rounded up multiple of the sector size */
-  Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
+        return(STATUS_BUFFER_OVERFLOW);
 
-//  Info->FileIndex=;
-  Info->EaSize = 0;
+    Info->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-  if (DeviceExt->CdInfo.JolietLevel == 0)
+    if (ShortFileName)
     {
-      /* Standard ISO-9660 format */
-      Info->ShortNameLength = Length;
-      memcpy(Info->ShortName, Fcb->ObjectName, Length);
+        /* Should we upcase the filename? */
+        ASSERT(ShortFileName->NameLength <= ARRAYSIZE(Info->ShortName));
+        Info->ShortNameLength = ShortFileName->NameLength * sizeof(WCHAR);
+        RtlCopyMemory(Info->ShortName, ShortFileName->Name, Info->ShortNameLength);
     }
-  else
+    else
     {
-      /* Joliet extension */
+        Info->ShortName[0] = 0;
+        Info->ShortNameLength = 0;
+    }
 
-      /* FIXME: Copy or create a short file name */
+    Info->CreationTime.QuadPart = FileName->CreationTime;
+    Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+    Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+    Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
-      Info->ShortName[0] = 0;
-      Info->ShortNameLength = 0;
-    }
+    /* Convert file flags */
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-  return(STATUS_SUCCESS);
+    Info->EndOfFile.QuadPart = FileName->AllocatedSize;
+    Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
+
+    Info->FileIndex = MFTIndex;
+    Info->EaSize = 0;
+
+    return STATUS_SUCCESS;
 }
-#endif
+
 
 NTSTATUS
 NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
 {
-  PIRP Irp;
-  //PDEVICE_OBJECT DeviceObject;
-  //PDEVICE_EXTENSION DeviceExtension;
-  //LONG BufferLength = 0;
-  PUNICODE_STRING SearchPattern = NULL;
-  //FILE_INFORMATION_CLASS FileInformationClass;
-  ULONG FileIndex = 0;
-  PUCHAR Buffer = NULL;
-  PFILE_NAMES_INFORMATION Buffer0 = NULL;
-  //PNTFS_FCB Fcb;
-  PNTFS_CCB Ccb;
-//  FCB TempFcb;
-  BOOLEAN First = FALSE;
-  PIO_STACK_LOCATION Stack;
-  PFILE_OBJECT FileObject;
-  //NTSTATUS Status = STATUS_SUCCESS;
-
-  DPRINT1("NtfsQueryDirectory() called\n");
-
-  ASSERT(IrpContext);
-  Irp = IrpContext->Irp;
-  //DeviceObject = IrpContext->DeviceObject;
-
-  //DeviceExtension = DeviceObject->DeviceExtension;
-  Stack = IoGetCurrentIrpStackLocation(Irp);
-  FileObject = Stack->FileObject;
-
-  Ccb = (PNTFS_CCB)FileObject->FsContext2;
-  //Fcb = (PNTFS_FCB)FileObject->FsContext;
-
-  /* Obtain the callers parameters */
-  //BufferLength = Stack->Parameters.QueryDirectory.Length;
-  SearchPattern = Stack->Parameters.QueryDirectory.FileName;
-  //FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
-  FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
-
-
-  if (SearchPattern != NULL)
-  {
-    if (!Ccb->DirectorySearchPattern)
+    PIRP Irp;
+    PDEVICE_OBJECT DeviceObject;
+    PDEVICE_EXTENSION DeviceExtension;
+    LONG BufferLength = 0;
+    PUNICODE_STRING SearchPattern = NULL;
+    FILE_INFORMATION_CLASS FileInformationClass;
+    ULONG FileIndex = 0;
+    PUCHAR Buffer = NULL;
+    PFILE_NAMES_INFORMATION Buffer0 = NULL;
+    PNTFS_FCB Fcb;
+    PNTFS_CCB Ccb;
+    BOOLEAN First = FALSE;
+    PIO_STACK_LOCATION Stack;
+    PFILE_OBJECT FileObject;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PFILE_RECORD_HEADER FileRecord;
+    PNTFS_ATTR_CONTEXT DataContext;
+    ULONGLONG MFTRecord, OldMFTRecord = 0;
+    UNICODE_STRING Pattern;
+
+    DPRINT1("NtfsQueryDirectory() called\n");
+
+    ASSERT(IrpContext);
+    Irp = IrpContext->Irp;
+    DeviceObject = IrpContext->DeviceObject;
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+    FileObject = Stack->FileObject;
+
+    Ccb = (PNTFS_CCB)FileObject->FsContext2;
+    Fcb = (PNTFS_FCB)FileObject->FsContext;
+
+    /* Obtain the callers parameters */
+    BufferLength = Stack->Parameters.QueryDirectory.Length;
+    SearchPattern = Stack->Parameters.QueryDirectory.FileName;
+    FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
+    FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
+
+    if (SearchPattern != NULL)
     {
-      First = TRUE;
-      Ccb->DirectorySearchPattern =
-        ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_NTFS);
-      if (!Ccb->DirectorySearchPattern)
-      {
-        return(STATUS_INSUFFICIENT_RESOURCES);
-      }
-
-      memcpy(Ccb->DirectorySearchPattern,
-             SearchPattern->Buffer,
-             SearchPattern->Length);
-      Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
+        if (!Ccb->DirectorySearchPattern)
+        {
+            First = TRUE;
+            Pattern.Length = 0;
+            Pattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
+            Ccb->DirectorySearchPattern = Pattern.Buffer =
+                ExAllocatePoolWithTag(NonPagedPool, Pattern.MaximumLength, TAG_NTFS);
+            if (!Ccb->DirectorySearchPattern)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            memcpy(Ccb->DirectorySearchPattern, SearchPattern->Buffer, SearchPattern->Length);
+            Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
+        }
     }
-  }
-  else if (!Ccb->DirectorySearchPattern)
-  {
-    First = TRUE;
-    Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
-    if (!Ccb->DirectorySearchPattern)
+    else if (!Ccb->DirectorySearchPattern)
     {
-      return(STATUS_INSUFFICIENT_RESOURCES);
+        First = TRUE;
+        Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
+        if (!Ccb->DirectorySearchPattern)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        Ccb->DirectorySearchPattern[0] = L'*';
+        Ccb->DirectorySearchPattern[1] = 0;
     }
-    Ccb->DirectorySearchPattern[0] = L'*';
-    Ccb->DirectorySearchPattern[1] = 0;
-  }
-  DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
-
-  /* Determine directory index */
-  if (Stack->Flags & SL_INDEX_SPECIFIED)
-  {
-    Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
-  }
-  else if (First || (Stack->Flags & SL_RESTART_SCAN))
-  {
-    Ccb->Entry = 0;
-  }
-
-  /* Determine Buffer for result */
-  if (Irp->MdlAddress)
-  {
-    Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
-  }
-  else
-  {
-    Buffer = Irp->UserBuffer;
-  }
-  DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
-#if 0
-  TempFcb.ObjectName = TempFcb.PathName;
-  while (Status == STATUS_SUCCESS && BufferLength > 0)
-    {
-      Status = CdfsFindFile(DeviceExtension,
-                           &TempFcb,
-                           Fcb,
-                           Ccb->DirectorySearchPattern,
-                           &Ccb->Entry,
-                           NULL);
-      DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
-
-      if (NT_SUCCESS(Status))
-       {
-         switch (FileInformationClass)
-           {
-             case FileNameInformation:
-               Status = CdfsGetNameInformation(&TempFcb,
-                                               DeviceExtension,
-                                               (PFILE_NAMES_INFORMATION)Buffer,
-                                               BufferLength);
-               break;
-
-             case FileDirectoryInformation:
-               Status = CdfsGetDirectoryInformation(&TempFcb,
-                                                    DeviceExtension,
-                                                    (PFILE_DIRECTORY_INFORMATION)Buffer,
-                                                    BufferLength);
-               break;
-
-             case FileFullDirectoryInformation:
-               Status = CdfsGetFullDirectoryInformation(&TempFcb,
-                                                        DeviceExtension,
-                                                        (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
-                                                        BufferLength);
-               break;
-
-             case FileBothDirectoryInformation:
-               Status = NtfsGetBothDirectoryInformation(&TempFcb,
-                                                        DeviceExtension,
-                                                        (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,
-                                                        BufferLength);
-               break;
-
-             default:
-               Status = STATUS_INVALID_INFO_CLASS;
-           }
 
-         if (Status == STATUS_BUFFER_OVERFLOW)
-           {
-             if (Buffer0)
-               {
-                 Buffer0->NextEntryOffset = 0;
-               }
-             break;
-           }
-       }
-      else
-       {
-         if (Buffer0)
-           {
-             Buffer0->NextEntryOffset = 0;
-           }
+    RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
+    DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
+    DPRINT("In: '%S'\n", Fcb->PathName);
 
-         if (First)
-           {
-             Status = STATUS_NO_SUCH_FILE;
-           }
-         else
-           {
-             Status = STATUS_NO_MORE_FILES;
-           }
-         break;
-       }
+    /* Determine directory index */
+    if (Stack->Flags & SL_INDEX_SPECIFIED)
+    {
+        Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
+    }
+    else if (First || (Stack->Flags & SL_RESTART_SCAN))
+    {
+        Ccb->Entry = 0;
+    }
+
+    /* Determine Buffer for result */
+    if (Irp->MdlAddress)
+    {
+        Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
+    }
+    else
+    {
+        Buffer = Irp->UserBuffer;
+    }
 
-      Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
-      Buffer0->FileIndex = FileIndex++;
-      Ccb->Entry++;
+    DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
 
-      if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
-       {
-         break;
-       }
-      BufferLength -= Buffer0->NextEntryOffset;
-      Buffer += Buffer0->NextEntryOffset;
+    while (Status == STATUS_SUCCESS && BufferLength > 0)
+    {
+        Status = NtfsFindFileAt(DeviceExtension,
+                                &Pattern,
+                                &Ccb->Entry,
+                                &FileRecord,
+                                &DataContext,
+                                &MFTRecord,
+                                Fcb->MFTIndex);
+
+        if (NT_SUCCESS(Status))
+        {
+            /* HACK: files with both a short name and a long name are present twice in the index.
+             * Ignore the second entry, if it is immediately following the first one.
+             */
+            if (MFTRecord == OldMFTRecord)
+            {
+                DPRINT("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
+                Ccb->Entry++;
+                ExFreePoolWithTag(FileRecord, TAG_NTFS);
+                continue;
+            }
+            OldMFTRecord = MFTRecord;
+
+            switch (FileInformationClass)
+            {
+                case FileNameInformation:
+                    Status = NtfsGetNameInformation(DeviceExtension,
+                                                    FileRecord,
+                                                    DataContext,
+                                                    (PFILE_NAMES_INFORMATION)Buffer,
+                                                    BufferLength);
+                    break;
+
+                case FileDirectoryInformation:
+                    Status = NtfsGetDirectoryInformation(DeviceExtension,
+                                                         FileRecord,
+                                                         DataContext,
+                                                         MFTRecord,
+                                                         (PFILE_DIRECTORY_INFORMATION)Buffer,
+                                                         BufferLength);
+                    break;
+
+                case FileFullDirectoryInformation:
+                    Status = NtfsGetFullDirectoryInformation(DeviceExtension,
+                                                             FileRecord,
+                                                             DataContext,
+                                                             MFTRecord,
+                                                             (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
+                                                             BufferLength);
+                    break;
+
+                case FileBothDirectoryInformation:
+                    Status = NtfsGetBothDirectoryInformation(DeviceExtension,
+                                                             FileRecord,
+                                                             DataContext,
+                                                             MFTRecord,
+                                                             (PFILE_BOTH_DIR_INFORMATION)Buffer,
+                                                             BufferLength);
+                    break;
+
+                default:
+                    Status = STATUS_INVALID_INFO_CLASS;
+            }
+
+            if (Status == STATUS_BUFFER_OVERFLOW)
+            {
+                if (Buffer0)
+                {
+                    Buffer0->NextEntryOffset = 0;
+                }
+                break;
+            }
+        }
+        else
+        {
+            if (Buffer0)
+            {
+                Buffer0->NextEntryOffset = 0;
+            }
+
+            if (First)
+            {
+                Status = STATUS_NO_SUCH_FILE;
+            }
+            else
+            {
+                Status = STATUS_NO_MORE_FILES;
+            }
+            break;
+        }
+
+        Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
+        Buffer0->FileIndex = FileIndex++;
+        Ccb->Entry++;
+
+        if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
+        {
+            break;
+        }
+        BufferLength -= Buffer0->NextEntryOffset;
+        Buffer += Buffer0->NextEntryOffset;
+        ExFreePoolWithTag(FileRecord, TAG_NTFS);
     }
-#endif
 
-  if (Buffer0)
-  {
-    Buffer0->NextEntryOffset = 0;
-  }
+    if (Buffer0)
+    {
+        Buffer0->NextEntryOffset = 0;
+    }
 
-  if (FileIndex > 0)
-  {
-    //Status = STATUS_SUCCESS;
-  }
+    if (FileIndex > 0)
+    {
+        Status = STATUS_SUCCESS;
+    }
 
-//  return(Status);
-  return(STATUS_NO_MORE_FILES);
+    return Status;
 }
 
 
-
-NTSTATUS NTAPI
+NTSTATUS
+NTAPI
 NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
                         PIRP Irp)
 {
-  PNTFS_IRP_CONTEXT IrpContext = NULL;
-  NTSTATUS Status = STATUS_UNSUCCESSFUL;
+    PNTFS_IRP_CONTEXT IrpContext = NULL;
+    NTSTATUS Status = STATUS_UNSUCCESSFUL;
 
-  DPRINT1("NtfsDirectoryControl() called\n");
+    DPRINT1("NtfsDirectoryControl() called\n");
 
-  FsRtlEnterFileSystem();
-  ASSERT(DeviceObject);
-  ASSERT(Irp);
+    FsRtlEnterFileSystem();
+    ASSERT(DeviceObject);
+    ASSERT(Irp);
 
-  NtfsIsIrpTopLevel(Irp);
+    NtfsIsIrpTopLevel(Irp);
 
-  IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
-  if (IrpContext)
-  {
-    switch (IrpContext->MinorFunction)
+    IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
+    if (IrpContext)
     {
-      case IRP_MN_QUERY_DIRECTORY:
-        Status = NtfsQueryDirectory(IrpContext);
-        break;
-      
-      case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
-        DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
-        Status = STATUS_NOT_IMPLEMENTED;
-        break;
-        
-      default:
-        Status = STATUS_INVALID_DEVICE_REQUEST;
-        break;
+        switch (IrpContext->MinorFunction)
+        {
+            case IRP_MN_QUERY_DIRECTORY:
+                Status = NtfsQueryDirectory(IrpContext);
+                break;
+
+            case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
+                DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
+                Status = STATUS_NOT_IMPLEMENTED;
+                break;
+
+            default:
+                Status = STATUS_INVALID_DEVICE_REQUEST;
+                break;
+        }
     }
-  }
-  else
-    Status = STATUS_INSUFFICIENT_RESOURCES;
-  
-  Irp->IoStatus.Status = Status;
-  Irp->IoStatus.Information = 0;
-  IoCompleteRequest(Irp, IO_NO_INCREMENT);
-  
-  if (IrpContext)
-    ExFreePoolWithTag(IrpContext, 'PRIN');
-  
-  IoSetTopLevelIrp(NULL);
-  FsRtlExitFileSystem();
-  return Status;
+    else
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    if (IrpContext)
+        ExFreePoolWithTag(IrpContext, 'PRIN');
+
+    IoSetTopLevelIrp(NULL);
+    FsRtlExitFileSystem();
+    return Status;
 }
 
 /* EOF */