[NTFS] - In the NtfsAddFilenameToDirectory() function, rename DirectoryContext parame...
[reactos.git] / drivers / filesystems / ntfs / dirctl.c
index 088b69f..4d19052 100644 (file)
 
 /* 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);
+    // Open the parent directory
+    Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        DPRINT1("ERROR: Couldn't read parent directory with index %I64u\n",
+                DirectoryMftIndex);
+        return Status;
+    }
 
-  if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
+    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))
     {
-      wcscpy(Name, L".");
+        DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent directory with MFT #: %I64u!\n",
+                DirectoryMftIndex);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return Status;
     }
-  else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
+
+    I30IndexRootLength = AttributeDataLength(&IndexRootContext->Record);
+
+    // Allocate memory for the index root data
+    I30IndexRoot = (PINDEX_ROOT_ATTRIBUTE)ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS);
+    if (!I30IndexRoot)
     {
-      wcscpy(Name, L"..");
+        DPRINT1("ERROR: Couldn't allocate memory for index root attribute!\n");
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
     }
-  else
+
+    // Read the Index Root
+    Status = ReadAttribute(DeviceExt, IndexRootContext, 0, (PCHAR)I30IndexRoot, I30IndexRootLength);
+    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: Couln't read index root attribute for Mft index #%I64u\n", DirectoryMftIndex);
+        ReleaseAttributeContext(IndexRootContext);
+        ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+        ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+        return Status;
     }
 
-  DPRINT("Name '%S'\n", Name);
+    // 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)
+    {
+        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;
+    }
+    
+    // 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))
+    {
+        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;
+    }
 
-  *Ptr = Record;
+    // Update the parent directory with the new index root
+    Status = WriteAttribute(DeviceExt,
+                            IndexRootContext,
+                            0,
+                            (PUCHAR)NewIndexRoot,
+                            AttributeLength,
+                            &LengthWritten);
+    if (!NT_SUCCESS(Status) )
+    {
+        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;
+    }
+    
+    // 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
+    {
+        DPRINT1("Dumping new parent file record:\n");
+        NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
+    }
 
-  *pIndex = Index;
+    // Cleanup
+    ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+    ReleaseAttributeContext(IndexRootContext);
+    ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+    ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
 
-  return(STATUS_SUCCESS);
+    return Status;
+}
+
+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;
+
+    Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Stream, StreamLength, &DataContext, NULL);
+    if (NT_SUCCESS(Status))
+    {
+        Size = AttributeDataLength(&DataContext->Record);
+        Allocated = AttributeAllocatedLength(&DataContext->Record);
+        ReleaseAttributeContext(DataContext);
+    }
+
+    if (AllocatedSize != NULL) *AllocatedSize = Allocated;
+
+    return Size;
 }
-#endif
 
 
 static NTSTATUS
 NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
                        PFILE_RECORD_HEADER FileRecord,
-                       PNTFS_ATTR_CONTEXT DataContext,
+                       ULONGLONG MFTIndex,
                        PFILE_NAMES_INFORMATION Info,
                        ULONG BufferLength)
 {
@@ -137,16 +323,13 @@ NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
 
     DPRINT("NtfsGetNameInformation() called\n");
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
-        FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
-        if (FileName == NULL)
-        {
-            FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
-        }
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
     }
-    ASSERT(FileName != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
@@ -164,25 +347,26 @@ NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
 static NTSTATUS
 NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
                             PFILE_RECORD_HEADER FileRecord,
-                            PNTFS_ATTR_CONTEXT DataContext,
+                            ULONGLONG MFTIndex,
                             PFILE_DIRECTORY_INFORMATION Info,
                             ULONG BufferLength)
 {
     ULONG Length;
     PFILENAME_ATTRIBUTE FileName;
+    PSTANDARD_INFORMATION StdInfo;
 
     DPRINT("NtfsGetDirectoryInformation() called\n");
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
-        FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
-        if (FileName == NULL)
-        {
-            FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
-        }
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
     }
-    ASSERT(FileName != NULL);
+
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
+    ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
@@ -199,12 +383,11 @@ NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
     Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
     /* Convert file flags */
