private FileRecord ReadMftRecord(bool useMftMirror, bool readMftMirror) { NTFSBootRecord bootRecord = m_volume.BootRecord; long mftStartLCN = useMftMirror ? (long)bootRecord.MftMirrorStartLCN : (long)bootRecord.MftStartLCN; long mftSegmentNumber = readMftMirror ? MftMirrorSegmentNumber : MasterFileTableSegmentNumber; FileRecordSegment mftRecordSegment; try { mftRecordSegment = ReadMftRecordSegment(mftStartLCN, mftSegmentNumber); } catch (InvalidDataException) { throw new InvalidDataException("Invalid MFT base record segment"); } if (!mftRecordSegment.IsBaseFileRecord) { throw new InvalidDataException("Invalid MFT file record, MFT segment number did not correspond to a base file record segment"); } AttributeRecord attributeListRecord = mftRecordSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); if (attributeListRecord == null) { return(new FileRecord(mftRecordSegment)); } else { AttributeList attributeList = new AttributeList(m_volume, attributeListRecord); List <AttributeListEntry> entries = attributeList.ReadEntries(); List <MftSegmentReference> references = AttributeList.GetSegmentReferenceList(entries); int baseSegmentIndex = MftSegmentReference.IndexOfSegmentNumber(references, MasterFileTableSegmentNumber); if (baseSegmentIndex >= 0) { references.RemoveAt(baseSegmentIndex); } List <FileRecordSegment> recordSegments = new List <FileRecordSegment>(); // we want the base record segment first recordSegments.Add(mftRecordSegment); foreach (MftSegmentReference reference in references) { FileRecordSegment segment; try { segment = ReadMftRecordSegment(mftStartLCN, reference); } catch (InvalidDataException) { throw new InvalidDataException("Invalid MFT file record, referenced segment is invalid"); } recordSegments.Add(segment); } return(new FileRecord(recordSegments)); } }
private FileRecord ReadMftRecord(bool useMftMirror, bool readMftMirror) { NTFSBootRecord bootRecord = m_volume.BootRecord; if (bootRecord != null) { long mftStartLCN = useMftMirror ? (long)bootRecord.MftMirrorStartLCN : (long)bootRecord.MftStartLCN; long mftSegmentNumber = readMftMirror ? MftMirrorSegmentNumber : MasterFileTableSegmentNumber; FileRecordSegment mftRecordSegment = ReadFileRecordSegment(mftStartLCN, mftSegmentNumber); if (!mftRecordSegment.IsBaseFileRecord) { throw new InvalidDataException("Invalid MFT record, not a base record"); } AttributeRecord attributeListRecord = mftRecordSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); if (attributeListRecord == null) { return(new FileRecord(mftRecordSegment)); } else { // I have never personally seen an MFT with an attribute list AttributeList attributeList = new AttributeList(m_volume, attributeListRecord); List <AttributeListEntry> entries = attributeList.ReadEntries(); List <MftSegmentReference> references = AttributeList.GetSegmentReferenceList(entries); int baseSegmentIndex = MftSegmentReference.IndexOfSegmentNumber(references, MasterFileTableSegmentNumber); if (baseSegmentIndex >= 0) { references.RemoveAt(baseSegmentIndex); } List <FileRecordSegment> recordSegments = new List <FileRecordSegment>(); // we want the base record segment first recordSegments.Add(mftRecordSegment); foreach (MftSegmentReference reference in references) { FileRecordSegment segment = ReadFileRecordSegment(mftStartLCN, reference); if (segment != null) { recordSegments.Add(segment); } else { throw new InvalidDataException("Invalid MFT record, missing segment"); } } return(new FileRecord(recordSegments)); } } else { return(null); } }
public FileRecord GetFileRecord(long baseSegmentNumber) { FileRecordSegment baseSegment = GetFileRecordSegment(baseSegmentNumber); if (baseSegment != null && baseSegment.IsBaseFileRecord) { AttributeRecord attributeListRecord = baseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); if (attributeListRecord == null) { return(new FileRecord(baseSegment)); } else { // The attribute list contains entries for every attribute the record has (excluding the attribute list), // including attributes that reside within the base record segment. AttributeList attributeList = new AttributeList(m_volume, attributeListRecord); List <AttributeListEntry> entries = attributeList.ReadEntries(); List <MftSegmentReference> references = AttributeList.GetSegmentReferenceList(entries); int baseSegmentIndex = MftSegmentReference.IndexOfSegmentNumber(references, baseSegmentNumber); if (baseSegmentIndex >= 0) { references.RemoveAt(baseSegmentIndex); } List <FileRecordSegment> recordSegments = new List <FileRecordSegment>(); // we want the base record segment first recordSegments.Add(baseSegment); foreach (MftSegmentReference reference in references) { FileRecordSegment segment = GetFileRecordSegment(reference); if (segment != null) { recordSegments.Add(segment); } else { // record is invalid return(null); } } return(new FileRecord(recordSegments)); } } else { return(null); } }
public void UpdateFileRecord(FileRecord fileRecord) { AttributeRecord oldAttributeList = fileRecord.BaseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); fileRecord.UpdateSegments(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); FileRecordSegment baseSegment = fileRecord.BaseSegment; for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++) { FileRecordSegment segment = fileRecord.Segments[segmentIndex]; if (segment.SegmentReference == MftSegmentReference.NullReference) { // New segment, we must allocate space for it MftSegmentReference segmentReference; if (baseSegment.SegmentNumber == MasterFileTable.MasterFileTableSegmentNumber) { segmentReference = AllocateReservedFileRecordSegment(); } else { segmentReference = AllocateFileRecordSegment(); } FileRecordSegment newSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber, baseSegment.SegmentReference); newSegment.IsInUse = true; newSegment.IsDirectory = fileRecord.IsDirectory; newSegment.NextAttributeInstance = segment.NextAttributeInstance; newSegment.ImmediateAttributes.AddRange(segment.ImmediateAttributes); fileRecord.Segments[segmentIndex] = newSegment; } else if (segment.ImmediateAttributes.Count == 0) { DeallocateFileRecordSegment(segment); fileRecord.Segments.RemoveAt(segmentIndex); segmentIndex--; } } foreach (FileRecordSegment segment in fileRecord.Segments) { UpdateFileRecordSegment(segment); } if (oldAttributeList is NonResidentAttributeRecord) { new NonResidentAttributeData(m_volume, null, (NonResidentAttributeRecord)oldAttributeList).Truncate(0); } bool needsAttributeList = (fileRecord.Segments.Count > 1); if (needsAttributeList) { List <AttributeListEntry> entries = FileRecordHelper.BuildAttributeList(fileRecord.Segments, m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); int dataLength = AttributeList.GetLength(entries); int attributeListRecordLength = ResidentAttributeRecord.GetRecordLength(0, dataLength); int numberOfBytesFreeInBaseSegment = baseSegment.GetNumberOfBytesFree(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); bool isResident = (attributeListRecordLength <= numberOfBytesFreeInBaseSegment); AttributeRecord attributeListRecord = baseSegment.CreateAttributeListRecord(isResident); AttributeList attributeList = new AttributeList(m_volume, attributeListRecord); attributeList.WriteEntries(entries); UpdateFileRecordSegment(baseSegment); } }
public void UpdateFileRecord(FileRecord fileRecord, uint transactionID) { Dictionary <MftSegmentReference, byte[]> undoDictionary = new Dictionary <MftSegmentReference, byte[]>(); foreach (FileRecordSegment segment in fileRecord.Segments) { byte[] segmentBytes = segment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); undoDictionary.Add(segment.SegmentReference, segmentBytes); } AttributeRecord oldAttributeList = fileRecord.BaseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); fileRecord.UpdateSegments(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); FileRecordSegment baseSegment = fileRecord.BaseSegment; for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++) { FileRecordSegment segment = fileRecord.Segments[segmentIndex]; if (segment.SegmentReference == MftSegmentReference.NullReference) { // New segment, we must allocate space for it MftSegmentReference segmentReference; if (baseSegment.SegmentNumber == MasterFileTable.MasterFileTableSegmentNumber) { segmentReference = AllocateReservedFileRecordSegment(transactionID); } else { segmentReference = AllocateFileRecordSegment(transactionID); } FileRecordSegment newSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber, baseSegment.SegmentReference); newSegment.IsInUse = true; newSegment.IsDirectory = fileRecord.IsDirectory; newSegment.NextAttributeInstance = segment.NextAttributeInstance; newSegment.ImmediateAttributes.AddRange(segment.ImmediateAttributes); fileRecord.Segments[segmentIndex] = newSegment; } else if (segment.ImmediateAttributes.Count == 0) { byte[] undoData = undoDictionary[segment.SegmentReference]; ulong streamOffset = (ulong)(segment.SegmentNumber * m_volume.BytesPerFileRecordSegment); m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], NTFSLogOperation.InitializeFileRecordSegment, undoData, transactionID); DeallocateFileRecordSegment(segment, transactionID); fileRecord.Segments.RemoveAt(segmentIndex); segmentIndex--; } } for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++) { FileRecordSegment segment = fileRecord.Segments[segmentIndex]; byte[] undoData; byte[] redoData = segment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); ulong streamOffset = (ulong)(segment.SegmentNumber * m_volume.BytesPerFileRecordSegment); if (undoDictionary.TryGetValue(segment.SegmentReference, out undoData)) { m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.InitializeFileRecordSegment, undoData, transactionID); } else { // New segment m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], transactionID); } UpdateFileRecordSegment(segment); } if (oldAttributeList is NonResidentAttributeRecord) { new NonResidentAttributeData(m_volume, null, (NonResidentAttributeRecord)oldAttributeList).Truncate(0); } bool needsAttributeList = (fileRecord.Segments.Count > 1); if (needsAttributeList) { List <AttributeListEntry> entries = FileRecordHelper.BuildAttributeList(fileRecord.Segments, m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); int dataLength = AttributeList.GetLength(entries); int attributeListRecordLength = ResidentAttributeRecord.GetRecordLength(0, dataLength); int numberOfBytesFreeInBaseSegment = baseSegment.GetNumberOfBytesFree(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); bool isResident = (attributeListRecordLength <= numberOfBytesFreeInBaseSegment); AttributeRecord attributeListRecord = baseSegment.CreateAttributeListRecord(isResident); AttributeList attributeList = new AttributeList(m_volume, attributeListRecord); attributeList.WriteEntries(entries); } byte[] baseRecordUndoData = undoDictionary[baseSegment.SegmentReference]; byte[] baseRecordRedoData = baseSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); ulong baseRecordStreamOffset = (ulong)(baseSegment.SegmentNumber * m_volume.BytesPerFileRecordSegment); m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, baseRecordStreamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, baseRecordRedoData, NTFSLogOperation.InitializeFileRecordSegment, baseRecordUndoData, transactionID); UpdateFileRecordSegment(baseSegment); }