source: box/trunk/lib/backupstore/BackupStoreFileEncodeStream.cpp @ 2945

Revision 2945, 20.9 KB checked in by chris, 13 months ago (diff)

Major refactoring to make lib/backupclient depend on lib/backupstore rather
than the other way around. This is needed to allow clients to have all the
code that they'd need to implement local backups (using the Local protocol)
in subsequent commits.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreFileEncodeStream.cpp
5//              Purpose: Implement stream-based file encoding for the backup store
6//              Created: 12/1/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <string.h>
13
14#include "BackupClientFileAttributes.h"
15#include "BackupStoreConstants.h"
16#include "BackupStoreException.h"
17#include "BackupStoreFile.h"
18#include "BackupStoreFileCryptVar.h"
19#include "BackupStoreFileEncodeStream.h"
20#include "BackupStoreFileWire.h"
21#include "BackupStoreObjectMagic.h"
22#include "BoxTime.h"
23#include "FileStream.h"
24#include "Random.h"
25#include "RollingChecksum.h"
26
27#include "MemLeakFindOn.h"
28
29#include <cstring>
30
31using namespace BackupStoreFileCryptVar;
32
33
34// --------------------------------------------------------------------------
35//
36// Function
37//              Name:    BackupStoreFileEncodeStream::BackupStoreFileEncodeStream
38//              Purpose: Constructor (opens file)
39//              Created: 8/12/03
40//
41// --------------------------------------------------------------------------
42BackupStoreFileEncodeStream::BackupStoreFileEncodeStream()
43        : mpRecipe(0),
44          mpFile(0),
45          mpLogging(0),
46          mpRunStatusProvider(NULL),
47          mStatus(Status_Header),
48          mSendData(true),
49          mTotalBlocks(0),
50          mAbsoluteBlockNumber(-1),
51          mInstructionNumber(-1),
52          mNumBlocks(0),
53          mCurrentBlock(-1),
54          mCurrentBlockEncodedSize(0),
55          mPositionInCurrentBlock(0),
56          mBlockSize(BACKUP_FILE_MIN_BLOCK_SIZE),
57          mLastBlockSize(0),
58          mTotalBytesSent(0),
59          mpRawBuffer(0),
60          mAllocatedBufferSize(0),
61          mEntryIVBase(0)
62{
63}
64
65// --------------------------------------------------------------------------
66//
67// Function
68//              Name:    BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
69//              Purpose: Destructor
70//              Created: 8/12/03
71//
72// --------------------------------------------------------------------------
73BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
74{
75        // Free buffers
76        if(mpRawBuffer)
77        {
78                ::free(mpRawBuffer);
79                mpRawBuffer = 0;
80        }
81       
82        // Close the file, which we might have open
83        if(mpFile)
84        {
85                delete mpFile;
86                mpFile = 0;
87        }
88       
89        // Clear up logging stream
90        if(mpLogging)
91        {
92                delete mpLogging;
93                mpLogging = 0;
94        }
95       
96        // Free the recipe
97        if(mpRecipe != 0)
98        {
99                delete mpRecipe;
100                mpRecipe = 0;
101        }
102}
103
104
105// --------------------------------------------------------------------------
106//
107// Function
108//              Name:    BackupStoreFileEncodeStream::Setup(const char *, Recipe *, int64_t, const BackupStoreFilename &, int64_t *)
109//              Purpose: Reads file information, and builds file header reading for sending.
110//                               Takes ownership of the Recipe.
111//              Created: 8/12/03
112//
113// --------------------------------------------------------------------------
114void BackupStoreFileEncodeStream::Setup(const char *Filename,
115        BackupStoreFileEncodeStream::Recipe *pRecipe,
116        int64_t ContainerID, const BackupStoreFilename &rStoreFilename,
117        int64_t *pModificationTime, ReadLoggingStream::Logger* pLogger,
118        RunStatusProvider* pRunStatusProvider)
119{
120        // Pointer to a blank recipe which we might create
121        BackupStoreFileEncodeStream::Recipe *pblankRecipe = 0;
122
123        try
124        {
125                // Get file attributes
126                box_time_t modTime = 0;
127                int64_t fileSize = 0;
128                BackupClientFileAttributes attr;
129                attr.ReadAttributes(Filename, false /* no zeroing of modification times */, &modTime,
130                        0 /* not interested in attr mod time */, &fileSize);
131       
132                // Might need to create a blank recipe...
133                if(pRecipe == 0)
134                {
135                        pblankRecipe = new BackupStoreFileEncodeStream::Recipe(0, 0);
136                       
137                        BackupStoreFileEncodeStream::RecipeInstruction instruction;
138                        instruction.mSpaceBefore = fileSize; // whole file
139                        instruction.mBlocks = 0; // no blocks
140                        instruction.mpStartBlock = 0; // no block
141                        pblankRecipe->push_back(instruction);           
142
143                        pRecipe = pblankRecipe;
144                }
145       
146                // Tell caller?
147                if(pModificationTime != 0)
148                {
149                        *pModificationTime = modTime;
150                }
151               
152                // Go through each instruction in the recipe and work out how many blocks
153                // it will add, and the max clear size of these blocks
154                int maxBlockClearSize = 0;
155                for(uint64_t inst = 0; inst < pRecipe->size(); ++inst)
156                {
157                        if((*pRecipe)[inst].mSpaceBefore > 0)
158                        {
159                                // Calculate the number of blocks the space before requires
160                                int64_t numBlocks;
161                                int32_t blockSize, lastBlockSize;
162                                CalculateBlockSizes((*pRecipe)[inst].mSpaceBefore, numBlocks, blockSize, lastBlockSize);
163                                // Add to accumlated total
164                                mTotalBlocks += numBlocks;
165                                // Update maximum clear size
166                                if(blockSize > maxBlockClearSize) maxBlockClearSize = blockSize;
167                                if(lastBlockSize > maxBlockClearSize) maxBlockClearSize = lastBlockSize;
168                        }
169                       
170                        // Add number of blocks copied from the previous file
171                        mTotalBlocks += (*pRecipe)[inst].mBlocks;
172                       
173                        // Check for bad things
174                        if((*pRecipe)[inst].mBlocks < 0 || ((*pRecipe)[inst].mBlocks != 0 && (*pRecipe)[inst].mpStartBlock == 0))
175                        {
176                                THROW_EXCEPTION(BackupStoreException, Internal)
177                        }
178
179                        // Run through blocks to get the max clear size
180                        for(int32_t b = 0; b < (*pRecipe)[inst].mBlocks; ++b)
181                        {
182                                if((*pRecipe)[inst].mpStartBlock[b].mSize > maxBlockClearSize) maxBlockClearSize = (*pRecipe)[inst].mpStartBlock[b].mSize;
183                        }
184                }
185               
186                // Send data? (symlinks don't have any data in them)
187                mSendData = !attr.IsSymLink();
188
189                // If not data is being sent, then the max clear block size is zero
190                if(!mSendData)
191                {
192                        maxBlockClearSize = 0;
193                }
194               
195                // Header
196                file_StreamFormat hdr;
197                hdr.mMagicValue = htonl(OBJECTMAGIC_FILE_MAGIC_VALUE_V1);
198                hdr.mNumBlocks = (mSendData)?(box_hton64(mTotalBlocks)):(0);
199                hdr.mContainerID = box_hton64(ContainerID);
200                hdr.mModificationTime = box_hton64(modTime);
201                // add a bit to make it harder to tell what's going on -- try not to give away too much info about file size
202                hdr.mMaxBlockClearSize = htonl(maxBlockClearSize + 128);
203                hdr.mOptions = 0;               // no options defined yet
204               
205                // Write header to stream
206                mData.Write(&hdr, sizeof(hdr));
207               
208                // Write filename to stream
209                rStoreFilename.WriteToStream(mData);
210               
211                // Write attributes to stream
212                attr.WriteToStream(mData);
213       
214                // Allocate some buffers for writing data
215                if(mSendData)
216                {
217                        // Open the file
218                        mpFile = new FileStream(Filename);
219
220                        if (pLogger)
221                        {
222                                // Create logging stream
223                                mpLogging = new ReadLoggingStream(*mpFile,
224                                        *pLogger);
225                        }
226                        else
227                        {
228                                // re-use FileStream instead
229                                mpLogging = mpFile;
230                                mpFile = NULL;
231                        }
232               
233                        // Work out the largest possible block required for the encoded data
234                        mAllocatedBufferSize = BackupStoreFile::MaxBlockSizeForChunkSize(maxBlockClearSize);
235                       
236                        // Then allocate two blocks of this size
237                        mpRawBuffer = (uint8_t*)::malloc(mAllocatedBufferSize);
238                        if(mpRawBuffer == 0)
239                        {
240                                throw std::bad_alloc();
241                        }
242#ifndef BOX_RELEASE_BUILD
243                        // In debug builds, make sure that the reallocation code is exercised.
244                        mEncodedBuffer.Allocate(mAllocatedBufferSize / 4);
245#else
246                        mEncodedBuffer.Allocate(mAllocatedBufferSize);
247#endif
248                }
249                else
250                {
251                        // Write an empty block index for the symlink
252                        file_BlockIndexHeader blkhdr;
253                        blkhdr.mMagicValue = htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1);
254                        blkhdr.mOtherFileID = box_hton64(0);    // not other file ID
255                        blkhdr.mEntryIVBase = box_hton64(0);
256                        blkhdr.mNumBlocks = box_hton64(0);
257                        mData.Write(&blkhdr, sizeof(blkhdr));
258                }
259       
260                // Ready for reading
261                mData.SetForReading();
262               
263                // Update stats
264                BackupStoreFile::msStats.mBytesInEncodedFiles += fileSize;
265               
266                // Finally, store the pointer to the recipe, when we know exceptions won't occur
267                mpRecipe = pRecipe;
268        }
269        catch(...)
270        {
271                // Clean up any blank recipe
272                if(pblankRecipe != 0)
273                {
274                        delete pblankRecipe;
275                        pblankRecipe = 0;
276                }
277                throw;
278        }
279       
280        mpRunStatusProvider = pRunStatusProvider;
281}
282
283
284// --------------------------------------------------------------------------
285//
286// Function
287//              Name:    BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t &, int32_t &, int32_t &)
288//              Purpose: Calculates the sizes of blocks in a section of the file
289//              Created: 16/1/04
290//
291// --------------------------------------------------------------------------
292void BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t DataSize, int64_t &rNumBlocksOut, int32_t &rBlockSizeOut, int32_t &rLastBlockSizeOut)
293{
294        // How many blocks, and how big?
295        rBlockSizeOut = BACKUP_FILE_MIN_BLOCK_SIZE / 2;
296        do
297        {
298                rBlockSizeOut *= 2;
299               
300                rNumBlocksOut = (DataSize + rBlockSizeOut - 1) / rBlockSizeOut;
301               
302        } while(rBlockSizeOut < BACKUP_FILE_MAX_BLOCK_SIZE && rNumBlocksOut > BACKUP_FILE_INCREASE_BLOCK_SIZE_AFTER);
303       
304        // Last block size
305        rLastBlockSizeOut = DataSize - ((rNumBlocksOut - 1) * rBlockSizeOut);
306       
307        // Avoid small blocks?
308        if(rLastBlockSizeOut < BACKUP_FILE_AVOID_BLOCKS_LESS_THAN
309                && rNumBlocksOut > 1)
310        {
311                // Add the small bit of data to the last block
312                --rNumBlocksOut;
313                rLastBlockSizeOut += rBlockSizeOut;
314        }
315       
316        // checks!
317        ASSERT((((rNumBlocksOut-1) * rBlockSizeOut) + rLastBlockSizeOut) == DataSize);
318        //TRACE4("CalcBlockSize, sz %lld, num %lld, blocksize %d, last %d\n", DataSize, rNumBlocksOut, (int32_t)rBlockSizeOut, (int32_t)rLastBlockSizeOut);
319}
320
321
322
323// --------------------------------------------------------------------------
324//
325// Function
326//              Name:    BackupStoreFileEncodeStream::Read(void *, int, int)
327//              Purpose: As interface -- generates encoded file data on the fly from the raw file
328//              Created: 8/12/03
329//
330// --------------------------------------------------------------------------
331int BackupStoreFileEncodeStream::Read(void *pBuffer, int NBytes, int Timeout)
332{
333        // Check there's something to do.
334        if(mStatus == Status_Finished)
335        {
336                return 0;
337        }
338       
339        if(mpRunStatusProvider && mpRunStatusProvider->StopRun())
340        {
341                THROW_EXCEPTION(BackupStoreException, SignalReceived);
342        }
343
344        int bytesToRead = NBytes;
345        uint8_t *buffer = (uint8_t*)pBuffer;
346       
347        while(bytesToRead > 0 && mStatus != Status_Finished)
348        {
349                if(mStatus == Status_Header || mStatus == Status_BlockListing)
350                {
351                        // Header or block listing phase -- send from the buffered stream
352               
353                        // Send bytes from the data buffer
354                        int b = mData.Read(buffer, bytesToRead, Timeout);
355                        bytesToRead -= b;
356                        buffer += b;
357                       
358                        // Check to see if all the data has been used from this stream
359                        if(!mData.StreamDataLeft())
360                        {
361                                // Yes, move on to next phase (or finish, if there's no file data)
362                                if(!mSendData)
363                                {
364                                        mStatus = Status_Finished;
365                                }
366                                else
367                                {
368                                        // Reset the buffer so it can be used for the next phase
369                                        mData.Reset();
370               
371                                        // Get buffer ready for index?
372                                        if(mStatus == Status_Header)
373                                        {
374                                                // Just finished doing the stream header, create the block index header
375                                                file_BlockIndexHeader blkhdr;
376                                                blkhdr.mMagicValue = htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1);
377                                                ASSERT(mpRecipe != 0);
378                                                blkhdr.mOtherFileID = box_hton64(mpRecipe->GetOtherFileID());
379                                                blkhdr.mNumBlocks = box_hton64(mTotalBlocks);
380                                               
381                                                // Generate the IV base
382                                                Random::Generate(&mEntryIVBase, sizeof(mEntryIVBase));
383                                                blkhdr.mEntryIVBase = box_hton64(mEntryIVBase);
384                                               
385                                                mData.Write(&blkhdr, sizeof(blkhdr));
386                                        }
387                               
388                                        ++mStatus;
389                                }
390                        }
391                }
392                else if(mStatus == Status_Blocks)
393                {
394                        // Block sending phase
395                       
396                        if(mPositionInCurrentBlock >= mCurrentBlockEncodedSize)
397                        {
398                                // Next block!
399                                ++mCurrentBlock;
400                                ++mAbsoluteBlockNumber;
401                                if(mCurrentBlock >= mNumBlocks)
402                                {
403                                        // Output extra blocks for this instruction and move forward in file
404                                        if(mInstructionNumber >= 0)
405                                        {
406                                                SkipPreviousBlocksInInstruction();
407                                        }
408                               
409                                        // Is there another instruction to go?
410                                        ++mInstructionNumber;
411                                       
412                                        // Skip instructions which don't contain any data
413                                        while(mInstructionNumber < static_cast<int64_t>(mpRecipe->size())
414                                                && (*mpRecipe)[mInstructionNumber].mSpaceBefore == 0)
415                                        {
416                                                SkipPreviousBlocksInInstruction();
417                                                ++mInstructionNumber;
418                                        }
419                                       
420                                        if(mInstructionNumber >= static_cast<int64_t>(mpRecipe->size()))
421                                        {
422                                                // End of blocks, go to next phase
423                                                ++mStatus;
424                                               
425                                                // Set the data to reading so the index can be written
426                                                mData.SetForReading();
427                                        }
428                                        else
429                                        {
430                                                // Get ready for this instruction
431                                                SetForInstruction();
432                                        }
433                                }
434
435                                // Can't use 'else' here as SetForInstruction() will change this
436                                if(mCurrentBlock < mNumBlocks)
437                                {
438                                        EncodeCurrentBlock();
439                                }
440                        }
441                       
442                        // Send data from the current block (if there's data to send)
443                        if(mPositionInCurrentBlock < mCurrentBlockEncodedSize)
444                        {
445                                // How much data to put in the buffer?
446                                int s = mCurrentBlockEncodedSize - mPositionInCurrentBlock;
447                                if(s > bytesToRead) s = bytesToRead;
448                               
449                                // Copy it in
450                                ::memcpy(buffer, mEncodedBuffer.mpBuffer + mPositionInCurrentBlock, s);
451                               
452                                // Update variables
453                                bytesToRead -= s;
454                                buffer += s;
455                                mPositionInCurrentBlock += s;
456                        }
457                }
458                else
459                {
460                        // Should never get here, as it'd be an invalid status
461                        ASSERT(false);
462                }
463        }
464       
465        // Add encoded size to stats
466        BackupStoreFile::msStats.mTotalFileStreamSize += (NBytes - bytesToRead);
467        mTotalBytesSent += (NBytes - bytesToRead);
468       
469        // Return size of data to caller
470        return NBytes - bytesToRead;
471}
472
473
474// --------------------------------------------------------------------------
475//
476// Function
477//              Name:    BackupStoreFileEncodeStream::StorePreviousBlocksInInstruction()
478//              Purpose: Private. Stores the blocks of the old file referenced in the current
479//                               instruction into the index and skips over the data in the file
480//              Created: 16/1/04
481//
482// --------------------------------------------------------------------------
483void BackupStoreFileEncodeStream::SkipPreviousBlocksInInstruction()
484{
485        // Check something is necessary
486        if((*mpRecipe)[mInstructionNumber].mpStartBlock == 0 || (*mpRecipe)[mInstructionNumber].mBlocks == 0)
487        {
488                return;
489        }
490
491        // Index of the first block in old file (being diffed from)
492        int firstIndex = mpRecipe->BlockPtrToIndex((*mpRecipe)[mInstructionNumber].mpStartBlock);
493       
494        int64_t sizeToSkip = 0;
495
496        for(int32_t b = 0; b < (*mpRecipe)[mInstructionNumber].mBlocks; ++b)
497        {
498                // Update stats
499                BackupStoreFile::msStats.mBytesAlreadyOnServer += (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize;
500       
501                // Store the entry
502                StoreBlockIndexEntry(0 - (firstIndex + b),
503                        (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize,
504                        (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mWeakChecksum,
505                        (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mStrongChecksum);       
506
507                // Increment the absolute block number -- kept encryption IV in sync
508                ++mAbsoluteBlockNumber;
509               
510                // Add the size of this block to the size to skip
511                sizeToSkip += (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize;
512        }
513       
514        // Move forward in the stream
515        mpLogging->Seek(sizeToSkip, IOStream::SeekType_Relative);
516}
517
518
519// --------------------------------------------------------------------------
520//
521// Function
522//              Name:    BackupStoreFileEncodeStream::SetForInstruction()
523//              Purpose: Private. Sets the state of the internal variables for the current instruction in the recipe
524//              Created: 16/1/04
525//
526// --------------------------------------------------------------------------
527void BackupStoreFileEncodeStream::SetForInstruction()
528{
529        // Calculate block sizes
530        CalculateBlockSizes((*mpRecipe)[mInstructionNumber].mSpaceBefore, mNumBlocks, mBlockSize, mLastBlockSize);
531       
532        // Set variables
533        mCurrentBlock = 0;
534        mCurrentBlockEncodedSize = 0;
535        mPositionInCurrentBlock = 0;
536}
537
538
539
540// --------------------------------------------------------------------------
541//
542// Function
543//              Name:    BackupStoreFileEncodeStream::EncodeCurrentBlock()
544//              Purpose: Private. Encodes the current block, and writes the block data to the index
545//              Created: 8/12/03
546//
547// --------------------------------------------------------------------------
548void BackupStoreFileEncodeStream::EncodeCurrentBlock()
549{
550        // How big is the block, raw?
551        int blockRawSize = mBlockSize;
552        if(mCurrentBlock == (mNumBlocks - 1))
553        {
554                blockRawSize = mLastBlockSize;
555        }
556        ASSERT(blockRawSize < mAllocatedBufferSize);
557
558        // Check file open
559        if(mpLogging == 0)
560        {
561                // File should be open, but isn't. So logical error.
562                THROW_EXCEPTION(BackupStoreException, Internal)
563        }
564       
565        // Read the data in
566        if(!mpLogging->ReadFullBuffer(mpRawBuffer, blockRawSize,
567                0 /* not interested in size if failure */))
568        {
569                // TODO: Do something more intelligent, and abort
570                // this upload because the file has changed.
571                THROW_EXCEPTION(BackupStoreException,
572                        Temp_FileEncodeStreamDidntReadBuffer)
573        }
574       
575        // Encode it
576        mCurrentBlockEncodedSize = BackupStoreFile::EncodeChunk(mpRawBuffer,
577                blockRawSize, mEncodedBuffer);
578       
579        //TRACE2("Encode: Encoded size of block %d is %d\n", (int32_t)mCurrentBlock, (int32_t)mCurrentBlockEncodedSize);
580       
581        // Create block listing data -- generate checksums
582        RollingChecksum weakChecksum(mpRawBuffer, blockRawSize);
583        MD5Digest strongChecksum;
584        strongChecksum.Add(mpRawBuffer, blockRawSize);
585        strongChecksum.Finish();
586
587        // Add entry to the index
588        StoreBlockIndexEntry(mCurrentBlockEncodedSize, blockRawSize,
589                weakChecksum.GetChecksum(), strongChecksum.DigestAsData());
590       
591        // Set vars to reading this block
592        mPositionInCurrentBlock = 0;
593}
594
595// --------------------------------------------------------------------------
596//
597// Function
598//              Name:    BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t, int32_t, uint32_t, uint8_t *)
599//              Purpose: Private. Adds an entry to the index currently being stored for sending at end of the stream.
600//              Created: 16/1/04
601//
602// --------------------------------------------------------------------------
603void BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t EncSizeOrBlkIndex, int32_t ClearSize, uint32_t WeakChecksum, uint8_t *pStrongChecksum)
604{
605        // First, the encrypted section
606        file_BlockIndexEntryEnc entryEnc;
607        entryEnc.mSize = htonl(ClearSize);
608        entryEnc.mWeakChecksum = htonl(WeakChecksum);
609        ::memcpy(entryEnc.mStrongChecksum, pStrongChecksum, sizeof(entryEnc.mStrongChecksum));
610
611        // Then the clear section
612        file_BlockIndexEntry entry;
613        entry.mEncodedSize = box_hton64(((uint64_t)EncSizeOrBlkIndex));
614       
615        // Then encrypt the encryted section
616        // Generate the IV from the block number
617        if(sBlowfishEncryptBlockEntry.GetIVLength() != sizeof(mEntryIVBase))
618        {
619                THROW_EXCEPTION(BackupStoreException, IVLengthForEncodedBlockSizeDoesntMeetLengthRequirements)
620        }
621        uint64_t iv = mEntryIVBase;
622        iv += mAbsoluteBlockNumber;
623        // Convert to network byte order before encrypting with it, so that restores work on
624        // platforms with different endiannesses.
625        iv = box_hton64(iv);
626        sBlowfishEncryptBlockEntry.SetIV(&iv);
627
628        // Encode the data
629        int encodedSize = sBlowfishEncryptBlockEntry.TransformBlock(entry.mEnEnc, sizeof(entry.mEnEnc), &entryEnc, sizeof(entryEnc));
630        if(encodedSize != sizeof(entry.mEnEnc))
631        {
632                THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
633        }
634
635        // Save to data block for sending at the end of the stream
636        mData.Write(&entry, sizeof(entry));
637}
638
639
640// --------------------------------------------------------------------------
641//
642// Function
643//              Name:    BackupStoreFileEncodeStream::Write(const void *, int)
644//              Purpose: As interface. Exceptions.
645//              Created: 8/12/03
646//
647// --------------------------------------------------------------------------
648void BackupStoreFileEncodeStream::Write(const void *pBuffer, int NBytes)
649{
650        THROW_EXCEPTION(BackupStoreException, CantWriteToEncodedFileStream)
651}
652
653// --------------------------------------------------------------------------
654//
655// Function
656//              Name:    BackupStoreFileEncodeStream::StreamDataLeft()
657//              Purpose: As interface -- end of stream reached?
658//              Created: 8/12/03
659//
660// --------------------------------------------------------------------------
661bool BackupStoreFileEncodeStream::StreamDataLeft()
662{
663        return (mStatus != Status_Finished);
664}
665
666
667// --------------------------------------------------------------------------
668//
669// Function
670//              Name:    BackupStoreFileEncodeStream::StreamClosed()
671//              Purpose: As interface
672//              Created: 8/12/03
673//
674// --------------------------------------------------------------------------
675bool BackupStoreFileEncodeStream::StreamClosed()
676{
677        return true;
678}
679
680
681// --------------------------------------------------------------------------
682//
683// Function
684//              Name:    BackupStoreFileEncodeStream::Recipe::Recipe(BackupStoreFileCreation::BlocksAvailableEntry *, int64_t)
685//              Purpose: Constructor. Takes ownership of the block index, and will delete it when it's deleted
686//              Created: 15/1/04
687//
688// --------------------------------------------------------------------------
689BackupStoreFileEncodeStream::Recipe::Recipe(BackupStoreFileCreation::BlocksAvailableEntry *pBlockIndex,
690                int64_t NumBlocksInIndex, int64_t OtherFileID)
691        : mpBlockIndex(pBlockIndex),
692          mNumBlocksInIndex(NumBlocksInIndex),
693          mOtherFileID(OtherFileID)
694{
695        ASSERT((mpBlockIndex == 0) || (NumBlocksInIndex != 0))
696}
697
698// --------------------------------------------------------------------------
699//
700// Function
701//              Name:    BackupStoreFileEncodeStream::Recipe::~Recipe()
702//              Purpose: Destructor
703//              Created: 15/1/04
704//
705// --------------------------------------------------------------------------
706BackupStoreFileEncodeStream::Recipe::~Recipe()
707{
708        // Free the block index, if there is one
709        if(mpBlockIndex != 0)
710        {
711                ::free(mpBlockIndex);
712        }
713}
714
715
716
717
Note: See TracBrowser for help on using the repository browser.