public IndexData(NTFSVolume volume, FileRecord fileRecord, AttributeType indexedAttributeType) { m_volume = volume; m_fileRecord = fileRecord; m_indexedAttributeType = indexedAttributeType; m_indexName = IndexHelper.GetIndexName(indexedAttributeType); m_rootRecord = (IndexRootRecord)m_fileRecord.GetAttributeRecord(AttributeType.IndexRoot, m_indexName); // I have observed the NTFS v5.1 driver keeping the IndexAllocation and associated Bitmap attributes after deleting files from the directory even though m_rootRecord.IsParentNode is set to false. m_indexAllocationRecord = (IndexAllocationRecord)m_fileRecord.GetAttributeRecord(AttributeType.IndexAllocation, m_indexName); m_bitmapRecord = m_fileRecord.GetAttributeRecord(AttributeType.Bitmap, m_indexName); if (m_indexAllocationRecord != null && m_bitmapRecord != null) { m_indexAllocationData = new NonResidentAttributeData(m_volume, m_fileRecord, m_indexAllocationRecord); long numberOfUsableBits = (long)(m_indexAllocationRecord.DataLength / m_rootRecord.BytesPerIndexRecord); m_bitmapData = new BitmapData(m_volume, m_fileRecord, m_bitmapRecord, numberOfUsableBits); } else if (m_rootRecord.IsParentNode && m_indexAllocationRecord == null) { throw new InvalidDataException("Missing Index Allocation Record"); } else if (m_rootRecord.IsParentNode && m_bitmapRecord == null) { throw new InvalidDataException("Missing Index Bitmap Record"); } }
public void AddEntry(MftSegmentReference fileReference, byte[] key) { IndexEntry entry = new IndexEntry(); entry.FileReference = fileReference; entry.Key = key; if (!m_rootRecord.IsParentNode) { int insertIndex = CollationHelper.FindIndexForSortedInsert(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule); m_rootRecord.IndexEntries.Insert(insertIndex, entry); if (m_rootRecord.RecordLength >= m_volume.AttributeRecordLengthToMakeNonResident) { if (m_indexAllocationRecord == null) { m_indexAllocationRecord = (IndexAllocationRecord)m_fileRecord.CreateAttributeRecord(AttributeType.IndexAllocation, m_indexName); m_indexAllocationData = new NonResidentAttributeData(m_volume, m_fileRecord, m_indexAllocationRecord); m_bitmapRecord = m_fileRecord.CreateAttributeRecord(AttributeType.Bitmap, m_indexName); m_bitmapData = new BitmapData(m_volume, m_fileRecord, m_bitmapRecord, 0); } SplitRootIndexRecord(); } else { m_volume.UpdateFileRecord(m_fileRecord); } } else { KeyValuePairList <int, IndexRecord> path = FindInsertPath(key); IndexRecord leafRecord = path[path.Count - 1].Value; long leafRecordVBN = leafRecord.RecordVBN; int insertIndex = CollationHelper.FindIndexForSortedInsert(leafRecord.IndexEntries, key, m_rootRecord.CollationRule); leafRecord.IndexEntries.Insert(insertIndex, entry); long leafRecordIndex = ConvertToRecordIndex(leafRecordVBN); if (leafRecord.DoesFit((int)m_rootRecord.BytesPerIndexRecord)) { WriteIndexRecord(leafRecordIndex, leafRecord); } else { // Split index record SplitIndexRecord(path); } } }
private KeyValuePairList <MftSegmentReference, FileNameRecord> GetFileNameRecordsInDirectory(long directoryBaseSegmentNumber) { FileRecord record = m_mft.GetFileRecord(directoryBaseSegmentNumber); KeyValuePairList <MftSegmentReference, FileNameRecord> result = null; if (record != null && record.IsDirectory) { IndexRootRecord indexRoot = (IndexRootRecord)record.GetAttributeRecord(AttributeType.IndexRoot, IndexRootRecord.FileNameIndexName); IndexAllocationRecord indexAllocation = (IndexAllocationRecord)record.GetAttributeRecord(AttributeType.IndexAllocation, IndexRootRecord.FileNameIndexName); if (indexRoot.IsLargeIndex) { if (indexAllocation != null) { result = indexAllocation.GetAllEntries(this, indexRoot); } } else { result = indexRoot.GetSmallIndexEntries(); } if (result != null) { for (int index = 0; index < result.Count; index++) { if (result[index].Value.Namespace == FilenameNamespace.DOS) { // The same FileRecord can have multiple entries, each with it's own namespace result.RemoveAt(index); index--; } } } } return(result); }
public static NTFSVolume Format(Volume volume, byte majorNTFSVersion, byte minorNTFSVersion, int bytesPerCluster, string volumeLabel) { if (volumeLabel.Length > VolumeNameRecord.MaxVolumeNameLength) { throw new InvalidNameException(); } if (bytesPerCluster % volume.BytesPerSector > 0) { throw new ArgumentException("bytesPerCluster must be a multiple of volume.BytesPerSector"); } if (majorNTFSVersion != 3 || (minorNTFSVersion != 0 && minorNTFSVersion != 1)) { throw new NotSupportedException(); } long volumeClusterCount = (volume.Size - NTFSBootRecord.Length) / bytesPerCluster; // We wish to make WriteVolumeBitmap() as simple as possible so we use a multiple of ExtendGranularity to avoid having to set bits at the end of the bitmap volumeClusterCount = (long)Math.Floor((double)volumeClusterCount / (VolumeBitmap.ExtendGranularity * 8)) * (VolumeBitmap.ExtendGranularity * 8); int sectorsPerCluster = bytesPerCluster / volume.BytesPerSector; int bytesPerFileRecordSegment = 1024; // Supported values are 1024 or 4096 (when formatted with /L) int bytesPerIndexRecord = 4096; // Legal values are 1024, 2048 or 4096. NTFS v5.1 driver will always use 4096. int bootSegmentFileSize = 8192; int bootSegmentAllocatedLength = (int)Math.Ceiling((double)bootSegmentFileSize / bytesPerCluster) * bytesPerCluster; FileNameRecord bootFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$Boot", false, DateTime.Now); bootFileNameRecord.AllocatedLength = (ulong)bootSegmentAllocatedLength; bootFileNameRecord.FileSize = (ulong)bootSegmentFileSize; bootFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment bootSegment = CreateBaseRecordSegment(MasterFileTable.BootSegmentNumber, (ushort)MasterFileTable.BootSegmentNumber, bootFileNameRecord); bootSegment.ReferenceCount = 1; NonResidentAttributeRecord bootDataRecord = (NonResidentAttributeRecord)bootSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); bootDataRecord.AllocatedLength = (ulong)bootSegmentAllocatedLength; bootDataRecord.FileSize = (ulong)bootSegmentFileSize; bootDataRecord.ValidDataLength = (ulong)bootSegmentFileSize; int bootDataClusterCount = (int)Math.Ceiling((double)8192 / bytesPerCluster); long bootDataStartLCN = 0; bootDataRecord.DataRunSequence.Add(new DataRun(bootDataClusterCount, bootDataStartLCN)); bootDataRecord.HighestVCN = bootDataClusterCount - 1; long volumeBitmapFileSize = (long)Math.Ceiling((double)volumeClusterCount / (VolumeBitmap.ExtendGranularity * 8)) * VolumeBitmap.ExtendGranularity; long numberOfVolumeBitmapClusters = (long)Math.Ceiling((double)volumeBitmapFileSize / bytesPerCluster); long volumeBitmapAllocatedLength = numberOfVolumeBitmapClusters * bytesPerCluster; FileNameRecord volumeBitmapFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$Bitmap", false, DateTime.Now); volumeBitmapFileNameRecord.AllocatedLength = (ulong)volumeBitmapAllocatedLength; volumeBitmapFileNameRecord.FileSize = (ulong)volumeBitmapFileSize; volumeBitmapFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment volumeBitmapSegment = CreateBaseRecordSegment(MasterFileTable.BitmapSegmentNumber, (ushort)MasterFileTable.BitmapSegmentNumber, volumeBitmapFileNameRecord); volumeBitmapSegment.ReferenceCount = 1; NonResidentAttributeRecord volumeBitmapDataRecord = (NonResidentAttributeRecord)volumeBitmapSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); long volumeBitmapStartLCN = bootDataClusterCount; volumeBitmapDataRecord.AllocatedLength = (ulong)volumeBitmapAllocatedLength; volumeBitmapDataRecord.FileSize = (ulong)volumeBitmapFileSize; volumeBitmapDataRecord.ValidDataLength = (ulong)volumeBitmapFileSize; volumeBitmapDataRecord.DataRunSequence.Add(new DataRun(numberOfVolumeBitmapClusters, volumeBitmapStartLCN)); volumeBitmapDataRecord.HighestVCN = numberOfVolumeBitmapClusters - 1; int numberOfMftRecords = 64; int mftDataLength = numberOfMftRecords * bytesPerFileRecordSegment; FileNameRecord mftFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$MFT", false, DateTime.Now); mftFileNameRecord.AllocatedLength = (ulong)mftDataLength; mftFileNameRecord.FileSize = (ulong)mftDataLength; mftFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment mftSegment = CreateBaseRecordSegment(MasterFileTable.MasterFileTableSegmentNumber, 1, mftFileNameRecord); mftSegment.ReferenceCount = 1; NonResidentAttributeRecord mftDataRecord = (NonResidentAttributeRecord)mftSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); mftDataRecord.AllocatedLength = (ulong)mftDataLength; mftDataRecord.FileSize = (ulong)mftDataLength; mftDataRecord.ValidDataLength = (ulong)mftDataLength; int mftDataClusterCount = (int)Math.Ceiling((double)mftDataLength / bytesPerCluster); long mftDataStartLCN = volumeBitmapStartLCN + numberOfVolumeBitmapClusters; mftDataRecord.DataRunSequence.Add(new DataRun(mftDataClusterCount, mftDataStartLCN)); mftDataRecord.HighestVCN = mftDataClusterCount - 1; NonResidentAttributeRecord mftBitmapRecord = (NonResidentAttributeRecord)mftSegment.CreateAttributeRecord(AttributeType.Bitmap, String.Empty, false); int mftBitmapLength = (int)Math.Ceiling((double)numberOfMftRecords / (BitmapData.ExtendGranularity * 8)) * BitmapData.ExtendGranularity; int mftBitmapClusterCount = (int)Math.Ceiling((double)mftBitmapLength / bytesPerCluster); mftBitmapRecord.AllocatedLength = (ulong)(mftBitmapClusterCount * bytesPerCluster); mftBitmapRecord.FileSize = (ulong)mftBitmapLength; mftBitmapRecord.ValidDataLength = (ulong)mftBitmapLength; long mftBitmapStartLCN = mftDataStartLCN + mftDataClusterCount; mftBitmapRecord.DataRunSequence.Add(new DataRun(mftBitmapClusterCount, mftBitmapStartLCN)); mftBitmapRecord.HighestVCN = 0; int bytesPerLogPage = 4096; int logFileDataLength = 512 * bytesPerLogPage; FileNameRecord logFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$LogFile", false, DateTime.Now); logFileNameRecord.AllocatedLength = (ulong)logFileDataLength; logFileNameRecord.FileSize = (ulong)logFileDataLength; logFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment logFileSegment = CreateBaseRecordSegment(MasterFileTable.LogFileSegmentNumber, (ushort)MasterFileTable.LogFileSegmentNumber, logFileNameRecord); logFileSegment.ReferenceCount = 1; NonResidentAttributeRecord logFileDataRecord = (NonResidentAttributeRecord)logFileSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); logFileDataRecord.AllocatedLength = (ulong)logFileDataLength; logFileDataRecord.FileSize = (ulong)logFileDataLength; logFileDataRecord.ValidDataLength = (ulong)logFileDataLength; int logFileClusterCount = (int)Math.Ceiling((double)logFileDataLength / bytesPerCluster); long logFileStartLCN = mftBitmapStartLCN + mftBitmapClusterCount; logFileDataRecord.DataRunSequence.Add(new DataRun(logFileClusterCount, logFileStartLCN)); logFileDataRecord.HighestVCN = logFileClusterCount - 1; FileNameRecord volumeFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$Volume", false, DateTime.Now); volumeFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment volumeSegment = CreateBaseRecordSegment(MasterFileTable.VolumeSegmentNumber, (ushort)MasterFileTable.VolumeSegmentNumber, volumeFileNameRecord); volumeSegment.ReferenceCount = 1; VolumeNameRecord volumeName = (VolumeNameRecord)volumeSegment.CreateAttributeRecord(AttributeType.VolumeName, String.Empty); volumeName.VolumeName = volumeLabel; VolumeInformationRecord volumeInformation = (VolumeInformationRecord)volumeSegment.CreateAttributeRecord(AttributeType.VolumeInformation, String.Empty); volumeInformation.MajorVersion = majorNTFSVersion; volumeInformation.MinorVersion = minorNTFSVersion; volumeSegment.CreateAttributeRecord(AttributeType.Data, String.Empty); long logFileDataStartSector = logFileStartLCN * sectorsPerCluster; WriteLogFile(volume, logFileDataStartSector, logFileDataLength, bytesPerLogPage); long attributeDefinitionStartLCN = logFileStartLCN + logFileClusterCount; long attributeDefinitionStartSector = attributeDefinitionStartLCN * sectorsPerCluster; int attributeDefinitionLength = WriteAttributeDefinition(volume, attributeDefinitionStartSector, bytesPerCluster); int attributeDefinitionClusterCount = (int)Math.Ceiling((double)attributeDefinitionLength / bytesPerCluster); int attributeDefinitionAllocatedLength = attributeDefinitionClusterCount * bytesPerCluster; FileNameRecord attributeDefinitionFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$AttrDef", false, DateTime.Now); attributeDefinitionFileNameRecord.AllocatedLength = (ulong)attributeDefinitionAllocatedLength; attributeDefinitionFileNameRecord.FileSize = (ulong)attributeDefinitionLength; attributeDefinitionFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment attributeDefinitionSegment = CreateBaseRecordSegment(MasterFileTable.AttrDefSegmentNumber, (ushort)MasterFileTable.AttrDefSegmentNumber, attributeDefinitionFileNameRecord); attributeDefinitionSegment.ReferenceCount = 1; NonResidentAttributeRecord attributeDefinitionDataRecord = (NonResidentAttributeRecord)attributeDefinitionSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); attributeDefinitionDataRecord.AllocatedLength = (ulong)attributeDefinitionAllocatedLength; attributeDefinitionDataRecord.FileSize = (ulong)attributeDefinitionLength; attributeDefinitionDataRecord.ValidDataLength = (ulong)attributeDefinitionLength; attributeDefinitionDataRecord.DataRunSequence.Add(new DataRun(attributeDefinitionClusterCount, attributeDefinitionStartLCN)); attributeDefinitionDataRecord.HighestVCN = attributeDefinitionClusterCount - 1; FileNameRecord badClustersFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$BadClus", false, DateTime.Now); badClustersFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment badClustersSegment = CreateBaseRecordSegment(MasterFileTable.BadClusSegmentNumber, (ushort)MasterFileTable.BadClusSegmentNumber, badClustersFileNameRecord); badClustersSegment.ReferenceCount = 1; badClustersSegment.CreateAttributeRecord(AttributeType.Data, String.Empty); NonResidentAttributeRecord badClustersData = (NonResidentAttributeRecord)badClustersSegment.CreateAttributeRecord(AttributeType.Data, "$Bad", false); DataRun volumeDataRun = new DataRun(); volumeDataRun.RunLength = volumeClusterCount; volumeDataRun.IsSparse = true; badClustersData.DataRunSequence.Add(volumeDataRun); badClustersData.HighestVCN = volumeClusterCount - 1; badClustersData.AllocatedLength = (ulong)(volumeClusterCount * bytesPerCluster); badClustersData.FileSize = 0; badClustersData.ValidDataLength = 0; FileNameRecord secureFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$Secure", false, DateTime.Now); secureFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment secureSegment = CreateBaseRecordSegment(MasterFileTable.SecureSegmentNumber, (ushort)MasterFileTable.SecureSegmentNumber, secureFileNameRecord); secureSegment.IsSpecialIndex = true; secureSegment.ReferenceCount = 1; secureSegment.CreateAttributeRecord(AttributeType.Data, "$SDS"); IndexRootRecord sdh = (IndexRootRecord)secureSegment.CreateAttributeRecord(AttributeType.IndexRoot, "$SDH"); IndexHelper.InitializeIndexRoot(sdh, AttributeType.None, CollationRule.SecurityHash, bytesPerIndexRecord, bytesPerCluster); IndexRootRecord sii = (IndexRootRecord)secureSegment.CreateAttributeRecord(AttributeType.IndexRoot, "$SII"); IndexHelper.InitializeIndexRoot(sii, AttributeType.None, CollationRule.UnsignedLong, bytesPerIndexRecord, bytesPerCluster); int upcaseDataClusterCount = (int)Math.Ceiling((double)UpcaseFileLength / bytesPerCluster); FileNameRecord upcaseFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$UpCase", false, DateTime.Now); upcaseFileNameRecord.AllocatedLength = UpcaseFileLength; upcaseFileNameRecord.FileSize = UpcaseFileLength; upcaseFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment upcaseSegment = CreateBaseRecordSegment(MasterFileTable.UpCaseSegmentNumber, (ushort)MasterFileTable.UpCaseSegmentNumber, upcaseFileNameRecord); upcaseSegment.ReferenceCount = 1; NonResidentAttributeRecord upcaseFileDataRecord = (NonResidentAttributeRecord)upcaseSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); upcaseFileDataRecord.AllocatedLength = UpcaseFileLength; upcaseFileDataRecord.FileSize = UpcaseFileLength; upcaseFileDataRecord.ValidDataLength = UpcaseFileLength; long upcaseDataStartLCN = attributeDefinitionStartLCN + attributeDefinitionClusterCount; upcaseFileDataRecord.DataRunSequence.Add(new DataRun(upcaseDataClusterCount, upcaseDataStartLCN)); upcaseFileDataRecord.HighestVCN = upcaseDataClusterCount - 1; FileNameRecord extendFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$Extend", true, DateTime.Now); extendFileNameRecord.FileAttributes = FileAttributes.System | FileAttributes.Hidden | FileAttributes.FileNameIndexPresent; FileRecordSegment extendSegment = CreateBaseRecordSegment(MasterFileTable.ExtendSegmentNumber, (ushort)MasterFileTable.ExtendSegmentNumber, extendFileNameRecord); extendSegment.IsDirectory = true; extendSegment.ReferenceCount = 1; IndexRootRecord extendIndexRoot = (IndexRootRecord)extendSegment.CreateAttributeRecord(AttributeType.IndexRoot, IndexHelper.GetIndexName(AttributeType.FileName)); IndexHelper.InitializeIndexRoot(extendIndexRoot, AttributeType.FileName, CollationRule.Filename, bytesPerIndexRecord, bytesPerCluster); FileNameRecord mftMirrorFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, "$MFTMirr", false, DateTime.Now); int mftMirrorDataLength = 4 * bytesPerFileRecordSegment; int mftMirrorDataClusterCount = (int)Math.Ceiling((double)mftMirrorDataLength / bytesPerCluster); int mftMirrorAllocatedLength = mftMirrorDataClusterCount * bytesPerCluster; mftMirrorFileNameRecord.AllocatedLength = (ulong)mftMirrorAllocatedLength; mftMirrorFileNameRecord.FileSize = (ulong)mftMirrorDataLength; mftMirrorFileNameRecord.FileAttributes = FileAttributes.Hidden | FileAttributes.System; FileRecordSegment mftMirrorSegment = CreateBaseRecordSegment(MasterFileTable.MftMirrorSegmentNumber, (ushort)MasterFileTable.MftMirrorSegmentNumber, mftMirrorFileNameRecord); mftMirrorSegment.ReferenceCount = 1; NonResidentAttributeRecord mftMirrorDataRecord = (NonResidentAttributeRecord)mftMirrorSegment.CreateAttributeRecord(AttributeType.Data, String.Empty, false); mftMirrorDataRecord.AllocatedLength = (ulong)mftMirrorAllocatedLength; mftMirrorDataRecord.FileSize = (ulong)mftMirrorDataLength; mftMirrorDataRecord.ValidDataLength = (ulong)mftMirrorDataLength; long mftMirrorDataStartLCN = upcaseDataStartLCN + upcaseDataClusterCount; mftMirrorDataRecord.DataRunSequence.Add(new DataRun(mftMirrorDataClusterCount, mftMirrorDataStartLCN)); mftMirrorDataRecord.HighestVCN = mftMirrorDataClusterCount - 1; FileNameRecord rootDirFileNameRecord = new FileNameRecord(MasterFileTable.RootDirSegmentReference, ".", true, DateTime.Now); rootDirFileNameRecord.FileAttributes = FileAttributes.System | FileAttributes.Hidden | FileAttributes.FileNameIndexPresent; FileRecordSegment rootDirSegment = CreateBaseRecordSegment(MasterFileTable.RootDirSegmentNumber, (ushort)MasterFileTable.RootDirSegmentNumber, rootDirFileNameRecord); rootDirSegment.IsDirectory = true; rootDirSegment.ReferenceCount = 1; IndexRecord rootDirIndexRecord = new IndexRecord(); rootDirIndexRecord.RecordVBN = 0; // Note that we add the index entries according to collation rules rootDirIndexRecord.IndexEntries.Add(new IndexEntry(attributeDefinitionSegment.SegmentReference, attributeDefinitionFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(badClustersSegment.SegmentReference, badClustersFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(volumeBitmapSegment.SegmentReference, volumeBitmapFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(bootSegment.SegmentReference, bootFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(extendSegment.SegmentReference, extendFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(logFileSegment.SegmentReference, logFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(mftSegment.SegmentReference, mftFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(mftMirrorSegment.SegmentReference, mftMirrorFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(secureSegment.SegmentReference, secureFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(upcaseSegment.SegmentReference, upcaseFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(volumeSegment.SegmentReference, volumeFileNameRecord.GetBytes())); rootDirIndexRecord.IndexEntries.Add(new IndexEntry(rootDirSegment.SegmentReference, rootDirFileNameRecord.GetBytes())); long rootDirIndexRecordStartLCN = mftMirrorDataStartLCN + mftMirrorDataClusterCount; int rootDirIndexRecordClusterCount = (int)Math.Ceiling((double)bytesPerIndexRecord / bytesPerCluster); int rootDirIndexRecordAllocatedLength = rootDirIndexRecordClusterCount * bytesPerCluster; string rootDirIndexName = IndexHelper.GetIndexName(AttributeType.FileName); IndexRootRecord rootDirIndexRoot = (IndexRootRecord)rootDirSegment.CreateAttributeRecord(AttributeType.IndexRoot, rootDirIndexName); IndexHelper.InitializeIndexRoot(rootDirIndexRoot, AttributeType.FileName, CollationRule.Filename, bytesPerIndexRecord, bytesPerCluster); rootDirIndexRoot.IsParentNode = true; IndexEntry rootEntry = new IndexEntry(); rootEntry.ParentNodeForm = true; rootEntry.SubnodeVBN = 0; rootDirIndexRoot.IndexEntries.Add(rootEntry); IndexAllocationRecord rootDirIndexAllocation = (IndexAllocationRecord)rootDirSegment.CreateAttributeRecord(AttributeType.IndexAllocation, rootDirIndexName, false); rootDirIndexAllocation.AllocatedLength = (uint)rootDirIndexRecordAllocatedLength; rootDirIndexAllocation.FileSize = (uint)bytesPerIndexRecord; rootDirIndexAllocation.ValidDataLength = (uint)bytesPerIndexRecord; rootDirIndexAllocation.DataRunSequence.Add(new DataRun(rootDirIndexRecordClusterCount, rootDirIndexRecordStartLCN)); rootDirIndexAllocation.HighestVCN = rootDirIndexRecordClusterCount - 1; ResidentAttributeRecord rootDirBitmap = (ResidentAttributeRecord)rootDirSegment.CreateAttributeRecord(AttributeType.Bitmap, rootDirIndexName); rootDirBitmap.Data = new byte[BitmapData.ExtendGranularity]; BitmapData.SetBit(rootDirBitmap.Data, 0); long numberOfClustersInUse = rootDirIndexRecordStartLCN + rootDirIndexRecordClusterCount; long volumeBitmapStartSector = volumeBitmapStartLCN * sectorsPerCluster; WriteVolumeBitmap(volume, volumeBitmapStartSector, volumeClusterCount, numberOfClustersInUse); long mftBitmapStartSector = mftBitmapStartLCN * sectorsPerCluster; WriteMftBitmap(volume, mftBitmapStartSector, numberOfMftRecords, mftBitmapLength); // Write MFT data byte[] mftData = new byte[mftDataLength]; long mftDataStartSector = mftDataStartLCN * sectorsPerCluster; WriteFileRecordSegment(mftData, mftSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, mftMirrorSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, logFileSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, volumeSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, attributeDefinitionSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, rootDirSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, volumeBitmapSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, bootSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, badClustersSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, secureSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, upcaseSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftData, extendSegment, bytesPerFileRecordSegment, minorNTFSVersion); for (long segmentNumber = MasterFileTable.ExtendSegmentNumber + 1; segmentNumber < MasterFileTable.FirstReservedSegmentNumber; segmentNumber++) { FileRecordSegment systemSegment = CreateSystemReservedSegment(segmentNumber); WriteFileRecordSegment(mftData, systemSegment, bytesPerFileRecordSegment, minorNTFSVersion); } volume.WriteSectors(mftDataStartSector, mftData); long upcaseDataStartSector = upcaseDataStartLCN * sectorsPerCluster; WriteUpCaseFile(volume, upcaseDataStartSector); long rootDirIndexRecordStartSector = rootDirIndexRecordStartLCN * sectorsPerCluster; WriteIndexRecord(volume, rootDirIndexRecordStartSector, rootDirIndexRecord, bytesPerIndexRecord); // Write MFT mirror data byte[] mftMirrorData = new byte[mftMirrorDataLength]; long mftMirrorDataStartSector = mftMirrorDataStartLCN * sectorsPerCluster; WriteFileRecordSegment(mftMirrorData, mftSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftMirrorData, mftMirrorSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftMirrorData, logFileSegment, bytesPerFileRecordSegment, minorNTFSVersion); WriteFileRecordSegment(mftMirrorData, volumeSegment, bytesPerFileRecordSegment, minorNTFSVersion); volume.WriteSectors(mftMirrorDataStartSector, mftMirrorData); NTFSBootRecord bootRecord = CreateNTFSBootRecord(volumeClusterCount, sectorsPerCluster, volume.BytesPerSector, bytesPerFileRecordSegment, bytesPerIndexRecord, mftDataStartLCN, mftMirrorDataStartLCN); volume.WriteSectors(0, bootRecord.GetBytes()); volume.WriteSectors(volume.TotalSectors - 1, bootRecord.GetBytes()); return(new NTFSVolume(volume)); }