Exemplo n.º 1
0
        public DataBlock GetDataBlock(int dataBlockIndex)
        {
            if (m_rootBlock == null)
            {
                throw new Exception("Data tree root block is null");
            }
            else if (m_rootBlock is DataBlock)
            {
                if (dataBlockIndex == 0)
                {
                    // We do not want to return the reference
                    return((DataBlock)m_rootBlock.Clone());
                }
                else
                {
                    throw new ArgumentException("Data tree root block is a data block, data block index must be 0");
                }
            }
            else if (m_rootBlock is XBlock)
            {
                XBlock rootBlock = (XBlock)m_rootBlock;
                if (dataBlockIndex < rootBlock.rgbid.Count)
                {
                    BlockID   blockID = rootBlock.rgbid[dataBlockIndex];
                    DataBlock block   = (DataBlock)GetBlock(blockID.Value);
                    return(block);
                }
                else
                {
                    throw new ArgumentException("Invalid data block index");
                }
            }
            else // XXBlock
            {
                // We assume that all XBlocks are completely filled except the last one.
                int xBlockIndex            = dataBlockIndex / XBlock.MaximumNumberOfDataBlocks;
                int dataBlockIndexInXBlock = dataBlockIndex % XBlock.MaximumNumberOfDataBlocks;

                XXBlock rootBlock = (XXBlock)m_rootBlock;
                if (xBlockIndex < rootBlock.NumberOfXBlocks)
                {
                    XBlock xBlock = (XBlock)GetBlock(rootBlock.rgbid[xBlockIndex]);
                    if (dataBlockIndexInXBlock < xBlock.NumberOfDataBlocks)
                    {
                        BlockID   blockID = xBlock.rgbid[dataBlockIndexInXBlock];
                        DataBlock block   = (DataBlock)GetBlock(blockID.Value);
                        return(block);
                    }
                    else
                    {
                        throw new ArgumentException("Invalid data block index");
                    }
                }
                else
                {
                    throw new ArgumentException("Invalid XBlock index");
                }
            }
        }
Exemplo n.º 2
0
        public override Block Clone()
        {
            XXBlock result = (XXBlock)MemberwiseClone();

            result.rgbid = new List <BlockID>();
            foreach (BlockID blockID in rgbid)
            {
                result.rgbid.Add(blockID.Clone());
            }
            return(result);
        }
Exemplo n.º 3
0
        public bool IsDataBlockPendingWrite(int dataBlockIndex)
        {
            if (m_rootBlock is DataBlock)
            {
                return(IsBlockPendingWrite(m_rootBlock));
            }
            else if (m_rootBlock is XBlock)
            {
                BlockID blockID = ((XBlock)m_rootBlock).rgbid[dataBlockIndex];
                return(IsBlockPendingWrite(blockID));
            }
            else // XXBlock
            {
                int xBlockIndex            = dataBlockIndex / XBlock.MaximumNumberOfDataBlocks;
                int dataBlockIndexInXBlock = dataBlockIndex % XBlock.MaximumNumberOfDataBlocks;

                XXBlock rootBlock = (XXBlock)m_rootBlock;
                XBlock  xBlock    = (XBlock)GetBlock(rootBlock.rgbid[xBlockIndex]);
                BlockID blockID   = xBlock.rgbid[dataBlockIndexInXBlock];
                return(IsBlockPendingWrite(blockID));
            }
        }
