[NTFS] - In the NtfsAddFilenameToDirectory() function, rename DirectoryContext parame...
[reactos.git] / drivers / filesystems / ntfs / dirctl.c
index 7024e00..4d19052 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 *****************************************************************/
 
 /* FUNCTIONS ****************************************************************/
 
-#if 0
-static NTSTATUS
-CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
-                PVOID *Context,
-                PVOID *Block,
-                PLARGE_INTEGER StreamOffset,
-                ULONG DirLength,
-                PVOID *Ptr,
-                PWSTR Name,
-                PULONG pIndex,
-                PULONG pIndex2)
-/*
- * FUNCTION: Retrieves the file name, be it in short or long file name format
- */
+/**
+* @name NtfsAddFilenameToDirectory
+* @implemented
+*
+* Adds a $FILE_NAME attribute to a given directory index.
+*
+* @param DeviceExt
+* Points to the target disk's DEVICE_EXTENSION.
+*
+* @param DirectoryMftIndex
+* Mft index of the parent directory which will receive the file.
+*
+* @param FileReferenceNumber
+* File reference of the file to be added to the directory. This is a combination of the 
+* Mft index and sequence number.
+*
+* @param FilenameAttribute
+* Pointer to the FILENAME_ATTRIBUTE of the file being added to the directory.
+*
+* @return
+* STATUS_SUCCESS on success.
+* STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
+* STATUS_NOT_IMPLEMENTED if target address isn't at the end of the given file record.
+*
+* @remarks
+* WIP - Can only support an empty directory.
+* One FILENAME_ATTRIBUTE is added to the directory's index for each link to that file. So, each
+* file which contains one FILENAME_ATTRIBUTE for a long name and another for the 8.3 name, will
+* get both attributes added to its parent directory.
+*/
+NTSTATUS
+NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
+                           ULONGLONG DirectoryMftIndex,
+                           ULONGLONG FileReferenceNumber,
+                           PFILENAME_ATTRIBUTE FilenameAttribute)
 {
-  PDIR_RECORD Record;
-  NTSTATUS Status;
-  ULONG Index = 0;
-  ULONG Offset = 0;
-  ULONG BlockOffset = 0;
-
-  Record = (PDIR_RECORD)*Block;
-  while(Index < *pIndex)
+    NTSTATUS Status = STATUS_SUCCESS;
+    PFILE_RECORD_HEADER ParentFileRecord;
+    PNTFS_ATTR_CONTEXT IndexRootContext;
+    PINDEX_ROOT_ATTRIBUTE I30IndexRoot;
+    ULONG IndexRootOffset;
+    ULONGLONG I30IndexRootLength;
+    PINDEX_ENTRY_ATTRIBUTE IndexNodeEntry;
+    ULONG LengthWritten;
+    PNTFS_ATTR_RECORD DestinationAttribute;
+    PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
+    ULONG AttributeLength;
+    PNTFS_ATTR_RECORD NextAttribute;
+
+    // Allocate memory for the parent directory
+    ParentFileRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                             DeviceExt->NtfsInfo.BytesPerFileRecord,
+                                             TAG_NTFS);
+    if (!ParentFileRecord)
     {
-      BlockOffset += Record->RecordLength;
-      Offset += Record->RecordLength;
-
-      Record = (PDIR_RECORD)(*Block + BlockOffset);
-      if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
-       {
-         DPRINT("Map next sector\n");
-         CcUnpinData(*Context);
-         StreamOffset->QuadPart += BLOCKSIZE;
-         Offset = ROUND_UP(Offset, BLOCKSIZE);
-         BlockOffset = 0;
-
-         if (!CcMapData(DeviceExt->StreamFileObject,
-                        StreamOffset,
-                        BLOCKSIZE, TRUE,
-                        Context, Block))
-           {
-             DPRINT("CcMapData() failed\n");
-             return(STATUS_UNSUCCESSFUL);
-           }
-         Record = (PDIR_RECORD)(*Block + BlockOffset);
-       }
-
-      if (Offset >= DirLength)
-       return(STATUS_NO_MORE_ENTRIES);
-
-      Index++;
+        DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-  DPRINT("Index %lu  RecordLength %lu  Offset %lu\n",
-        Index, Record->RecordLength, Offset);
-
-  if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
-    {
-      wcscpy(Name, L".");
-    }
-  else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
+    // Open the parent directory
+    Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+    if (!NT_SUCCESS(Status))
     {
-      wcscpy(Name, L"..");
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        DPRINT1("ERROR: Couldn't read parent directory with index %I64u\n",
+                DirectoryMftIndex);
+        return Status;
     }
-  else
+
+    DPRINT1("Dumping old parent file record:\n");
+    NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
+
+    // Find the index root attribute for the directory
+    Status = FindAttribute(DeviceExt,
+                           ParentFileRecord,
+                           AttributeIndexRoot,
+                           L"$I30",
+                           4,
+                           &IndexRootContext,
+                           &IndexRootOffset);
+    if (!NT_SUCCESS(Status))
     {
-      if (DeviceExt->CdInfo.JolietLevel == 0)
-       {
-         ULONG i;
-
-         for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
-           Name[i] = (WCHAR)Record->FileId[i];
-         Name[i] = 0;
-       }
-      else
-       {
-         CdfsSwapString(Name, Record->FileId, Record->FileIdLength);
-       }
+        DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent directory with MFT #: %I64u!\n",
+                DirectoryMftIndex);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return Status;
     }
 
