Пример #1
0
        private KeyValuePairList <int, IndexRecord> FindRemovalPath(byte[] key, out int indexOfEntryToRemove)
        {
            bool isParentNode         = true;
            List <IndexEntry> entries = m_rootRecord.IndexEntries;
            KeyValuePairList <int, IndexRecord> path = new KeyValuePairList <int, IndexRecord>();

            while (isParentNode)
            {
                int index = CollationHelper.FindIndexInParentNode(entries, key, m_rootRecord.CollationRule);
                if (!entries[index].IsLastEntry && CollationHelper.Compare(entries[index].Key, key, m_rootRecord.CollationRule) == 0)
                {
                    indexOfEntryToRemove = index;
                    return(path);
                }
                long        subnodeVBN  = entries[index].SubnodeVBN;
                IndexRecord indexRecord = ReadIndexRecord(subnodeVBN);
                isParentNode = indexRecord.IsParentNode;
                entries      = indexRecord.IndexEntries;
                path.Add(index, indexRecord);
            }

            indexOfEntryToRemove = CollationHelper.FindIndexInLeafNode(entries, key, m_rootRecord.CollationRule);
            if (indexOfEntryToRemove >= 0)
            {
                return(path);
            }
            else
            {
                return(null);
            }
        }
Пример #2
0
        private void WriteIndexRecord(long recordIndex, IndexRecord indexRecord)
        {
            long sectorsPerIndexRecord = m_rootRecord.BytesPerIndexRecord / m_volume.BytesPerSector;
            long sectorIndex           = recordIndex * sectorsPerIndexRecord;

            m_indexAllocationData.WriteSectors(sectorIndex, indexRecord.GetBytes((int)m_rootRecord.BytesPerIndexRecord, true));
        }
Пример #3
0
        private IndexRecord ReadIndexRecord(long subnodeVBN)
        {
            long sectorIndex = ConvertToSectorIndex(subnodeVBN);

            byte[]      recordBytes = m_indexAllocationData.ReadSectors(sectorIndex, this.SectorsPerIndexRecord);
            IndexRecord record      = new IndexRecord(recordBytes, 0);

            return(record);
        }
        internal IndexRecord ReadIndexRecord(long subnodeVBN)
        {
            long sectorIndex = ConvertToSectorIndex(subnodeVBN);

            byte[] recordBytes = m_indexAllocationData.ReadSectors(sectorIndex, this.SectorsPerIndexRecord);
            MultiSectorHelper.RevertUsaProtection(recordBytes, 0);
            IndexRecord record = new IndexRecord(recordBytes, 0);

            return(record);
        }
        public KeyValuePairList <MftSegmentReference, FileNameRecord> GetAllEntries(NTFSVolume volume, IndexRootRecord rootRecord)
        {
            KeyValuePairList <MftSegmentReference, FileNameRecord> result = new KeyValuePairList <MftSegmentReference, FileNameRecord>();
            List <IndexNodeEntry> parents = new List <IndexNodeEntry>(rootRecord.IndexEntries);
            List <IndexRecord>    leaves  = new List <IndexRecord>();

            int parentIndex = 0;

            while (parentIndex < parents.Count)
            {
                IndexNodeEntry parent   = parents[parentIndex];
                byte[]         clusters = this.ReadDataClusters(volume, parent.SubnodeVCN, rootRecord.ClustersPerIndexRecord);
                IndexRecord    record   = new IndexRecord(clusters, 0);
                if (record.HasChildren)
                {
                    foreach (IndexNodeEntry node in record.IndexEntries)
                    {
                        parents.Add(node);
                    }
                }
                else
                {
                    leaves.Add(record);
                }

                parentIndex++;
            }

            foreach (IndexNodeEntry node in parents)
            {
                if (!node.IsLastEntry)
                {
                    // Some of the tree data in NTFS is contained in non-leaf keys
                    FileNameRecord parentRecord = new FileNameRecord(node.Key, 0);
                    result.Add(node.SegmentReference, parentRecord);
                }
            }

            foreach (IndexRecord record in leaves)
            {
                foreach (FileNameIndexEntry entry in record.FileNameEntries)
                {
                    result.Add(entry.FileReference, entry.Record);
                }
            }

            result.Sort(Compare);

            return(result);
        }
