Lay some groundwork for extending allocation size.
+AddRun() - Unimplemented
+GetLastClusterInDataRun()
+NtfsAllocateClusters()

svn path=/branches/GSoC_2016/NTFS/; revision=71696
This commit is contained in:
Trevor Thompson 2016-06-29 16:35:36 +00:00 committed by Thomas Faber
parent 84a1280fd6
commit 77fc65dc0e
4 changed files with 223 additions and 5 deletions

View file

@ -35,6 +35,19 @@
/* 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,
@ -551,6 +564,50 @@ GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
return NULL;
}
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)
{
// sparse run
if (*DataRun == 0)
{
// if it's the last run, return the last cluster of the last run
*LastCluster = LastLCN + DataRunLength - 1;
break;
}
}
else
{
// Normal data run.
DataRunStartLCN = LastLCN + DataRunOffset;
LastLCN = DataRunStartLCN;
}
if (*DataRun == 0)
{
*LastCluster = LastLCN + DataRunLength - 1;
break;
}
}
return STATUS_SUCCESS;
}
PSTANDARD_INFORMATION
GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
PFILE_RECORD_HEADER FileRecord)

View file

@ -151,7 +151,7 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
}
ULONG
ULONGLONG
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
{
if (AttrRecord->IsNonResident)
@ -181,9 +181,49 @@ SetAttributeDataLength(PFILE_OBJECT FileObject,
{
if (AttrContext->Record.IsNonResident)
{
ULONG BytesPerCluster = Fcb->Vcb->NtfsInfo.BytesPerCluster;
ULONGLONG AllocationSize = ROUND_UP(DataSize->QuadPart, BytesPerCluster);
// do we need to increase the allocation size?
if (AttrContext->Record.NonResident.AllocatedSize < DataSize->QuadPart)
{
if (AttrContext->Record.NonResident.AllocatedSize < AllocationSize)
{
ULONG ExistingClusters = AttrContext->Record.NonResident.AllocatedSize / BytesPerCluster;
ULONG ClustersNeeded = (AllocationSize / BytesPerCluster) - ExistingClusters;
LARGE_INTEGER LastClusterInDataRun;
ULONG NextAssignedCluster;
ULONG AssignedClusters;
NTSTATUS Status = GetLastClusterInDataRun(Fcb->Vcb, &AttrContext->Record, &LastClusterInDataRun.QuadPart);
DPRINT1("GetLastClusterInDataRun returned: %I64u\n", LastClusterInDataRun.QuadPart);
DPRINT1("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN);
while (ClustersNeeded > 0)
{
Status = NtfsAllocateClusters(Fcb->Vcb,
LastClusterInDataRun.LowPart + 1,
ClustersNeeded,
&NextAssignedCluster,
&AssignedClusters);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Unable to allocate requested clusters!\n");
return Status;
}
// now we need to add the clusters we allocated to the data run
Status = AddRun(AttrContext, NextAssignedCluster, AssignedClusters);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Unable to add data run!\n");
return Status;
}
ClustersNeeded -= AssignedClusters;
LastClusterInDataRun.LowPart = NextAssignedCluster + AssignedClusters - 1;
}
DPRINT1("FixMe: Increasing allocation size is unimplemented!\n");
return STATUS_NOT_IMPLEMENTED;
}
@ -459,7 +499,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
PUCHAR SourceBuffer = Buffer;
LONGLONG StartingOffset;
DPRINT("WriteAttribute(%p, %p, %I64U, %p, %lu)\n", Vcb, Context, Offset, Buffer, Length);
DPRINT("WriteAttribute(%p, %p, %I64u, %p, %lu, %p)\n", Vcb, Context, Offset, Buffer, Length, RealLengthWritten);
// is this a resident attribute?
if (!Context->Record.IsNonResident)

View file

@ -511,6 +511,11 @@ NtfsMarkIrpContextForQueue(PNTFS_IRP_CONTEXT IrpContext)
//VOID
//NtfsDumpAttribute(PATTRIBUTE Attribute);
NTSTATUS
AddRun(PNTFS_ATTR_CONTEXT AttrContext,
ULONGLONG NextAssignedCluster,
ULONG RunLength);
PUCHAR
DecodeRun(PUCHAR DataRun,
LONGLONG *DataRunOffset,
@ -529,6 +534,11 @@ GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
PFILE_RECORD_HEADER FileRecord,
UCHAR NameType);
NTSTATUS
GetLastClusterInDataRun(PDEVICE_EXTENSION Vcb,
PNTFS_ATTR_RECORD Attribute,
PULONGLONG LastCluster);
PFILENAME_ATTRIBUTE
GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb,
PFILE_RECORD_HEADER FileRecord);
@ -774,7 +784,7 @@ SetAttributeDataLength(PFILE_OBJECT FileObject,
PFILE_RECORD_HEADER FileRecord,
PLARGE_INTEGER DataSize);
ULONG
ULONGLONG
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
BOOLEAN
@ -915,6 +925,13 @@ NtfsWrite(PNTFS_IRP_CONTEXT IrpContext);
/* volinfo.c */
NTSTATUS
NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt,
ULONG FirstDesiredCluster,
ULONG DesiredClusters,
PULONG FirstAssignedCluster,
PULONG AssignedClusters);
ULONGLONG
NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt);

