[NTFS] - Allow for resizing an attribute in the middle of a file record. Add a helper function and minor improvements:

AddRun() - Allow for resizing the size of the data runs when the attribute isn't the last in the file record. Fix some comments.
CreateIndexBufferFromBTreeNode(), CreateIndexRootFromBTree - Fix math of IndexSize when checking if the index buffer is too large.
InternalSetResidentAttributeLength() - Allow changing the length of an attribute in the middle of a file record. Adjust the position of every attribute after the one being resized.
+MoveAttributes() - Moves a block of attributes to a new location in the file Record.
PrintAllVCNs() - Add consideration for an index allocation with a size of 0.
WriteAttribute() - Add optional parameter for a pointer to the file record being written to. If passed a file record, WriteAttribute() will skip reading the file record from disk, and will update the file record in memory before returning. This helps callers that use the file record after writing an attribute to stay in-sync with what's on disk.

svn path=/branches/GSoC_2016/NTFS/; revision=75554
This commit is contained in:
Trevor Thompson 2017-08-15 19:32:20 +00:00 committed by Thomas Faber
parent 4dfcd1d582
commit d484d91eba
6 changed files with 222 additions and 107 deletions

View file

@ -352,18 +352,35 @@ AddRun(PNTFS_VCB Vcb,
PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
PNTFS_ATTR_RECORD NewRecord;
DataRunMaxLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2);
// Add free space at the end of the file record to DataRunMaxLength
DataRunMaxLength += Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
// Can we move the end of the attribute?
if (NextAttribute->Type != AttributeEnd || DataRunMaxLength < RunBufferSize - 1)
// Can we resize the attribute?
if (DataRunMaxLength < RunBufferSize)
{
DPRINT1("FIXME: Need to create attribute list! Max Data Run Length available: %d\n", DataRunMaxLength);
if (NextAttribute->Type != AttributeEnd)
DPRINT1("There's another attribute after this one with type %0xlx\n", NextAttribute->Type);
DPRINT1("FIXME: Need to create attribute list! Max Data Run Length available: %d, RunBufferSize: %d\n", DataRunMaxLength, RunBufferSize);
ExFreePoolWithTag(RunBuffer, TAG_NTFS);
return STATUS_NOT_IMPLEMENTED;
}
// Are there more attributes after the one we're resizing?
if (NextAttribute->Type != AttributeEnd)
{
PNTFS_ATTR_RECORD FinalAttribute;
// Calculate where to move the trailing attributes
ULONG_PTR MoveTo = (ULONG_PTR)DestinationAttribute + AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize;
MoveTo = ALIGN_UP_BY(MoveTo, ATTR_RECORD_ALIGNMENT);
DPRINT1("Moving attribute(s) after this one starting with type 0x%lx\n", NextAttribute->Type);
// Move the trailing attributes; FinalAttribute will point to the end marker
FinalAttribute = MoveAttributes(Vcb, NextAttribute, NextAttributeOffset, MoveTo);
// set the file record end
SetFileRecordEnd(FileRecord, FinalAttribute, FILE_RECORD_END);
}
// calculate position of end markers
NextAttributeOffset = AttrOffset + AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize;
NextAttributeOffset = ALIGN_UP_BY(NextAttributeOffset, ATTR_RECORD_ALIGNMENT);
@ -371,20 +388,24 @@ AddRun(PNTFS_VCB Vcb,
// Update the length of the destination attribute
DestinationAttribute->Length = NextAttributeOffset - AttrOffset;
// Create a new copy of the attribute
// Create a new copy of the attribute record
NewRecord = ExAllocatePoolWithTag(NonPagedPool, DestinationAttribute->Length, TAG_NTFS);
RtlCopyMemory(NewRecord, AttrContext->pRecord, AttrContext->pRecord->Length);
NewRecord->Length = DestinationAttribute->Length;
// Free the old copy of the attribute, which won't be large enough
// Free the old copy of the attribute record, which won't be large enough
ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS);
// Set the attribute context's record to the new copy
AttrContext->pRecord = NewRecord;
// End the file record
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END);
// if NextAttribute is the AttributeEnd marker
if (NextAttribute->Type == AttributeEnd)
{
// End the file record
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END);
}
}
// Update HighestVCN
@ -397,7 +418,7 @@ AddRun(PNTFS_VCB Vcb,
RunBuffer,
RunBufferSize);
// Update the attribute copy in the attribute context
// Update the attribute record in the attribute context
RtlCopyMemory((PVOID)((ULONG_PTR)AttrContext->pRecord + AttrContext->pRecord->NonResident.MappingPairsOffset),
RunBuffer,
RunBufferSize);
@ -827,7 +848,7 @@ FreeClusters(PNTFS_VCB Vcb,
}
// update $BITMAP file on disk
Status = WriteAttribute(Vcb, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten);
Status = WriteAttribute(Vcb, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten, FileRecord);
if (!NT_SUCCESS(Status))
{
ReleaseAttributeContext(DataContext);