public BlockTrailer(byte[] buffer, int offset) { cb = LittleEndianConverter.ToUInt16(buffer, offset + 0); wSig = LittleEndianConverter.ToUInt16(buffer, offset + 2); dwCRC = LittleEndianConverter.ToUInt32(buffer, offset + 4); bid = new BlockID(buffer, offset + 8); }
/// <summary> /// Find the SubnodeLeafBlock where the entry with the given key should be located /// We use this method for search and insertion /// </summary> public SubnodeLeafBlock FindLeafBlock(uint subnodeID) { if (m_rootBlock == null) { return(null); } else if (m_rootBlock is SubnodeLeafBlock) { // We do not want to return the reference return((SubnodeLeafBlock)m_rootBlock.Clone()); } else if (m_rootBlock is SubnodeIntermediateBlock) { SubnodeIntermediateBlock intermediateBlock = (SubnodeIntermediateBlock)m_rootBlock; int index = intermediateBlock.IndexOfIntermediateEntryWithMatchingRange(subnodeID); BlockID blockID = intermediateBlock.rgentries[index].bid; return((SubnodeLeafBlock)GetBlock(blockID.LookupValue)); } else { throw new Exception("Invalid Subnode BTree root block"); } }
public SubnodeLeafEntry(byte[] buffer, int offset) { // the 4-byte NID is extended to its 8-byte equivalent nid = new NodeID(buffer, offset + 0); bidData = new BlockID(buffer, offset + 8); bidSub = new BlockID(buffer, offset + 16); }
public void WriteToPage(byte[] buffer, ulong fileOffset) { if (ptype == PageTypeName.ptypeBBT || ptype == PageTypeName.ptypeNBT || ptype == PageTypeName.ptypeDL) { wSig = BlockTrailer.ComputeSignature(fileOffset, bid.Value); } else { wSig = 0; // AMap, PMap, FMap, and FPMap pages have a special convention where their BID is assigned the same value as their IB bid = new BlockID(fileOffset); } dwCRC = PSTCRCCalculation.ComputeCRC(buffer, OffsetFromPageStart); int offset = OffsetFromPageStart; buffer[offset + 0] = (byte)ptype; buffer[offset + 1] = (byte)ptype; LittleEndianWriter.WriteUInt16(buffer, offset + 2, wSig); LittleEndianWriter.WriteUInt32(buffer, offset + 4, dwCRC); LittleEndianWriter.WriteUInt64(buffer, offset + 8, bid.Value); }
private void InsertSorted(ulong btkey, BlockID blockID) { BTreeIndexEntry entry = new BTreeIndexEntry(); entry.BREF.bid = blockID; InsertSorted(entry); }
/// <summary> /// Since the PST is immutable, any change will result in a new BBT root page /// Note: we may leave an empty leaf page /// </summary> /// <returns>New BlockBTree root page</returns> public void DeleteBlockEntry(BlockID blockID) { BlockBTreeLeafPage leaf = (BlockBTreeLeafPage)FindLeafBTreePage(blockID.LookupValue); // Remove the entry int index = leaf.RemoveEntry(blockID.LookupValue); if (index == 0) { // scanpst.exe report an error if page key does not match the first entry, // so we want to update the parent if (leaf.ParentPage != null) { if (leaf.BlockEntryList.Count > 0) { UpdateIndexEntry(leaf.ParentPage, leaf.BlockID, leaf.PageKey); } else { DeleteIndexEntry(leaf.ParentPage, leaf.BlockID); DeletePage(leaf); return; } } } // now we have to store the new leaf page, and cascade the changes up to the root page UpdatePageAndReferences(leaf); }
public NodeBTreeEntry(byte[] buffer, int offset) { nid = new NodeID(buffer, offset + 0); bidData = new BlockID(buffer, offset + 8); bidSub = new BlockID(buffer, offset + 16); nidParent = new NodeID(buffer, offset + 24); // 4 bytes of padding (Outlook does not always set these bytes to 0) }
/// <summary> /// UNDOCUMENTED: Outlook increments bidNextP by 1 /// Note: bidNextP have no special purpose for the two least insignificant bits /// </summary> /// <returns></returns> public BlockID AllocateNextPageBlockID() { BlockID result = bidNextP.Clone(); // MS-PST (2.6.1.1.4): bidNextB must be incremented as well AllocateNextBlockID(); bidNextP = new BlockID(bidNextP.Value + 1); return(result); }
public PageTrailer(byte[] buffer, int offset) { ptype = (PageTypeName)buffer[offset + 0]; PageTypeName ptypeRepeat = (PageTypeName)buffer[offset + 1]; wSig = LittleEndianConverter.ToUInt16(buffer, offset + 2); dwCRC = LittleEndianConverter.ToUInt32(buffer, offset + 4); bid = new BlockID(buffer, offset + 8); }
public void InsertBlockEntry(BlockID blockID, long offset, int dataLength) { BlockBTreeEntry entryToInsert = new BlockBTreeEntry(); entryToInsert.BREF.bid = blockID; entryToInsert.BREF.ib = (ulong)offset; entryToInsert.cb = (ushort)dataLength; entryToInsert.cRef = 2; // Any leaf BBT entry that points to a BID holds a reference count to it InsertBlockEntry(entryToInsert); }
public PSTHeader(byte[] buffer) { dwMagic = ByteReader.ReadAnsiString(buffer, 0, 4); CRCPartial = LittleEndianConverter.ToUInt32(buffer, 4); wMagicClient = ByteReader.ReadAnsiString(buffer, 8, 2); wVer = LittleEndianConverter.ToUInt16(buffer, 10); wVerClient = LittleEndianConverter.ToUInt16(buffer, 12); bPlatformCreate = buffer[14]; bPlatformAccess = buffer[15]; dwReserved1 = LittleEndianConverter.ToUInt32(buffer, 16); dwReserved2 = LittleEndianConverter.ToUInt32(buffer, 20); // bidUnused - which is not necessarily zeroed out bidUnused = new BlockID(buffer, 24); bidNextP = new BlockID(buffer, 32); dwUnique = LittleEndianConverter.ToUInt32(buffer, 40); int position = 44; for (int index = 0; index < 32; index++) { rgnid[index] = LittleEndianConverter.ToUInt32(buffer, position); position += 4; } root = new RootStructure(buffer, 180); dwAlign = LittleEndianConverter.ToUInt32(buffer, 252); Array.Copy(buffer, 256, rgbFM, 0, 128); Array.Copy(buffer, 384, rgbFP, 0, 128); bSentinel = buffer[512]; bCryptMethod = (bCryptMethodName)buffer[513]; bidNextB = new BlockID(buffer, 516); dwCRCFull = LittleEndianConverter.ToUInt32(buffer, 524); Array.Copy(buffer, 528, rgbReserved2, 0, 3); bReserved = buffer[531]; Array.Copy(buffer, 532, rgbReserved3, 0, 32); uint partial = PSTCRCCalculation.ComputeCRC(buffer, 8, 471); if (partial != CRCPartial) { throw new InvalidChecksumException(); } uint full = PSTCRCCalculation.ComputeCRC(buffer, 8, 516); if (full != dwCRCFull) { throw new InvalidChecksumException(); } }
public void UpdateBlockEntry(BlockID blockID, ushort cRef) { BlockBTreeLeafPage leaf = (BlockBTreeLeafPage)FindLeafBTreePage(blockID.LookupValue); int index = leaf.GetIndexOfEntry(blockID.LookupValue); if (index >= 0) { leaf.BlockEntryList[index].cRef = cRef; // now we have to store the new leaf page, and cascade the changes up to the root page UpdatePageAndReferences(leaf); } }
public BlockID AllocateNextBlockID() { BlockID result = bidNextB.Clone(); if (bidNextB.bidIndex < BlockID.MaximumBidIndex) { bidNextB.bidIndex++; // this will increment the value itself by 4, as required } else { throw new Exception("Could not allocate bidIndex"); } return(result); }
public XXBlock(byte[] buffer) : base(buffer) { btype = (BlockType)buffer[0]; cLevel = buffer[1]; ushort cEnt = LittleEndianConverter.ToUInt16(buffer, 2); lcbTotal = LittleEndianConverter.ToUInt32(buffer, 4); int position = 8; for (int index = 0; index < cEnt; index++) { BlockID bid = new BlockID(buffer, position); rgbid.Add(bid); position += 8; } }
public SubnodeLeafBlock GetLeafBlock(int blockIndex) { if (m_rootBlock is SubnodeLeafBlock) { if (blockIndex == 0) { return((SubnodeLeafBlock)m_rootBlock); } else { throw new ArgumentOutOfRangeException("blockIndex", "Invalid leaf block index"); } } else { SubnodeIntermediateBlock intermediateBlock = (SubnodeIntermediateBlock)m_rootBlock; BlockID blockID = intermediateBlock.rgentries[blockIndex].bid; return((SubnodeLeafBlock)GetBlock(blockID.LookupValue)); } }
public SubnodeIntermediateEntry(NodeID nodeID, BlockID blockID) { nid = nodeID; bid = blockID; }
protected void InsertIntermediateEntry(SubnodeIntermediateBlock intermediateBlock, uint key, BlockID blockID) { SubnodeIntermediateEntry intermediateEntry = new SubnodeIntermediateEntry(); intermediateEntry.nid = new NodeID(key); intermediateEntry.bid = blockID; InsertIntermediateEntry(intermediateBlock, intermediateEntry); }
public void IncrementBlockEntryReferenceCount(BlockID blockID) { BlockBTreeEntry entry = FindBlockEntryByBlockID(blockID.LookupValue); UpdateBlockEntry(blockID, (ushort)(entry.cRef + 1)); }
public Block FindBlockByBlockID(BlockID blockID) { return(FindBlockByBlockID(blockID.LookupValue)); }
protected bool IsBlockPendingWrite(BlockID blockID) { return(m_blocksToWrite.Contains(blockID.Value)); }
protected Block GetBlock(BlockID blockID) { return(GetBlock(blockID.Value)); }
public void UpdateIntermediateEntry(SubnodeIntermediateBlock intermediateBlock, BlockID blockIDOfChild, uint newKeyOfChild) { for (int index = 0; index < intermediateBlock.rgentries.Count; index++) { SubnodeIntermediateEntry entry = intermediateBlock.rgentries[index]; if (entry.bid.Value == blockIDOfChild.Value) { entry.nid = new NodeID(newKeyOfChild); } } }
public SubnodeIntermediateEntry(byte[] buffer, int offset) { // the 4-byte NID is extended to its 8-byte equivalent nid = new NodeID(buffer, offset); bid = new BlockID(buffer, offset + 8); }
public BlockRef(byte[] buffer, int offset) { bid = new BlockID(buffer, offset + 0); ib = LittleEndianConverter.ToUInt64(buffer, offset + 8); }