summaryrefslogtreecommitdiff
path: root/lib/backupclient/BackupStoreFileEncodeStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/backupclient/BackupStoreFileEncodeStream.cpp')
-rw-r--r--lib/backupclient/BackupStoreFileEncodeStream.cpp717
1 files changed, 0 insertions, 717 deletions
diff --git a/lib/backupclient/BackupStoreFileEncodeStream.cpp b/lib/backupclient/BackupStoreFileEncodeStream.cpp
deleted file mode 100644
index e9d773f0..00000000
--- a/lib/backupclient/BackupStoreFileEncodeStream.cpp
+++ /dev/null
@@ -1,717 +0,0 @@
-// --------------------------------------------------------------------------
-//
-// File
-// Name: BackupStoreFileEncodeStream.cpp
-// Purpose: Implement stream-based file encoding for the backup store
-// Created: 12/1/04
-//
-// --------------------------------------------------------------------------
-
-#include "Box.h"
-
-#include <string.h>
-
-#include "BackupClientFileAttributes.h"
-#include "BackupStoreConstants.h"
-#include "BackupStoreException.h"
-#include "BackupStoreFile.h"
-#include "BackupStoreFileCryptVar.h"
-#include "BackupStoreFileEncodeStream.h"
-#include "BackupStoreFileWire.h"
-#include "BackupStoreObjectMagic.h"
-#include "BoxTime.h"
-#include "FileStream.h"
-#include "Random.h"
-#include "RollingChecksum.h"
-
-#include "MemLeakFindOn.h"
-
-#include <cstring>
-
-using namespace BackupStoreFileCryptVar;
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::BackupStoreFileEncodeStream
-// Purpose: Constructor (opens file)
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-BackupStoreFileEncodeStream::BackupStoreFileEncodeStream()
- : mpRecipe(0),
- mpFile(0),
- mpLogging(0),
- mpRunStatusProvider(NULL),
- mStatus(Status_Header),
- mSendData(true),
- mTotalBlocks(0),
- mAbsoluteBlockNumber(-1),
- mInstructionNumber(-1),
- mNumBlocks(0),
- mCurrentBlock(-1),
- mCurrentBlockEncodedSize(0),
- mPositionInCurrentBlock(0),
- mBlockSize(BACKUP_FILE_MIN_BLOCK_SIZE),
- mLastBlockSize(0),
- mTotalBytesSent(0),
- mpRawBuffer(0),
- mAllocatedBufferSize(0),
- mEntryIVBase(0)
-{
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
-// Purpose: Destructor
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
-{
- // Free buffers
- if(mpRawBuffer)
- {
- ::free(mpRawBuffer);
- mpRawBuffer = 0;
- }
-
- // Close the file, which we might have open
- if(mpFile)
- {
- delete mpFile;
- mpFile = 0;
- }
-
- // Clear up logging stream
- if(mpLogging)
- {
- delete mpLogging;
- mpLogging = 0;
- }
-
- // Free the recipe
- if(mpRecipe != 0)
- {
- delete mpRecipe;
- mpRecipe = 0;
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::Setup(const char *, Recipe *, int64_t, const BackupStoreFilename &, int64_t *)
-// Purpose: Reads file information, and builds file header reading for sending.
-// Takes ownership of the Recipe.
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::Setup(const char *Filename,
- BackupStoreFileEncodeStream::Recipe *pRecipe,
- int64_t ContainerID, const BackupStoreFilename &rStoreFilename,
- int64_t *pModificationTime, ReadLoggingStream::Logger* pLogger,
- RunStatusProvider* pRunStatusProvider)
-{
- // Pointer to a blank recipe which we might create
- BackupStoreFileEncodeStream::Recipe *pblankRecipe = 0;
-
- try
- {
- // Get file attributes
- box_time_t modTime = 0;
- int64_t fileSize = 0;
- BackupClientFileAttributes attr;
- attr.ReadAttributes(Filename, false /* no zeroing of modification times */, &modTime,
- 0 /* not interested in attr mod time */, &fileSize);
-
- // Might need to create a blank recipe...
- if(pRecipe == 0)
- {
- pblankRecipe = new BackupStoreFileEncodeStream::Recipe(0, 0);
-
- BackupStoreFileEncodeStream::RecipeInstruction instruction;
- instruction.mSpaceBefore = fileSize; // whole file
- instruction.mBlocks = 0; // no blocks
- instruction.mpStartBlock = 0; // no block
- pblankRecipe->push_back(instruction);
-
- pRecipe = pblankRecipe;
- }
-
- // Tell caller?
- if(pModificationTime != 0)
- {
- *pModificationTime = modTime;
- }
-
- // Go through each instruction in the recipe and work out how many blocks
- // it will add, and the max clear size of these blocks
- int maxBlockClearSize = 0;
- for(uint64_t inst = 0; inst < pRecipe->size(); ++inst)
- {
- if((*pRecipe)[inst].mSpaceBefore > 0)
- {
- // Calculate the number of blocks the space before requires
- int64_t numBlocks;
- int32_t blockSize, lastBlockSize;
- CalculateBlockSizes((*pRecipe)[inst].mSpaceBefore, numBlocks, blockSize, lastBlockSize);
- // Add to accumlated total
- mTotalBlocks += numBlocks;
- // Update maximum clear size
- if(blockSize > maxBlockClearSize) maxBlockClearSize = blockSize;
- if(lastBlockSize > maxBlockClearSize) maxBlockClearSize = lastBlockSize;
- }
-
- // Add number of blocks copied from the previous file
- mTotalBlocks += (*pRecipe)[inst].mBlocks;
-
- // Check for bad things
- if((*pRecipe)[inst].mBlocks < 0 || ((*pRecipe)[inst].mBlocks != 0 && (*pRecipe)[inst].mpStartBlock == 0))
- {
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
-
- // Run through blocks to get the max clear size
- for(int32_t b = 0; b < (*pRecipe)[inst].mBlocks; ++b)
- {
- if((*pRecipe)[inst].mpStartBlock[b].mSize > maxBlockClearSize) maxBlockClearSize = (*pRecipe)[inst].mpStartBlock[b].mSize;
- }
- }
-
- // Send data? (symlinks don't have any data in them)
- mSendData = !attr.IsSymLink();
-
- // If not data is being sent, then the max clear block size is zero
- if(!mSendData)
- {
- maxBlockClearSize = 0;
- }
-
- // Header
- file_StreamFormat hdr;
- hdr.mMagicValue = htonl(OBJECTMAGIC_FILE_MAGIC_VALUE_V1);
- hdr.mNumBlocks = (mSendData)?(box_hton64(mTotalBlocks)):(0);
- hdr.mContainerID = box_hton64(ContainerID);
- hdr.mModificationTime = box_hton64(modTime);
- // add a bit to make it harder to tell what's going on -- try not to give away too much info about file size
- hdr.mMaxBlockClearSize = htonl(maxBlockClearSize + 128);
- hdr.mOptions = 0; // no options defined yet
-
- // Write header to stream
- mData.Write(&hdr, sizeof(hdr));
-
- // Write filename to stream
- rStoreFilename.WriteToStream(mData);
-
- // Write attributes to stream
- attr.WriteToStream(mData);
-
- // Allocate some buffers for writing data
- if(mSendData)
- {
- // Open the file
- mpFile = new FileStream(Filename);
-
- if (pLogger)
- {
- // Create logging stream
- mpLogging = new ReadLoggingStream(*mpFile,
- *pLogger);
- }
- else
- {
- // re-use FileStream instead
- mpLogging = mpFile;
- mpFile = NULL;
- }
-
- // Work out the largest possible block required for the encoded data
- mAllocatedBufferSize = BackupStoreFile::MaxBlockSizeForChunkSize(maxBlockClearSize);
-
- // Then allocate two blocks of this size
- mpRawBuffer = (uint8_t*)::malloc(mAllocatedBufferSize);
- if(mpRawBuffer == 0)
- {
- throw std::bad_alloc();
- }
-#ifndef BOX_RELEASE_BUILD
- // In debug builds, make sure that the reallocation code is exercised.
- mEncodedBuffer.Allocate(mAllocatedBufferSize / 4);
-#else
- mEncodedBuffer.Allocate(mAllocatedBufferSize);
-#endif
- }
- else
- {
- // Write an empty block index for the symlink
- file_BlockIndexHeader blkhdr;
- blkhdr.mMagicValue = htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1);
- blkhdr.mOtherFileID = box_hton64(0); // not other file ID
- blkhdr.mEntryIVBase = box_hton64(0);
- blkhdr.mNumBlocks = box_hton64(0);
- mData.Write(&blkhdr, sizeof(blkhdr));
- }
-
- // Ready for reading
- mData.SetForReading();
-
- // Update stats
- BackupStoreFile::msStats.mBytesInEncodedFiles += fileSize;
-
- // Finally, store the pointer to the recipe, when we know exceptions won't occur
- mpRecipe = pRecipe;
- }
- catch(...)
- {
- // Clean up any blank recipe
- if(pblankRecipe != 0)
- {
- delete pblankRecipe;
- pblankRecipe = 0;
- }
- throw;
- }
-
- mpRunStatusProvider = pRunStatusProvider;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t &, int32_t &, int32_t &)
-// Purpose: Calculates the sizes of blocks in a section of the file
-// Created: 16/1/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t DataSize, int64_t &rNumBlocksOut, int32_t &rBlockSizeOut, int32_t &rLastBlockSizeOut)
-{
- // How many blocks, and how big?
- rBlockSizeOut = BACKUP_FILE_MIN_BLOCK_SIZE / 2;
- do
- {
- rBlockSizeOut *= 2;
-
- rNumBlocksOut = (DataSize + rBlockSizeOut - 1) / rBlockSizeOut;
-
- } while(rBlockSizeOut < BACKUP_FILE_MAX_BLOCK_SIZE && rNumBlocksOut > BACKUP_FILE_INCREASE_BLOCK_SIZE_AFTER);
-
- // Last block size
- rLastBlockSizeOut = DataSize - ((rNumBlocksOut - 1) * rBlockSizeOut);
-
- // Avoid small blocks?
- if(rLastBlockSizeOut < BACKUP_FILE_AVOID_BLOCKS_LESS_THAN
- && rNumBlocksOut > 1)
- {
- // Add the small bit of data to the last block
- --rNumBlocksOut;
- rLastBlockSizeOut += rBlockSizeOut;
- }
-
- // checks!
- ASSERT((((rNumBlocksOut-1) * rBlockSizeOut) + rLastBlockSizeOut) == DataSize);
- //TRACE4("CalcBlockSize, sz %lld, num %lld, blocksize %d, last %d\n", DataSize, rNumBlocksOut, (int32_t)rBlockSizeOut, (int32_t)rLastBlockSizeOut);
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::Read(void *, int, int)
-// Purpose: As interface -- generates encoded file data on the fly from the raw file
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-int BackupStoreFileEncodeStream::Read(void *pBuffer, int NBytes, int Timeout)
-{
- // Check there's something to do.
- if(mStatus == Status_Finished)
- {
- return 0;
- }
-
- if(mpRunStatusProvider && mpRunStatusProvider->StopRun())
- {
- THROW_EXCEPTION(BackupStoreException, SignalReceived);
- }
-
- int bytesToRead = NBytes;
- uint8_t *buffer = (uint8_t*)pBuffer;
-
- while(bytesToRead > 0 && mStatus != Status_Finished)
- {
- if(mStatus == Status_Header || mStatus == Status_BlockListing)
- {
- // Header or block listing phase -- send from the buffered stream
-
- // Send bytes from the data buffer
- int b = mData.Read(buffer, bytesToRead, Timeout);
- bytesToRead -= b;
- buffer += b;
-
- // Check to see if all the data has been used from this stream
- if(!mData.StreamDataLeft())
- {
- // Yes, move on to next phase (or finish, if there's no file data)
- if(!mSendData)
- {
- mStatus = Status_Finished;
- }
- else
- {
- // Reset the buffer so it can be used for the next phase
- mData.Reset();
-
- // Get buffer ready for index?
- if(mStatus == Status_Header)
- {
- // Just finished doing the stream header, create the block index header
- file_BlockIndexHeader blkhdr;
- blkhdr.mMagicValue = htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1);
- ASSERT(mpRecipe != 0);
- blkhdr.mOtherFileID = box_hton64(mpRecipe->GetOtherFileID());
- blkhdr.mNumBlocks = box_hton64(mTotalBlocks);
-
- // Generate the IV base
- Random::Generate(&mEntryIVBase, sizeof(mEntryIVBase));
- blkhdr.mEntryIVBase = box_hton64(mEntryIVBase);
-
- mData.Write(&blkhdr, sizeof(blkhdr));
- }
-
- ++mStatus;
- }
- }
- }
- else if(mStatus == Status_Blocks)
- {
- // Block sending phase
-
- if(mPositionInCurrentBlock >= mCurrentBlockEncodedSize)
- {
- // Next block!
- ++mCurrentBlock;
- ++mAbsoluteBlockNumber;
- if(mCurrentBlock >= mNumBlocks)
- {
- // Output extra blocks for this instruction and move forward in file
- if(mInstructionNumber >= 0)
- {
- SkipPreviousBlocksInInstruction();
- }
-
- // Is there another instruction to go?
- ++mInstructionNumber;
-
- // Skip instructions which don't contain any data
- while(mInstructionNumber < static_cast<int64_t>(mpRecipe->size())
- && (*mpRecipe)[mInstructionNumber].mSpaceBefore == 0)
- {
- SkipPreviousBlocksInInstruction();
- ++mInstructionNumber;
- }
-
- if(mInstructionNumber >= static_cast<int64_t>(mpRecipe->size()))
- {
- // End of blocks, go to next phase
- ++mStatus;
-
- // Set the data to reading so the index can be written
- mData.SetForReading();
- }
- else
- {
- // Get ready for this instruction
- SetForInstruction();
- }
- }
-
- // Can't use 'else' here as SetForInstruction() will change this
- if(mCurrentBlock < mNumBlocks)
- {
- EncodeCurrentBlock();
- }
- }
-
- // Send data from the current block (if there's data to send)
- if(mPositionInCurrentBlock < mCurrentBlockEncodedSize)
- {
- // How much data to put in the buffer?
- int s = mCurrentBlockEncodedSize - mPositionInCurrentBlock;
- if(s > bytesToRead) s = bytesToRead;
-
- // Copy it in
- ::memcpy(buffer, mEncodedBuffer.mpBuffer + mPositionInCurrentBlock, s);
-
- // Update variables
- bytesToRead -= s;
- buffer += s;
- mPositionInCurrentBlock += s;
- }
- }
- else
- {
- // Should never get here, as it'd be an invalid status
- ASSERT(false);
- }
- }
-
- // Add encoded size to stats
- BackupStoreFile::msStats.mTotalFileStreamSize += (NBytes - bytesToRead);
- mTotalBytesSent += (NBytes - bytesToRead);
-
- // Return size of data to caller
- return NBytes - bytesToRead;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::StorePreviousBlocksInInstruction()
-// Purpose: Private. Stores the blocks of the old file referenced in the current
-// instruction into the index and skips over the data in the file
-// Created: 16/1/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::SkipPreviousBlocksInInstruction()
-{
- // Check something is necessary
- if((*mpRecipe)[mInstructionNumber].mpStartBlock == 0 || (*mpRecipe)[mInstructionNumber].mBlocks == 0)
- {
- return;
- }
-
- // Index of the first block in old file (being diffed from)
- int firstIndex = mpRecipe->BlockPtrToIndex((*mpRecipe)[mInstructionNumber].mpStartBlock);
-
- int64_t sizeToSkip = 0;
-
- for(int32_t b = 0; b < (*mpRecipe)[mInstructionNumber].mBlocks; ++b)
- {
- // Update stats
- BackupStoreFile::msStats.mBytesAlreadyOnServer += (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize;
-
- // Store the entry
- StoreBlockIndexEntry(0 - (firstIndex + b),
- (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize,
- (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mWeakChecksum,
- (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mStrongChecksum);
-
- // Increment the absolute block number -- kept encryption IV in sync
- ++mAbsoluteBlockNumber;
-
- // Add the size of this block to the size to skip
- sizeToSkip += (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize;
- }
-
- // Move forward in the stream
- mpLogging->Seek(sizeToSkip, IOStream::SeekType_Relative);
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::SetForInstruction()
-// Purpose: Private. Sets the state of the internal variables for the current instruction in the recipe
-// Created: 16/1/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::SetForInstruction()
-{
- // Calculate block sizes
- CalculateBlockSizes((*mpRecipe)[mInstructionNumber].mSpaceBefore, mNumBlocks, mBlockSize, mLastBlockSize);
-
- // Set variables
- mCurrentBlock = 0;
- mCurrentBlockEncodedSize = 0;
- mPositionInCurrentBlock = 0;
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::EncodeCurrentBlock()
-// Purpose: Private. Encodes the current block, and writes the block data to the index
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::EncodeCurrentBlock()
-{
- // How big is the block, raw?
- int blockRawSize = mBlockSize;
- if(mCurrentBlock == (mNumBlocks - 1))
- {
- blockRawSize = mLastBlockSize;
- }
- ASSERT(blockRawSize < mAllocatedBufferSize);
-
- // Check file open
- if(mpLogging == 0)
- {
- // File should be open, but isn't. So logical error.
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
-
- // Read the data in
- if(!mpLogging->ReadFullBuffer(mpRawBuffer, blockRawSize,
- 0 /* not interested in size if failure */))
- {
- // TODO: Do something more intelligent, and abort
- // this upload because the file has changed.
- THROW_EXCEPTION(BackupStoreException,
- Temp_FileEncodeStreamDidntReadBuffer)
- }
-
- // Encode it
- mCurrentBlockEncodedSize = BackupStoreFile::EncodeChunk(mpRawBuffer,
- blockRawSize, mEncodedBuffer);
-
- //TRACE2("Encode: Encoded size of block %d is %d\n", (int32_t)mCurrentBlock, (int32_t)mCurrentBlockEncodedSize);
-
- // Create block listing data -- generate checksums
- RollingChecksum weakChecksum(mpRawBuffer, blockRawSize);
- MD5Digest strongChecksum;
- strongChecksum.Add(mpRawBuffer, blockRawSize);
- strongChecksum.Finish();
-
- // Add entry to the index
- StoreBlockIndexEntry(mCurrentBlockEncodedSize, blockRawSize,
- weakChecksum.GetChecksum(), strongChecksum.DigestAsData());
-
- // Set vars to reading this block
- mPositionInCurrentBlock = 0;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t, int32_t, uint32_t, uint8_t *)
-// Purpose: Private. Adds an entry to the index currently being stored for sending at end of the stream.
-// Created: 16/1/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t EncSizeOrBlkIndex, int32_t ClearSize, uint32_t WeakChecksum, uint8_t *pStrongChecksum)
-{
- // First, the encrypted section
- file_BlockIndexEntryEnc entryEnc;
- entryEnc.mSize = htonl(ClearSize);
- entryEnc.mWeakChecksum = htonl(WeakChecksum);
- ::memcpy(entryEnc.mStrongChecksum, pStrongChecksum, sizeof(entryEnc.mStrongChecksum));
-
- // Then the clear section
- file_BlockIndexEntry entry;
- entry.mEncodedSize = box_hton64(((uint64_t)EncSizeOrBlkIndex));
-
- // Then encrypt the encryted section
- // Generate the IV from the block number
- if(sBlowfishEncryptBlockEntry.GetIVLength() != sizeof(mEntryIVBase))
- {
- THROW_EXCEPTION(BackupStoreException, IVLengthForEncodedBlockSizeDoesntMeetLengthRequirements)
- }
- uint64_t iv = mEntryIVBase;
- iv += mAbsoluteBlockNumber;
- // Convert to network byte order before encrypting with it, so that restores work on
- // platforms with different endiannesses.
- iv = box_hton64(iv);
- sBlowfishEncryptBlockEntry.SetIV(&iv);
-
- // Encode the data
- int encodedSize = sBlowfishEncryptBlockEntry.TransformBlock(entry.mEnEnc, sizeof(entry.mEnEnc), &entryEnc, sizeof(entryEnc));
- if(encodedSize != sizeof(entry.mEnEnc))
- {
- THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
- }
-
- // Save to data block for sending at the end of the stream
- mData.Write(&entry, sizeof(entry));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::Write(const void *, int)
-// Purpose: As interface. Exceptions.
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreFileEncodeStream::Write(const void *pBuffer, int NBytes)
-{
- THROW_EXCEPTION(BackupStoreException, CantWriteToEncodedFileStream)
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::StreamDataLeft()
-// Purpose: As interface -- end of stream reached?
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-bool BackupStoreFileEncodeStream::StreamDataLeft()
-{
- return (mStatus != Status_Finished);
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::StreamClosed()
-// Purpose: As interface
-// Created: 8/12/03
-//
-// --------------------------------------------------------------------------
-bool BackupStoreFileEncodeStream::StreamClosed()
-{
- return true;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::Recipe::Recipe(BackupStoreFileCreation::BlocksAvailableEntry *, int64_t)
-// Purpose: Constructor. Takes ownership of the block index, and will delete it when it's deleted
-// Created: 15/1/04
-//
-// --------------------------------------------------------------------------
-BackupStoreFileEncodeStream::Recipe::Recipe(BackupStoreFileCreation::BlocksAvailableEntry *pBlockIndex,
- int64_t NumBlocksInIndex, int64_t OtherFileID)
- : mpBlockIndex(pBlockIndex),
- mNumBlocksInIndex(NumBlocksInIndex),
- mOtherFileID(OtherFileID)
-{
- ASSERT((mpBlockIndex == 0) || (NumBlocksInIndex != 0))
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFileEncodeStream::Recipe::~Recipe()
-// Purpose: Destructor
-// Created: 15/1/04
-//
-// --------------------------------------------------------------------------
-BackupStoreFileEncodeStream::Recipe::~Recipe()
-{
- // Free the block index, if there is one
- if(mpBlockIndex != 0)
- {
- ::free(mpBlockIndex);
- }
-}
-
-
-
-