-    NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-    Info->EndOfFile.QuadPart = FileName->AllocatedSize;
-    Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
+    Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
 
-//  Info->FileIndex=;
+    Info->FileIndex = MFTIndex;
 
     return STATUS_SUCCESS;
 }
@@ -213,25 +396,26 @@ NtfsGetDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
 static NTSTATUS
 NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
                                 PFILE_RECORD_HEADER FileRecord,
-                                PNTFS_ATTR_CONTEXT DataContext,
+                                ULONGLONG MFTIndex,
                                 PFILE_FULL_DIRECTORY_INFORMATION Info,
                                 ULONG BufferLength)
 {
     ULONG Length;
     PFILENAME_ATTRIBUTE FileName;
+    PSTANDARD_INFORMATION StdInfo;
 
     DPRINT("NtfsGetFullDirectoryInformation() called\n");
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
-        FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
-        if (FileName == NULL)
-        {
-            FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
-        }
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
     }
-    ASSERT(FileName != NULL);
+
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
+    ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
@@ -248,12 +432,11 @@ NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
     Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
     /* Convert file flags */
-    NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-    Info->EndOfFile.QuadPart = FileName->AllocatedSize;
-    Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
+    Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
 
-//  Info->FileIndex=;
+    Info->FileIndex = MFTIndex;
     Info->EaSize = 0;
 
     return STATUS_SUCCESS;
@@ -263,26 +446,27 @@ NtfsGetFullDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
 static NTSTATUS
 NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
                                 PFILE_RECORD_HEADER FileRecord,
-                                PNTFS_ATTR_CONTEXT DataContext,
+                                ULONGLONG MFTIndex,
                                 PFILE_BOTH_DIR_INFORMATION Info,
                                 ULONG BufferLength)
 {
     ULONG Length;
     PFILENAME_ATTRIBUTE FileName, ShortFileName;
+    PSTANDARD_INFORMATION StdInfo;
 
     DPRINT("NtfsGetBothDirectoryInformation() called\n");
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
+    FileName = GetBestFileNameFromRecord(DeviceExt, FileRecord);
     if (FileName == NULL)
     {
-        FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
-        if (FileName == NULL)
-        {
-            FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
-        }
+        DPRINT1("No name information for file ID: %#I64x\n", MFTIndex);
+        NtfsDumpFileAttributes(DeviceExt, FileRecord);
+        return STATUS_OBJECT_NAME_NOT_FOUND;
     }
-    ASSERT(FileName != NULL);
-    ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
+    ShortFileName = GetFileNameFromRecord(DeviceExt, FileRecord, NTFS_FILE_NAME_DOS);
+
+    StdInfo = GetStandardInformationFromRecord(DeviceExt, FileRecord);
+    ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
@@ -312,12 +496,11 @@ NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
     Info->ChangeTime.QuadPart = FileName->ChangeTime;
 
     /* Convert file flags */
-    NtfsFileFlagsToAttributes(FileName->FileAttributes, &Info->FileAttributes);
+    NtfsFileFlagsToAttributes(FileName->FileAttributes | StdInfo->FileAttribute, &Info->FileAttributes);
 
-    Info->EndOfFile.QuadPart = FileName->AllocatedSize;
-    Info->AllocationSize.QuadPart = ROUND_UP(FileName->AllocatedSize, DeviceExt->NtfsInfo.BytesPerCluster);
+    Info->EndOfFile.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&Info->AllocationSize.QuadPart);
 
-//  Info->FileIndex=;
+    Info->FileIndex = MFTIndex;
     Info->EaSize = 0;
 
     return STATUS_SUCCESS;
@@ -343,7 +526,6 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
     PFILE_OBJECT FileObject;
     NTSTATUS Status = STATUS_SUCCESS;
     PFILE_RECORD_HEADER FileRecord;
-    PNTFS_ATTR_CONTEXT DataContext;
     ULONGLONG MFTRecord, OldMFTRecord = 0;
     UNICODE_STRING Pattern;
 
@@ -366,6 +548,19 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
     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)