Exemplo n.º 4
0
        public void DeleteLastDataBlock()
        {
            if (m_rootBlock == null)
            {
                return;
            }
            else if (m_rootBlock is DataBlock)
            {
                DeleteBlock(m_rootBlock);
                m_rootBlock = null;
            }
            else if (m_rootBlock is XBlock)
            {
                XBlock    rootBlock         = (XBlock)m_rootBlock;
                int       dataBlockIndex    = rootBlock.rgbid.Count - 1;
                ulong     currentBlockID    = rootBlock.rgbid[dataBlockIndex].Value;
                DataBlock dataBlock         = (DataBlock)GetBlock(currentBlockID);
                int       currentDataLength = dataBlock.Data.Length;

                DeleteBlock(dataBlock);

                rootBlock.rgbid.RemoveAt(dataBlockIndex);
                // Update the total length
                uint totalLength = (uint)(rootBlock.lcbTotal - currentDataLength);
                rootBlock.lcbTotal = totalLength;
                UpdateBlock(rootBlock);
            }
            else // XXBlock
            {
                XXBlock rootBlock = (XXBlock)m_rootBlock;

                BlockID lastXBlockID = rootBlock.rgbid[rootBlock.NumberOfXBlocks - 1];
                XBlock  lastXBlock   = (XBlock)GetBlock(lastXBlockID);
                if (lastXBlock.NumberOfDataBlocks > 1)
                {
                    int       dataBlockIndexInXBlock = lastXBlock.NumberOfDataBlocks - 1;
                    ulong     currentBlockID         = lastXBlock.rgbid[dataBlockIndexInXBlock].Value;
                    DataBlock dataBlock         = (DataBlock)GetBlock(currentBlockID);
                    int       currentDataLength = dataBlock.Data.Length;

                    DeleteBlock(dataBlock);

                    lastXBlock.rgbid.RemoveAt(dataBlockIndexInXBlock);
                    // Update the total length
                    uint xBlockTotalLength = (uint)(lastXBlock.lcbTotal - currentDataLength);
                    lastXBlock.lcbTotal = xBlockTotalLength;
                    UpdateBlock(lastXBlock);

                    uint totalLength = (uint)(rootBlock.lcbTotal - currentDataLength);
                    rootBlock.lcbTotal = totalLength;
                    UpdateBlock(rootBlock);
                }
                else if (lastXBlock.NumberOfDataBlocks == 1)
                {
                    ulong     currentBlockID    = lastXBlock.rgbid[0].Value;
                    DataBlock dataBlock         = (DataBlock)GetBlock(currentBlockID);
                    int       currentDataLength = dataBlock.Data.Length;

                    DeleteBlock(dataBlock);
                    DeleteBlock(lastXBlock);

                    int lastXBlockIndex = rootBlock.rgbid.Count - 1;
                    rootBlock.rgbid.RemoveAt(lastXBlockIndex);
                    rootBlock.lcbTotal = (uint)(rootBlock.lcbTotal - currentDataLength);
                    UpdateBlock(rootBlock);
                }
            }
        }
