private void Truncate(long value) { long endVcn = Utilities.Ceil(value, _bytesPerCluster); // Release the clusters _activeStream.TruncateToClusters(endVcn); // First, remove any extents that are now redundant. Dictionary <AttributeReference, AttributeRecord> extentCache = new Dictionary <AttributeReference, AttributeRecord>(_attribute.Extents); foreach (var extent in extentCache) { if (extent.Value.StartVcn >= endVcn) { NonResidentAttributeRecord record = (NonResidentAttributeRecord)extent.Value; _file.RemoveAttributeExtent(extent.Key); _attribute.RemoveExtentCacheSafe(extent.Key); } } PrimaryAttributeRecord.LastVcn = Math.Max(0, endVcn - 1); PrimaryAttributeRecord.AllocatedLength = endVcn * _bytesPerCluster; PrimaryAttributeRecord.DataLength = value; PrimaryAttributeRecord.InitializedDataLength = Math.Min(PrimaryAttributeRecord.InitializedDataLength, value); _file.MarkMftRecordDirty(); }
public void Append(IEnumerable <DataRun> rawRuns, NonResidentAttributeRecord attributeExtent) { long vcn = NextVirtualCluster; long lcn = 0; foreach (var run in rawRuns) { _runs.Add(new CookedDataRun(run, vcn, lcn, attributeExtent)); vcn += run.RunLength; lcn += run.RunOffset; } }
public CookedDataRun(DataRun raw, long startVcn, long prevLcn, NonResidentAttributeRecord attributeExtent) { _raw = raw; _startVcn = startVcn; _startLcn = prevLcn + raw.RunOffset; _attributeExtent = attributeExtent; if (startVcn < 0) { throw new ArgumentOutOfRangeException("startVcn", startVcn, "VCN must be >= 0"); } if (_startLcn < 0) { throw new ArgumentOutOfRangeException("prevLcn", prevLcn, "LCN must be >= 0"); } }
public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate) { long totalVirtualClusters = _cookedRuns.NextVirtualCluster; if (totalVirtualClusters < numVirtualClusters) { NonResidentAttributeRecord realExtent = extent; if (realExtent == null) { realExtent = _cookedRuns.Last.AttributeExtent; } DataRun newRun = new DataRun(0, numVirtualClusters - totalVirtualClusters, true); realExtent.DataRuns.Add(newRun); _cookedRuns.Append(newRun, extent); realExtent.LastVcn = numVirtualClusters - 1; } if (allocate) { AllocateClusters(totalVirtualClusters, (int)(numVirtualClusters - totalVirtualClusters)); } }
public CookedDataRuns(IEnumerable <DataRun> rawRuns, NonResidentAttributeRecord attributeExtent) { _runs = new List <CookedDataRun>(); Append(rawRuns, attributeExtent); }
public void Append(DataRun rawRun, NonResidentAttributeRecord attributeExtent) { CookedDataRun last = Last; _runs.Add(new CookedDataRun(rawRun, NextVirtualCluster, last == null ? 0 : last.StartLcn, attributeExtent)); }
public abstract void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate);
public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate) { _rawStream.ExpandToClusters(Utilities.RoundUp(numVirtualClusters, _attr.CompressionUnitSize), extent, false); }
private bool VerifyMftRecord(byte[] recordData, bool presentInBitmap, int bytesPerSector) { bool ok = true; // // Verify the attributes seem OK... // byte[] tempBuffer = new byte[recordData.Length]; Array.Copy(recordData, tempBuffer, tempBuffer.Length); GenericFixupRecord genericRecord = new GenericFixupRecord(bytesPerSector); genericRecord.FromBytes(tempBuffer, 0); int pos = Utilities.ToUInt16LittleEndian(genericRecord.Content, 0x14); while (Utilities.ToUInt32LittleEndian(genericRecord.Content, pos) != 0xFFFFFFFF) { int attrLen; try { AttributeRecord ar = AttributeRecord.FromBytes(genericRecord.Content, pos, out attrLen); if (attrLen != ar.Size) { ReportError("Attribute size is different to calculated size. AttrId={0}", ar.AttributeId); ok = false; } if (ar.IsNonResident) { NonResidentAttributeRecord nrr = (NonResidentAttributeRecord)ar; if (nrr.DataRuns.Count > 0) { long totalVcn = 0; foreach (var run in nrr.DataRuns) { totalVcn += run.RunLength; } if (totalVcn != nrr.LastVcn - nrr.StartVcn + 1) { ReportError("Declared VCNs doesn't match data runs. AttrId={0}", ar.AttributeId); ok = false; } } } } catch { ReportError("Failure parsing attribute at pos={0}", pos); return(false); } pos += attrLen; } // // Now consider record as a whole // FileRecord record = new FileRecord(bytesPerSector); record.FromBytes(recordData, 0); bool inUse = (record.Flags & FileRecordFlags.InUse) != 0; if (inUse != presentInBitmap) { ReportError("MFT bitmap and record in-use flag don't agree. Mft={0}, Record={1}", presentInBitmap ? "InUse" : "Free", inUse ? "InUse" : "Free"); ok = false; } if (record.Size != record.RealSize) { ReportError("MFT record real size is different to calculated size. Stored in MFT={0}, Calculated={1}", record.RealSize, record.Size); ok = false; } if (Utilities.ToUInt32LittleEndian(recordData, (int)record.RealSize - 8) != uint.MaxValue) { ReportError("MFT record is not correctly terminated with 0xFFFFFFFF"); ok = false; } return(ok); }
public NonResidentDataBuffer(INtfsContext context, NonResidentAttributeRecord record) : this(context, new CookedDataRuns(record.DataRuns, record), false) { }
public CookedDataRuns(IEnumerable<DataRun> rawRuns, NonResidentAttributeRecord attributeExtent) { _runs = new List<CookedDataRun>(); Append(rawRuns, attributeExtent); }
public void Append(IEnumerable<DataRun> rawRuns, NonResidentAttributeRecord attributeExtent) { long vcn = NextVirtualCluster; long lcn = 0; foreach (var run in rawRuns) { _runs.Add(new CookedDataRun(run, vcn, lcn, attributeExtent)); vcn += run.RunLength; lcn += run.RunOffset; } }
public override void ExpandToClusters(long numVirtualClusters, NonResidentAttributeRecord extent, bool allocate) { _rawStream.ExpandToClusters(CompressionStart(numVirtualClusters), extent, false); }
private bool SplitAttribute(FileRecord record, NonResidentAttributeRecord targetAttr, bool atStart) { if (targetAttr.DataRuns.Count <= 1) { return false; } int splitIndex = 1; if (!atStart) { List<DataRun> runs = targetAttr.DataRuns; splitIndex = runs.Count - 1; int saved = runs[splitIndex].Size; while (splitIndex > 1 && record.Size - saved > record.AllocatedSize) { --splitIndex; saved += runs[splitIndex].Size; } } AttributeRecord newAttr = targetAttr.Split(splitIndex); // Find a home for the new attribute record FileRecord newAttrHome = null; foreach (var targetRecord in _records) { if (!targetRecord.IsMftRecord && _mft.RecordSize - targetRecord.Size >= newAttr.Size) { targetRecord.AddAttribute(newAttr); newAttrHome = targetRecord; } } if (newAttrHome == null) { newAttrHome = _mft.AllocateRecord(_records[0].Flags & (~FileRecordFlags.InUse), record.IsMftRecord); newAttrHome.BaseFile = record.BaseFile.IsNull ? record.Reference : record.BaseFile; _records.Add(newAttrHome); newAttrHome.AddAttribute(newAttr); } // Add the new attribute record as an extent on the attribute it split from bool added = false; foreach (var attr in _attributes) { foreach (var existingRecord in attr.Extents) { if (existingRecord.Key.File == record.Reference && existingRecord.Key.AttributeId == targetAttr.AttributeId) { attr.AddExtent(newAttrHome.Reference, newAttr); added = true; break; } } if (added) { break; } } UpdateAttributeList(); return true; }
private bool SplitAttribute(FileRecord record, NonResidentAttributeRecord targetAttr, bool atStart) { if (targetAttr.DataRuns.Count <= 1) { return(false); } int splitIndex = 1; if (!atStart) { List <DataRun> runs = targetAttr.DataRuns; splitIndex = runs.Count - 1; int saved = runs[splitIndex].Size; while (splitIndex > 1 && record.Size - saved > record.AllocatedSize) { --splitIndex; saved += runs[splitIndex].Size; } } AttributeRecord newAttr = targetAttr.Split(splitIndex); // Find a home for the new attribute record FileRecord newAttrHome = null; foreach (var targetRecord in _records) { if (!targetRecord.IsMftRecord && _mft.RecordSize - targetRecord.Size >= newAttr.Size) { targetRecord.AddAttribute(newAttr); newAttrHome = targetRecord; } } if (newAttrHome == null) { newAttrHome = _mft.AllocateRecord(_records[0].Flags & (~FileRecordFlags.InUse), record.IsMftRecord); newAttrHome.BaseFile = record.BaseFile.IsNull ? record.Reference : record.BaseFile; _records.Add(newAttrHome); newAttrHome.AddAttribute(newAttr); } // Add the new attribute record as an extent on the attribute it split from bool added = false; foreach (var attr in _attributes) { foreach (var existingRecord in attr.Extents) { if (existingRecord.Key.File == record.Reference && existingRecord.Key.AttributeId == targetAttr.AttributeId) { attr.AddExtent(newAttrHome.Reference, newAttr); added = true; break; } } if (added) { break; } } UpdateAttributeList(); return(true); }