[NTFS]
[reactos.git] / drivers / filesystems / ntfs / attrib.c
index 12474f6..f34072d 100644 (file)
 
 /* FUNCTIONS ****************************************************************/
 
+NTSTATUS
+AddRun(PNTFS_ATTR_CONTEXT AttrContext,
+       ULONGLONG NextAssignedCluster,
+       ULONG RunLength)
+{
+    UNIMPLEMENTED;
+
+    if (!AttrContext->Record.IsNonResident)
+        return STATUS_INVALID_PARAMETER;
+
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 PUCHAR
 DecodeRun(PUCHAR DataRun,
           LONGLONG *DataRunOffset,
@@ -168,6 +181,14 @@ InternalGetNextAttribute(PFIND_ATTR_CONTXT Context)
         }
 
         NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length);
+
+        if (NextAttribute > Context->LastAttr || NextAttribute < Context->FirstAttr)
+        {
+            DPRINT1("Broken length: 0x%lx!\n", Context->CurrAttr->Length);
+            Context->CurrAttr = (PVOID)-1;
+            return NULL;
+        }
+        
         Context->Offset += ((ULONG_PTR)NextAttribute - (ULONG_PTR)Context->CurrAttr);
         Context->CurrAttr = NextAttribute;
 
@@ -496,7 +517,75 @@ NtfsDumpAttribute(PDEVICE_EXTENSION Vcb,
             DbgPrint("  logical clusters: %I64u - %I64u\n",
                      lcn, lcn + runcount - 1);
         }
+        else
+            DbgPrint("    %u bytes of data\n", Attribute->Resident.ValueLength);
+    }
+}
+
+
+VOID NtfsDumpDataRunData(PUCHAR DataRun)
+{
+    UCHAR DataRunOffsetSize;
+    UCHAR DataRunLengthSize;
+    CHAR i;
+
+    DbgPrint("%02x ", *DataRun);
+
+    if (*DataRun == 0)
+        return;
+
+    DataRunOffsetSize = (*DataRun >> 4) & 0xF;
+    DataRunLengthSize = *DataRun & 0xF;
+
+    DataRun++;
+    for (i = 0; i < DataRunLengthSize; i++)
+    {
+        DbgPrint("%02x ", *DataRun);
+        DataRun++;
+    }
+
+    for (i = 0; i < DataRunOffsetSize; i++)
+    {
+        DbgPrint("%02x ", *DataRun);
+        DataRun++;
+    }
+
+    NtfsDumpDataRunData(DataRun);
+}
+
+
+VOID
+NtfsDumpDataRuns(PVOID StartOfRun,
+                 ULONGLONG CurrentLCN)
+{
+    PUCHAR DataRun = StartOfRun;
+    LONGLONG DataRunOffset;
+    ULONGLONG DataRunLength;
+
+    if (CurrentLCN == 0)
+    {
+        DPRINT1("Dumping data runs.\n\tData:\n\t\t");
+        NtfsDumpDataRunData(StartOfRun);
+        DbgPrint("\n\tRuns:\n\t\tOff\t\tLCN\t\tLength\n");
     }
+
+    DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
+
+    if (DataRunOffset != -1)
+        CurrentLCN += DataRunOffset;
+
+    DbgPrint("\t\t%I64d\t", DataRunOffset);
+    if (DataRunOffset < 99999)
+        DbgPrint("\t");
+    DbgPrint("%I64u\t", CurrentLCN);
+    if (CurrentLCN < 99999)
+        DbgPrint("\t");
+    DbgPrint("%I64u\n", DataRunLength);
+
+    if (*DataRun == 0)
+        DbgPrint("\t\t00\n");
+    else
+        NtfsDumpDataRuns(DataRun, CurrentLCN);
 }
 
 
@@ -551,6 +640,108 @@ GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
     return NULL;
 }
 
+/**
+* GetPackedByteCount
+* Returns the minimum number of bytes needed to represent the value of a
+* 64-bit number. Used to encode data runs.
+*/
+UCHAR
+GetPackedByteCount(LONGLONG NumberToPack,
+                   BOOLEAN IsSigned)
+{
+    int bytes = 0;
+    if (!IsSigned)
+    {
+        if (NumberToPack >= 0x0100000000000000)
+            return 8;
+        if (NumberToPack >= 0x0001000000000000)
+            return 7;
+        if (NumberToPack >= 0x0000010000000000)
+            return 6;
+        if (NumberToPack >= 0x0000000100000000)
+            return 5;
+        if (NumberToPack >= 0x0000000001000000)
+            return 4;
+        if (NumberToPack >= 0x0000000000010000)
+            return 3;
+        if (NumberToPack >= 0x0000000000000100)
+            return 2;
+        return 1;
+    }
+
+    if (NumberToPack > 0)
+    {
+        // we have to make sure the number that gets encoded won't be interpreted as negative
+        if (NumberToPack >= 0x0080000000000000)
+            return 8;
+        if (NumberToPack >= 0x0000800000000000)
+            return 7;
+        if (NumberToPack >= 0x0000008000000000)
+            return 6;
+        if (NumberToPack >= 0x0000000080000000)
+            return 5;
+        if (NumberToPack >= 0x0000000000800000)
+            return 4;
+        if (NumberToPack >= 0x0000000000008000)
+            return 3;
+        if (NumberToPack >= 0x0000000000000080)
+            return 2;
+        return 1;
+    }
+    else
+    {
+        // negative number
+        if (NumberToPack <= 0xff80000000000000)
+            return 8;
+        if (NumberToPack <= 0xffff800000000000)
+            return 7;
+        if (NumberToPack <= 0xffffff8000000000)
+            return 6;
+        if (NumberToPack <= 0xffffffff80000000)
+            return 5;
+        if (NumberToPack <= 0xffffffffff800000)
+            return 4;
+        if (NumberToPack <= 0xffffffffffff8000)
+            return 3;
+        if (NumberToPack <= 0xffffffffffffff80)
+            return 2;
+        return 1;
+    }
+    return bytes;
+}
+
+NTSTATUS
+GetLastClusterInDataRun(PDEVICE_EXTENSION Vcb, PNTFS_ATTR_RECORD Attribute, PULONGLONG LastCluster)
+{
+    LONGLONG DataRunOffset;
+    ULONGLONG DataRunLength;
+    LONGLONG DataRunStartLCN;
+
+    ULONGLONG LastLCN = 0;
+    PUCHAR DataRun = (PUCHAR)Attribute + Attribute->NonResident.MappingPairsOffset;
+
+    if (!Attribute->IsNonResident)
+        return STATUS_INVALID_PARAMETER;
+
+    while (1)
+    {
+        DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
+       
+        if (DataRunOffset != -1)
+        {
+            // Normal data run.
+            DataRunStartLCN = LastLCN + DataRunOffset;
+            LastLCN = DataRunStartLCN;
+            *LastCluster = LastLCN + DataRunLength - 1;
+        }             
+
+        if (*DataRun == 0)            
+            break;
+    }
+
+    return STATUS_SUCCESS;
+}
+
 PSTANDARD_INFORMATION
 GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
                                  PFILE_RECORD_HEADER FileRecord)