Exemplo n.º 5
0
        public void AddDataBlock(byte[] blockData)
        {
            // http://social.msdn.microsoft.com/Forums/en-US/os_binaryfile/thread/a5f9c653-40f5-4638-85d3-00c54607d984/
            // We must completely fill the previous block in order for Outlook 2003 to read the next block
            // This is true for both the Subnode containing the rows of a Table Context
            // and for the DataTree containing the heap items of a Table Context.

            // Emphasis: The block that must be filled is the one preceding the block that was added.
            if (DataBlockCount > 0)
            {
                ZeroFillBlock(DataBlockCount - 1);
            }

            DataBlock block = new DataBlock(m_bCryptMethod);

            block.Data = blockData;
            AddBlock(block);

            // update the root
            if (m_rootBlock == null)
            {
                m_rootBlock = block;
            }
            else if (m_rootBlock is DataBlock)
            {
                DataBlock firstDataBlock = (DataBlock)m_rootBlock;

                // Create an XBlock:
                XBlock rootBlock = new XBlock();
                rootBlock.rgbid.Add(firstDataBlock.BlockID);
                rootBlock.rgbid.Add(block.BlockID);
                rootBlock.lcbTotal = (uint)(firstDataBlock.Data.Length + blockData.Length);
                AddBlock(rootBlock);
                m_rootBlock = rootBlock;

                // Note: the reference from the node to the rootblock will be updated later
            }
            else if (m_rootBlock is XBlock)
            {
                XBlock rootBlock = (XBlock)m_rootBlock;
                if (rootBlock.NumberOfDataBlocks < XBlock.MaximumNumberOfDataBlocks)
                {
                    rootBlock.rgbid.Add(block.BlockID);
                    rootBlock.lcbTotal += (uint)blockData.Length;
                    UpdateBlock(rootBlock);
                }
                else // We need to create a new XXBlock
                {
                    // Create an XBlock:
                    XBlock xBlock = new XBlock();
                    xBlock.rgbid.Add(block.BlockID);
                    xBlock.lcbTotal = (uint)blockData.Length;
                    AddBlock(xBlock);

                    // Create an XXBlock
                    XXBlock newRootBlock = new XXBlock();
                    newRootBlock.rgbid.Add(rootBlock.BlockID);
                    newRootBlock.rgbid.Add(xBlock.BlockID);
                    newRootBlock.lcbTotal = rootBlock.lcbTotal + xBlock.lcbTotal;
                    AddBlock(newRootBlock);
                    m_rootBlock = newRootBlock;

                    // Note: the reference from the node to the rootblock will be updated later
                }
            }
            else // XXBlock
            {
                XXBlock rootBlock = (XXBlock)m_rootBlock;

                BlockID lastXBlockID = rootBlock.rgbid[rootBlock.NumberOfXBlocks - 1];
                XBlock  lastXBlock   = (XBlock)GetBlock(lastXBlockID);

                if (lastXBlock.NumberOfDataBlocks < XBlock.MaximumNumberOfDataBlocks)
                {
                    lastXBlock.rgbid.Add(block.BlockID);
                    lastXBlock.lcbTotal += (uint)blockData.Length;
                    UpdateBlock(lastXBlock);

                    rootBlock.lcbTotal += (uint)blockData.Length;
                    UpdateBlock(rootBlock);
                }
                else if (rootBlock.NumberOfXBlocks < XXBlock.MaximumNumberOfXBlocks)
                {
                    // Create an XBlock:
                    XBlock xBlock = new XBlock();
                    xBlock.rgbid.Add(block.BlockID);
                    xBlock.lcbTotal = (uint)blockData.Length;
                    AddBlock(xBlock);

                    rootBlock.rgbid.Add(xBlock.BlockID);
                    rootBlock.lcbTotal += (uint)blockData.Length;
                    UpdateBlock(rootBlock);
                }
                else
                {
                    throw new Exception("Data Tree is full");
                }
            }
        }
Exemplo n.º 6
0
        public void UpdateDataBlock(int dataBlockIndex, byte[] blockData)
        {
            if (m_rootBlock == null)
            {
                throw new Exception("Data tree root block is null");
            }
            else if (m_rootBlock is DataBlock)
            {
                if (dataBlockIndex == 0)
                {
                    ((DataBlock)m_rootBlock).Data = blockData;
                    UpdateBlock(m_rootBlock);
                }
                else
                {
                    throw new ArgumentException("Data tree root block is a data block, data block index must be 0");
                }
            }
            else if (m_rootBlock is XBlock)
            {
                XBlock rootBlock = (XBlock)m_rootBlock;
                if (dataBlockIndex < rootBlock.rgbid.Count)
                {
                    ulong currentBlockID    = rootBlock.rgbid[dataBlockIndex].Value;
                    int   currentDataLength = ((DataBlock)GetBlock(currentBlockID)).Data.Length;

                    DataBlock block = new DataBlock(m_bCryptMethod);
                    block.Data    = blockData;
                    block.BlockID = new BlockID(currentBlockID);

                    UpdateBlock(block);

                    if (block.BlockID.Value != currentBlockID)
                    {
                        // A new block has been written instead of the old one,
                        // update the root block
                        rootBlock.rgbid[dataBlockIndex] = block.BlockID;
                    }
                    // Update the total length
                    uint totalLength = (uint)(rootBlock.lcbTotal + blockData.Length - currentDataLength);
                    rootBlock.lcbTotal = totalLength;
                    UpdateBlock(rootBlock);
                }
                else
                {
                    throw new ArgumentException("Invalid data block index");
                }
            }
            else // XXBlock
            {
                int xBlockIndex            = dataBlockIndex / XBlock.MaximumNumberOfDataBlocks;
                int dataBlockIndexInXBlock = dataBlockIndex % XBlock.MaximumNumberOfDataBlocks;

                XXBlock rootBlock = (XXBlock)m_rootBlock;

                if (xBlockIndex < rootBlock.NumberOfXBlocks)
                {
                    XBlock xBlock = (XBlock)GetBlock(rootBlock.rgbid[xBlockIndex]);
                    if (dataBlockIndexInXBlock < xBlock.NumberOfDataBlocks)
                    {
                        ulong currentBlockID    = xBlock.rgbid[dataBlockIndexInXBlock].Value;
                        int   currentDataLength = ((DataBlock)GetBlock(currentBlockID)).Data.Length;

                        DataBlock block = new DataBlock(m_bCryptMethod);
                        block.Data    = blockData;
                        block.BlockID = new BlockID(currentBlockID);

                        UpdateBlock(block);

                        if (block.BlockID.Value != currentBlockID)
                        {
                            // A new block has been written instead of the old one,
                            // update the root block
                            xBlock.rgbid[dataBlockIndexInXBlock] = block.BlockID;
                        }
                        // Update the total length
                        uint xBlockTotalLength = (uint)(xBlock.lcbTotal + blockData.Length - currentDataLength);
                        xBlock.lcbTotal = xBlockTotalLength;

                        ulong currentXBlockID = rootBlock.rgbid[xBlockIndex].Value;
                        UpdateBlock(xBlock);
                        if (xBlock.BlockID.Value != currentXBlockID)
                        {
                            rootBlock.rgbid[xBlockIndex] = xBlock.BlockID;
                        }

                        uint totalLength = (uint)(rootBlock.lcbTotal + blockData.Length - currentDataLength);
                        rootBlock.lcbTotal = totalLength;
                        UpdateBlock(rootBlock);
                    }
                    else
                    {
                        throw new ArgumentException("Invalid data block index");
                    }
                }
                else
                {
                    throw new ArgumentException("Invalid XBlock index");
                }
            }
        }
