/// <summary>
 /// Makes a shadow copy of a data cluster.
 /// </summary>
 /// <param name="sourceClusterAddress">the address of the first block in the cluster.
 /// If address is zero, it simply creates an empty cluster.</param>
 /// <param name="indexValue">the index value of this first block</param>
 /// <param name="destinationClusterAddress">the first block of the destination cluster</param>
 private void ShadowCopyDataCluster(uint sourceClusterAddress, uint indexValue, uint destinationClusterAddress)
 {
     //if source exist
     if (sourceClusterAddress != 0)
     {
         DiskIoSession sourceData      = m_ioSessions.SourceData;
         DiskIoSession destinationData = m_ioSessions.DestinationData;
         sourceData.ReadOld(sourceClusterAddress, BlockType.DataBlock, indexValue);
         destinationData.WriteToNewBlock(destinationClusterAddress, BlockType.DataBlock, indexValue);
         Memory.Copy(sourceData.Pointer, destinationData.Pointer, sourceData.Length);
         m_ioSessions.SwapData();
     }
     //if source cluster does not exist.
     else
     {
         m_ioSessions.SourceData.WriteToNewBlock(destinationClusterAddress, BlockType.DataBlock, indexValue);
         Memory.Clear(m_ioSessions.SourceData.Pointer, m_ioSessions.SourceData.Length);
     }
 }
        /// <summary>
        /// Makes a shadow copy of the indirect index passed to this function. If the block does not exists, it creates it.
        /// </summary>
        /// <param name="sourceBlockAddress">The block to be copied</param>
        /// <param name="indexValue">the index value that goes in the footer of the file.</param>
        /// <param name="blockType">Gets the expected block type</param>
        /// <param name="remoteAddressOffset">the offset of the remote address that needs to be updated.</param>
        /// <param name="remoteBlockAddress">the value of the remote address.</param>
        /// <returns>Returns true if the block had to be shadowed, false if it did not change</returns>
        private bool ShadowCopyIndexIndirect(ref uint sourceBlockAddress, uint indexValue, BlockType blockType, int remoteAddressOffset, uint remoteBlockAddress)
        {
            uint indexIndirectBlock;

            //Make a copy of the index block referenced

            //if the block does not exist, create it.
            if (sourceBlockAddress == 0)
            {
                DiskIoSession buffer = m_ioSessions.SourceIndex;
                indexIndirectBlock = m_fileHeaderBlock.AllocateFreeBlocks(1);
                m_subFileHeader.TotalBlockCount++;

                buffer.WriteToNewBlock(indexIndirectBlock, blockType, indexValue);
                Memory.Clear(buffer.Pointer, buffer.Length);
                WriteIndexIndirectBlock(buffer.Pointer, remoteAddressOffset, remoteBlockAddress);

                sourceBlockAddress = indexIndirectBlock;
                return(true);
            }
            //if the data page is an old page, allocate space to create a new copy
            else if (sourceBlockAddress <= m_lastReadOnlyBlock)
            {
                indexIndirectBlock = m_fileHeaderBlock.AllocateFreeBlocks(1);
                m_subFileHeader.TotalBlockCount++;

                ReadThenWriteIndexIndirectBlock(sourceBlockAddress, indexIndirectBlock, indexValue, blockType, remoteAddressOffset, remoteBlockAddress);
                sourceBlockAddress = indexIndirectBlock;
                return(true);
            }
            //The page has already been copied, use the existing address.
            else
            {
                ReadThenWriteIndexIndirectBlock(sourceBlockAddress, sourceBlockAddress, indexValue, blockType, remoteAddressOffset, remoteBlockAddress);
                return(false);
            }
        }
        /// <summary>
        /// Makes a shadow copy of an index indirect block and updates a remote address.
        /// </summary>
        /// <param name="sourceBlockAddress">the address of the source.</param>
        /// <param name="destinationBlockAddress">the address of the destination. This can be the same as the source.</param>
        /// <param name="indexValue">the index value that goes in the footer of the file.</param>
        /// <param name="blockType">Gets the expected block type</param>
        /// <param name="remoteAddressOffset">the offset of the remote address that needs to be updated.</param>
        /// <param name="remoteBlockAddress">the value of the remote address.</param>
        private void ReadThenWriteIndexIndirectBlock(uint sourceBlockAddress, uint destinationBlockAddress, uint indexValue, BlockType blockType, int remoteAddressOffset, uint remoteBlockAddress)
        {
            DiskIoSession bufferSource = m_ioSessions.SourceIndex;

            if (sourceBlockAddress == destinationBlockAddress)
            {
                if (*(int *)(bufferSource.Pointer + (remoteAddressOffset << 2)) != remoteBlockAddress)
                {
                    bufferSource.WriteToExistingBlock(destinationBlockAddress, blockType, indexValue);

                    WriteIndexIndirectBlock(bufferSource.Pointer, remoteAddressOffset, remoteBlockAddress);
                }
            }
            else
            {
                bufferSource.ReadOld(sourceBlockAddress, blockType, indexValue);

                DiskIoSession destination = m_ioSessions.DestinationIndex;
                destination.WriteToNewBlock(destinationBlockAddress, blockType, indexValue);
                Memory.Copy(bufferSource.Pointer, destination.Pointer, destination.Length);
                WriteIndexIndirectBlock(destination.Pointer, remoteAddressOffset, remoteBlockAddress);
                m_ioSessions.SwapIndex();
            }
        }