Example #1
0
        public virtual KeyValuePairList <MftSegmentReference, FileNameRecord> GetFileNameRecordsInDirectory(MftSegmentReference directoryReference)
        {
            FileRecord directoryRecord = GetFileRecord(directoryReference);
            KeyValuePairList <MftSegmentReference, FileNameRecord> result = null;

            if (directoryRecord != null && directoryRecord.IsDirectory)
            {
                m_mftLock.AcquireReaderLock(Timeout.Infinite);
                IndexData indexData = new IndexData(this, directoryRecord, AttributeType.FileName);
                result = indexData.GetAllFileNameRecords();
                m_mftLock.ReleaseReaderLock();

                for (int index = 0; index < result.Count; index++)
                {
                    bool isMetaFile = (result[index].Key.SegmentNumber < MasterFileTable.FirstUserSegmentNumber);
                    if (result[index].Value.Flags == FileNameFlags.DOS || isMetaFile)
                    {
                        // The same FileRecord can have multiple FileNameRecord entries, each with its own namespace
                        result.RemoveAt(index);
                        index--;
                    }
                }
            }
            return(result);
        }
Example #2
0
        // Note: The PC is simply a BTH with cbKey set to 2 and cbEnt set to 6
        public List <T> GetAll()
        {
            List <T> result = new List <T>();

            List <byte[]> leaves = new List <byte[]>();

            if (BTreeHeader.bIdxLevels > 0)
            {
                KeyValuePairList <byte[], byte> parents = new KeyValuePairList <byte[], byte>();
                parents.Add(GetHeapItem(BTreeHeader.hidRoot), BTreeHeader.bIdxLevels);
                while (parents.Count > 0)
                {
                    byte[] parentBytes = parents[0].Key;
                    byte   level       = parents[0].Value;

                    int offset = 0;
                    while (offset < parentBytes.Length)
                    {
                        HeapID hid   = new HeapID(parentBytes, offset + BTreeHeader.cbKey);
                        byte[] bytes = GetHeapItem(hid);
                        if (level == 1)
                        {
                            leaves.Add(bytes);
                        }
                        else
                        {
                            parents.Add(bytes, (byte)(level - 1));
                        }
                        offset += BTreeHeader.cbKey + HeapID.Length;
                    }
                    parents.RemoveAt(0);
                }
            }
            else
            {
                leaves.Add(GetHeapItem(BTreeHeader.hidRoot));
            }

            foreach (byte[] leafBytes in leaves)
            {
                int offset = 0;

                while (offset < leafBytes.Length)
                {
                    T record = BTreeOnHeapDataRecord.CreateInstance <T>(leafBytes, offset);
                    result.Add(record);
                    offset += BTreeHeader.cbKey + BTreeHeader.cbEnt;
                }
            }

            return(result);
        }
Example #3
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);
            }
        }
Example #4
0
        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);
        }
Example #5
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);
                    }
                }
            }
        }
Example #6
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);
                }
            }
        }