View file

@ -99,6 +99,110 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
return FreeClusters;
}
/**
* NtfsAllocateClusters
* Allocates a run of clusters. The run allocated might be smaller than DesiredClusters.
*/
NTSTATUS
NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt,
ULONG FirstDesiredCluster,
ULONG DesiredClusters,
PULONG FirstAssignedCluster,
PULONG AssignedClusters)
{
NTSTATUS Status;
PFILE_RECORD_HEADER BitmapRecord;
PNTFS_ATTR_CONTEXT DataContext;
ULONGLONG BitmapDataSize;
PCHAR BitmapData;
ULONGLONG FreeClusters = 0;
ULONG Read = 0;
RTL_BITMAP Bitmap;
DPRINT1("NtfsAllocateClusters(%p, %lu, %lu, %p)\n", DeviceExt, DesiredClusters, FirstDesiredCluster, FirstAssignedCluster, AssignedClusters);
BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
DeviceExt->NtfsInfo.BytesPerFileRecord,
TAG_NTFS);
if (BitmapRecord == NULL)
{
return 0;
}
Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
return 0;
}
Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
return 0;
}
BitmapDataSize = AttributeDataLength(&DataContext->Record);
BitmapDataSize = min(BitmapDataSize, 0xffffffff);
ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount);
BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
if (BitmapData == NULL)
{
ReleaseAttributeContext(DataContext);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
return 0;
}
DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount);
DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
ReadAttribute(DeviceExt, DataContext, Read, (PCHAR)((ULONG_PTR)BitmapData + Read), (ULONG)BitmapDataSize);
RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
FreeClusters = RtlNumberOfClearBits(&Bitmap);
if (FreeClusters >= DesiredClusters)
{
// TODO: Observe MFT reservation zone
// Can we get one contiguous run?
ULONG AssignedRun = RtlFindClearBitsAndSet(&Bitmap, DesiredClusters, FirstDesiredCluster);
ULONG LengthWritten;
if (AssignedRun != 0xFFFFFFFF)
{
*FirstAssignedCluster = AssignedRun;
*AssignedClusters = DesiredClusters;
}
else
{
// we can't get one contiguous run
*AssignedClusters = RtlFindNextForwardRunClear(&Bitmap, FirstDesiredCluster, FirstAssignedCluster);
if (*AssignedClusters == 0)
{
// we couldn't find any runs starting at DesiredFirstCluster
*AssignedClusters = RtlFindLongestRunClear(&Bitmap, FirstAssignedCluster);
}
}
Status = WriteAttribute(DeviceExt, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten);
}
else
Status = STATUS_DISK_FULL;
ReleaseAttributeContext(DataContext);
ExFreePoolWithTag(BitmapData, TAG_NTFS);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
return Status;
}
static
NTSTATUS
NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,