protected override void Read(byte[] buffer, int offset) { _logFileSequenceNumber = Utilities.ToUInt64LittleEndian(buffer, offset + 0x08); _sequenceNumber = Utilities.ToUInt16LittleEndian(buffer, offset + 0x10); _hardLinkCount = Utilities.ToUInt16LittleEndian(buffer, offset + 0x12); _firstAttributeOffset = Utilities.ToUInt16LittleEndian(buffer, offset + 0x14); _flags = (FileRecordFlags)Utilities.ToUInt16LittleEndian(buffer, offset + 0x16); _recordRealSize = Utilities.ToUInt32LittleEndian(buffer, offset + 0x18); _recordAllocatedSize = Utilities.ToUInt32LittleEndian(buffer, offset + 0x1C); _baseFile = new FileRecordReference(Utilities.ToUInt64LittleEndian(buffer, offset + 0x20)); _nextAttributeId = Utilities.ToUInt16LittleEndian(buffer, offset + 0x28); if (UpdateSequenceOffset >= 0x30) { _index = Utilities.ToUInt32LittleEndian(buffer, offset + 0x2C); _haveIndex = true; } _attributes = new List <AttributeRecord>(); int focus = _firstAttributeOffset; while (true) { int length; AttributeRecord attr = AttributeRecord.FromBytes(buffer, focus, out length); if (attr == null) { break; } _attributes.Add(attr); focus += (int)length; } }
/// <summary> /// Adds an existing attribute. /// </summary> /// <param name="attrRec">The attribute to add</param> /// <returns>The new Id of the attribute</returns> /// <remarks>This method is used to move an attribute between different MFT records</remarks> public ushort AddAttribute(AttributeRecord attrRec) { attrRec.AttributeId = _nextAttributeId++; _attributes.Add(attrRec); _attributes.Sort(); return(attrRec.AttributeId); }
protected NtfsAttribute(File file, FileRecordReference containingFile, AttributeRecord record) { _file = file; _containingFile = containingFile; _primaryRecord = record; _extents = new Dictionary <AttributeReference, AttributeRecord>(); _extents.Add(new AttributeReference(containingFile, record.AttributeId), _primaryRecord); }
public void SetExtent(FileRecordReference containingFile, AttributeRecord record) { _cachedRawBuffer = null; _containingFile = containingFile; _primaryRecord = record; _extents.Clear(); _extents.Add(new AttributeReference(containingFile, record.AttributeId), record); }
/// <summary> /// Creates a new attribute at a fixed cluster. /// </summary> /// <param name="type">The type of the new attribute</param> /// <param name="name">The name of the new attribute</param> /// <param name="flags">The flags of the new attribute</param> /// <param name="firstCluster">The first cluster to assign to the attribute</param> /// <param name="numClusters">The number of sequential clusters to assign to the attribute</param> /// <param name="bytesPerCluster">The number of bytes in each cluster</param> /// <returns>The new attribute</returns> private NtfsAttribute CreateAttribute(AttributeType type, string name, AttributeFlags flags, long firstCluster, ulong numClusters, uint bytesPerCluster) { bool indexed = _context.AttributeDefinitions.IsIndexed(type); ushort id = _records[0].CreateNonResidentAttribute(type, name, flags, firstCluster, numClusters, bytesPerCluster); AttributeRecord newAttrRecord = _records[0].GetAttribute(id); NtfsAttribute newAttr = NtfsAttribute.FromRecord(this, MftReference, newAttrRecord); _attributes.Add(newAttr); UpdateAttributeList(); MarkMftRecordDirty(); return(newAttr); }
/// <summary> /// Creates a new attribute. /// </summary> /// <param name="type">The type of the new attribute</param> /// <param name="name">The name of the new attribute</param> /// <param name="flags">The flags of the new attribute</param> /// <returns>The new attribute</returns> private NtfsAttribute CreateAttribute(AttributeType type, string name, AttributeFlags flags) { bool indexed = _context.AttributeDefinitions.IsIndexed(type); ushort id = _records[0].CreateAttribute(type, name, indexed, flags); AttributeRecord newAttrRecord = _records[0].GetAttribute(id); NtfsAttribute newAttr = NtfsAttribute.FromRecord(this, MftReference, newAttrRecord); _attributes.Add(newAttr); UpdateAttributeList(); MarkMftRecordDirty(); return(newAttr); }
private void MoveAttribute(FileRecord record, AttributeRecord attrRec, FileRecord targetRecord) { AttributeReference oldRef = new AttributeReference(record.Reference, attrRec.AttributeId); record.RemoveAttribute(attrRec.AttributeId); targetRecord.AddAttribute(attrRec); AttributeReference newRef = new AttributeReference(targetRecord.Reference, attrRec.AttributeId); foreach (var attr in _attributes) { attr.ReplaceExtent(oldRef, newRef, attrRec); } UpdateAttributeList(); }
private bool ExpelAttribute(FileRecord record) { if (record.MasterFileTableIndex == MasterFileTable.MftIndex) { // Special case for MFT - can't fully expel attributes, instead split most of the data runs off. List <AttributeRecord> attrs = record.Attributes; for (int i = attrs.Count - 1; i >= 0; --i) { AttributeRecord attr = attrs[i]; if (attr.AttributeType == AttributeType.Data) { if (SplitAttribute(record, (NonResidentAttributeRecord)attr, true)) { return(true); } } } } else { List <AttributeRecord> attrs = record.Attributes; for (int i = attrs.Count - 1; i >= 0; --i) { AttributeRecord attr = attrs[i]; if (attr.AttributeType > AttributeType.AttributeList) { foreach (var targetRecord in _records) { if (_mft.RecordSize - targetRecord.Size >= attr.Size) { MoveAttribute(record, attr, targetRecord); return(true); } } FileRecord newFileRecord = _mft.AllocateRecord(FileRecordFlags.None, record.IsMftRecord); newFileRecord.BaseFile = record.Reference; _records.Add(newFileRecord); MoveAttribute(record, attr, newFileRecord); return(true); } } } return(false); }
public static AttributeListRecord FromAttribute(AttributeRecord attr, FileRecordReference mftRecord) { AttributeListRecord newRecord = new AttributeListRecord() { Type = attr.AttributeType, Name = attr.Name, StartVcn = 0, BaseFileReference = mftRecord, AttributeId = attr.AttributeId }; if (attr.IsNonResident) { newRecord.StartVcn = (ulong)((NonResidentAttributeRecord)attr).StartVcn; } return(newRecord); }
public bool ReplaceExtent(AttributeReference oldRef, AttributeReference newRef, AttributeRecord record) { _cachedRawBuffer = null; if (!_extents.Remove(oldRef)) { return(false); } else { if (oldRef.Equals(Reference) || _extents.Count == 0) { _primaryRecord = record; _containingFile = newRef.File; } _extents.Add(newRef, record); return(true); } }
internal void MakeAttributeNonResident(AttributeReference attrRef, int maxData) { NtfsAttribute attr = GetAttribute(attrRef); if (attr.IsNonResident) { throw new InvalidOperationException("Attribute is already non-resident"); } ushort id = _records[0].CreateNonResidentAttribute(attr.Type, attr.Name, attr.Flags); AttributeRecord newAttrRecord = _records[0].GetAttribute(id); IBuffer attrBuffer = attr.GetDataBuffer(); byte[] tempData = Utilities.ReadFully(attrBuffer, 0, (int)Math.Min(maxData, attrBuffer.Capacity)); RemoveAttributeExtents(attr); attr.SetExtent(_records[0].Reference, newAttrRecord); attr.GetDataBuffer().Write(0, tempData, 0, tempData.Length); UpdateAttributeList(); }
private bool SplitAttribute(FileRecord record, NonResidentAttributeRecord targetAttr, bool atStart) { if (targetAttr.DataRuns.Count <= 1) { return(false); } int splitIndex = 1; if (!atStart) { // Approximation only - assumes each run is at least one byte saved. Could calculate the // actual index here. splitIndex = (int)(targetAttr.DataRuns.Count - (record.Size - record.AllocatedSize)); } 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 void LoadAttributes() { Dictionary <long, FileRecord> extraFileRecords = new Dictionary <long, FileRecord>(); AttributeRecord attrListRec = _records[0].GetAttribute(AttributeType.AttributeList); if (attrListRec != null) { NtfsAttribute lastAttr = null; StructuredNtfsAttribute <AttributeList> attrListAttr = (StructuredNtfsAttribute <AttributeList>)NtfsAttribute.FromRecord(this, MftReference, attrListRec); var attrList = attrListAttr.Content; _attributes.Add(attrListAttr); foreach (var record in attrList) { FileRecord attrFileRecord = _records[0]; if (record.BaseFileReference.MftIndex != _records[0].MasterFileTableIndex) { if (!extraFileRecords.TryGetValue(record.BaseFileReference.MftIndex, out attrFileRecord)) { attrFileRecord = _context.Mft.GetRecord(record.BaseFileReference); if (attrFileRecord != null) { extraFileRecords[attrFileRecord.MasterFileTableIndex] = attrFileRecord; } } } if (attrFileRecord != null) { AttributeRecord attrRec = attrFileRecord.GetAttribute(record.AttributeId); if (attrRec != null) { if (record.StartVcn == 0) { lastAttr = NtfsAttribute.FromRecord(this, record.BaseFileReference, attrRec); _attributes.Add(lastAttr); } else { lastAttr.AddExtent(record.BaseFileReference, attrRec); } } } } foreach (var extraFileRecord in extraFileRecords) { _records.Add(extraFileRecord.Value); } } else { foreach (var record in _records[0].Attributes) { _attributes.Add(NtfsAttribute.FromRecord(this, MftReference, record)); } } }
public StructuredNtfsAttribute(File file, FileRecordReference containingFile, AttributeRecord record) : base(file, containingFile, record) { _structure = new T(); }
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 void AddExtent(FileRecordReference containingFile, AttributeRecord record) { _cachedRawBuffer = null; _extents.Add(new AttributeReference(containingFile, record.AttributeId), record); }
public static NtfsAttribute FromRecord(File file, FileRecordReference recordFile, AttributeRecord record) { switch (record.AttributeType) { case AttributeType.StandardInformation: return(new StructuredNtfsAttribute <StandardInformation>(file, recordFile, record)); case AttributeType.FileName: return(new StructuredNtfsAttribute <FileNameRecord>(file, recordFile, record)); case AttributeType.SecurityDescriptor: return(new StructuredNtfsAttribute <SecurityDescriptor>(file, recordFile, record)); case AttributeType.Data: return(new NtfsAttribute(file, recordFile, record)); case AttributeType.Bitmap: return(new NtfsAttribute(file, recordFile, record)); case AttributeType.VolumeName: return(new StructuredNtfsAttribute <VolumeName>(file, recordFile, record)); case AttributeType.VolumeInformation: return(new StructuredNtfsAttribute <VolumeInformation>(file, recordFile, record)); case AttributeType.IndexRoot: return(new NtfsAttribute(file, recordFile, record)); case AttributeType.IndexAllocation: return(new NtfsAttribute(file, recordFile, record)); case AttributeType.ObjectId: return(new StructuredNtfsAttribute <ObjectId>(file, recordFile, record)); case AttributeType.ReparsePoint: return(new StructuredNtfsAttribute <ReparsePointRecord>(file, recordFile, record)); case AttributeType.AttributeList: return(new StructuredNtfsAttribute <AttributeList>(file, recordFile, record)); default: return(new NtfsAttribute(file, recordFile, record)); } }