public NTFSVolume(Volume volume, bool useMftMirror) { m_volume = volume; byte[] bootSector = m_volume.ReadSector(0); m_bootRecord = NTFSBootRecord.ReadRecord(bootSector); if (m_bootRecord == null) { throw new InvalidDataException("The volume does not contain a valid NTFS boot record"); } m_mft = new MasterFileTable(this, useMftMirror); m_volumeInformation = GetVolumeInformationRecord(); if (m_volumeInformation.IsDirty) { throw new NotSupportedException("The volume is marked dirty, please run CHKDSK to repair the volume"); } // Note: We could support NTFS v1.2 with minimal effort, but there isn't really any point. if (!(m_volumeInformation.MajorVersion == 3 && m_volumeInformation.MinorVersion == 0) && !(m_volumeInformation.MajorVersion == 3 && m_volumeInformation.MinorVersion == 1)) { throw new NotSupportedException(String.Format("NTFS v{0}.{1} is not supported", m_volumeInformation.MajorVersion, m_volumeInformation.MinorVersion)); } m_logFile = new LogFile(this); m_logClient = new NTFSLogClient(m_logFile); m_bitmap = new VolumeBitmap(this); NumberOfClustersRequiredToExtendIndex = (int)Math.Ceiling((double)(IndexData.ExtendGranularity * m_bootRecord.BytesPerIndexRecord) / m_bootRecord.BytesPerCluster); }
public override string ToString() { StringBuilder builder = new StringBuilder(); if (m_bootRecord != null) { builder.AppendLine("Bytes Per Sector: " + m_bootRecord.BytesPerSector); builder.AppendLine("Bytes Per Cluster: " + m_bootRecord.BytesPerCluster); builder.AppendLine("Bytes Per File Record Segment: " + m_bootRecord.BytesPerFileRecordSegment); builder.AppendLine("First MFT Cluster (LCN): " + m_bootRecord.MftStartLCN); builder.AppendLine("First MFT Mirror Cluster (LCN): " + m_bootRecord.MftMirrorStartLCN); builder.AppendLine("Volume size (bytes): " + this.Size); builder.AppendLine(); VolumeInformationRecord volumeInformationRecord = GetVolumeInformationRecord(); if (volumeInformationRecord != null) { builder.AppendFormat("NTFS Version: {0}.{1}\n", volumeInformationRecord.MajorVersion, volumeInformationRecord.MinorVersion); builder.AppendLine(); } FileRecord mftRecord = m_mft.GetMftRecord(); if (mftRecord != null) { builder.AppendLine("Number of $MFT Data Runs: " + mftRecord.NonResidentDataRecord.DataRunSequence.Count); builder.AppendLine("$MFT Size in Clusters: " + mftRecord.NonResidentDataRecord.DataRunSequence.DataClusterCount); builder.Append(mftRecord.NonResidentDataRecord.DataRunSequence.ToString()); builder.AppendLine("Number of $MFT Attributes: " + mftRecord.Attributes.Count); builder.AppendLine("Length of $MFT Attributes: " + mftRecord.AttributesLengthOnDisk); builder.AppendLine(); FileRecord volumeBitmapRecord = m_mft.GetVolumeBitmapRecord(); if (volumeBitmapRecord != null) { builder.AppendLine("Volume Bitmap Start LCN: " + volumeBitmapRecord.NonResidentDataRecord.DataRunSequence.FirstDataRunLCN); builder.AppendLine("Volume Bitmap Size in Clusters: " + volumeBitmapRecord.NonResidentDataRecord.DataRunSequence.DataClusterCount); builder.AppendLine("Number of Volume Bitmap Attributes: " + volumeBitmapRecord.Attributes.Count); builder.AppendLine("Length of Volume Bitmap Attributes: " + volumeBitmapRecord.AttributesLengthOnDisk); } } byte[] bootRecord = ReadSectors(0, 1); long backupBootSectorIndex = (long)m_bootRecord.TotalSectors; byte[] backupBootRecord = ReadSectors(backupBootSectorIndex, 1); builder.AppendLine(); builder.AppendLine("Valid backup boot sector: " + ByteUtils.AreByteArraysEqual(bootRecord, backupBootRecord)); builder.AppendLine("Free space: " + this.FreeSpace); } return(builder.ToString()); }
public NTFSVolume(Volume volume, bool useMftMirror) { m_volume = volume; byte[] bootSector = m_volume.ReadSector(0); m_bootRecord = NTFSBootRecord.ReadRecord(bootSector); if (m_bootRecord != null) { m_mft = new MasterFileTable(this, useMftMirror); m_bitmap = new VolumeBitmap(this); m_volumeInformation = GetVolumeInformationRecord(); } }
public VolumeInformationRecord GetVolumeInformationRecord() { FileRecord volumeRecord = m_mft.GetVolumeRecord(); if (volumeRecord != null) { VolumeInformationRecord volumeInformationRecord = (VolumeInformationRecord)volumeRecord.GetAttributeRecord(AttributeType.VolumeInformation, String.Empty); return(volumeInformationRecord); } else { throw new InvalidDataException("Invalid NTFS volume record"); } }
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)); }