ULONG RunLength)
{
NTSTATUS Status;
- PUCHAR DataRun = (PUCHAR)&AttrContext->Record + AttrContext->Record.NonResident.MappingPairsOffset;
int DataRunMaxLength;
PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
- LARGE_MCB DataRunsMCB;
ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length;
- ULONGLONG NextVBN = AttrContext->Record.NonResident.LowestVCN;
+ ULONGLONG NextVBN = 0;
- // Allocate some memory for the RunBuffer
PUCHAR RunBuffer;
- ULONG RunBufferOffset = 0;
+ ULONG RunBufferSize;
if (!AttrContext->Record.IsNonResident)
return STATUS_INVALID_PARAMETER;
- RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
- if (!RunBuffer)
- {
- DPRINT1("ERROR: Couldn't allocate memory for data runs!\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- // Convert the data runs to a map control block
- Status = ConvertDataRunsToLargeMCB(DataRun, &DataRunsMCB, &NextVBN);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Unable to convert data runs to MCB (probably ran out of memory)!\n");
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
- return Status;
- }
+ if (AttrContext->Record.NonResident.AllocatedSize != 0)
+ NextVBN = AttrContext->Record.NonResident.HighestVCN + 1;
// Add newly-assigned clusters to mcb
_SEH2_TRY{
- if (!FsRtlAddLargeMcbEntry(&DataRunsMCB,
+ if (!FsRtlAddLargeMcbEntry(&AttrContext->DataRunsMCB,
NextVBN,
NextAssignedCluster,
RunLength))
ExRaiseStatus(STATUS_UNSUCCESSFUL);
}
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
_SEH2_YIELD(_SEH2_GetExceptionCode());
} _SEH2_END;
+ RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+ if (!RunBuffer)
+ {
+ DPRINT1("ERROR: Couldn't allocate memory for data runs!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
// Convert the map control block back to encoded data runs
- ConvertLargeMCBToDataRuns(&DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferOffset);
+ ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize);
// Get the amount of free space between the start of the of the first data run and the attribute end
DataRunMaxLength = AttrContext->Record.Length - AttrContext->Record.NonResident.MappingPairsOffset;
// Do we need to extend the attribute (or convert to attribute list)?
- if (DataRunMaxLength < RunBufferOffset)
+ if (DataRunMaxLength < RunBufferSize)
{
PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
DataRunMaxLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2);
// Can we move the end of the attribute?
- if (NextAttribute->Type != AttributeEnd || DataRunMaxLength < RunBufferOffset - 1)
+ if (NextAttribute->Type != AttributeEnd || DataRunMaxLength < RunBufferSize - 1)
{
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);
ExFreePoolWithTag(RunBuffer, TAG_NTFS);
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
return STATUS_NOT_IMPLEMENTED;
}
// calculate position of end markers
- NextAttributeOffset = AttrOffset + AttrContext->Record.NonResident.MappingPairsOffset + RunBufferOffset;
+ NextAttributeOffset = AttrOffset + AttrContext->Record.NonResident.MappingPairsOffset + RunBufferSize;
NextAttributeOffset = ALIGN_UP_BY(NextAttributeOffset, 8);
- // Write the end markers
- NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
- NextAttribute->Type = AttributeEnd;
- NextAttribute->Length = FILE_RECORD_END;
-
// Update the length
DestinationAttribute->Length = NextAttributeOffset - AttrOffset;
AttrContext->Record.Length = DestinationAttribute->Length;
- // We need to increase the FileRecord size
- FileRecord->BytesInUse = NextAttributeOffset + (sizeof(ULONG) * 2);
+ // End the file record
+ NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
+ SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END);
}
- // NOTE: from this point on the original attribute record will contain invalid data in it's runbuffer
- // TODO: Elegant fix? Could we free the old Record and allocate a new one without issue?
-
// Update HighestVCN
DestinationAttribute->NonResident.HighestVCN =
- AttrContext->Record.NonResident.HighestVCN = max(NextVBN - 1 + RunLength,
+ AttrContext->Record.NonResident.HighestVCN = max(NextVBN - 1 + RunLength,
AttrContext->Record.NonResident.HighestVCN);
// Write data runs to destination attribute
RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset),
RunBuffer,
- RunBufferOffset);
+ RunBufferSize);
// Update the file record
Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
ExFreePoolWithTag(RunBuffer, TAG_NTFS);
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), 0);
DataRunLengthSize = GetPackedByteCount(Count, TRUE);
DPRINT("%d bytes needed.\n", DataRunLengthSize);
- // ensure the next data run + end marker would be > Max buffer size
+ // ensure the next data run + end marker would be <= Max buffer size
if (RunBufferOffset + 2 + DataRunLengthSize + DataRunOffsetSize > MaxBufferSize)
{
Status = STATUS_BUFFER_TOO_SMALL;
NTSTATUS Status = STATUS_SUCCESS;
ULONG ClustersLeftToFree = ClustersToFree;
- // convert data runs to mcb
- PUCHAR DataRun = (PUCHAR)&AttrContext->Record + AttrContext->Record.NonResident.MappingPairsOffset;
PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
- LARGE_MCB DataRunsMCB;
ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length;
PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
- ULONGLONG NextVBN = AttrContext->Record.NonResident.LowestVCN;
- // Allocate some memory for the RunBuffer
PUCHAR RunBuffer;
- ULONG RunBufferOffset = 0;
+ ULONG RunBufferSize = 0;
PFILE_RECORD_HEADER BitmapRecord;
PNTFS_ATTR_CONTEXT DataContext;
return STATUS_INVALID_PARAMETER;
}
- RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
- if (!RunBuffer)
- {
- DPRINT1("ERROR: Couldn't allocate memory for data runs!\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- // Convert the data runs to a map control block
- Status = ConvertDataRunsToLargeMCB(DataRun, &DataRunsMCB, &NextVBN);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Unable to convert data runs to MCB (probably ran out of memory)!\n");
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
- return Status;
- }
-
+ // Read the $Bitmap file
BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
Vcb->NtfsInfo.BytesPerFileRecord,
TAG_NTFS);
if (BitmapRecord == NULL)
{
DPRINT1("Error: Unable to allocate memory for bitmap file record!\n");
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
return STATUS_NO_MEMORY;
}
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Unable to read file record for bitmap!\n");
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
return 0;
}
if (!NT_SUCCESS(Status))
{
DPRINT1("Error: Unable to find data attribute for bitmap file!\n");
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
return 0;
}
{
DPRINT1("Error: Unable to allocate memory for bitmap file data!\n");
ReleaseAttributeContext(DataContext);
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
return 0;
}
{
LONGLONG LargeVbn, LargeLbn;
- if (!FsRtlLookupLastLargeMcbEntry(&DataRunsMCB, &LargeVbn, &LargeLbn))
+ if (!FsRtlLookupLastLargeMcbEntry(&AttrContext->DataRunsMCB, &LargeVbn, &LargeLbn))
{
Status = STATUS_INVALID_PARAMETER;
DPRINT1("DRIVER ERROR: FreeClusters called to free %lu clusters, which is %lu more clusters than are assigned to attribute!",
// deallocate this cluster
RtlClearBits(&Bitmap, LargeLbn, 1);
}
- FsRtlTruncateLargeMcb(&DataRunsMCB, AttrContext->Record.NonResident.HighestVCN);
+ FsRtlTruncateLargeMcb(&AttrContext->DataRunsMCB, AttrContext->Record.NonResident.HighestVCN);
+
+ // decrement HighestVCN, but don't let it go below 0
AttrContext->Record.NonResident.HighestVCN = min(AttrContext->Record.NonResident.HighestVCN, AttrContext->Record.NonResident.HighestVCN - 1);
ClustersLeftToFree--;
}
if (!NT_SUCCESS(Status))
{
ReleaseAttributeContext(DataContext);
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
ExFreePoolWithTag(BitmapData, TAG_NTFS);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
- ExFreePoolWithTag(RunBuffer, TAG_NTFS);
return Status;
}
ReleaseAttributeContext(DataContext);
ExFreePoolWithTag(BitmapData, TAG_NTFS);
ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+
+ // Save updated data runs to file record
+
+ // Allocate some memory for a new RunBuffer
+ RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+ if (!RunBuffer)
+ {
+ DPRINT1("ERROR: Couldn't allocate memory for data runs!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
// Convert the map control block back to encoded data runs
- ConvertLargeMCBToDataRuns(&DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferOffset);
+ ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize);
// Update HighestVCN
DestinationAttribute->NonResident.HighestVCN = AttrContext->Record.NonResident.HighestVCN;
// Write data runs to destination attribute
RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset),
RunBuffer,
- RunBufferOffset);
+ RunBufferSize);
+ // Is DestinationAttribute the last attribute in the file record?
if (NextAttribute->Type == AttributeEnd)
{
// update attribute length
- AttrContext->Record.Length = ALIGN_UP_BY(AttrContext->Record.NonResident.MappingPairsOffset + RunBufferOffset, 8);
+ AttrContext->Record.Length = ALIGN_UP_BY(AttrContext->Record.NonResident.MappingPairsOffset + RunBufferSize, 8);
DestinationAttribute->Length = AttrContext->Record.Length;
// write end markers
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length);
- NextAttribute->Type = AttributeEnd;
- NextAttribute->Length = FILE_RECORD_END;
-
- // update file record length
- FileRecord->BytesInUse = AttrOffset + DestinationAttribute->Length + (sizeof(ULONG) * 2);
+ SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END);
}
// Update the file record
Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
- FsRtlUninitializeLargeMcb(&DataRunsMCB);
ExFreePoolWithTag(RunBuffer, TAG_NTFS);
NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), 0);
{
LONGLONG DataRunOffset;
ULONGLONG DataRunLength;
+ ULONGLONG NextVBN = 0;
+ PUCHAR DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
- Context->CacheRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
+ Context->CacheRun = DataRun;
Context->CacheRunOffset = 0;
Context->CacheRun = DecodeRun(Context->CacheRun, &DataRunOffset, &DataRunLength);
Context->CacheRunLength = DataRunLength;
Context->CacheRunLastLCN = 0;
}
Context->CacheRunCurrentOffset = 0;
+
+ // Convert the data runs to a map control block
+ if (!NT_SUCCESS(ConvertDataRunsToLargeMCB(DataRun, &Context->DataRunsMCB, &NextVBN)))
+ {
+ DPRINT1("Unable to convert data runs to MCB!\n");
+ ExFreePoolWithTag(Context, TAG_NTFS);
+ return NULL;
+ }
}
return Context;
VOID
ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context)
{
+ if (Context->Record.IsNonResident)
+ {
+ FsRtlUninitializeLargeMcb(&Context->DataRunsMCB);
+ }
+
ExFreePoolWithTag(Context, TAG_NTFS);
}
ULONG NextAssignedCluster;
ULONG AssignedClusters;
- NTSTATUS Status = GetLastClusterInDataRun(Fcb->Vcb, &AttrContext->Record, (PULONGLONG)&LastClusterInDataRun.QuadPart);
+ if (ExistingClusters == 0)
+ {
+ LastClusterInDataRun.QuadPart = 0;
+ }
+ else
+ {
+ if (!FsRtlLookupLargeMcbEntry(&AttrContext->DataRunsMCB,
+ (LONGLONG)AttrContext->Record.NonResident.HighestVCN,
+ (PLONGLONG)&LastClusterInDataRun.QuadPart,
+ NULL,
+ NULL,
+ NULL,
+ NULL))
+ {
+ DPRINT1("Error looking up final large MCB entry!\n");
- DPRINT1("GetLastClusterInDataRun returned: %I64u\n", LastClusterInDataRun.QuadPart);
- DPRINT1("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN);
+ // Most likely, HighestVCN went above the largest mapping
+ DPRINT1("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ DPRINT("LastClusterInDataRun: %I64u\n", LastClusterInDataRun.QuadPart);
+ DPRINT("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN);
while (ClustersNeeded > 0)
{
ULONG ReadLength;
ULONG AlreadyRead;
NTSTATUS Status;
+
+ //TEMPTEMP
+ PUCHAR TempBuffer;
if (!Context->Record.IsNonResident)
{
}
else
{
+ //TEMPTEMP
+ ULONG UsedBufferSize;
+ TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+
LastLCN = 0;
- DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
CurrentOffset = 0;
+ // This will be rewritten in the next iteration to just use the DataRuns MCB directly
+ ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
+ TempBuffer,
+ Vcb->NtfsInfo.BytesPerFileRecord,
+ &UsedBufferSize);
+
+ DataRun = TempBuffer;
+
while (1)
{
DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
} /* if Disk */
+ // TEMPTEMP
+ if (Context->Record.IsNonResident)
+ ExFreePoolWithTag(TempBuffer, TAG_NTFS);
+
Context->CacheRun = DataRun;
Context->CacheRunOffset = Offset + AlreadyRead;
Context->CacheRunStartLCN = DataRunStartLCN;
NTSTATUS Status;
PUCHAR SourceBuffer = Buffer;
LONGLONG StartingOffset;
+
+ //TEMPTEMP
+ PUCHAR TempBuffer;
+
DPRINT("WriteAttribute(%p, %p, %I64u, %p, %lu, %p)\n", Vcb, Context, Offset, Buffer, Length, RealLengthWritten);
}
else*/
{
+ ULONG UsedBufferSize;
LastLCN = 0;
- DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
- CurrentOffset = 0;
+ CurrentOffset = 0;
+
+ // This will be rewritten in the next iteration to just use the DataRuns MCB directly
+ TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+
+ ConvertLargeMCBToDataRuns(&Context->DataRunsMCB,
+ TempBuffer,
+ Vcb->NtfsInfo.BytesPerFileRecord,
+ &UsedBufferSize);
+
+ DataRun = TempBuffer;
while (1)
{
}
} // end while (Length > 0) [more data to write]
+ // TEMPTEMP
+ if(Context->Record.IsNonResident)
+ ExFreePoolWithTag(TempBuffer, TAG_NTFS);
+
Context->CacheRun = DataRun;
Context->CacheRunOffset = Offset + *RealLengthWritten;
Context->CacheRunStartLCN = DataRunStartLCN;