-  DPRINT("Name '%S'\n", Name);
-
-  *Ptr = Record;
-
-  *pIndex = Index;
-
-  return(STATUS_SUCCESS);
-}
+    I30IndexRootLength = AttributeDataLength(&IndexRootContext->Record);
 
+    // Allocate memory for the index root data
+    I30IndexRoot = (PINDEX_ROOT_ATTRIBUTE)ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS);
+    if (!I30IndexRoot)
+    {
+        DPRINT1("ERROR: Couldn't allocate memory for index root attribute!\n");
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+    }
 
-static NTSTATUS
-CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
-            PFCB Fcb,
-            PFCB Parent,
-            PWSTR FileToFind,
-            PULONG pDirIndex,
-            PULONG pDirIndex2)
-/*
- * FUNCTION: Find a file
- */
-{
-  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)
+    // Read the Index Root
+    Status = ReadAttribute(DeviceExt, IndexRootContext, 0, (PCHAR)I30IndexRoot, I30IndexRootLength);
+    if (!NT_SUCCESS(Status))
     {
-      CHECKPOINT;
-      TempStr[0] = (WCHAR) '.';
-      TempStr[1] = 0;
-      FileToFind = (PWSTR)&TempStr;
+        DPRINT1("ERROR: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex);
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return Status;
     }
 
-  if (Parent)
+    // Make sure it's empty (temporarily)
+    IndexNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)I30IndexRoot + I30IndexRoot->Header.FirstEntryOffset + 0x10);
+    if (IndexNodeEntry->Data.Directory.IndexedFile != 0 || IndexNodeEntry->Flags != 2)
+    {
+        DPRINT1("FIXME: File-creation is only supported in empty directories right now! Be patient! :)\n");
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return STATUS_NOT_IMPLEMENTED;
+    }
+    
+    // Now we need to setup a new index root attribute to replace the old one
+    NewIndexRoot = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
+    if (!NewIndexRoot)
+    {
+        DPRINT1("ERROR: Unable to allocate memory for new index root attribute!\n");
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    
+    // Setup the new index record
+    RtlZeroMemory(NewIndexRoot, DeviceExt->NtfsInfo.BytesPerIndexRecord);   // shouldn't be necessary but aids in debugging
+
+    NewIndexRoot->AttributeType = AttributeFileName;
+    NewIndexRoot->CollationRule = COLLATION_FILE_NAME;
+    NewIndexRoot->SizeOfEntry = DeviceExt->NtfsInfo.BytesPerIndexRecord;
+    // If Bytes per index record is less than cluster size, clusters per index record becomes sectors per index
+    if(NewIndexRoot->SizeOfEntry < DeviceExt->NtfsInfo.BytesPerCluster)
+        NewIndexRoot->ClustersPerIndexRecord = NewIndexRoot->SizeOfEntry / DeviceExt->NtfsInfo.BytesPerSector;
+    else    
+        NewIndexRoot->ClustersPerIndexRecord = NewIndexRoot->SizeOfEntry / DeviceExt->NtfsInfo.BytesPerCluster;
+
+    // Setup the Index node header
+    NewIndexRoot->Header.FirstEntryOffset = 0x10;
+    NewIndexRoot->Header.Flags = INDEX_ROOT_SMALL;
+    // still need to calculate sizes
+
+    // The first index node entry will be for the filename we're adding
+    IndexNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)NewIndexRoot + NewIndexRoot->Header.FirstEntryOffset + 0x10);
+    IndexNodeEntry->Data.Directory.IndexedFile = FileReferenceNumber;
+    IndexNodeEntry->Flags = INDEX_ROOT_SMALL;
+    IndexNodeEntry->KeyLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + (2 * FilenameAttribute->NameLength);
+    IndexNodeEntry->Length = ALIGN_UP_BY(IndexNodeEntry->KeyLength, 8) + FIELD_OFFSET(INDEX_ENTRY_ATTRIBUTE, FileName);
+
+    // Now we can calculate the Node length (temp logic)
+    NewIndexRoot->Header.TotalSizeOfEntries = NewIndexRoot->Header.FirstEntryOffset + IndexNodeEntry->Length + 0x10;
+    NewIndexRoot->Header.AllocatedSize = NewIndexRoot->Header.TotalSizeOfEntries;
+
+    DPRINT1("New Index Node Entry Stream Length: %u\nNew Inde Node Entry Length: %u\n",
+            IndexNodeEntry->KeyLength,
+            IndexNodeEntry->Length);
+
+    // copy over the attribute proper
+    RtlCopyMemory(&IndexNodeEntry->FileName, FilenameAttribute, IndexNodeEntry->KeyLength);
+
+    // Now setup the dummy key
+    IndexNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexNodeEntry + IndexNodeEntry->Length);
+
+    IndexNodeEntry->Data.Directory.IndexedFile = 0;
+    IndexNodeEntry->Length = 0x10;
+    IndexNodeEntry->KeyLength = 0;
+    IndexNodeEntry->Flags = NTFS_INDEX_ENTRY_END;
+
+    // This is when we'd normally setup the length (already done above)
+
+    // Write back the new index root attribute to the parent directory file record
+
+    // First, we need to make sure the attribute is large enough.
+    // We can't set the size as we normally would, because if we extend past the file record, 
+    // we must create an index allocation and index bitmap (TODO). Also TODO: support file records with
+    // $ATTRIBUTE_LIST's.
+    AttributeLength = NewIndexRoot->Header.AllocatedSize + FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header);
+    DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset);
+
+    NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length);
+    if (NextAttribute->Type != AttributeEnd)
     {
-      if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
-       {
-         IsRoot = TRUE;
-       }
+        DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n");
+        ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return STATUS_NOT_IMPLEMENTED;
     }
