// distribution boxbackup-0.10 (svn version: 494)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All use of this software and associated advertising materials must
// display the following acknowledgment:
// This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// [Where legally impermissible the Authors do not disclaim liability for
// direct physical injury or death caused solely by defects in the software
// unless it is modified by a third party.]
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//
//
// --------------------------------------------------------------------------
//
// File
// Name: BackupStoreFileCmbIdx.cpp
// Purpose: Combine indicies of a delta file and the file it's a diff from.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
#include "Box.h"
#include <new>
#include <string.h>
#include "BackupStoreFile.h"
#include "BackupStoreFileWire.h"
#include "BackupStoreObjectMagic.h"
#include "BackupStoreException.h"
#include "BackupStoreConstants.h"
#include "BackupStoreFilename.h"
#include "MemLeakFindOn.h"
// Hide from outside world
namespace
{
class BSFCombinedIndexStream : public IOStream
{
public:
BSFCombinedIndexStream(IOStream *pDiff);
~BSFCombinedIndexStream();
virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
virtual void Write(const void *pBuffer, int NBytes);
virtual bool StreamDataLeft();
virtual bool StreamClosed();
virtual void Initialise(IOStream &rFrom);
private:
IOStream *mpDiff;
bool mIsInitialised;
bool mHeaderWritten;
file_BlockIndexHeader mHeader;
int64_t mNumEntriesToGo;
int64_t mNumEntriesInFromFile;
int64_t *mFromBlockSizes; // NOTE: Entries in network byte order
};
};
// --------------------------------------------------------------------------
//
// Function
// Name: BackupStoreFile::CombineFileIndices(IOStream &, IOStream &, bool)
// Purpose: Given a diff file and the file it's a diff from, return a stream from which
// can be read the index of the combined file, without actually combining them.
// The stream of the diff must have a lifetime greater than or equal to the
// lifetime of the returned stream object. The full "from" file stream
// only needs to exist during the actual function call.
// If you pass in dodgy files which aren't related, then you will either
// get an error or bad results. So don't do that.
// If DiffIsIndexOnly is true, then rDiff is assumed to be a stream positioned
// at the beginning of the block index. Similarly for FromIsIndexOnly.
// WARNING: Reads of the returned streams with buffer sizes less than 64 bytes
// will not return any data.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
std::auto_ptr<IOStream> BackupStoreFile::CombineFileIndices(IOStream &rDiff, IOStream &rFrom, bool DiffIsIndexOnly, bool FromIsIndexOnly)
{
// Reposition file pointers?
if(!DiffIsIndexOnly)
{
MoveStreamPositionToBlockIndex(rDiff);
}
if(!FromIsIndexOnly)
{
MoveStreamPositionToBlockIndex(rFrom);
}
// Create object
std::auto_ptr<IOStream> stream(new BSFCombinedIndexStream(&rDiff));
// Initialise it
((BSFCombinedIndexStream *)stream.get())->Initialise(rFrom);
// And return the stream
return stream;
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::BSFCombinedIndexStream()
// Purpose: Private class. Constructor.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
BSFCombinedIndexStream::BSFCombinedIndexStream(IOStream *pDiff)
: mpDiff(pDiff),
mIsInitialised(false),
mHeaderWritten(false),
mNumEntriesToGo(0),
mNumEntriesInFromFile(0),
mFromBlockSizes(0)
{
ASSERT(mpDiff != 0);
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::~BSFCombinedIndexStream()
// Purpose: Private class. Destructor.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
BSFCombinedIndexStream::~BSFCombinedIndexStream()
{
if(mFromBlockSizes != 0)
{
::free(mFromBlockSizes);
mFromBlockSizes = 0;
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::Initialise(IOStream &)
// Purpose: Private class. Initalise from the streams (diff passed in constructor).
// Both streams must have file pointer positioned at the block index.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
void BSFCombinedIndexStream::Initialise(IOStream &rFrom)
{
// Paranoia is good.
if(mIsInitialised)
{
THROW_EXCEPTION(BackupStoreException, Internal)
}
// Look at the diff file: Read in the header
if(!mpDiff->ReadFullBuffer(&mHeader, sizeof(mHeader), 0))
{
THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
}
if(ntohl(mHeader.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
{
THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
}
// Read relevant data.
mNumEntriesToGo = box_ntoh64(mHeader.mNumBlocks);
// Adjust a bit to reflect the fact it's no longer a diff
mHeader.mOtherFileID = box_hton64(0);
// Now look at the from file: Read header
file_BlockIndexHeader fromHdr;
if(!rFrom.ReadFullBuffer(&fromHdr, sizeof(fromHdr), 0))
{
THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
}
if(ntohl(fromHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
{
THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
}
// Then... allocate memory for the list of sizes
mNumEntriesInFromFile = box_ntoh64(fromHdr.mNumBlocks);
mFromBlockSizes = (int64_t*)::malloc(mNumEntriesInFromFile * sizeof(int64_t));
if(mFromBlockSizes == 0)
{
throw std::bad_alloc();
}
// And read them all in!
for(int64_t b = 0; b < mNumEntriesInFromFile; ++b)
{
file_BlockIndexEntry e;
if(!rFrom.ReadFullBuffer(&e, sizeof(e), 0))
{
THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
}
// Check that the from file isn't a delta in itself
if(box_ntoh64(e.mEncodedSize) <= 0)
{
THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
}
// Store size (in network byte order)
mFromBlockSizes[b] = e.mEncodedSize;
}
// Flag as initialised
mIsInitialised = true;
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::Read(void *, int, int)
// Purpose: Private class. As interface.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
int BSFCombinedIndexStream::Read(void *pBuffer, int NBytes, int Timeout)
{
// Paranoia is good.
if(!mIsInitialised || mFromBlockSizes == 0 || mpDiff == 0)
{
THROW_EXCEPTION(BackupStoreException, Internal)
}
int written = 0;
// Header output yet?
if(!mHeaderWritten)
{
// Enough space?
if(NBytes < (int)sizeof(mHeader)) return 0;
// Copy in
::memcpy(pBuffer, &mHeader, sizeof(mHeader));
NBytes -= sizeof(mHeader);
written += sizeof(mHeader);
// Flag it's done
mHeaderWritten = true;
}
// How many entries can be written?
int entriesToWrite = NBytes / sizeof(file_BlockIndexEntry);
if(entriesToWrite > mNumEntriesToGo)
{
entriesToWrite = mNumEntriesToGo;
}
// Setup ready to go
file_BlockIndexEntry *poutput = (file_BlockIndexEntry*)(((uint8_t*)pBuffer) + written);
// Write entries
for(int b = 0; b < entriesToWrite; ++b)
{
if(!mpDiff->ReadFullBuffer(&(poutput[b]), sizeof(file_BlockIndexEntry), 0))
{
THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
}
// Does this need adjusting?
int s = box_ntoh64(poutput[b].mEncodedSize);
if(s <= 0)
{
// A reference to a block in the from file
int block = 0 - s;
ASSERT(block >= 0);
if(block >= mNumEntriesInFromFile)
{
// That's not good, the block doesn't exist
THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
}
// Adjust the entry in the buffer
poutput[b].mEncodedSize = mFromBlockSizes[block]; // stored in network byte order, no translation necessary
}
}
// Update written count
written += entriesToWrite * sizeof(file_BlockIndexEntry);
mNumEntriesToGo -= entriesToWrite;
return written;
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::Write(const void *, int)
// Purpose: Private class. As interface.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
void BSFCombinedIndexStream::Write(const void *pBuffer, int NBytes)
{
THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures)
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::StreamDataLeft()
// Purpose: Private class. As interface
// Created: 8/7/04
//
// --------------------------------------------------------------------------
bool BSFCombinedIndexStream::StreamDataLeft()
{
return (!mHeaderWritten) || (mNumEntriesToGo > 0);
}
// --------------------------------------------------------------------------
//
// Function
// Name: BSFCombinedIndexStream::StreamClosed()
// Purpose: Private class. As interface.
// Created: 8/7/04
//
// --------------------------------------------------------------------------
bool BSFCombinedIndexStream::StreamClosed()
{
return true; // doesn't do writing
}
syntax highlighted by Code2HTML, v. 0.9.1