mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[NTFS]
Lay some groundwork for extending allocation size. +AddRun() - Unimplemented +GetLastClusterInDataRun() +NtfsAllocateClusters() svn path=/branches/GSoC_2016/NTFS/; revision=71696
This commit is contained in:
parent
84a1280fd6
commit
77fc65dc0e
4 changed files with 223 additions and 5 deletions
|
@ -35,6 +35,19 @@
|
||||||
|
|
||||||
/* FUNCTIONS ****************************************************************/
|
/* 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
|
PUCHAR
|
||||||
DecodeRun(PUCHAR DataRun,
|
DecodeRun(PUCHAR DataRun,
|
||||||
LONGLONG *DataRunOffset,
|
LONGLONG *DataRunOffset,
|
||||||
|
@ -551,6 +564,50 @@ GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
|
||||||
return NULL;
|
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
|
PSTANDARD_INFORMATION
|
||||||
GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
|
GetStandardInformationFromRecord(PDEVICE_EXTENSION Vcb,
|
||||||
PFILE_RECORD_HEADER FileRecord)
|
PFILE_RECORD_HEADER FileRecord)
|
||||||
|
|
|
@ -151,7 +151,7 @@ FindAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ULONG
|
ULONGLONG
|
||||||
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
|
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord)
|
||||||
{
|
{
|
||||||
if (AttrRecord->IsNonResident)
|
if (AttrRecord->IsNonResident)
|
||||||
|
@ -181,9 +181,49 @@ SetAttributeDataLength(PFILE_OBJECT FileObject,
|
||||||
{
|
{
|
||||||
if (AttrContext->Record.IsNonResident)
|
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?
|
// 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");
|
DPRINT1("FixMe: Increasing allocation size is unimplemented!\n");
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
@ -459,7 +499,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
|
||||||
PUCHAR SourceBuffer = Buffer;
|
PUCHAR SourceBuffer = Buffer;
|
||||||
LONGLONG StartingOffset;
|
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?
|
// is this a resident attribute?
|
||||||
if (!Context->Record.IsNonResident)
|
if (!Context->Record.IsNonResident)
|
||||||
|
|
|
@ -511,6 +511,11 @@ NtfsMarkIrpContextForQueue(PNTFS_IRP_CONTEXT IrpContext)
|
||||||
//VOID
|
//VOID
|
||||||
//NtfsDumpAttribute(PATTRIBUTE Attribute);
|
//NtfsDumpAttribute(PATTRIBUTE Attribute);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
AddRun(PNTFS_ATTR_CONTEXT AttrContext,
|
||||||
|
ULONGLONG NextAssignedCluster,
|
||||||
|
ULONG RunLength);
|
||||||
|
|
||||||
PUCHAR
|
PUCHAR
|
||||||
DecodeRun(PUCHAR DataRun,
|
DecodeRun(PUCHAR DataRun,
|
||||||
LONGLONG *DataRunOffset,
|
LONGLONG *DataRunOffset,
|
||||||
|
@ -529,6 +534,11 @@ GetFileNameFromRecord(PDEVICE_EXTENSION Vcb,
|
||||||
PFILE_RECORD_HEADER FileRecord,
|
PFILE_RECORD_HEADER FileRecord,
|
||||||
UCHAR NameType);
|
UCHAR NameType);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
GetLastClusterInDataRun(PDEVICE_EXTENSION Vcb,
|
||||||
|
PNTFS_ATTR_RECORD Attribute,
|
||||||
|
PULONGLONG LastCluster);
|
||||||
|
|
||||||
PFILENAME_ATTRIBUTE
|
PFILENAME_ATTRIBUTE
|
||||||
GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb,
|
GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb,
|
||||||
PFILE_RECORD_HEADER FileRecord);
|
PFILE_RECORD_HEADER FileRecord);
|
||||||
|
@ -774,7 +784,7 @@ SetAttributeDataLength(PFILE_OBJECT FileObject,
|
||||||
PFILE_RECORD_HEADER FileRecord,
|
PFILE_RECORD_HEADER FileRecord,
|
||||||
PLARGE_INTEGER DataSize);
|
PLARGE_INTEGER DataSize);
|
||||||
|
|
||||||
ULONG
|
ULONGLONG
|
||||||
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
|
AttributeAllocatedLength(PNTFS_ATTR_RECORD AttrRecord);
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
@ -915,6 +925,13 @@ NtfsWrite(PNTFS_IRP_CONTEXT IrpContext);
|
||||||
|
|
||||||
/* volinfo.c */
|
/* volinfo.c */
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt,
|
||||||
|
ULONG FirstDesiredCluster,
|
||||||
|
ULONG DesiredClusters,
|
||||||
|
PULONG FirstAssignedCluster,
|
||||||
|
PULONG AssignedClusters);
|
||||||
|
|
||||||
ULONGLONG
|
ULONGLONG
|
||||||
NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt);
|
NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt);
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,110 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
|
||||||
return FreeClusters;
|
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
|
static
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
|
NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
|
||||||
|
|
Loading…
Reference in a new issue