@@ -377,17 +572,11 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                 ExAllocatePoolWithTag(NonPagedPool, Pattern.MaximumLength, TAG_NTFS);
             if (!Ccb->DirectorySearchPattern)
             {
+                ExReleaseResourceLite(&Fcb->MainResource);
                 return STATUS_INSUFFICIENT_RESOURCES;
             }
 
-            Status = RtlUpcaseUnicodeString(&Pattern, SearchPattern, FALSE);
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("RtlUpcaseUnicodeString('%wZ') failed with status 0x%08lx\n", &Pattern, Status);
-                ExFreePoolWithTag(Ccb->DirectorySearchPattern, TAG_NTFS);
-                Ccb->DirectorySearchPattern = NULL;
-                return Status;
-            }
+            memcpy(Ccb->DirectorySearchPattern, SearchPattern->Buffer, SearchPattern->Length);
             Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
         }
     }
@@ -397,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;
         }
 
@@ -418,27 +608,27 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
         Ccb->Entry = 0;
     }
 
-    /* Determine Buffer for result */
-    if (Irp->MdlAddress)
-    {
-        Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
-    }
-    else
-    {
-        Buffer = Irp->UserBuffer;
-    }
+    /* 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)))
+    {
+        ExReleaseResourceLite(&Fcb->MainResource);
+        return STATUS_PENDING;
+    }
+
     while (Status == STATUS_SUCCESS && BufferLength > 0)
     {
         Status = NtfsFindFileAt(DeviceExtension,
                                 &Pattern,
                                 &Ccb->Entry,
                                 &FileRecord,
-                                &DataContext,
                                 &MFTRecord,
-                                Fcb->MFTIndex);
+                                Fcb->MFTIndex,
+                                (Stack->Flags & SL_CASE_SENSITIVE));
 
         if (NT_SUCCESS(Status))
         {
@@ -447,7 +637,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
              */
             if (MFTRecord == OldMFTRecord)
             {
-                DPRINT("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
+                DPRINT1("Ignoring duplicate MFT entry 0x%x\n", MFTRecord);
                 Ccb->Entry++;
                 ExFreePoolWithTag(FileRecord, TAG_NTFS);
                 continue;
@@ -459,7 +649,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                 case FileNameInformation:
                     Status = NtfsGetNameInformation(DeviceExtension,
                                                     FileRecord,
-                                                    DataContext,
+                                                    MFTRecord,
                                                     (PFILE_NAMES_INFORMATION)Buffer,
                                                     BufferLength);
                     break;
@@ -467,7 +657,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                 case FileDirectoryInformation:
                     Status = NtfsGetDirectoryInformation(DeviceExtension,
                                                          FileRecord,
-                                                         DataContext,
+                                                         MFTRecord,
                                                          (PFILE_DIRECTORY_INFORMATION)Buffer,
                                                          BufferLength);
                     break;
@@ -475,7 +665,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                 case FileFullDirectoryInformation:
                     Status = NtfsGetFullDirectoryInformation(DeviceExtension,
                                                              FileRecord,
-                                                             DataContext,
+                                                             MFTRecord,
                                                              (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
                                                              BufferLength);
                     break;
@@ -483,7 +673,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                 case FileBothDirectoryInformation:
                     Status = NtfsGetBothDirectoryInformation(DeviceExtension,
                                                              FileRecord,
-                                                             DataContext,
+                                                             MFTRecord,
                                                              (PFILE_BOTH_DIR_INFORMATION)Buffer,
                                                              BufferLength);
                     break;
@@ -537,6 +727,9 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
         Buffer0->NextEntryOffset = 0;
     }
 
+    ExReleaseResourceLite(&DeviceExtension->DirResource);
+    ExReleaseResourceLite(&Fcb->MainResource);
+
     if (FileIndex > 0)
     {
         Status = STATUS_SUCCESS;
@@ -547,52 +740,35 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
 
 
 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_QUERY_DIRECTORY:
+            Status = NtfsQueryDirectory(IrpContext);
+            break;
 
-            case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
-                DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
-                Status = STATUS_NOT_IMPLEMENTED;
-                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;
-        }
+        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;
 }