-  else
+    
+    // Update the length of the attribute in the file record of the parent directory
+    InternalSetResidentAttributeLength(IndexRootContext,
+                                       ParentFileRecord,
+                                       IndexRootOffset,
+                                       AttributeLength);
+
+    Status = UpdateFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+    if (!NT_SUCCESS(Status))
     {
-      IsRoot = TRUE;
+        DPRINT1("ERROR: Failed to update file record of directory with index: %llx\n", DirectoryMftIndex);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        return Status;
     }
 
-  if (IsRoot == TRUE)
+    // Update the parent directory with the new index root
+    Status = WriteAttribute(DeviceExt,
+                            IndexRootContext,
+                            0,
+                            (PUCHAR)NewIndexRoot,
+                            AttributeLength,
+                            &LengthWritten);
+    if (!NT_SUCCESS(Status) )
     {
-      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);
-       }
+        DPRINT1("ERROR: Unable to write new index root attribute to parent directory!\n");
+        ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return Status;
     }
-  else
+    
+    // re-read the parent file record, so we can dump it
+    Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("ERROR: Couldn't read parent directory after messing with it!\n");
+    }
+    else
     {
-      StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
-      DirSize = Parent->Entry.DataLengthL;
+        DPRINT1("Dumping new parent file record:\n");
+        NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
     }
 