Exemplo n.º 7
0
        public static Block ReadFromStream(Stream stream, BlockRef blockRef, int dataLength, bCryptMethodName bCryptMethod)
        {
            long offset      = (long)blockRef.ib;
            int  totalLength = GetTotalBlockLength(dataLength);

            stream.Seek(offset, SeekOrigin.Begin);
            byte[] buffer = new byte[totalLength];
            stream.Read(buffer, 0, totalLength);

            BlockTrailer trailer = BlockTrailer.ReadFromEndOfBuffer(buffer);
            Block        block;

            if (trailer.bid.Internal)
            {
                // XBlock or XXBlock
                byte btype  = buffer[0];
                byte cLevel = buffer[1];
                if (btype == (byte)BlockType.XBlock && cLevel == 0x01)
                {
                    // XBLOCK
                    block = new XBlock(buffer);
                }
                else if (btype == (byte)BlockType.XXBlock && cLevel == 0x02)
                {
                    // XXBLOCK
                    block = new XXBlock(buffer);
                }
                else if (btype == (byte)BlockType.SLBLOCK && cLevel == 0x00)
                {
                    // SLBLock
                    block = new SubnodeLeafBlock(buffer);
                }
                else if (btype == (byte)BlockType.SIBLOCK && cLevel == 0x01)
                {
                    // SIBLock
                    block = new SubnodeIntermediateBlock(buffer);
                }
                else
                {
                    throw new Exception("Internal block, but not XBLOCK, XXBlock, SLBLOCK or SIBLOCK");
                }
            }
            else
            {
                block = new DataBlock(buffer, bCryptMethod);
            }

            // See question 3 at:
            // http://social.msdn.microsoft.com/Forums/en-CA/os_binaryfile/thread/923f5964-4a89-4811-86c2-06a553c34510
            // However, so far all tests suggest that there should be no problem to use BlockID.Value for both arguments
            if (blockRef.bid.LookupValue != block.BlockID.LookupValue)
            {
                throw new InvalidBlockIDException();
            }

            if (dataLength != trailer.cb)
            {
                throw new Exception("Invalid block length");
            }

            uint crc = PSTCRCCalculation.ComputeCRC(buffer, dataLength);

            if (block.BlockTrailer.dwCRC != crc)
            {
                throw new InvalidChecksumException();
            }

            uint signature = BlockTrailer.ComputeSignature(blockRef.ib, blockRef.bid.Value);

            if (block.BlockTrailer.wSig != signature)
            {
                throw new InvalidChecksumException();
            }

            return(block);
        }