public Index(File file, string name, BiosParameterBlock bpb, UpperCase upCase) { _file = file; _name = name; _bpb = bpb; _isFileIndex = name == "$I30"; _blockCache = new ObjectCache<long, IndexBlock>(); _root = _file.GetStream(AttributeType.IndexRoot, _name).GetContent<IndexRoot>(); _comparer = _root.GetCollator(upCase); using (Stream s = _file.OpenStream(AttributeType.IndexRoot, _name, FileAccess.Read)) { byte[] buffer = Utilities.ReadFully(s, (int)s.Length); _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, true, buffer, IndexRoot.HeaderOffset); // Give the attribute some room to breathe, so long as it doesn't squeeze others out // BROKEN, BROKEN, BROKEN - how to figure this out? Query at the point of adding entries to the root node? _rootNode.TotalSpaceAvailable += _file.MftRecordFreeSpace(AttributeType.IndexRoot, _name) - 100; } if (_file.StreamExists(AttributeType.IndexAllocation, _name)) { _indexStream = _file.OpenStream(AttributeType.IndexAllocation, _name, FileAccess.ReadWrite); } if (_file.StreamExists(AttributeType.Bitmap, _name)) { _indexBitmap = new Bitmap(_file.OpenStream(AttributeType.Bitmap, _name, FileAccess.ReadWrite), long.MaxValue); } }
/// <summary> /// Removes redundant nodes (that contain only an 'End' entry). /// </summary> /// <param name="entryIndex">The index of the entry that may have a redundant child</param> /// <returns>An entry that needs to be promoted to the parent node (if any)</returns> private IndexEntry LiftNode(int entryIndex) { if ((_entries[entryIndex].Flags & IndexEntryFlags.Node) != 0) { IndexNode childNode = _index.GetSubBlock(_entries[entryIndex]).Node; if (childNode._entries.Count == 1) { long freeBlock = _entries[entryIndex].ChildrenVirtualCluster; _entries[entryIndex].Flags = (_entries[entryIndex].Flags & ~IndexEntryFlags.Node) | (childNode._entries[0].Flags & IndexEntryFlags.Node); _entries[entryIndex].ChildrenVirtualCluster = childNode._entries[0].ChildrenVirtualCluster; _index.FreeBlock(freeBlock); } if ((_entries[entryIndex].Flags & (IndexEntryFlags.Node | IndexEntryFlags.End)) == 0) { IndexEntry entry = _entries[entryIndex]; _entries.RemoveAt(entryIndex); IndexNode nextNode = _index.GetSubBlock(_entries[entryIndex]).Node; return(nextNode.AddEntry(entry)); } } return(null); }
public bool TryFindEntry(byte[] key, out IndexEntry entry, out IndexNode node) { foreach (var focus in _entries) { if ((focus.Flags & IndexEntryFlags.End) != 0) { if ((focus.Flags & IndexEntryFlags.Node) != 0) { IndexBlock subNode = _index.GetSubBlock(focus); return(subNode.Node.TryFindEntry(key, out entry, out node)); } break; } else { int compVal = _index.Compare(key, focus.KeyBuffer); if (compVal == 0) { entry = focus; node = this; return(true); } else if (compVal < 0 && (focus.Flags & (IndexEntryFlags.End | IndexEntryFlags.Node)) != 0) { IndexBlock subNode = _index.GetSubBlock(focus); return(subNode.Node.TryFindEntry(key, out entry, out node)); } } } entry = null; node = null; return(false); }
private IndexBlock(Index index, bool isRoot, long vcn, BiosParameterBlock bpb) : base("INDX", bpb.BytesPerSector, bpb.IndexBufferSize) { _index = index; _isRoot = isRoot; _indexBlockVcn = (ulong)vcn; _streamPosition = vcn * bpb.BytesPerSector * bpb.SectorsPerCluster; _node = new IndexNode(WriteToDisk, UpdateSequenceSize, _index, isRoot, (uint)bpb.IndexBufferSize - FieldSize); WriteToDisk(); }
private IEnumerable <IndexEntry> FindAllIn(IComparable <byte[]> query, IndexNode node) { foreach (var focus in node.Entries) { bool searchChildren = true; bool matches = false; bool keepIterating = true; if ((focus.Flags & IndexEntryFlags.End) == 0) { int compVal = query.CompareTo(focus.KeyBuffer); if (compVal == 0) { matches = true; } else if (compVal > 0) { searchChildren = false; } else if (compVal < 0) { keepIterating = false; } } if (searchChildren && (focus.Flags & IndexEntryFlags.Node) != 0) { IndexBlock block = GetSubBlock(focus); foreach (var entry in FindAllIn(query, block.Node)) { yield return(entry); } } if (matches) { yield return(focus); } if (!keepIterating) { yield break; } } }
protected IEnumerable <IndexEntry> Enumerate(IndexNode node) { foreach (var focus in node.Entries) { if ((focus.Flags & IndexEntryFlags.Node) != 0) { IndexBlock block = GetSubBlock(focus); foreach (var subEntry in Enumerate(block.Node)) { yield return(subEntry); } } if ((focus.Flags & IndexEntryFlags.End) == 0) { yield return(focus); } } }
private void NodeAsString(TextWriter writer, string prefix, IndexNode node, string id) { writer.WriteLine(prefix + id + ":"); foreach (var entry in node.Entries) { if ((entry.Flags & IndexEntryFlags.End) != 0) { writer.WriteLine(prefix + " E"); } else { writer.WriteLine(prefix + " " + EntryAsString(entry, _file.BestName, _name)); } if ((entry.Flags & IndexEntryFlags.Node) != 0) { NodeAsString(writer, prefix + " ", GetSubBlock(entry).Node, ":i" + entry.ChildrenVirtualCluster); } } }
private Index(AttributeType attrType, AttributeCollationRule collationRule, File file, string name, BiosParameterBlock bpb, UpperCase upCase) { _file = file; _name = name; _bpb = bpb; _isFileIndex = name == "$I30"; _blockCache = new ObjectCache <long, IndexBlock>(); _file.CreateStream(AttributeType.IndexRoot, _name); _root = new IndexRoot() { AttributeType = (uint)attrType, CollationRule = collationRule, IndexAllocationSize = (uint)bpb.IndexBufferSize, RawClustersPerIndexRecord = bpb.RawIndexBufferSize }; _comparer = _root.GetCollator(upCase); _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, true, 32); }
protected override void Read(byte[] buffer, int offset) { // Skip FixupRecord fields... _logSequenceNumber = Utilities.ToUInt64LittleEndian(buffer, offset + 0x08); _indexBlockVcn = Utilities.ToUInt64LittleEndian(buffer, offset + 0x10); _node = new IndexNode(WriteToDisk, UpdateSequenceSize, _index, _isRoot, buffer, offset + FieldSize); }
private Index(AttributeType attrType, AttributeCollationRule collationRule, File file, string name, BiosParameterBlock bpb, UpperCase upCase) { _file = file; _name = name; _bpb = bpb; _isFileIndex = name == "$I30"; _blockCache = new ObjectCache<long, IndexBlock>(); _file.CreateStream(AttributeType.IndexRoot, _name); _root = new IndexRoot() { AttributeType = (uint)attrType, CollationRule = collationRule, IndexAllocationSize = (uint)bpb.IndexBufferSize, RawClustersPerIndexRecord = bpb.RawIndexBufferSize }; _comparer = _root.GetCollator(upCase); _rootNode = new IndexNode(WriteRootNodeToDisk, 0, this, true, 32); }
private IEnumerable<IndexEntry> FindAllIn(IComparable<byte[]> query, IndexNode node) { foreach (var focus in node.Entries) { bool searchChildren = true; bool matches = false; bool keepIterating = true; if ((focus.Flags & IndexEntryFlags.End) == 0) { int compVal = query.CompareTo(focus.KeyBuffer); if (compVal == 0) { matches = true; } else if (compVal > 0) { searchChildren = false; } else if (compVal < 0) { keepIterating = false; } } if (searchChildren && (focus.Flags & IndexEntryFlags.Node) != 0) { IndexBlock block = GetSubBlock(focus); foreach (var entry in FindAllIn(query, block.Node)) { yield return entry; } } if (matches) { yield return focus; } if (!keepIterating) { yield break; } } }
protected IEnumerable<IndexEntry> Enumerate(IndexNode node) { foreach (var focus in node.Entries) { if ((focus.Flags & IndexEntryFlags.Node) != 0) { IndexBlock block = GetSubBlock(focus); foreach (var subEntry in Enumerate(block.Node)) { yield return subEntry; } } if ((focus.Flags & IndexEntryFlags.End) == 0) { yield return focus; } } }
public bool RemoveEntry(byte[] key, out IndexEntry newParentEntry) { bool exactMatch; int entryIndex = GetEntry(key, out exactMatch); IndexEntry entry = _entries[entryIndex]; if (exactMatch) { if ((entry.Flags & IndexEntryFlags.Node) != 0) { IndexNode childNode = _index.GetSubBlock(entry).Node; IndexEntry rLeaf = childNode.FindLargestLeaf(); byte[] newKey = rLeaf.KeyBuffer; byte[] newData = rLeaf.DataBuffer; IndexEntry newEntry; childNode.RemoveEntry(newKey, out newEntry); entry.KeyBuffer = newKey; entry.DataBuffer = newData; if (newEntry != null) { InsertEntryThisNode(newEntry); } newEntry = LiftNode(entryIndex); if (newEntry != null) { InsertEntryThisNode(newEntry); } newEntry = PopulateEnd(); if (newEntry != null) { InsertEntryThisNode(newEntry); } // New entry could be larger than old, so may need // to divide this node... newParentEntry = EnsureNodeSize(); } else { _entries.RemoveAt(entryIndex); newParentEntry = null; } _store(); return(true); } else if ((entry.Flags & IndexEntryFlags.Node) != 0) { IndexNode childNode = _index.GetSubBlock(entry).Node; IndexEntry newEntry; if (childNode.RemoveEntry(key, out newEntry)) { if (newEntry != null) { InsertEntryThisNode(newEntry); } newEntry = LiftNode(entryIndex); if (newEntry != null) { InsertEntryThisNode(newEntry); } newEntry = PopulateEnd(); if (newEntry != null) { InsertEntryThisNode(newEntry); } // New entry could be larger than old, so may need // to divide this node... newParentEntry = EnsureNodeSize(); _store(); return(true); } } newParentEntry = null; return(false); }
public bool TryFindEntry(byte[] key, out IndexEntry entry, out IndexNode node) { foreach (var focus in _entries) { if ((focus.Flags & IndexEntryFlags.End) != 0) { if ((focus.Flags & IndexEntryFlags.Node) != 0) { IndexBlock subNode = _index.GetSubBlock(focus); return subNode.Node.TryFindEntry(key, out entry, out node); } break; } else { int compVal = _index.Compare(key, focus.KeyBuffer); if (compVal == 0) { entry = focus; node = this; return true; } else if (compVal < 0 && (focus.Flags & (IndexEntryFlags.End | IndexEntryFlags.Node)) != 0) { IndexBlock subNode = _index.GetSubBlock(focus); return subNode.Node.TryFindEntry(key, out entry, out node); } } } entry = null; node = null; return false; }