-  DPRINT("StreamOffset %I64u  DirSize %lu\n", StreamOffset.QuadPart, DirSize);
+    // Cleanup
+    ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+    ReleaseAttributeContext(IndexRootContext);
+    ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+    ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
 
-  if (pDirIndex && (*pDirIndex))
-    DirIndex = *pDirIndex;
+    return Status;
+}
 
-  if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
-               BLOCKSIZE, TRUE, &Context, &Block))
-  {
-    DPRINT("CcMapData() failed\n");
-    return(STATUS_UNSUCCESSFUL);
-  }
+ULONGLONG
+NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
+                PFILE_RECORD_HEADER FileRecord,
+                PCWSTR Stream,
+                ULONG StreamLength,
+                PULONGLONG AllocatedSize)
+{
+    ULONGLONG Size = 0ULL;
+    ULONGLONG Allocated = 0ULL;
+    NTSTATUS Status;
+    PNTFS_ATTR_CONTEXT DataContext;
 
-  Ptr = (PUCHAR)Block;
-  while(TRUE)
+    Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Stream, StreamLength, &DataContext, NULL);
+    if (NT_SUCCESS(Status))
     {
-      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];
-           }
-
-         DPRINT("PathName '%S'  ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
-
-         memcpy(&Fcb->Entry, Ptr, sizeof(DIR_RECORD));
-         wcsncpy(Fcb->ObjectName, name, MAX_PATH);
-         if (pDirIndex)
-           *pDirIndex = DirIndex;
-
-         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;
-       }
+        Size = AttributeDataLength(&DataContext->Record);
+        Allocated = AttributeAllocatedLength(&DataContext->Record);
+        ReleaseAttributeContext(DataContext);
     }
 
-  CcUnpinData(Context);
+    if (AllocatedSize != NULL) *AllocatedSize = Allocated;
 
-  if (pDirIndex)
-    *pDirIndex = DirIndex;
-
-  return(STATUS_UNSUCCESSFUL);
+    return Size;
 }
 
 
 static NTSTATUS
