[NTFS]
[reactos.git] / drivers / filesystems / ntfs / mft.c
index 1294264..a53b37f 100644 (file)
@@ -81,13 +81,24 @@ ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
 }
 
 
+/**
+* @name FindAttribute
+* @implemented
+* 
+* Searches a file record for an attribute matching the given type and name.
+*
+* @param Offset
+* Optional pointer to a ULONG that will receive the offset of the found attribute
+* from the beginning of the record. Can be set to NULL.
+*/
 NTSTATUS
 FindAttribute(PDEVICE_EXTENSION Vcb,
               PFILE_RECORD_HEADER MftRecord,
               ULONG Type,
               PCWSTR Name,
               ULONG NameLength,
-              PNTFS_ATTR_CONTEXT * AttrCtx)
+              PNTFS_ATTR_CONTEXT * AttrCtx,
+              PULONG Offset)
 {
     BOOLEAN Found;
     NTSTATUS Status;
@@ -123,6 +134,10 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
                 /* Found it, fill up the context and return. */
                 DPRINT("Found context\n");
                 *AttrCtx = PrepareAttributeContext(Attribute);
+
+                if (Offset != NULL)
+                    *Offset = Context.Offset;
+
                 FindCloseAttribute(&Context);
                 return STATUS_SUCCESS;
             }
@@ -156,6 +171,61 @@ AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
 }
 
 
+NTSTATUS
+SetAttributeDataLength(PFILE_OBJECT FileObject,
+                       PNTFS_FCB Fcb,
+                       PNTFS_ATTR_CONTEXT AttrContext,
+                       ULONG AttrOffset,
+                       PFILE_RECORD_HEADER FileRecord,
+                       PDEVICE_EXTENSION DeviceExt,
+                       PLARGE_INTEGER DataSize)
+{
+    if (AttrContext->Record.IsNonResident)
+    {
+        // do we need to increase the allocation size?
+        if (AttrContext->Record.NonResident.AllocatedSize < DataSize->QuadPart)
+        {            
+            DPRINT1("FixMe: Increasing allocation size is unimplemented!\n");
+            return STATUS_NOT_IMPLEMENTED;
+        }
+
+        // TODO: is the file compressed, encrypted, or sparse?
+
+        // NOTE: we need to have acquired the main resource exclusively, as well as(?) the PagingIoResource
+
+        // TODO: update the allocated size on-disk
+        DPRINT("Allocated Size: %I64u\n", AttrContext->Record.NonResident.AllocatedSize);
+
+        AttrContext->Record.NonResident.DataSize = DataSize->QuadPart;
+        AttrContext->Record.NonResident.InitializedSize = DataSize->QuadPart;
+
+        Fcb->RFCB.FileSize = *DataSize;
+        Fcb->RFCB.ValidDataLength = *DataSize;
+
+        DPRINT("Data Size: %I64u\n", Fcb->RFCB.FileSize.QuadPart);
+
+        //NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
+
+        // copy the attribute back into the FileRecord
+        RtlCopyMemory((PCHAR)FileRecord + AttrOffset, &AttrContext->Record, AttrContext->Record.Length);
+
+        //NtfsDumpFileAttributes(Fcb->Vcb, FileRecord);
+
+        // write the updated file record back to disk
+        UpdateFileRecord(Fcb->Vcb, Fcb->MFTIndex, FileRecord);
+
+        CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
+    }
+    else
+    {
+        // we can't yet handle resident attributes
+        DPRINT1("FixMe: Can't handle increasing length of resident attribute\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    return STATUS_SUCCESS;
+}
+
 ULONG
 ReadAttribute(PDEVICE_EXTENSION Vcb,
               PNTFS_ATTR_CONTEXT Context,
@@ -612,8 +682,39 @@ ReadFileRecord(PDEVICE_EXTENSION Vcb,
     return FixupUpdateSequenceArray(Vcb, &file->Ntfs);
 }
 
+/**
+* UpdateFileRecord
+* @implemented
+* Writes a file record to the master file table, at a given index.
+*/
+NTSTATUS
+UpdateFileRecord(PDEVICE_EXTENSION Vcb,
+                 ULONGLONG index,
+                 PFILE_RECORD_HEADER file)
+{
+    ULONG BytesWritten;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DPRINT("UpdateFileRecord(%p, %I64x, %p)\n", Vcb, index, file);
+
+    // Add the fixup array to prepare the data for writing to disk
+    AddFixupArray(Vcb, file);
+
+    // write the file record to the master file table
+    Status = WriteAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (const PUCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord, &BytesWritten);
+
+    // TODO: Update MFT mirror
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("UpdateFileRecord failed: %I64u written, %u expected\n", BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
+    }
+
+    return Status;
+}
+
 
-NTSTATUS 
+NTSTATUS
 FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
                          PNTFS_RECORD_HEADER Record)
 {
@@ -627,6 +728,8 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
     USACount = Record->UsaCount - 1; /* Exclude the USA Number. */
     Block = (USHORT*)((PCHAR)Record + Vcb->NtfsInfo.BytesPerSector - 2);
 
+    DPRINT("FixupUpdateSequenceArray(%p, %p)\nUSANumber: %u\tUSACount: %u\n", Vcb, Record, USANumber, USACount);
+
     while (USACount)
     {
         if (*Block != USANumber)
@@ -642,6 +745,36 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
     return STATUS_SUCCESS;
 }
 
+NTSTATUS
+AddFixupArray(PDEVICE_EXTENSION Vcb,
+              PFILE_RECORD_HEADER Record)
+{
+    USHORT *pShortToFixUp;
+    unsigned int ArrayEntryCount = Record->BytesAllocated / Vcb->NtfsInfo.BytesPerSector;
+    unsigned int Offset = Vcb->NtfsInfo.BytesPerSector - 2;
+    int i;
+
+    PFIXUP_ARRAY fixupArray = (PFIXUP_ARRAY)((UCHAR*)Record + Record->Ntfs.UsaOffset);
+
+    DPRINT("AddFixupArray(%p, %p)\n fixupArray->USN: %u, ArrayEntryCount: %u\n", Vcb, Record, fixupArray->USN, ArrayEntryCount);
+
+    if (Record->BytesAllocated % Vcb->NtfsInfo.BytesPerSector != 0)
+        ArrayEntryCount++;
+
+    fixupArray->USN++;
+
+    for (i = 0; i < ArrayEntryCount; i++)
+    {
+        DPRINT("USN: %u\tOffset: %u\n", fixupArray->USN, Offset);
+
+        pShortToFixUp = (USHORT*)((UCHAR*)Record + Offset);
+        fixupArray->Array[i] = *pShortToFixUp;
+        *pShortToFixUp = fixupArray->USN;
+        Offset += Vcb->NtfsInfo.BytesPerSector;
+    }
+
+    return STATUS_SUCCESS;
+}
 
 NTSTATUS
 ReadLCN(PDEVICE_EXTENSION Vcb,
@@ -780,7 +913,7 @@ BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
         return STATUS_OBJECT_PATH_NOT_FOUND; 
     }
 
-    Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx);
+    Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
     if (!NT_SUCCESS(Status))
     {
         DPRINT("Corrupted filesystem!\n");
@@ -850,7 +983,7 @@ NtfsFindMftRecord(PDEVICE_EXTENSION Vcb,
     }
 
     ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
-    Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx);
+    Status = FindAttribute(Vcb, MftRecord, AttributeIndexRoot, L"$I30", 4, &IndexRootCtx, NULL);
     if (!NT_SUCCESS(Status))
     {
         ExFreePoolWithTag(MftRecord, TAG_NTFS);