public void Extend() { if (NumberOfClustersRequiredToExtend > m_volume.NumberOfFreeClusters) { throw new DiskFullException(); } int additionalDataLength = m_volume.BytesPerFileRecordSegment * ExtendGranularity; // MFT Bitmap: ValidDataLength could be smaller than FileSize, however, we will later copy the value of ValidDataLength. // to the MFT mirror, we have to make sure that the copy will not become stale after writing beyond the current ValidDataLength. m_mftBitmap.ExtendBitmap(ExtendGranularity, true); // MFT Data: ValidDataLength must be equal to FileSize. // We are opting to skip updating the FileNameRecord and RootDirectory index. // Note: The NTFS v5.1 driver does not bother updating the FileNameRecord. while (additionalDataLength > 0) { int transferSize = Math.Min(Settings.MaximumTransferSizeLBA * m_volume.BytesPerSector, additionalDataLength); m_mftData.WriteBytes(m_mftData.Length, new byte[transferSize]); additionalDataLength -= transferSize; } // Update the MFT mirror MasterFileTable mftMirror = new MasterFileTable(m_volume, false, true); // When the MFT has an attribute list, CHKDSK expects the mirror to contain the segment references from the MFT as-is. FileRecordSegment mftRecordSegmentFromMirror = mftMirror.GetFileRecordSegment(MasterFileTableSegmentNumber); mftRecordSegmentFromMirror.ImmediateAttributes.Clear(); mftRecordSegmentFromMirror.ImmediateAttributes.AddRange(m_mftRecord.BaseSegment.ImmediateAttributes); // CHKDSK seems to expect the mirror's NextAttributeInstance to be the same as the MFT. mftRecordSegmentFromMirror.NextAttributeInstance = m_mftRecord.BaseSegment.NextAttributeInstance; mftMirror.UpdateFileRecordSegment(mftRecordSegmentFromMirror); }
public void Extend() { ulong additionalDataLength = (ulong)(m_volume.BytesPerFileRecordSegment * ExtendGranularity); ulong additionalBitmapLength = ExtendGranularity / 8; // We calculate the maximum possible number of free cluster required long numberOfClustersRequiredForData = (long)Math.Ceiling((double)additionalDataLength / m_volume.BytesPerCluster); long numberOfClustersRequiredForBitmap = (long)Math.Ceiling((double)additionalBitmapLength / m_volume.BytesPerCluster); if (numberOfClustersRequiredForData + numberOfClustersRequiredForBitmap > m_volume.NumberOfFreeClusters) { throw new DiskFullException(); } // We have to extend the bitmap first because one of the constructor parameters is the size of the data. // MFT Bitmap: ValidDataLength could be smaller than FileSize, however, we will later copy the value of ValidDataLength. // to the MFT mirror, we have to make sure that the copy will not become stale after writing beyond the current ValidDataLength. m_mftFile.Bitmap.ExtendBitmap(ExtendGranularity, true); // MFT Data: ValidDataLength must be equal to FileSize. // This will take care of the FileNameRecord and RootDirectory index as well. // Note: The NTFS v5.1 driver does not bother updating the FileNameRecord. m_mftFile.WriteData(m_mftFile.Data.Length, new byte[additionalDataLength]); // Update the MFT mirror MasterFileTable mftMirror = new MasterFileTable(m_volume, false, true); // When the MFT has an attribute list, CHKDSK expects the mirror to contain the segment references from the MFT as-is. FileRecordSegment mftRecordSegmentFromMirror = mftMirror.GetFileRecordSegment(MasterFileTableSegmentNumber); mftRecordSegmentFromMirror.ImmediateAttributes.Clear(); mftRecordSegmentFromMirror.ImmediateAttributes.AddRange(m_mftFile.FileRecord.BaseSegment.ImmediateAttributes); // CHKDSK seems to expect the mirror's NextAttributeInstance to be the same as the MFT. mftRecordSegmentFromMirror.NextAttributeInstance = m_mftFile.FileRecord.BaseSegment.NextAttributeInstance; mftMirror.UpdateFileRecordSegment(mftRecordSegmentFromMirror); }
/// <summary> /// It's up to the caller to log the changes to the file record segment /// </summary> private void DeallocateFileRecordSegment(FileRecordSegment segment, uint transactionID) { ushort nextSequenceNumber = (ushort)(segment.SequenceNumber + 1); FileRecordSegment segmentToWrite = new FileRecordSegment(segment.SegmentNumber, nextSequenceNumber); UpdateFileRecordSegment(segmentToWrite); m_mftBitmap.DeallocateRecord(segment.SegmentNumber, transactionID); }
internal FileRecord(FileRecordSegment segment) { m_segments = new List <FileRecordSegment>(); m_segments.Add(segment); ReferenceCount = m_segments[0].ReferenceCount; IsInUse = m_segments[0].IsInUse; IsDirectory = m_segments[0].IsDirectory; }
/// <summary> /// This method is used to read the record segment of the MFT itself. /// Only after strapping the MFT we can use GetFileRecordSegment which relies on the MFT file record. /// </summary> private FileRecordSegment ReadFileRecordSegment(long mftStartLCN, long segmentNumber) { long sectorIndex = mftStartLCN * m_volume.SectorsPerCluster + segmentNumber * m_volume.SectorsPerFileRecordSegment; byte[] bytes = m_volume.ReadSectors(sectorIndex, m_volume.SectorsPerFileRecordSegment); FileRecordSegment result = new FileRecordSegment(bytes, 0, segmentNumber); return(result); }
private ushort?GetFileRecordSegmentSequenceNumber(long segmentNumber) { byte[] segmentBytes = GetFileRecordSegmentBytes(segmentNumber); if (FileRecordSegment.ContainsFileRecordSegment(segmentBytes)) { return(FileRecordSegment.GetSequenceNumber(segmentBytes)); } return(null); }
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); } }
/// <summary> /// This method is used to read the record segment(s) of the MFT itself. /// Only after strapping the MFT we can use GetFileRecordSegment which relies on the MFT file record. /// </summary> private FileRecordSegment ReadMftRecordSegment(long mftStartLCN, long segmentNumber) { long sectorIndex = mftStartLCN * m_volume.SectorsPerCluster + segmentNumber * m_volume.SectorsPerFileRecordSegment; byte[] segmentBytes = m_volume.ReadSectors(sectorIndex, m_volume.SectorsPerFileRecordSegment, ContentType.MftData); MultiSectorHelper.RevertUsaProtection(segmentBytes, 0); FileRecordSegment result = new FileRecordSegment(segmentBytes, 0, segmentNumber); return(result); }
public int GetNumberOfBytesFree(int bytesPerFileRecordSegment, ushort minorNTFSVersion) { int firstAttributeOffset = FileRecordSegment.GetFirstAttributeOffset(bytesPerFileRecordSegment, minorNTFSVersion); int numberOfBytesAvailable = bytesPerFileRecordSegment - firstAttributeOffset - EndMarkerLength; foreach (AttributeRecord attribute in m_immediateAttributes) { numberOfBytesAvailable -= attribute.RecordLength; } return(numberOfBytesAvailable); }
private FileRecordSegment ReadFileRecordSegment(long mftStartLCN, MftSegmentReference reference) { FileRecordSegment result = ReadFileRecordSegment(mftStartLCN, reference.SegmentNumber); if (result.SequenceNumber != reference.SequenceNumber) { // The file record segment has been freed and reallocated, and an obsolete version is being requested return(null); } return(result); }
private FileRecordSegment GetRecordSegmentOfMasterFileTable(long mftStartLCN, MftSegmentReference reference) { FileRecordSegment result = GetRecordSegmentOfMasterFileTable(mftStartLCN, reference.SegmentNumber); if (result.SequenceNumber != reference.SequenceNumber) { // The file record segment has been modified, and an older version has been requested return(null); } return(result); }
public FileRecordSegment GetFileRecordSegment(MftSegmentReference reference) { FileRecordSegment result = GetFileRecordSegment(reference.SegmentNumber); if (result.SequenceNumber != reference.SequenceNumber) { // The file record segment has been modified, and an older version has been requested throw new InvalidDataException("MftSegmentReference SequenceNumber does not match FileRecordSegment"); } return(result); }
private FileRecordSegment ReadMftRecordSegment(long mftStartLCN, MftSegmentReference reference) { FileRecordSegment result = ReadMftRecordSegment(mftStartLCN, reference.SegmentNumber); if (result.SequenceNumber != reference.SequenceNumber) { // The file record segment has been freed and reallocated, and an obsolete version is being requested throw new InvalidDataException("MftSegmentReference SequenceNumber does not match FileRecordSegment"); } return(result); }
public FileRecordSegment GetFileRecordSegment(MftSegmentReference reference) { FileRecordSegment result = GetFileRecordSegment(reference.SegmentNumber); if (result.SequenceNumber != reference.SequenceNumber) { // The file record segment has been modified, and an older version has been requested return(null); } return(result); }
public void UpdateFileRecordSegment(FileRecordSegment recordSegment) { long segmentNumber = recordSegment.MftSegmentNumber; NTFSBootRecord bootRecord = m_volume.BootRecord; long firstSectorIndex = segmentNumber * m_volume.SectorsPerFileRecordSegment; byte[] recordSegmentBytes = recordSegment.GetBytes(bootRecord.FileRecordSegmentLength, m_volume.BytesPerCluster, m_volume.MinorVersion); m_mftRecord.NonResidentDataRecord.WriteDataSectors(m_volume, firstSectorIndex, recordSegmentBytes); }
public FileRecord CreateFile(List <FileNameRecord> fileNameRecords, uint transactionID) { if (fileNameRecords.Count == 0) { throw new ArgumentException(); } bool isDirectory = fileNameRecords[0].IsDirectory; MftSegmentReference segmentReference = AllocateFileRecordSegment(transactionID); FileRecordSegment fileRecordSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber); // UpdateFileRecord() expects the base segment to be present on disk byte[] redoData = fileRecordSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); ulong streamOffset = (ulong)(fileRecordSegment.SegmentNumber * m_volume.BytesPerFileRecordSegment); m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], transactionID); UpdateFileRecordSegment(fileRecordSegment); fileRecordSegment.ReferenceCount = (ushort)fileNameRecords.Count; // Each FileNameRecord is about to be indexed fileRecordSegment.IsInUse = true; fileRecordSegment.IsDirectory = isDirectory; FileRecord fileRecord = new FileRecord(fileRecordSegment); StandardInformationRecord standardInformation = (StandardInformationRecord)fileRecord.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty); standardInformation.CreationTime = fileNameRecords[0].CreationTime; standardInformation.ModificationTime = fileNameRecords[0].ModificationTime; standardInformation.MftModificationTime = fileNameRecords[0].MftModificationTime; standardInformation.LastAccessTime = fileNameRecords[0].LastAccessTime; standardInformation.FileAttributes = 0; foreach (FileNameRecord fileNameRecord in fileNameRecords) { FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty); fileNameAttribute.IsIndexed = true; fileNameAttribute.Record = fileNameRecord; } if (isDirectory) { string indexName = IndexHelper.GetIndexName(AttributeType.FileName); IndexRootRecord indexRoot = (IndexRootRecord)fileRecord.CreateAttributeRecord(AttributeType.IndexRoot, indexName); IndexHelper.InitializeIndexRoot(indexRoot, AttributeType.FileName, m_volume.BytesPerIndexRecord, m_volume.BytesPerCluster); } else { fileRecord.CreateAttributeRecord(AttributeType.Data, String.Empty); } UpdateFileRecord(fileRecord, transactionID); return(fileRecord); }
private void DeallocateFileRecordSegment(FileRecordSegment segment) { BitmapData bitmap = m_mftFile.Bitmap; if (bitmap == null) { throw new InvalidDataException("Invalid MFT Record, missing Bitmap attribute"); } ushort nextSequenceNumber = (ushort)(segment.SequenceNumber + 1); FileRecordSegment segmentToWrite = new FileRecordSegment(segment.SegmentNumber, nextSequenceNumber); UpdateFileRecordSegment(segmentToWrite); bitmap.DeallocateRecord(segment.SegmentNumber); }
public void UpdateFileRecordSegment(FileRecordSegment recordSegment) { long segmentNumber = recordSegment.SegmentNumber; long firstSectorIndex = segmentNumber * m_volume.SectorsPerFileRecordSegment; if (segmentNumber >= FirstReservedSegmentNumber) { recordSegment.UpdateSequenceNumber++; } recordSegment.LogFileSequenceNumber = 0; byte[] recordSegmentBytes = recordSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); m_mftFile.Data.WriteSectors(firstSectorIndex, recordSegmentBytes); }
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); } }
private static FileRecordSegment CreateSystemReservedSegment(long segmentNumber) { FileRecordSegment baseRecordSegment = new FileRecordSegment(segmentNumber, (ushort)segmentNumber); baseRecordSegment.IsInUse = true; baseRecordSegment.UpdateSequenceNumber = 1; DateTime creationTime = DateTime.Now; StandardInformationRecord standardInformation = (StandardInformationRecord)baseRecordSegment.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty); standardInformation.CreationTime = creationTime; standardInformation.ModificationTime = creationTime; standardInformation.MftModificationTime = creationTime; standardInformation.LastAccessTime = creationTime; standardInformation.FileAttributes = FileAttributes.System | FileAttributes.Hidden; baseRecordSegment.CreateAttributeRecord(AttributeType.Data, String.Empty); return(baseRecordSegment); }
private static FileRecordSegment CreateBaseRecordSegment(long segmentNumber, ushort sequenceNumber, FileNameRecord fileNameRecord) { FileRecordSegment baseRecordSegment = new FileRecordSegment(segmentNumber, sequenceNumber); baseRecordSegment.IsInUse = true; baseRecordSegment.UpdateSequenceNumber = 1; StandardInformationRecord standardInformation = (StandardInformationRecord)baseRecordSegment.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty); standardInformation.CreationTime = fileNameRecord.CreationTime; standardInformation.ModificationTime = fileNameRecord.ModificationTime; standardInformation.MftModificationTime = fileNameRecord.MftModificationTime; standardInformation.LastAccessTime = fileNameRecord.LastAccessTime; standardInformation.FileAttributes = fileNameRecord.FileAttributes; FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)baseRecordSegment.CreateAttributeRecord(AttributeType.FileName, String.Empty); fileNameAttribute.IsIndexed = true; fileNameAttribute.Record = fileNameRecord; return(baseRecordSegment); }
public FileRecord CreateFile(List <FileNameRecord> fileNameRecords) { if (fileNameRecords.Count == 0) { throw new ArgumentException(); } bool isDirectory = fileNameRecords[0].IsDirectory; MftSegmentReference segmentReference = AllocateFileRecordSegment(); FileRecordSegment fileRecordSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber); fileRecordSegment.ReferenceCount = (ushort)fileNameRecords.Count; // Each FileNameRecord is about to be indexed fileRecordSegment.IsInUse = true; fileRecordSegment.IsDirectory = isDirectory; FileRecord fileRecord = new FileRecord(fileRecordSegment); StandardInformationRecord standardInformation = (StandardInformationRecord)fileRecord.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty); standardInformation.CreationTime = fileNameRecords[0].CreationTime; standardInformation.ModificationTime = fileNameRecords[0].ModificationTime; standardInformation.MftModificationTime = fileNameRecords[0].MftModificationTime; standardInformation.LastAccessTime = fileNameRecords[0].LastAccessTime; standardInformation.FileAttributes = 0; foreach (FileNameRecord fileNameRecord in fileNameRecords) { FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty); fileNameAttribute.IsIndexed = true; fileNameAttribute.Record = fileNameRecord; } if (isDirectory) { string indexName = IndexHelper.GetIndexName(AttributeType.FileName); IndexRootRecord indexRoot = (IndexRootRecord)fileRecord.CreateAttributeRecord(AttributeType.IndexRoot, indexName); IndexHelper.InitializeIndexRoot(indexRoot, AttributeType.FileName, m_volume.BytesPerIndexRecord, m_volume.BytesPerCluster); } else { fileRecord.CreateAttributeRecord(AttributeType.Data, String.Empty); } UpdateFileRecord(fileRecord); return(fileRecord); }
private MftSegmentReference AllocateReservedFileRecordSegment() { BitmapData bitmap = m_mftFile.Bitmap; if (bitmap == null) { throw new InvalidDataException("Invalid MFT Record, missing Bitmap attribute"); } long?segmentNumber = bitmap.AllocateRecord(FirstReservedSegmentNumber, FirstUserSegmentNumber - 1); if (!segmentNumber.HasValue) { throw new DiskFullException(); } FileRecordSegment previousSegment = GetFileRecordSegment(segmentNumber.Value); ushort sequenceNumber = (previousSegment == null) ? (ushort)1 : previousSegment.SequenceNumber; return(new MftSegmentReference(segmentNumber.Value, sequenceNumber)); }
private FileRecordSegment GetFileRecordSegment(long segmentNumber) { NTFSBootRecord bootRecord = m_volume.BootRecord; // Note: File record always start at the beginning of a sector // Note: Record can span multiple clusters, or alternatively, several records can be stored in the same cluster long firstSectorIndex = segmentNumber * m_volume.SectorsPerFileRecordSegment; byte[] segmentBytes = m_mftFile.Data.ReadSectors(firstSectorIndex, m_volume.SectorsPerFileRecordSegment); if (FileRecordSegment.ContainsFileRecordSegment(segmentBytes)) { FileRecordSegment recordSegment = new FileRecordSegment(segmentBytes, 0, segmentNumber); return(recordSegment); } else { return(null); } }
/// <remarks> /// https://blogs.technet.microsoft.com/askcore/2009/10/16/the-four-stages-of-ntfs-file-growth/ /// </remarks> public void UpdateSegments(int bytesPerFileRecordSegment, byte minorNTFSVersion) { m_segments[0].ReferenceCount = ReferenceCount; m_segments[0].IsInUse = IsInUse; m_segments[0].IsDirectory = IsDirectory; List <AttributeRecord> attributes = this.Attributes; foreach (FileRecordSegment segment in m_segments) { segment.ImmediateAttributes.Clear(); segment.NextAttributeInstance = 0; } int segmentLength = bytesPerFileRecordSegment - FileRecordSegment.GetNumberOfBytesAvailable(bytesPerFileRecordSegment, minorNTFSVersion); foreach (AttributeRecord attribute in attributes) { segmentLength += (int)attribute.RecordLength; } if (segmentLength <= bytesPerFileRecordSegment) { // A single record segment is needed foreach (AttributeRecord attribute in attributes) { m_segments[0].AddAttributeRecord(attribute.Clone()); } // Free the rest of the segments, if there are any for (int index = 1; index < m_segments.Count; index++) { m_segments[index].IsInUse = false; } } else { // We slice the attributes and put them in segments, the attribute list will be built by the caller after the new segments will be allocated FileRecordHelper.SliceAttributes(m_segments, attributes, bytesPerFileRecordSegment, minorNTFSVersion); } }
/// <remarks> /// https://blogs.technet.microsoft.com/askcore/2009/10/16/the-four-stages-of-ntfs-file-growth/ /// </remarks> public void UpdateSegments(int bytesPerFileRecordSegment, ushort minorNTFSVersion) { List <AttributeRecord> attributes = this.Attributes; foreach (FileRecordSegment segment in m_segments) { segment.ImmediateAttributes.Clear(); } int segmentLength = FileRecordSegment.GetFirstAttributeOffset(bytesPerFileRecordSegment, minorNTFSVersion); segmentLength += FileRecordSegment.EndMarkerLength; foreach (AttributeRecord attribute in attributes) { segmentLength += (int)attribute.RecordLength; } if (segmentLength <= bytesPerFileRecordSegment) { // A single record segment is needed foreach (AttributeRecord attribute in attributes) { m_segments[0].ImmediateAttributes.Add(attribute); } // free the rest of the segments, if there are any for (int index = 1; index < m_segments.Count; index++) { m_segments[index].IsInUse = false; } } else { // We slice the attributes and put them in segments, the attribute list will be built by the caller after the new segments will be allocated FileRecordHelper.SliceAttributes(m_segments, attributes, bytesPerFileRecordSegment, minorNTFSVersion); } }
public void UpdateSegments(int maximumSegmentLength, int bytesPerSector, ushort minorNTFSVersion) { foreach (FileRecordSegment segment in m_segments) { segment.ImmediateAttributes.Clear(); } int segmentLength = FileRecordSegment.GetFirstAttributeOffset(maximumSegmentLength, minorNTFSVersion); segmentLength += FileRecordSegment.EndMarkerLength; foreach (AttributeRecord attribute in this.Attributes) { segmentLength += (int)attribute.RecordLength; } if (segmentLength <= maximumSegmentLength) { // a single record segment is needed FileRecordSegment baseRecordSegment = m_segments[0]; foreach (AttributeRecord attribute in this.Attributes) { baseRecordSegment.ImmediateAttributes.Add(attribute); } // free the rest of the segments, if there are any for (int index = 1; index < m_segments.Count; index++) { m_segments[index].IsInUse = false; } } else { // we have to check if we can make some data streams non-resident, // otherwise we have to use child segments and create an attribute list throw new NotImplementedException(); } }
private MftSegmentReference AllocateFileRecordSegment() { BitmapData bitmap = m_mftFile.Bitmap; if (bitmap == null) { throw new InvalidDataException("Invalid MFT Record, missing Bitmap attribute"); } long mftBitmapSearchStartIndex = MasterFileTable.FirstUserSegmentNumber; long?segmentNumber = bitmap.AllocateRecord(mftBitmapSearchStartIndex); if (!segmentNumber.HasValue) { long numberOfUsableBits = bitmap.NumberOfUsableBits; Extend(); segmentNumber = bitmap.AllocateRecord(numberOfUsableBits); } FileRecordSegment previousSegment = GetFileRecordSegment(segmentNumber.Value); ushort sequenceNumber = (previousSegment == null) ? (ushort)1 : previousSegment.SequenceNumber; return(new MftSegmentReference(segmentNumber.Value, sequenceNumber)); }
/// <remarks> /// An attribute list MUST be sorted by AttributeType with a secondary sort by AttributeName. /// </remarks> public static List <AttributeListEntry> BuildAttributeList(List <FileRecordSegment> segments, int bytesPerFileRecordSegment, ushort minorNTFSVersion) { int bytesAvailableInSegment = FileRecordSegment.GetNumberOfBytesAvailable(bytesPerFileRecordSegment, minorNTFSVersion); List <AttributeListEntry> result = new List <AttributeListEntry>(); foreach (FileRecordSegment segment in segments) { foreach (AttributeRecord attribute in segment.ImmediateAttributes) { AttributeListEntry entry = new AttributeListEntry(); entry.AttributeType = attribute.AttributeType; if (attribute is NonResidentAttributeRecord) { entry.LowestVCN = ((NonResidentAttributeRecord)attribute).LowestVCN; } entry.SegmentReference = segment.SegmentReference; entry.Instance = attribute.Instance; entry.AttributeName = attribute.Name; result.Add(entry); } } return(result); }
public FileRecord(FileRecordSegment segment) { m_segments = new List <FileRecordSegment>(); m_segments.Add(segment); }