-CdfsGetNameInformation(PFCB Fcb,
-                      PDEVICE_EXTENSION DeviceExt,
-                      PFILE_NAMES_INFORMATION Info,
-                      ULONG BufferLength)
+NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
+                       PFILE_RECORD_HEADER FileRecord,
+                       ULONGLONG MFTIndex,
+                       PFILE_NAMES_INFORMATION Info,
+                       ULONG BufferLength)
 {
-  ULONG Length;
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName;
+
+    DPRINT("NtfsGetNameInformation() called\n");
 
-  DPRINT("CdfsGetNameInformation() called\n");
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
+    if (FileName == NULL)
+    {
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
 
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_NAMES_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->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-  return(STATUS_SUCCESS);
+    return(STATUS_SUCCESS);
 }
 
 
 static NTSTATUS
-CdfsGetDirectoryInformation(PFCB Fcb,
-                           PDEVICE_EXTENSION DeviceExt,
-                           PFILE_DIRECTORY_INFORMATION Info,
-                           ULONG BufferLength)
+NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
+                            PFILE_RECORD_HEADER FileRecord,
+                            ULONGLONG MFTIndex,
+                            PFILE_DIRECTORY_INFORMATION Info,
+                            ULONG BufferLength)
 {
-  ULONG Length;
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName;
+    PSTANDARD_INFORMATION StdInfo;
+
+    DPRINT("NtfsGetDirectoryInformation() called\n");
 
-  DPRINT("CdfsGetDirectoryInformation() called\n");
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
+    if (FileName == NULL)
+    {
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
 
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
+    ASSERT(StdInfo != NULL);
 
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
+        return(STATUS_BUFFER_OVERFLOW);
 
-  /* Convert file times */
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->CreationTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastAccessTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastWriteTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->ChangeTime);
+    Info->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-  /* Convert file flags */
-  CdfsFileFlagsToAttributes(Fcb,
-                           &Info->FileAttributes);
+    Info->CreationTime.QuadPart = FileName->CreationTime;
+    Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+    Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+    Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
-  Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
+    /* Convert file flags */
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-  /* Make AllocSize a rounded up multiple of the sector size */
-  Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
+    Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
 
-//  Info->FileIndex=;
+    Info->FileIndex = MFTIndex;
 
-  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,
+                                ULONGLONG MFTIndex,
+                                PFILE_FULL_DIRECTORY_INFORMATION Info,
+                                ULONG BufferLength)
 {
-  ULONG Length;
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName;
+    PSTANDARD_INFORMATION StdInfo;
+
+    DPRINT("NtfsGetFullDirectoryInformation() called\n");
 
-  DPRINT("CdfsGetFullDirectoryInformation() called\n");
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
+    if (FileName == NULL)
+    {
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
 
-  Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
-  if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
-    return(STATUS_BUFFER_OVERFLOW);
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
+    ASSERT(StdInfo != NULL);
 
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    Length = FileName->NameLength * sizeof (WCHAR);
+    if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
+        return(STATUS_BUFFER_OVERFLOW);
 
-  /* Convert file times */
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->CreationTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastAccessTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastWriteTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->ChangeTime);
+    Info->FileNameLength = Length;
+    Info->NextEntryOffset =
+        ROUND_UP(sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
+    RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
-  /* Convert file flags */
-  CdfsFileFlagsToAttributes(Fcb,
-                           &Info->FileAttributes);
+    Info->CreationTime.QuadPart = FileName->CreationTime;
+    Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
+    Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
+    Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
-  Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
+    /* Convert file flags */
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-  /* Make AllocSize a rounded up multiple of the sector size */
-  Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
+    Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
 
-//  Info->FileIndex=;
-  Info->EaSize = 0;
+    Info->FileIndex = MFTIndex;
+    Info->EaSize = 0;
 
-  return(STATUS_SUCCESS);
+    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,
+                                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);
+    ULONG Length;
+    PFILENAME_ATTRIBUTE FileName, ShortFileName;
+    PSTANDARD_INFORMATION StdInfo;
 
-  Info->FileNameLength = Length;
-  Info->NextEntryOffset =
-    ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
-  memcpy(Info->FileName, Fcb->ObjectName, Length);
+    DPRINT("NtfsGetBothDirectoryInformation() called\n");
 
-  /* Convert file times */
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->CreationTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastAccessTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->LastWriteTime);
-  CdfsDateTimeToFileTime(Fcb,
-                        &Info->ChangeTime);
-
-  /* Convert file flags */
-  CdfsFileFlagsToAttributes(Fcb,
-                           &Info->FileAttributes);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
+    if (FileName == NULL)
+    {
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
+    ShortFileName = GetFileNameFromRecord(DeviceExt, FileRecord, NTFS_FILE_NAME_DOS);
 
-  Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, 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 = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
+
+    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;
+    PDEVICE_OBJECT DeviceObject;
+    PDEVICE_EXTENSION DeviceExtension;
+    LONG BufferLength = 0;
     PUNICODE_STRING SearchPattern = NULL;
-    //FILE_INFORMATION_CLASS FileInformationClass;
+    FILE_INFORMATION_CLASS FileInformationClass;
     ULONG FileIndex = 0;
     PUCHAR Buffer = NULL;
     PFILE_NAMES_INFORMATION Buffer0 = NULL;
-    //PNTFS_FCB Fcb;
+    PNTFS_FCB Fcb;
     PNTFS_CCB Ccb;
-//    FCB TempFcb;
     BOOLEAN First = FALSE;
     PIO_STACK_LOCATION Stack;
     PFILE_OBJECT FileObject;
-    //NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PFILE_RECORD_HEADER FileRecord;
+    ULONGLONG MFTRecord, OldMFTRecord = 0;
+    UNICODE_STRING Pattern;
 
     DPRINT1("NtfsQueryDirectory() called\n");
 
     ASSERT(IrpContext);
     Irp = IrpContext->Irp;
-//    DeviceObject = IrpContext->DeviceObject;
+    DeviceObject = IrpContext->DeviceObject;
 
-//    DeviceExtension = DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
     Stack = IoGetCurrentIrpStackLocation(Irp);
     FileObject = Stack->FileObject;
 
     Ccb = (PNTFS_CCB)FileObject->FsContext2;
-//    Fcb = (PNTFS_FCB)FileObject->FsContext;
+    Fcb = (PNTFS_FCB)FileObject->FsContext;
 
     /* Obtain the callers parameters */
-    //BufferLength = Stack->Parameters.QueryDirectory.Length;
+    BufferLength = Stack->Parameters.QueryDirectory.Length;
     SearchPattern = Stack->Parameters.QueryDirectory.FileName;
-    //FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
+    FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
     FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
 
+    if (NtfsFCBIsCompressed(Fcb))
+    {
+        DPRINT1("Compressed directory!\n");
+        UNIMPLEMENTED;
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (!ExAcquireResourceSharedLite(&Fcb->MainResource,
+                                     BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+    {
+        return STATUS_PENDING;
+    }
 
     if (SearchPattern != NULL)
     {
         if (!Ccb->DirectorySearchPattern)
         {
             First = TRUE;
-            Ccb->DirectorySearchPattern =
-                ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_NTFS);
+            Pattern.Length = 0;
+            Pattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
+            Ccb->DirectorySearchPattern = Pattern.Buffer =
+                ExAllocatePoolWithTag(NonPagedPool, Pattern.MaximumLength, TAG_NTFS);
             if (!Ccb->DirectorySearchPattern)
             {
+                ExReleaseResourceLite(&Fcb->MainResource);
                 return STATUS_INSUFFICIENT_RESOURCES;
             }
 
-            memcpy(Ccb->DirectorySearchPattern,
-                   SearchPattern->Buffer,
-                   SearchPattern->Length);
+            memcpy(Ccb->DirectorySearchPattern, SearchPattern->Buffer, SearchPattern->Length);
             Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
         }
     }
@@ -539,6 +586,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
         Ccb->DirectorySearchPattern = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_NTFS);
         if (!Ccb->DirectorySearchPattern)
         {
+            ExReleaseResourceLite(&Fcb->MainResource);
             return STATUS_INSUFFICIENT_RESOURCES;
         }
 
@@ -546,7 +594,9 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
         Ccb->DirectorySearchPattern[1] = 0;
     }
 
+    RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
     DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
+    DPRINT("In: '%S'\n", Fcb->PathName);
 
     /* Determine directory index */
     if (Stack->Flags & SL_INDEX_SPECIFIED)
@@ -558,168 +608,167 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
         Ccb->Entry = 0;
     }
 
