https://git.reactos.org/?p=reactos.git;a=commitdiff;h=77fc65dc0e4f7b08cec05…
commit 77fc65dc0e4f7b08cec056bb3f017c70036748f6
Author: Trevor Thompson <tmt256(a)email.vccs.edu>
AuthorDate: Wed Jun 29 16:35:36 2016 +0000
[NTFS]
Lay some groundwork for extending allocation size.
+AddRun() - Unimplemented
+GetLastClusterInDataRun()
+NtfsAllocateClusters()
svn path=/branches/GSoC_2016/NTFS/; revision=71696
---
drivers/filesystems/ntfs/attrib.c | 57 ++++++++++++++++++++
drivers/filesystems/ntfs/mft.c | 48 +++++++++++++++--
drivers/filesystems/ntfs/ntfs.h | 19 ++++++-
drivers/filesystems/ntfs/volinfo.c | 104 +++++++++++++++++++++++++++++++++++++
4 files changed, 223 insertions(+), 5 deletions(-)
diff --git a/drivers/filesystems/ntfs/attrib.c b/drivers/filesystems/ntfs/attrib.c
index 12474f6c81..9608d1d17b 100644
--- a/drivers/filesystems/ntfs/attrib.c
+++ b/drivers/filesystems/ntfs/attrib.c
@@ -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)
diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c
index ae2a6cc2ba..e1725f9a50 100644
--- a/drivers/filesystems/ntfs/mft.c
+++ b/drivers/filesystems/ntfs/mft.c
@@ -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)
diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h
index 4435b4866e..66cb37f4bd 100644
--- a/drivers/filesystems/ntfs/ntfs.h
+++ b/drivers/filesystems/ntfs/ntfs.h
@@ -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);
diff --git a/drivers/filesystems/ntfs/volinfo.c b/drivers/filesystems/ntfs/volinfo.c
index 13a3b7af7f..c893562189 100644
--- a/drivers/filesystems/ntfs/volinfo.c
+++ b/drivers/filesystems/ntfs/volinfo.c
@@ -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,