/// <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> internal ushort AddAttribute(AttributeRecord attrRec) { attrRec.AttributeId = _nextAttributeId++; _attributes.Add(attrRec); _attributes.Sort(); return(attrRec.AttributeId); }
private bool ExpelAttribute(FileRecord record) { 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); newFileRecord.BaseFile = record.Reference; _records.Add(newFileRecord); MoveAttribute(record, attr, newFileRecord); return(true); } } return(false); }
/// <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); }
public void SetExtent(FileRecordReference containingFile, AttributeRecord record) { _containingFile = containingFile; _record = record; _extents.Clear(); _extents.Add(new AttributeReference(containingFile, record.AttributeId), record); }
private bool SplitAttribute(FileRecord record) { if (record.Attributes.Count != 1) { throw new InvalidOperationException("Attempting to split attribute in MFT record containing multiple attributes"); } AttributeRecord targetAttr = record.FirstAttribute; if (targetAttr.AttributeType != AttributeType.Data) { throw new InvalidOperationException("Attempting to split non-Data attribute"); } AttributeRecord newAttr = targetAttr.Split(record); // Find a home for the new attribute record FileRecord newAttrHome = null; foreach (var targetRecord in _records) { if (_mft.RecordSize - targetRecord.Size >= newAttr.Size) { targetRecord.AddAttribute(newAttr); newAttrHome = targetRecord; } } if (newAttrHome == null) { newAttrHome = _mft.AllocateRecord(FileRecordFlags.None); newAttrHome.BaseFile = 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); }
protected override void Read(byte[] buffer, int offset) { LogFileSequenceNumber = EndianUtilities.ToUInt64LittleEndian(buffer, offset + 0x08); SequenceNumber = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x10); HardLinkCount = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x12); _firstAttributeOffset = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x14); Flags = (FileRecordFlags)EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x16); RealSize = EndianUtilities.ToUInt32LittleEndian(buffer, offset + 0x18); AllocatedSize = EndianUtilities.ToUInt32LittleEndian(buffer, offset + 0x1C); BaseFile = new FileRecordReference(EndianUtilities.ToUInt64LittleEndian(buffer, offset + 0x20)); NextAttributeId = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x28); if (UpdateSequenceOffset >= 0x30) { _index = EndianUtilities.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 += length; } }
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); }
internal void Delete() { if (_records[0].HardLinkCount != 0) { throw new InvalidOperationException("Attempt to delete in-use file: " + ToString()); } NtfsStream objIdStream = GetStream(AttributeType.ObjectId, null); if (objIdStream != null) { ObjectId objId = objIdStream.GetContent <ObjectId>(); Context.ObjectIds.Remove(objId.Id); } foreach (var attr in _attributes) { attr.GetDataBuffer().SetCapacity(0); } AttributeRecord attrListRec = _records[0].GetAttribute(AttributeType.AttributeList); if (attrListRec != null) { StructuredNtfsAttribute <AttributeList> attrList = (StructuredNtfsAttribute <AttributeList>)GetAttribute(new AttributeReference(MftReference, attrListRec.AttributeId)); foreach (var record in attrList.Content) { FileRecord attrFileRecord = _records[0]; if (record.BaseFileReference.MftIndex != _records[0].MasterFileTableIndex) { attrFileRecord = _context.Mft.GetRecord(record.BaseFileReference); } if (attrFileRecord != null) { attrFileRecord.RemoveAttribute(record.AttributeId); if (attrFileRecord.Attributes.Count == 0) { _context.Mft.RemoveRecord(record.BaseFileReference); } } } } List <AttributeRecord> records = new List <AttributeRecord>(_records[0].Attributes); foreach (var record in records) { _records[0].RemoveAttribute(record.AttributeId); } _attributes.Clear(); _context.Mft.RemoveRecord(MftReference); _context.ForgetFile(this); }
public override int Read(long pos, byte[] buffer, int offset, int count) { AttributeRecord record = _attribute.PrimaryRecord; if (!CanRead) { throw new IOException("Attempt to read from file not opened for read"); } StreamUtilities.AssertBufferParameters(buffer, offset, count); if (pos >= Capacity) { return(0); } // Limit read to length of attribute int totalToRead = (int)Math.Min(count, Capacity - pos); int toRead = totalToRead; // Handle uninitialized bytes at end of attribute if (pos + totalToRead > record.InitializedDataLength) { if (pos >= record.InitializedDataLength) { // We're just reading zero bytes from the uninitialized area Array.Clear(buffer, offset, totalToRead); pos += totalToRead; return(totalToRead); } // Partial read of uninitialized area Array.Clear(buffer, offset + (int)(record.InitializedDataLength - pos), (int)(pos + toRead - record.InitializedDataLength)); toRead = (int)(record.InitializedDataLength - pos); } int numRead = 0; while (numRead < toRead) { IBuffer extentBuffer = _attribute.RawBuffer; int justRead = extentBuffer.Read(pos + numRead, buffer, offset + numRead, toRead - numRead); if (justRead == 0) { break; } numRead += justRead; } return(totalToRead); }
/// <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 (NtfsAttribute 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 (FileRecord 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 bool ReplaceExtent(AttributeReference oldRef, AttributeReference newRef, AttributeRecord record) { _cachedRawBuffer = null; if (!_extents.Remove(oldRef)) { return(false); } if (oldRef.Equals(Reference) || _extents.Count == 0) { _primaryRecord = record; _containingFile = newRef.File; } _extents.Add(newRef, record); return(true); }
public bool ReplaceExtent(AttributeReference oldRef, AttributeReference newRef, AttributeRecord record) { if (!_extents.Remove(oldRef)) { return(false); } else { if (oldRef.Equals(Reference) || _extents.Count == 0) { _record = record; _containingFile = newRef.File; } _extents.Add(newRef, record); return(true); } }
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 override void Clear(long pos, int count) { AttributeRecord record = _attribute.PrimaryRecord; if (!CanWrite) { throw new IOException("Attempt to write to file not opened for write"); } if (count == 0) { return; } _attribute.RawBuffer.Clear(pos, count); if (!record.IsNonResident) { _file.MarkMftRecordDirty(); } }
private IBuffer GetExtentBuffer(long targetPos, out long streamStartPos) { AttributeRecord rec = null; if (_attribute.Extents.Count == 1) { // Handled as a special case, because sometimes _file can be null (for diagnostics) rec = _attribute.LastExtent; streamStartPos = 0; } else { long bytesPerCluster = _file.Context.BiosParameterBlock.BytesPerCluster; long vcn = targetPos / bytesPerCluster; NonResidentAttributeRecord nonResident = _attribute.GetNonResidentExtent(vcn); streamStartPos = nonResident.StartVcn * bytesPerCluster; rec = nonResident; } return(rec.GetDataBuffer(_file)); }
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 = StreamUtilities.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(); }
public override void Write(long pos, byte[] buffer, int offset, int count) { AttributeRecord record = _attribute.PrimaryRecord; if (!CanWrite) { throw new IOException("Attempt to write to file not opened for write"); } StreamUtilities.AssertBufferParameters(buffer, offset, count); if (count == 0) { return; } _attribute.RawBuffer.Write(pos, buffer, offset, count); if (!record.IsNonResident) { _file.MarkMftRecordDirty(); } }
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)); } }
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); }
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 (FileRecord 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 (NtfsAttribute attr in _attributes) { foreach (KeyValuePair <AttributeReference, AttributeRecord> 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); AttributeList attrList = attrListAttr.Content; _attributes.Add(attrListAttr); foreach (AttributeListRecord 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 (KeyValuePair <long, FileRecord> extraFileRecord in extraFileRecords) { _records.Add(extraFileRecord.Value); } } else { foreach (AttributeRecord 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(); }