-    /* Determine Buffer for result */
-    if (Irp->MdlAddress)
+    /* Get Buffer for result */
+    Buffer = NtfsGetUserBuffer(Irp, FALSE);
+
+    DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
+
+    if (!ExAcquireResourceExclusiveLite(&DeviceExtension->DirResource,
+                                        BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
     {
-        Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
+        ExReleaseResourceLite(&Fcb->MainResource);
+        return STATUS_PENDING;
     }
-    else
+
+    while (Status == STATUS_SUCCESS && BufferLength > 0)
     {
-        Buffer = Irp->UserBuffer;
-    }
+        Status = NtfsFindFileAt(DeviceExtension,
+                                &Pattern,
+                                &Ccb->Entry,
+                                &FileRecord,
+                                &MFTRecord,
+                                Fcb->MFTIndex,
+                                (Stack->Flags & SL_CASE_SENSITIVE));
+
+        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)
+            {
+                DPRINT1("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
+                Ccb->Entry++;
+                ExFreePoolWithTag(FileRecord, TAG_NTFS);
+                continue;
+            }
+            OldMFTRecord = MFTRecord;
 
-    DPRINT("Buffer=%p tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
+            switch (FileInformationClass)
+            {
+                case FileNameInformation:
+                    Status = NtfsGetNameInformation(DeviceExtension,
+                                                    FileRecord,
+                                                    MFTRecord,
+                                                    (PFILE_NAMES_INFORMATION)Buffer,
+                                                    BufferLength);
+                    break;
+
+                case FileDirectoryInformation:
+                    Status = NtfsGetDirectoryInformation(DeviceExtension,
+                                                         FileRecord,
+                                                         MFTRecord,
+                                                         (PFILE_DIRECTORY_INFORMATION)Buffer,
+                                                         BufferLength);
+                    break;
+
+                case FileFullDirectoryInformation:
+                    Status = NtfsGetFullDirectoryInformation(DeviceExtension,
+                                                             FileRecord,
+                                                             MFTRecord,
+                                                             (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
+                                                             BufferLength);
+                    break;
+
+                case FileBothDirectoryInformation:
+                    Status = NtfsGetBothDirectoryInformation(DeviceExtension,
+                                                             FileRecord,
+                                                             MFTRecord,
+                                                             (PFILE_BOTH_DIR_INFORMATION)Buffer,
+                                                             BufferLength);
+                    break;
+
+                default:
+                    Status = STATUS_INVALID_INFO_CLASS;
+            }
 
-#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;
-           }
-
-         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;
+            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;
     }
 
+    ExReleaseResourceLite(&DeviceExtension->DirResource);
+    ExReleaseResourceLite(&Fcb->MainResource);
+
     if (FileIndex > 0)
     {
-        //Status = STATUS_SUCCESS;
+        Status = STATUS_SUCCESS;
     }
 
-//    return Status;
-    return STATUS_NO_MORE_FILES;
+    return Status;
 }
 
 
 NTSTATUS
-NTAPI
-NtfsFsdDirectoryControl(PDEVICE_OBJECT DeviceObject,
-                        PIRP Irp)
+NtfsDirectoryControl(PNTFS_IRP_CONTEXT IrpContext)
 {
-    PNTFS_IRP_CONTEXT IrpContext = NULL;
     NTSTATUS Status = STATUS_UNSUCCESSFUL;
 
     DPRINT1("NtfsDirectoryControl() called\n");
 
-    FsRtlEnterFileSystem();
-    ASSERT(DeviceObject);
-    ASSERT(Irp);
-
-    NtfsIsIrpTopLevel(Irp);
-
-    IrpContext = NtfsAllocateIrpContext(DeviceObject, Irp);
-    if (IrpContext)
+    switch (IrpContext->MinorFunction)
     {
-        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;
-        }
+        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 (Status == STATUS_PENDING && IrpContext->Flags & IRPCONTEXT_COMPLETE)
+    {
+        return NtfsMarkIrpContextForQueue(IrpContext);
+    }
 
-    if (IrpContext)
-        ExFreePoolWithTag(IrpContext, 'PRIN');
+    IrpContext->Irp->IoStatus.Information = 0;
 
-    IoSetTopLevelIrp(NULL);
-    FsRtlExitFileSystem();
     return Status;
 }