[NTFS]
[reactos.git] / drivers / filesystems / ntfs / attrib.c
index aa52547..12474f6 100644 (file)
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/filesystem/ntfs/attrib.c
  * PURPOSE:          NTFS filesystem driver
- * PROGRAMMER:       Eric Kohl
- * Updated     by       Valentin Verkhovsky  2003/09/12
+ * PROGRAMMERS:      Eric Kohl
+ *                   Valentin Verkhovsky
+ *                   HervĂ© Poussineau (hpoussin@reactos.org)
+ *                   Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
@@ -91,6 +93,216 @@ FindRun(PNTFS_ATTR_RECORD NresAttr,
     return TRUE;
 }
 
+static
+NTSTATUS
+InternalReadNonResidentAttributes(PFIND_ATTR_CONTXT Context)
+{
+    ULONGLONG ListSize;
+    PNTFS_ATTR_RECORD Attribute;
+    PNTFS_ATTR_CONTEXT ListContext;
+
+    DPRINT("InternalReadNonResidentAttributes(%p)\n", Context);
+
+    Attribute = Context->CurrAttr;
+    ASSERT(Attribute->Type == AttributeAttributeList);
+
+    if (Context->OnlyResident)
+    {
+        Context->NonResidentStart = NULL;
+        Context->NonResidentEnd = NULL;
+        return STATUS_SUCCESS;
+    }
+
+    if (Context->NonResidentStart != NULL)
+    {
+        return STATUS_FILE_CORRUPT_ERROR;
+    }
+
+    ListContext = PrepareAttributeContext(Attribute);
+    ListSize = AttributeDataLength(&ListContext->Record);
+    if (ListSize > 0xFFFFFFFF)
+    {
+        ReleaseAttributeContext(ListContext);
+        return STATUS_BUFFER_OVERFLOW;
+    }
+
+    Context->NonResidentStart = ExAllocatePoolWithTag(NonPagedPool, (ULONG)ListSize, TAG_NTFS);
+    if (Context->NonResidentStart == NULL)
+    {
+        ReleaseAttributeContext(ListContext);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (ReadAttribute(Context->Vcb, ListContext, 0, (PCHAR)Context->NonResidentStart, (ULONG)ListSize) != ListSize)
+    {
+        ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
+        Context->NonResidentStart = NULL;
+        ReleaseAttributeContext(ListContext);
+        return STATUS_FILE_CORRUPT_ERROR;
+    }
+
+    ReleaseAttributeContext(ListContext);
+    Context->NonResidentEnd = (PNTFS_ATTR_RECORD)((PCHAR)Context->NonResidentStart + ListSize);
+    return STATUS_SUCCESS;
+}
+
+static
+PNTFS_ATTR_RECORD
+InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
+{
+    PNTFS_ATTR_RECORD NextAttribute;
+
+    if (Context->CurrAttr == (PVOID)-1)
+    {
+        return NULL;
+    }
+
+    if (Context->CurrAttr >= Context->FirstAttr &&
+        Context->CurrAttr < Context->LastAttr)
+    {
+        if (Context->CurrAttr->Length == 0)
+        {
+            DPRINT1("Broken length!\n");
+            Context->CurrAttr = (PVOID)-1;
+            return NULL;
+        }
+
+        NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+        Context->Offset += ((ULONG_PTR)NextAttribute - (ULONG_PTR)Context->CurrAttr);
+        Context->CurrAttr = NextAttribute;
+
+        if (Context->CurrAttr < Context->LastAttr &&
+            Context->CurrAttr->Type != AttributeEnd)
+        {
+            return Context->CurrAttr;
+        }
+    }
+
+    if (Context->NonResidentStart == NULL)
+    {
+        Context->CurrAttr = (PVOID)-1;
+        return NULL;
+    }
+
+    if (Context->CurrAttr < Context->NonResidentStart ||
+        Context->CurrAttr >= Context->NonResidentEnd)
+    {
+        Context->CurrAttr = Context->NonResidentStart;
+    }
+    else if (Context->CurrAttr->Length != 0)
+    {
+        NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+        Context->Offset += ((ULONG_PTR)NextAttribute - (ULONG_PTR)Context->CurrAttr);
+        Context->CurrAttr = NextAttribute;
+    }
+    else
+    {
+        DPRINT1("Broken length!\n");
+        Context->CurrAttr = (PVOID)-1;
+        return NULL;
+    }
+
+    if (Context->CurrAttr < Context->NonResidentEnd &&
+        Context->CurrAttr->Type != AttributeEnd)
+    {
+        return Context->CurrAttr;
+    }
+
+    Context->CurrAttr = (PVOID)-1;
+    return NULL;
+}
+
+NTSTATUS
+FindFirstAttribute(PFIND_ATTR_CONTXT Context,
+                   PDEVICE_EXTENSION Vcb,
+                   PFILE_RECORD_HEADER FileRecord,
+                   BOOLEAN OnlyResident,
+                   PNTFS_ATTR_RECORD * Attribute)
+{
+    NTSTATUS Status;
+
+    DPRINT("FindFistAttribute(%p, %p, %p, %p, %u, %p)\n", Context, Vcb, FileRecord, OnlyResident, Attribute);
+
+    Context->Vcb = Vcb;
+    Context->OnlyResident = OnlyResident;
+    Context->FirstAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+    Context->CurrAttr = Context->FirstAttr;
+    Context->LastAttr = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse);
+    Context->NonResidentStart = NULL;
+    Context->NonResidentEnd = NULL;
+    Context->Offset = FileRecord->AttributeOffset;
+
+    if (Context->FirstAttr->Type == AttributeEnd)
+    {
+        Context->CurrAttr = (PVOID)-1;
+        return STATUS_END_OF_FILE;
+    }
+    else if (Context->FirstAttr->Type == AttributeAttributeList)
+    {
+        Status = InternalReadNonResidentAttributes(Context);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
+        *Attribute = InternalGetNextAttribute(Context);
+        if (*Attribute == NULL)
+        {
+            return STATUS_END_OF_FILE;
+        }
+    }
+    else
+    {
+        *Attribute = Context->CurrAttr;
+        Context->Offset = (UCHAR*)Context->CurrAttr - (UCHAR*)FileRecord;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FindNextAttribute(PFIND_ATTR_CONTXT Context,
+                  PNTFS_ATTR_RECORD * Attribute)
+{
+    NTSTATUS Status;
+
+    DPRINT("FindNextAttribute(%p, %p)\n", Context, Attribute);
+
+    *Attribute = InternalGetNextAttribute(Context);
+    if (*Attribute == NULL)
+    {
+        return STATUS_END_OF_FILE;
+    }
+
+    if (Context->CurrAttr->Type != AttributeAttributeList)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    Status = InternalReadNonResidentAttributes(Context);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    *Attribute = InternalGetNextAttribute(Context);
+    if (*Attribute == NULL)
+    {
+        return STATUS_END_OF_FILE;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+FindCloseAttribute(PFIND_ATTR_CONTXT Context)
+{
+    if (Context->NonResidentStart != NULL)
+    {
+        ExFreePoolWithTag(Context->NonResidentStart, TAG_NTFS);
+        Context->NonResidentStart = NULL;
+    }
+}
 
 static
 VOID
@@ -103,7 +315,24 @@ NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
 //    DbgPrint(" Length %lu  Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
 
     FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
-    DbgPrint(" '%.*S' ", FileNameAttr->NameLength, FileNameAttr->Name);
+    DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType, FileNameAttr->NameLength, FileNameAttr->Name);
+    DbgPrint(" '%x' \n", FileNameAttr->FileAttributes);
+    DbgPrint(" AllocatedSize: %I64u\nDataSize: %I64u\n", FileNameAttr->AllocatedSize, FileNameAttr->DataSize);
+}
+
+
+static
+VOID
+NtfsDumpStandardInformationAttribute(PNTFS_ATTR_RECORD Attribute)
+{
+    PSTANDARD_INFORMATION StandardInfoAttr;
+
+    DbgPrint("  $STANDARD_INFORMATION ");
+
+//    DbgPrint(" Length %lu  Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
+
+    StandardInfoAttr = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+    DbgPrint(" '%x' ", StandardInfoAttr->FileAttribute);
 }
 
 
@@ -167,7 +396,8 @@ NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
 
 static
 VOID
-NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
+NtfsDumpAttribute(PDEVICE_EXTENSION Vcb,
+                  PNTFS_ATTR_RECORD Attribute)
 {
     UNICODE_STRING Name;
 
@@ -181,11 +411,7 @@ NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
             break;
 
         case AttributeStandardInformation:
-            DbgPrint("  $STANDARD_INFORMATION ");
-            break;
-
-        case AttributeAttributeList:
-            DbgPrint("  $ATTRIBUTE_LIST ");
+            NtfsDumpStandardInformationAttribute(Attribute);
             break;
 
         case AttributeObjectId:
@@ -247,61 +473,127 @@ NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
             break;
     }
 
-    if (Attribute->NameLength != 0)
+    if (Attribute->Type != AttributeAttributeList)
     {
-        Name.Length = Attribute->NameLength * sizeof(WCHAR);
-        Name.MaximumLength = Name.Length;
-        Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
+        if (Attribute->NameLength != 0)
+        {
+            Name.Length = Attribute->NameLength * sizeof(WCHAR);
+            Name.MaximumLength = Name.Length;
+            Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
 
-        DbgPrint("'%wZ' ", &Name);
-    }
+            DbgPrint("'%wZ' ", &Name);
+        }
 
-    DbgPrint("(%s)\n",
-             Attribute->IsNonResident ? "non-resident" : "resident");
+        DbgPrint("(%s)\n",
+                 Attribute->IsNonResident ? "non-resident" : "resident");
 
-    if (Attribute->IsNonResident)
-    {
-        FindRun(Attribute,0,&lcn, &runcount);
+        if (Attribute->IsNonResident)
+        {
+            FindRun(Attribute,0,&lcn, &runcount);
 
-        DbgPrint("  AllocatedSize %I64u  DataSize %I64u\n",
-                 Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
-        DbgPrint("  logical clusters: %I64u - %I64u\n",
-                 lcn, lcn + runcount - 1);
+            DbgPrint("  AllocatedSize %I64u  DataSize %I64u InitilizedSize %I64u\n",
+                     Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize, Attribute->NonResident.InitializedSize);
+            DbgPrint("  logical clusters: %I64u - %I64u\n",
+                     lcn, lcn + runcount - 1);
+        }
     }
 }
 
 
 VOID
-NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord)
+NtfsDumpFileAttributes(PDEVICE_EXTENSION Vcb,
+                       PFILE_RECORD_HEADER FileRecord)
 {
+    NTSTATUS Status;
+    FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
-        NtfsDumpAttribute(Attribute);
+        NtfsDumpAttribute(Vcb, Attribute);
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        Status = FindNextAttribute(&Context, &Attribute);
     }
+
+    FindCloseAttribute(&Context);
 }
 
 PFILENAME_ATTRIBUTE
-GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord)
+GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
+                      PFILE_RECORD_HEADER FileRecord,
+                      UCHAR NameType)
 {
+    FIND_ATTR_CONTXT Context;
     PNTFS_ATTR_RECORD Attribute;
+    PFILENAME_ATTRIBUTE Name;
+    NTSTATUS Status;
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
         if (Attribute->Type == AttributeFileName)
-            return (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+        {
+            Name = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+            if (Name->NameType == NameType ||
+                (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_WIN32) ||
+                (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_DOS))
+            {
+                FindCloseAttribute(&Context);
+                return Name;
+            }
+        }
+
+        Status = FindNextAttribute(&Context, &Attribute);
+    }
+
+    FindCloseAttribute(&Context);
+    return NULL;
+}
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+PSTANDARD_INFORMATION
+GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
+                                 PFILE_RECORD_HEADER FileRecord)
+{
+    NTSTATUS Status;
+    FIND_ATTR_CONTXT Context;
+    PNTFS_ATTR_RECORD Attribute;
+    PSTANDARD_INFORMATION StdInfo;
+
+    Status = FindFirstAttribute(&Context, Vcb, FileRecord, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
+    {
+        if (Attribute->Type == AttributeStandardInformation)
+        {
+            StdInfo = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+            FindCloseAttribute(&Context);
+            return StdInfo;
+        }
+
+        Status = FindNextAttribute(&Context, &Attribute);
     }
 
+    FindCloseAttribute(&Context);
     return NULL;
 }
 
+PFILENAME_ATTRIBUTE
+GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb,
+                          PFILE_RECORD_HEADER FileRecord)
+{
+    PFILENAME_ATTRIBUTE FileName;
+
+    FileName = GetFileNameFromRecord(Vcb, FileRecord, NTFS_FILE_NAME_POSIX);
+    if (FileName == NULL)
+    {
+        FileName = GetFileNameFromRecord(Vcb, FileRecord, NTFS_FILE_NAME_WIN32);
+        if (FileName == NULL)
+        {
+            FileName = GetFileNameFromRecord(Vcb, FileRecord, NTFS_FILE_NAME_DOS);
+        }
+    }
+
+    return FileName;
+}
+
 /* EOF */