Пример #6
0
        public KeyValuePair <MftSegmentReference, byte[]>?FindEntry(byte[] key)
        {
            if (!m_rootRecord.IsParentNode)
            {
                int index = CollationHelper.FindIndexInLeafNode(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule);
                if (index >= 0)
                {
                    IndexEntry entry = m_rootRecord.IndexEntries[index];
                    return(new KeyValuePair <MftSegmentReference, byte[]>(entry.FileReference, entry.Key));
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                bool isParentNode         = true;
                List <IndexEntry> entries = m_rootRecord.IndexEntries;
                int index;
                while (isParentNode)
                {
                    index = CollationHelper.FindIndexInParentNode(entries, key, m_rootRecord.CollationRule);
                    IndexEntry entry = entries[index];
                    if (!entry.IsLastEntry && CollationHelper.Compare(entry.Key, key, m_rootRecord.CollationRule) == 0)
                    {
                        return(new KeyValuePair <MftSegmentReference, byte[]>(entry.FileReference, entry.Key));
                    }
                    else
                    {
                        long        subnodeVBN  = entry.SubnodeVBN;
                        IndexRecord indexRecord = ReadIndexRecord(subnodeVBN);
                        isParentNode = indexRecord.IsParentNode;
                        entries      = indexRecord.IndexEntries;
                    }
                }

                index = CollationHelper.FindIndexInLeafNode(entries, key, m_rootRecord.CollationRule);
                if (index >= 0)
                {
                    IndexEntry entry = entries[index];
                    return(new KeyValuePair <MftSegmentReference, byte[]>(entry.FileReference, entry.Key));
                }
                else
                {
                    return(null);
                }
            }
        }
Пример #7
0
        public KeyValuePairList <MftSegmentReference, byte[]> GetAllEntries()
        {
            KeyValuePairList <MftSegmentReference, byte[]> result = new KeyValuePairList <MftSegmentReference, byte[]>();

            if (!m_rootRecord.IsParentNode)
            {
                foreach (IndexEntry entry in m_rootRecord.IndexEntries)
                {
                    result.Add(entry.FileReference, entry.Key);
                }
            }
            else
            {
                List <IndexEntry> parents         = new List <IndexEntry>(m_rootRecord.IndexEntries);
                SortedList <long> subnodesVisited = new SortedList <long>();

                while (parents.Count > 0)
                {
                    IndexEntry parent = parents[0];
                    if (!subnodesVisited.Contains(parent.SubnodeVBN))
                    {
                        IndexRecord record = ReadIndexRecord(parent.SubnodeVBN);
                        if (record.IsParentNode)
                        {
                            parents.InsertRange(0, record.IndexEntries);
                        }
                        else
                        {
                            foreach (IndexEntry entry in record.IndexEntries)
                            {
                                result.Add(entry.FileReference, entry.Key);
                            }
                        }
                        subnodesVisited.Add(parent.SubnodeVBN);
                    }
                    else
                    {
                        if (!parent.IsLastEntry)
                        {
                            // Some of the tree data in NTFS is contained in non-leaf keys
                            result.Add(parent.FileReference, parent.Key);
                        }
                        parents.RemoveAt(0);
                    }
                }
            }
            return(result);
        }
Пример #8
0
        private KeyValuePairList <int, IndexRecord> FindPathToRightmostLeaf(KeyValuePairList <int, IndexRecord> startPath)
        {
            KeyValuePairList <int, IndexRecord> path = new KeyValuePairList <int, IndexRecord>(startPath);
            int         indexInParentRecord          = startPath[startPath.Count - 1].Key;
            IndexRecord indexRecord = startPath[startPath.Count - 1].Value;

            while (indexRecord.IsParentNode)
            {
                indexInParentRecord = indexRecord.IndexEntries.Count - 1;
                long subnodeVBN = indexRecord.IndexEntries[indexInParentRecord].SubnodeVBN;
                indexRecord = ReadIndexRecord(subnodeVBN);
                path.Add(indexInParentRecord, indexRecord);
            }

            return(path);
        }
Пример #9
0
        private KeyValuePairList <int, IndexRecord> FindInsertPath(byte[] key)
        {
            bool isParentNode         = true;
            List <IndexEntry> entries = m_rootRecord.IndexEntries;
            KeyValuePairList <int, IndexRecord> path = new KeyValuePairList <int, IndexRecord>();

            while (isParentNode)
            {
                int         index       = CollationHelper.FindIndexInParentNode(entries, key, m_rootRecord.CollationRule);
                long        subnodeVBN  = entries[index].SubnodeVBN;
                IndexRecord indexRecord = ReadIndexRecord(subnodeVBN);
                isParentNode = indexRecord.IsParentNode;
                entries      = indexRecord.IndexEntries;
                path.Add(index, indexRecord);
            }
            return(path);
        }
Пример #10
0
        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);
                }
            }
        }
