Пример #1
0
 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);
 }
Пример #2
0
        /// <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);
 }
Пример #4
0
        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);
        }
Пример #5
0
        private void InsertSorted(ulong btkey, BlockID blockID)
        {
            BTreeIndexEntry entry = new BTreeIndexEntry();

            entry.BREF.bid = blockID;
            InsertSorted(entry);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
 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)
 }
Пример #8
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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        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);
        }
Пример #11
0
        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();
            }
        }
Пример #12
0
        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);
            }
        }
Пример #13
0
        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);
        }
Пример #14
0
        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;
            }
        }
Пример #15
0
 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));
     }
 }
Пример #16
0
 public SubnodeIntermediateEntry(NodeID nodeID, BlockID blockID)
 {
     nid = nodeID;
     bid = blockID;
 }
Пример #17
0
        protected void InsertIntermediateEntry(SubnodeIntermediateBlock intermediateBlock, uint key, BlockID blockID)
        {
            SubnodeIntermediateEntry intermediateEntry = new SubnodeIntermediateEntry();

            intermediateEntry.nid = new NodeID(key);
            intermediateEntry.bid = blockID;
            InsertIntermediateEntry(intermediateBlock, intermediateEntry);
        }
Пример #18
0
        public void IncrementBlockEntryReferenceCount(BlockID blockID)
        {
            BlockBTreeEntry entry = FindBlockEntryByBlockID(blockID.LookupValue);

            UpdateBlockEntry(blockID, (ushort)(entry.cRef + 1));
        }
Пример #19
0
 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));
 }
Пример #22
0
 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);
         }
     }
 }
Пример #23
0
 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);
 }
Пример #24
0
 public BlockRef(byte[] buffer, int offset)
 {
     bid = new BlockID(buffer, offset + 0);
     ib  = LittleEndianConverter.ToUInt64(buffer, offset + 8);
 }