[NTFS]
[reactos.git] / reactos / drivers / filesystems / ntfs / dirctl.c
index 254cc19..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 *****************************************************************/
@@ -135,7 +137,7 @@ NtfsGetNameInformation(PDEVICE_EXTENSION DeviceExt,
 
     DPRINT("NtfsGetNameInformation() called\n");
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
+    FileName = GetBestFileNameFromRecord(FileRecord);
     ASSERT(FileName != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
@@ -155,17 +157,22 @@ 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_WIN32);
+    FileName = GetBestFileNameFromRecord(FileRecord);
     ASSERT(FileName != NULL);
 
+    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    ASSERT(StdInfo != NULL);
+
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
         return(STATUS_BUFFER_OVERFLOW);
@@ -181,12 +188,12 @@ 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->FileIndex=;
+    Info->FileIndex = MFTIndex;
 
     return STATUS_SUCCESS;
 }
@@ -196,17 +203,22 @@ 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_WIN32);
+    FileName = GetBestFileNameFromRecord(FileRecord);
     ASSERT(FileName != NULL);
 
+    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    ASSERT(StdInfo != NULL);
+
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_FULL_DIRECTORY_INFORMATION) + Length) > BufferLength)
         return(STATUS_BUFFER_OVERFLOW);
@@ -222,12 +234,12 @@ 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->FileIndex=;
+    Info->FileIndex = MFTIndex;
     Info->EaSize = 0;
 
     return STATUS_SUCCESS;
@@ -238,16 +250,22 @@ 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;
+    PFILENAME_ATTRIBUTE FileName, ShortFileName;
+    PSTANDARD_INFORMATION StdInfo;
 
     DPRINT("NtfsGetBothDirectoryInformation() called\n");
 
-    FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
+    FileName = GetBestFileNameFromRecord(FileRecord);
     ASSERT(FileName != NULL);
+    ShortFileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
+
+    StdInfo = GetStandardInformationFromRecord(FileRecord);
+    ASSERT(StdInfo != NULL);
 
     Length = FileName->NameLength * sizeof (WCHAR);
     if ((sizeof(FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
@@ -258,23 +276,33 @@ NtfsGetBothDirectoryInformation(PDEVICE_EXTENSION DeviceExt,
         ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
     RtlCopyMemory(Info->FileName, FileName->Name, Length);
 
+    if (ShortFileName)
+    {
+        /* 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
+    {
+        Info->ShortName[0] = 0;
+        Info->ShortNameLength = 0;
+    }
+
     Info->CreationTime.QuadPart = FileName->CreationTime;
     Info->LastAccessTime.QuadPart = FileName->LastAccessTime;
     Info->LastWriteTime.QuadPart = FileName->LastWriteTime;
     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->FileIndex=;
+    Info->FileIndex = MFTIndex;
     Info->EaSize = 0;
 
-    Info->ShortName[0] = 0;
-    Info->ShortNameLength = 0;
-
     return STATUS_SUCCESS;
 }
 
@@ -299,7 +327,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
     NTSTATUS Status = STATUS_SUCCESS;
     PFILE_RECORD_HEADER FileRecord;
     PNTFS_ATTR_CONTEXT DataContext;
-    ULONGLONG MFTRecord;
+    ULONGLONG MFTRecord, OldMFTRecord = 0;
     UNICODE_STRING Pattern;
 
     DPRINT1("NtfsQueryDirectory() called\n");
@@ -326,16 +354,16 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
         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)
             {
                 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;
         }
     }
@@ -353,9 +381,8 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
     }
 
     RtlInitUnicodeString(&Pattern, Ccb->DirectorySearchPattern);
-
-    DPRINT1("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
-    DPRINT1("In: '%S'\n", Fcb->PathName);
+    DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
+    DPRINT("In: '%S'\n", Fcb->PathName);
 
     /* Determine directory index */
     if (Stack->Flags & SL_INDEX_SPECIFIED)
@@ -388,10 +415,21 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                                 &DataContext,
                                 &MFTRecord,
                                 Fcb->MFTIndex);
-      //DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
 
         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:
@@ -406,6 +444,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                     Status = NtfsGetDirectoryInformation(DeviceExtension,
                                                          FileRecord,
                                                          DataContext,
+                                                         MFTRecord,
                                                          (PFILE_DIRECTORY_INFORMATION)Buffer,
                                                          BufferLength);
                     break;
@@ -414,6 +453,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                     Status = NtfsGetFullDirectoryInformation(DeviceExtension,
                                                              FileRecord,
                                                              DataContext,
+                                                             MFTRecord,
                                                              (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
                                                              BufferLength);
                     break;
@@ -422,6 +462,7 @@ NtfsQueryDirectory(PNTFS_IRP_CONTEXT IrpContext)
                     Status = NtfsGetBothDirectoryInformation(DeviceExtension,
                                                              FileRecord,
                                                              DataContext,
+                                                             MFTRecord,
                                                              (PFILE_BOTH_DIR_INFORMATION)Buffer,
                                                              BufferLength);
                     break;