Пример #11
0
        private KeyValuePairList <int, IndexRecord> FindPathToRightmostLeaf(KeyValuePairList <int, IndexRecord> startPath, int indexInLastEntry)
        {
            KeyValuePairList <int, IndexRecord> path = new KeyValuePairList <int, IndexRecord>(startPath);
            List <IndexEntry> entries;

            if (startPath.Count == 0)
            {
                entries = m_rootRecord.IndexEntries;
            }
            else
            {
                entries = startPath[startPath.Count - 1].Value.IndexEntries;
            }
            IndexRecord indexRecord = ReadIndexRecord(entries[indexInLastEntry].SubnodeVBN);

            path.Add(indexInLastEntry, indexRecord);
            return(FindPathToRightmostLeaf(path));
        }
Пример #12
0
        /// <summary>
        /// Will remove the pointer while preserving the entry (if present)
        /// </summary>
        private void RemovePointer(KeyValuePairList <int, IndexRecord> path, int indexOfEntryToRemove)
        {
            int         indexInParentRecord = path[path.Count - 1].Key;
            IndexRecord indexRecord         = path[path.Count - 1].Value;
            long        recordIndex         = ConvertToRecordIndex(indexRecord.RecordVBN);
            IndexEntry  pointer             = indexRecord.IndexEntries[indexOfEntryToRemove];

            if (pointer.IsLastEntry)
            {
                if (indexRecord.IndexEntries.Count == 1)
                {
                    if (path.Count > 1)
                    {
                        path.RemoveAt(path.Count - 1);
                        RemovePointer(path, indexInParentRecord);
                    }
                    else
                    {
                        RemovePointerFromRoot(indexInParentRecord);
                    }
                    DeallocateIndexRecord(recordIndex);
                }
                else
                {
                    MftSegmentReference fileReferenceToReinsert = indexRecord.IndexEntries[indexOfEntryToRemove - 1].FileReference;
                    byte[] keyToReinsert = indexRecord.IndexEntries[indexOfEntryToRemove - 1].Key;
                    indexRecord.IndexEntries.RemoveAt(indexOfEntryToRemove);
                    indexRecord.IndexEntries[indexOfEntryToRemove - 1].FileReference = MftSegmentReference.NullReference;
                    indexRecord.IndexEntries[indexOfEntryToRemove - 1].Key           = new byte[0];
                    WriteIndexRecord(recordIndex, indexRecord);
                    AddEntry(fileReferenceToReinsert, keyToReinsert);
                }
            }
            else
            {
                MftSegmentReference fileReferenceToReinsert = indexRecord.IndexEntries[indexOfEntryToRemove].FileReference;
                byte[] keyToReinsert = indexRecord.IndexEntries[indexOfEntryToRemove].Key;
                indexRecord.IndexEntries.RemoveAt(indexOfEntryToRemove);
                WriteIndexRecord(recordIndex, indexRecord);
                AddEntry(fileReferenceToReinsert, keyToReinsert);
            }
        }
Пример #13
0
        /// <remarks>
        /// The root node can contain a limited number of entries compare to an IndexRecord,
        /// so there is no point splitting it to two child nodes, a single one would be sufficient.
        /// </remarks>
        private void SplitRootIndexRecord()
        {
            IndexRecord childRecord = new IndexRecord();

            childRecord.IsParentNode = m_rootRecord.IsParentNode;
            childRecord.IndexEntries = new List <IndexEntry>(m_rootRecord.IndexEntries);
            long childRecordIndex = AllocateIndexRecord();

            childRecord.RecordVBN = ConvertToVirtualBlockNumber(childRecordIndex);
            WriteIndexRecord(childRecordIndex, childRecord);

            IndexEntry rootEntry = new IndexEntry();

            rootEntry.SubnodeVBN     = childRecord.RecordVBN;
            rootEntry.ParentNodeForm = true;

            m_rootRecord.IndexEntries.Clear();
            m_rootRecord.IsParentNode = true;
            m_rootRecord.IndexEntries.Add(rootEntry);
            m_volume.UpdateFileRecord(m_fileRecord);
        }
