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); } }
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); } } }
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); }
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); } } }
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); } } } }
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); }