Пример #14
0
        /// <param name="path">Key is index in parent node</param>
        private void SplitIndexRecord(KeyValuePairList <int, IndexRecord> path)
        {
            int indexInParentRecord = path[path.Count - 1].Key;
            // We will treat the record we want to split as the right node, and create a left node
            IndexRecord       rightNode        = path[path.Count - 1].Value;
            long              rightNodeVBN     = rightNode.RecordVBN;
            long              rightNodeIndex   = ConvertToRecordIndex(rightNodeVBN);
            List <IndexEntry> rightNodeEntries = rightNode.IndexEntries;
            int         splitIndex             = rightNodeEntries.Count / 2;
            IndexEntry  middleEntry            = rightNodeEntries[splitIndex];
            IndexRecord leftNode = new IndexRecord();

            leftNode.IsParentNode = rightNode.IsParentNode;
            leftNode.IndexEntries = rightNodeEntries.GetRange(0, splitIndex);
            rightNodeEntries.RemoveRange(0, splitIndex + 1);
            if (rightNode.IsParentNode)
            {
                // A parent node has n keys and points to (n + 1) subnodes,
                // When splitting it to two nodes we will take the pointer from the entry we wish to push to the parent node,
                // and use it as the last pointer in the left node.
                IndexEntry leftNodeLastEntry = new IndexEntry();
                leftNodeLastEntry.ParentNodeForm = true;
                leftNodeLastEntry.IsLastEntry    = true;
                leftNodeLastEntry.SubnodeVBN     = middleEntry.SubnodeVBN;
                leftNode.IndexEntries.Add(leftNodeLastEntry);
            }
            long leftNodeIndex = AllocateIndexRecord();

            leftNode.RecordVBN = ConvertToVirtualBlockNumber(leftNodeIndex);
            IndexEntry newParentEntry = new IndexEntry(middleEntry.FileReference, middleEntry.Key);

            newParentEntry.ParentNodeForm = true;
            newParentEntry.SubnodeVBN     = leftNode.RecordVBN;
            WriteIndexRecord(rightNodeIndex, rightNode);
            WriteIndexRecord(leftNodeIndex, leftNode);
            if (path.Count > 1)
            {
                IndexRecord       parentRecord      = path[path.Count - 2].Value;
                long              parentRecordIndex = ConvertToRecordIndex(parentRecord.RecordVBN);
                List <IndexEntry> parentEntries     = parentRecord.IndexEntries;
                parentEntries.Insert(indexInParentRecord, newParentEntry);
                if (parentRecord.DoesFit((int)m_rootRecord.BytesPerIndexRecord))
                {
                    WriteIndexRecord(parentRecordIndex, parentRecord);
                }
                else
                {
                    // Split parent index record
                    path.RemoveAt(path.Count - 1);
                    SplitIndexRecord(path);
                }
            }
            else
            {
                m_rootRecord.IndexEntries.Insert(indexInParentRecord, newParentEntry);
                if (m_rootRecord.RecordLength >= m_volume.AttributeRecordLengthToMakeNonResident)
                {
                    SplitRootIndexRecord();
                }
                else
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
        }
Пример #15
0
        public bool UpdateFileNameRecord(FileNameRecord fileNameRecord)
        {
            byte[] key = fileNameRecord.GetBytes();
            if (!m_rootRecord.IsParentNode)
            {
                int index = CollationHelper.FindIndexInLeafNode(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule);
                if (index >= 0)
                {
                    m_rootRecord.IndexEntries[index].Key = key;
                    m_volume.UpdateFileRecord(m_fileRecord);
                    return(true);
                }
            }
            else
            {
                IndexRecord       indexRecord  = null;
                bool              isParentNode = true;
                List <IndexEntry> entries      = m_rootRecord.IndexEntries;
                int index;
                while (isParentNode)
                {
                    index = CollationHelper.FindIndexInParentNode(entries, key, m_rootRecord.CollationRule);
                    IndexEntry entry = entries[index];
                    if (!entry.IsLastEntry && CollationHelper.Compare(entry.Key, key, m_rootRecord.CollationRule) == 0)
                    {
                        entries[index].Key = key;
                        if (indexRecord == null)
                        {
                            m_volume.UpdateFileRecord(m_fileRecord);
                        }
                        else
                        {
                            long recordIndex = ConvertToRecordIndex(indexRecord.RecordVBN);
                            WriteIndexRecord(recordIndex, indexRecord);
                        }
                        return(true);
                    }
                    else
                    {
                        long subnodeVBN = entry.SubnodeVBN;
                        indexRecord  = ReadIndexRecord(subnodeVBN);
                        isParentNode = indexRecord.IsParentNode;
                        entries      = indexRecord.IndexEntries;
                    }
                }

                index = CollationHelper.FindIndexInLeafNode(entries, key, m_rootRecord.CollationRule);
                if (index >= 0)
                {
                    entries[index].Key = key;
                    if (indexRecord == null)
                    {
                        m_volume.UpdateFileRecord(m_fileRecord);
                    }
                    else
                    {
                        long recordIndex = ConvertToRecordIndex(indexRecord.RecordVBN);
                        WriteIndexRecord(recordIndex, indexRecord);
                    }
                    return(true);
                }
            }

            return(false);
        }
Пример #16
0
        public void RemoveEntry(byte[] key)
        {
            if (!m_rootRecord.IsParentNode)
            {
                int index = CollationHelper.FindIndexInLeafNode(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule);
                if (index >= 0)
                {
                    m_rootRecord.IndexEntries.RemoveAt(index);
                }
                m_volume.UpdateFileRecord(m_fileRecord);
            }
            else
            {
                int indexOfEntryToRemove;
                KeyValuePairList <int, IndexRecord> path = FindRemovalPath(key, out indexOfEntryToRemove);
                if (path == null)
                {
                    return;
                }

                if ((path.Count > 0 && path[path.Count - 1].Value.IsParentNode) || path.Count == 0)
                {
                    // We find the rightmost leaf entry in the left branch and put it instead.
                    // Note: Excluding the root of the branch, the rightmost leaf entry in the branch collates last.
                    KeyValuePairList <int, IndexRecord> pathToLeaf = FindPathToRightmostLeaf(path, indexOfEntryToRemove);
                    IndexRecord leaf = pathToLeaf[pathToLeaf.Count - 1].Value;
                    IndexEntry  entryToRemoveFromLeaf = leaf.IndexEntries[leaf.IndexEntries.Count - 1];
                    leaf.IndexEntries.RemoveAt(leaf.IndexEntries.Count - 1);
                    long leafRecordIndex = ConvertToRecordIndex(leaf.RecordVBN);
                    // Note: CHKDSK does not accept an empty IndexRecord, however, we must not call RemovePointer just yet because it might affect the parent as well.
                    WriteIndexRecord(leafRecordIndex, leaf);

                    if (path.Count == 0)
                    {
                        m_rootRecord.IndexEntries[indexOfEntryToRemove].FileReference = entryToRemoveFromLeaf.FileReference;
                        m_rootRecord.IndexEntries[indexOfEntryToRemove].Key           = entryToRemoveFromLeaf.Key;
                        m_volume.UpdateFileRecord(m_fileRecord);
                    }
                    else
                    {
                        path[path.Count - 1].Value.IndexEntries[indexOfEntryToRemove].FileReference = entryToRemoveFromLeaf.FileReference;
                        path[path.Count - 1].Value.IndexEntries[indexOfEntryToRemove].Key           = entryToRemoveFromLeaf.Key;
                        long recordIndex = ConvertToRecordIndex(path[path.Count - 1].Value.RecordVBN);
                        WriteIndexRecord(recordIndex, path[path.Count - 1].Value);
                    }

                    if (leaf.IndexEntries.Count == 0)
                    {
                        int indexOfLeafPointer = pathToLeaf[pathToLeaf.Count - 1].Key;
                        RemovePointer(pathToLeaf.GetRange(0, pathToLeaf.Count - 1), indexOfLeafPointer);
                        DeallocateIndexRecord(leafRecordIndex);
                    }
                }
                else
                {
                    int         indexInParentRecord = path[path.Count - 1].Key;
                    IndexRecord leaf = path[path.Count - 1].Value;

                    leaf.IndexEntries.RemoveAt(indexOfEntryToRemove);
                    long recordIndex = ConvertToRecordIndex(leaf.RecordVBN);
                    if (leaf.IndexEntries.Count > 0)
                    {
                        WriteIndexRecord(recordIndex, leaf);
                    }
                    else
                    {
                        path.RemoveAt(path.Count - 1);
                        RemovePointer(path, indexInParentRecord);
                        DeallocateIndexRecord(recordIndex);
                    }
                }
            }
        }
Пример #17
0
        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));
        }
Пример #18
0
 private static void WriteIndexRecord(Volume volume, long indexRecordStartSector, IndexRecord indexRecord, int bytesPerIndexRecord)
 {
     byte[] indexRecordBytes = indexRecord.GetBytes(bytesPerIndexRecord, true);
     volume.WriteSectors(indexRecordStartSector, indexRecordBytes);
 }