summaryrefslogtreecommitdiff
path: root/bin/bbstored
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2011-04-26 18:44:26 +0000
committerChris Wilson <chris+github@qwirx.com>2011-04-26 18:44:26 +0000
commit1fe4e9308b8f50dbe70cc69bd500eb829a11b460 (patch)
tree738a016038b1bfbca588f688938d0d34fc55c06a /bin/bbstored
parent848ec8ab81adfa1c8d10e87c047c9db3ec6654b4 (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.
Diffstat (limited to 'bin/bbstored')
-rw-r--r--bin/bbstored/BackupCommands.cpp959
-rw-r--r--bin/bbstored/BackupConstants.h21
-rw-r--r--bin/bbstored/BackupStoreContext.cpp1808
-rw-r--r--bin/bbstored/BackupStoreContext.h186
-rw-r--r--bin/bbstored/Makefile.extra9
-rw-r--r--bin/bbstored/backupprotocol.txt235
6 files changed, 0 insertions, 3218 deletions
diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp
deleted file mode 100644
index 34f813df..00000000
--- a/bin/bbstored/BackupCommands.cpp
+++ /dev/null
@@ -1,959 +0,0 @@
-// --------------------------------------------------------------------------
-//
-// File
-// Name: BackupCommands.cpp
-// Purpose: Implement commands for the Backup store protocol
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-
-#include "Box.h"
-
-#include <set>
-#include <sstream>
-
-#include "autogen_BackupProtocolServer.h"
-#include "autogen_RaidFileException.h"
-#include "BackupConstants.h"
-#include "BackupStoreContext.h"
-#include "BackupStoreConstants.h"
-#include "BackupStoreDirectory.h"
-#include "BackupStoreException.h"
-#include "BackupStoreFile.h"
-#include "BackupStoreInfo.h"
-#include "BufferedStream.h"
-#include "CollectInBufferStream.h"
-#include "FileStream.h"
-#include "InvisibleTempFileStream.h"
-#include "RaidFileController.h"
-#include "StreamableMemBlock.h"
-
-#include "MemLeakFindOn.h"
-
-#define PROTOCOL_ERROR(code) \
- std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( \
- BackupProtocolServerError::ErrorType, \
- BackupProtocolServerError::code));
-
-#define CHECK_PHASE(phase) \
- if(rContext.GetPhase() != BackupStoreContext::phase) \
- { \
- return PROTOCOL_ERROR(Err_NotInRightProtocolPhase); \
- }
-
-#define CHECK_WRITEABLE_SESSION \
- if(rContext.SessionIsReadOnly()) \
- { \
- return PROTOCOL_ERROR(Err_SessionReadOnly); \
- }
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerVersion::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Return the current version, or an error if the requested version isn't allowed
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerVersion::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Version)
-
- // Correct version?
- if(mVersion != BACKUP_STORE_SERVER_VERSION)
- {
- return PROTOCOL_ERROR(Err_WrongVersion);
- }
-
- // Mark the next phase
- rContext.SetPhase(BackupStoreContext::Phase_Login);
-
- // Return our version
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerVersion(BACKUP_STORE_SERVER_VERSION));
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerLogin::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Return the current version, or an error if the requested version isn't allowed
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Login)
-
- // Check given client ID against the ID in the certificate certificate
- // and that the client actually has an account on this machine
- if(mClientID != rContext.GetClientID())
- {
- BOX_WARNING("Failed login from client ID " <<
- BOX_FORMAT_ACCOUNT(mClientID) <<
- ": wrong certificate for this account");
- return PROTOCOL_ERROR(Err_BadLogin);
- }
-
- if(!rContext.GetClientHasAccount())
- {
- BOX_WARNING("Failed login from client ID " <<
- BOX_FORMAT_ACCOUNT(mClientID) <<
- ": no such account on this server");
- return PROTOCOL_ERROR(Err_BadLogin);
- }
-
- // If we need to write, check that nothing else has got a write lock
- if((mFlags & Flags_ReadOnly) != Flags_ReadOnly)
- {
- // See if the context will get the lock
- if(!rContext.AttemptToGetWriteLock())
- {
- BOX_WARNING("Failed to get write lock for Client ID " <<
- BOX_FORMAT_ACCOUNT(mClientID));
- return PROTOCOL_ERROR(Err_CannotLockStoreForWriting);
- }
-
- // Debug: check we got the lock
- ASSERT(!rContext.SessionIsReadOnly());
- }
-
- // Load the store info
- rContext.LoadStoreInfo();
-
- // Get the last client store marker
- int64_t clientStoreMarker = rContext.GetClientStoreMarker();
-
- // Mark the next phase
- rContext.SetPhase(BackupStoreContext::Phase_Commands);
-
- // Log login
- BOX_NOTICE("Login from Client ID " <<
- BOX_FORMAT_ACCOUNT(mClientID) <<
- " " <<
- (((mFlags & Flags_ReadOnly) != Flags_ReadOnly)
- ?"Read/Write":"Read-only"));
-
- // Get the usage info for reporting to the client
- int64_t blocksUsed = 0, blocksSoftLimit = 0, blocksHardLimit = 0;
- rContext.GetStoreDiscUsageInfo(blocksUsed, blocksSoftLimit, blocksHardLimit);
-
- // Return success
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerLoginConfirmed(clientStoreMarker, blocksUsed, blocksSoftLimit, blocksHardLimit));
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerFinished::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Marks end of conversation (Protocol framework handles this)
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- BOX_NOTICE("Session finished for Client ID " <<
- BOX_FORMAT_ACCOUNT(rContext.GetClientID()));
-
- // Let the context know about it
- rContext.ReceivedFinishCommand();
-
- // can be called in any phase
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerFinished);
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerListDirectory::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Command to list a directory
-// Created: 2003/09/02
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerListDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Store the listing to a stream
- std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
-
- try
- {
- // Ask the context for a directory
- const BackupStoreDirectory &rdir(
- rContext.GetDirectory(mObjectID));
- rdir.WriteToStream(*stream, mFlagsMustBeSet,
- mFlagsNotToBeSet, mSendAttributes,
- false /* never send dependency info to the client */);
- }
- catch (RaidFileException &e)
- {
- if (e.GetSubType() == RaidFileException::RaidFileDoesntExist)
- {
- return PROTOCOL_ERROR(Err_DoesNotExist);
- }
- throw;
- }
-
- stream->SetForReading();
-
- // Get the protocol to send the stream
- rProtocol.SendStreamAfterCommand(stream.release());
-
- return std::auto_ptr<ProtocolObject>(
- new BackupProtocolServerSuccess(mObjectID));
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerStoreFile::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Command to store a file on the server
-// Created: 2003/09/02
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerStoreFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- std::auto_ptr<ProtocolObject> hookResult =
- rContext.StartCommandHook(*this);
- if(hookResult.get())
- {
- return hookResult;
- }
-
- // Check that the diff from file actually exists, if it's specified
- if(mDiffFromFileID != 0)
- {
- if(!rContext.ObjectExists(mDiffFromFileID,
- BackupStoreContext::ObjectExists_File))
- {
- return PROTOCOL_ERROR(Err_DiffFromFileDoesNotExist);
- }
- }
-
- // A stream follows, which contains the file
- std::auto_ptr<IOStream> dirstream(rProtocol.ReceiveStream());
-
- // Ask the context to store it
- int64_t id = 0;
- try
- {
- id = rContext.AddFile(*dirstream, mDirectoryObjectID,
- mModificationTime, mAttributesHash, mDiffFromFileID,
- mFilename,
- true /* mark files with same name as old versions */);
- }
- catch(BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::AddedFileDoesNotVerify)
- {
- return PROTOCOL_ERROR(Err_FileDoesNotVerify);
- }
- else if(e.GetSubType() == BackupStoreException::AddedFileExceedsStorageLimit)
- {
- return PROTOCOL_ERROR(Err_StorageLimitExceeded);
- }
- else
- {
- throw;
- }
- }
-
- // Tell the caller what the file was
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(id));
-}
-
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetObject::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Command to get an arbitary object from the server
-// Created: 2003/09/03
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetObject::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Check the object exists
- if(!rContext.ObjectExists(mObjectID))
- {
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(NoObject));
- }
-
- // Open the object
- std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
-
- // Stream it to the peer
- rProtocol.SendStreamAfterCommand(object.release());
-
- // Tell the caller what the file was
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetFile::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Command to get an file object from the server -- may have to do a bit of
-// work to get the object.
-// Created: 2003/09/03
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Check the objects exist
- if(!rContext.ObjectExists(mObjectID)
- || !rContext.ObjectExists(mInDirectory))
- {
- return PROTOCOL_ERROR(Err_DoesNotExist);
- }
-
- // Get the directory it's in
- const BackupStoreDirectory &rdir(rContext.GetDirectory(mInDirectory));
-
- // Find the object within the directory
- BackupStoreDirectory::Entry *pfileEntry = rdir.FindEntryByID(mObjectID);
- if(pfileEntry == 0)
- {
- return PROTOCOL_ERROR(Err_DoesNotExistInDirectory);
- }
-
- // The result
- std::auto_ptr<IOStream> stream;
-
- // Does this depend on anything?
- if(pfileEntry->GetDependsNewer() != 0)
- {
- // File exists, but is a patch from a new version. Generate the older version.
- std::vector<int64_t> patchChain;
- int64_t id = mObjectID;
- BackupStoreDirectory::Entry *en = 0;
- do
- {
- patchChain.push_back(id);
- en = rdir.FindEntryByID(id);
- if(en == 0)
- {
- BOX_ERROR("Object " <<
- BOX_FORMAT_OBJECTID(mObjectID) <<
- " in dir " <<
- BOX_FORMAT_OBJECTID(mInDirectory) <<
- " for account " <<
- BOX_FORMAT_ACCOUNT(rContext.GetClientID()) <<
- " references object " <<
- BOX_FORMAT_OBJECTID(id) <<
- " which does not exist in dir");
- return PROTOCOL_ERROR(Err_PatchConsistencyError);
- }
- id = en->GetDependsNewer();
- }
- while(en != 0 && id != 0);
-
- // OK! The last entry in the chain is the full file, the others are patches back from it.
- // Open the last one, which is the current from file
- std::auto_ptr<IOStream> from(rContext.OpenObject(patchChain[patchChain.size() - 1]));
-
- // Then, for each patch in the chain, do a combine
- for(int p = ((int)patchChain.size()) - 2; p >= 0; --p)
- {
- // ID of patch
- int64_t patchID = patchChain[p];
-
- // Open it a couple of times
- std::auto_ptr<IOStream> diff(rContext.OpenObject(patchID));
- std::auto_ptr<IOStream> diff2(rContext.OpenObject(patchID));
-
- // Choose a temporary filename for the result of the combination
- std::ostringstream fs;
- fs << rContext.GetStoreRoot() << ".recombinetemp." << p;
- std::string tempFn =
- RaidFileController::DiscSetPathToFileSystemPath(
- rContext.GetStoreDiscSet(), fs.str(),
- p + 16);
-
- // Open the temporary file
- std::auto_ptr<IOStream> combined;
- try
- {
- {
- // Write nastily to allow this to work with gcc 2.x
- std::auto_ptr<IOStream> t(
- new InvisibleTempFileStream(
- tempFn.c_str(),
- O_RDWR | O_CREAT |
- O_EXCL | O_BINARY |
- O_TRUNC));
- combined = t;
- }
- }
- catch(...)
- {
- // Make sure it goes
- ::unlink(tempFn.c_str());
- throw;
- }
-
- // Do the combining
- BackupStoreFile::CombineFile(*diff, *diff2, *from, *combined);
-
- // Move to the beginning of the combined file
- combined->Seek(0, IOStream::SeekType_Absolute);
-
- // Then shuffle round for the next go
- if (from.get()) from->Close();
- from = combined;
- }
-
- // Now, from contains a nice file to send to the client. Reorder it
- {
- // Write nastily to allow this to work with gcc 2.x
- std::auto_ptr<IOStream> t(BackupStoreFile::ReorderFileToStreamOrder(from.get(), true /* take ownership */));
- stream = t;
- }
-
- // Release from file to avoid double deletion
- from.release();
- }
- else
- {
- // Simple case: file already exists on disc ready to go
-
- // Open the object
- std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
- BufferedStream buf(*object);
-
- // Verify it
- if(!BackupStoreFile::VerifyEncodedFileFormat(buf))
- {
- return PROTOCOL_ERROR(Err_FileDoesNotVerify);
- }
-
- // Reset stream -- seek to beginning
- object->Seek(0, IOStream::SeekType_Absolute);
-
- // Reorder the stream/file into stream order
- {
- // Write nastily to allow this to work with gcc 2.x
- std::auto_ptr<IOStream> t(BackupStoreFile::ReorderFileToStreamOrder(object.get(), true /* take ownership */));
- stream = t;
- }
-
- // Object will be deleted when the stream is deleted,
- // so can release the object auto_ptr here to avoid
- // premature deletion
- object.release();
- }
-
- // Stream the reordered stream to the peer
- rProtocol.SendStreamAfterCommand(stream.get());
-
- // Don't delete the stream here
- stream.release();
-
- // Tell the caller what the file was
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerCreateDirectory::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Create directory command
-// Created: 2003/09/04
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerCreateDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Get the stream containing the attributes
- std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
- // Collect the attributes -- do this now so no matter what the outcome,
- // the data has been absorbed.
- StreamableMemBlock attr;
- attr.Set(*attrstream, rProtocol.GetTimeout());
-
- // Check to see if the hard limit has been exceeded
- if(rContext.HardLimitExceeded())
- {
- // Won't allow creation if the limit has been exceeded
- return PROTOCOL_ERROR(Err_StorageLimitExceeded);
- }
-
- bool alreadyExists = false;
- int64_t id = rContext.AddDirectory(mContainingDirectoryID, mDirectoryName, attr, mAttributesModTime, alreadyExists);
-
- if(alreadyExists)
- {
- return PROTOCOL_ERROR(Err_DirectoryAlreadyExists);
- }
-
- // Tell the caller what the file was
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(id));
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerChangeDirAttributes::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Change attributes on directory
-// Created: 2003/09/06
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerChangeDirAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Get the stream containing the attributes
- std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
- // Collect the attributes -- do this now so no matter what the outcome,
- // the data has been absorbed.
- StreamableMemBlock attr;
- attr.Set(*attrstream, rProtocol.GetTimeout());
-
- // Get the context to do it's magic
- rContext.ChangeDirAttributes(mObjectID, attr, mAttributesModTime);
-
- // Tell the caller what the file was
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerSetReplacementFileAttributes::DoCommand(Protocol &, BackupStoreContext &)
-// Purpose: Change attributes on directory
-// Created: 2003/09/06
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerSetReplacementFileAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Get the stream containing the attributes
- std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
- // Collect the attributes -- do this now so no matter what the outcome,
- // the data has been absorbed.
- StreamableMemBlock attr;
- attr.Set(*attrstream, rProtocol.GetTimeout());
-
- // Get the context to do it's magic
- int64_t objectID = 0;
- if(!rContext.ChangeFileAttributes(mFilename, mInDirectory, attr, mAttributesHash, objectID))
- {
- // Didn't exist
- return PROTOCOL_ERROR(Err_DoesNotExist);
- }
-
- // Tell the caller what the file was
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(objectID));
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Delete a file
-// Created: 2003/10/21
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Context handles this
- int64_t objectID = 0;
- rContext.DeleteFile(mFilename, mInDirectory, objectID);
-
- // return the object ID or zero for not found
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(objectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerUndeleteFile::DoCommand(
-// BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Undelete a file
-// Created: 2008-09-12
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteFile::DoCommand(
- BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Context handles this
- bool result = rContext.UndeleteFile(mObjectID, mInDirectory);
-
- // return the object ID or zero for not found
- return std::auto_ptr<ProtocolObject>(
- new BackupProtocolServerSuccess(result ? mObjectID : 0));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Delete a directory
-// Created: 2003/10/21
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Check it's not asking for the root directory to be deleted
- if(mObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
- {
- return PROTOCOL_ERROR(Err_CannotDeleteRoot);
- }
-
- // Context handles this
- try
- {
- rContext.DeleteDirectory(mObjectID);
- }
- catch (BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::MultiplyReferencedObject)
- {
- return PROTOCOL_ERROR(Err_MultiplyReferencedObject);
- }
-
- throw;
- }
-
- // return the object ID
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Undelete a directory
-// Created: 23/11/03
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Check it's not asking for the root directory to be deleted
- if(mObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
- {
- return PROTOCOL_ERROR(Err_CannotDeleteRoot);
- }
-
- // Context handles this
- rContext.DeleteDirectory(mObjectID, true /* undelete */);
-
- // return the object ID
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Command to set the client's store marker
-// Created: 2003/10/29
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Set the marker
- rContext.SetClientStoreMarker(mClientStoreMarker);
-
- // return store marker set
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mClientStoreMarker));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Command to move an object from one directory to another
-// Created: 2003/11/12
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
- CHECK_WRITEABLE_SESSION
-
- // Let context do this, but modify error reporting on exceptions...
- try
- {
- rContext.MoveObject(mObjectID, mMoveFromDirectory, mMoveToDirectory,
- mNewFilename, (mFlags & Flags_MoveAllWithSameName) == Flags_MoveAllWithSameName,
- (mFlags & Flags_AllowMoveOverDeletedObject) == Flags_AllowMoveOverDeletedObject);
- }
- catch(BackupStoreException &e)
- {
- if(e.GetSubType() == BackupStoreException::CouldNotFindEntryInDirectory)
- {
- return PROTOCOL_ERROR(Err_DoesNotExist);
- }
- else if(e.GetSubType() == BackupStoreException::NameAlreadyExistsInDirectory)
- {
- return PROTOCOL_ERROR(Err_TargetNameExists);
- }
- else
- {
- throw;
- }
- }
-
- // Return the object ID
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Command to find the name of an object
-// Created: 12/11/03
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Create a stream for the list of filenames
- std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
-
- // Object and directory IDs
- int64_t objectID = mObjectID;
- int64_t dirID = mContainingDirectoryID;
-
- // Data to return in the reply
- int32_t numNameElements = 0;
- int16_t objectFlags = 0;
- int64_t modTime = 0;
- uint64_t attrModHash = 0;
- bool haveModTimes = false;
-
- do
- {
- // Check the directory really exists
- if(!rContext.ObjectExists(dirID, BackupStoreContext::ObjectExists_Directory))
- {
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(BackupProtocolServerObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0));
- }
-
- // Load up the directory
- const BackupStoreDirectory &rdir(rContext.GetDirectory(dirID));
-
- // Find the element in this directory and store it's name
- if(objectID != ObjectID_DirectoryOnly)
- {
- const BackupStoreDirectory::Entry *en = rdir.FindEntryByID(objectID);
-
- // If this can't be found, then there is a problem... tell the caller it can't be found
- if(en == 0)
- {
- // Abort!
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(BackupProtocolServerObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0));
- }
-
- // Store flags?
- if(objectFlags == 0)
- {
- objectFlags = en->GetFlags();
- }
-
- // Store modification times?
- if(!haveModTimes)
- {
- modTime = en->GetModificationTime();
- attrModHash = en->GetAttributesHash();
- haveModTimes = true;
- }
-
- // Store the name in the stream
- en->GetName().WriteToStream(*stream);
-
- // Count of name elements
- ++numNameElements;
- }
-
- // Setup for next time round
- objectID = dirID;
- dirID = rdir.GetContainerID();
-
- } while(objectID != 0 && objectID != BACKUPSTORE_ROOT_DIRECTORY_ID);
-
- // Stream to send?
- if(numNameElements > 0)
- {
- // Get the stream ready to go
- stream->SetForReading();
- // Tell the protocol to send the stream
- rProtocol.SendStreamAfterCommand(stream.release());
- }
-
- // Make reply
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(numNameElements, modTime, attrModHash, objectFlags));
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Get the block index from a file, by ID
-// Created: 19/1/04
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Open the file
- std::auto_ptr<IOStream> stream(rContext.OpenObject(mObjectID));
-
- // Move the file pointer to the block index
- BackupStoreFile::MoveStreamPositionToBlockIndex(*stream);
-
- // Return the stream to the client
- rProtocol.SendStreamAfterCommand(stream.release());
-
- // Return the object ID
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Get the block index from a file, by name within a directory
-// Created: 19/1/04
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Get the directory
- const BackupStoreDirectory &dir(rContext.GetDirectory(mInDirectory));
-
- // Find the latest object ID within it which has the same name
- int64_t objectID = 0;
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *en = 0;
- while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0)
- {
- if(en->GetName() == mFilename)
- {
- // Store the ID, if it's a newer ID than the last one
- if(en->GetObjectID() > objectID)
- {
- objectID = en->GetObjectID();
- }
- }
- }
-
- // Found anything?
- if(objectID == 0)
- {
- // No... return a zero object ID
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(0));
- }
-
- // Open the file
- std::auto_ptr<IOStream> stream(rContext.OpenObject(objectID));
-
- // Move the file pointer to the block index
- BackupStoreFile::MoveStreamPositionToBlockIndex(*stream);
-
- // Return the stream to the client
- rProtocol.SendStreamAfterCommand(stream.release());
-
- // Return the object ID
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(objectID));
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Return the amount of disc space used
-// Created: 19/4/04
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- // Get store info from context
- const BackupStoreInfo &rinfo(rContext.GetBackupStoreInfo());
-
- // Find block size
- RaidFileController &rcontroller(RaidFileController::GetController());
- RaidFileDiscSet &rdiscSet(rcontroller.GetDiscSet(rinfo.GetDiscSetNumber()));
-
- // Return info
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerAccountUsage(
- rinfo.GetBlocksUsed(),
- rinfo.GetBlocksInOldFiles(),
- rinfo.GetBlocksInDeletedFiles(),
- rinfo.GetBlocksInDirectories(),
- rinfo.GetBlocksSoftLimit(),
- rinfo.GetBlocksHardLimit(),
- rdiscSet.GetBlockSize()
- ));
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &, BackupStoreContext &)
-// Purpose: Return the amount of disc space used
-// Created: 19/4/04
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<ProtocolObject> BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
-{
- CHECK_PHASE(Phase_Commands)
-
- //
- // NOOP
- //
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerIsAlive());
-}
diff --git a/bin/bbstored/BackupConstants.h b/bin/bbstored/BackupConstants.h
deleted file mode 100644
index 19d06a15..00000000
--- a/bin/bbstored/BackupConstants.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// --------------------------------------------------------------------------
-//
-// File
-// Name: BackupConstants.h
-// Purpose: Constants for the backup server and client
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-
-#ifndef BACKUPCONSTANTS__H
-#define BACKUPCONSTANTS__H
-
-// 15 minutes to timeout (milliseconds)
-#define BACKUP_STORE_TIMEOUT (15*60*1000)
-
-// Should the store daemon convert files to Raid immediately?
-#define BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY true
-
-#endif // BACKUPCONSTANTS__H
-
-
diff --git a/bin/bbstored/BackupStoreContext.cpp b/bin/bbstored/BackupStoreContext.cpp
deleted file mode 100644
index 9a98decf..00000000
--- a/bin/bbstored/BackupStoreContext.cpp
+++ /dev/null
@@ -1,1808 +0,0 @@
-// --------------------------------------------------------------------------
-//
-// File
-// Name: BackupStoreContext.cpp
-// Purpose: Context for backup store server
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-
-#include "Box.h"
-
-#include <stdio.h>
-
-#include "BackupConstants.h"
-#include "BackupStoreContext.h"
-#include "BackupStoreDaemon.h"
-#include "BackupStoreDirectory.h"
-#include "BackupStoreException.h"
-#include "BackupStoreFile.h"
-#include "BackupStoreInfo.h"
-#include "BackupStoreObjectMagic.h"
-#include "BufferedStream.h"
-#include "BufferedWriteStream.h"
-#include "FileStream.h"
-#include "InvisibleTempFileStream.h"
-#include "RaidFileController.h"
-#include "RaidFileRead.h"
-#include "RaidFileWrite.h"
-#include "StoreStructure.h"
-
-#include "MemLeakFindOn.h"
-
-
-// Maximum number of directories to keep in the cache
-// When the cache is bigger than this, everything gets
-// deleted.
-#ifdef BOX_RELEASE_BUILD
- #define MAX_CACHE_SIZE 32
-#else
- #define MAX_CACHE_SIZE 2
-#endif
-
-// Allow the housekeeping process 4 seconds to release an account
-#define MAX_WAIT_FOR_HOUSEKEEPING_TO_RELEASE_ACCOUNT 4
-
-// Maximum amount of store info updates before it's actually saved to disc.
-#define STORE_INFO_SAVE_DELAY 96
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::BackupStoreContext()
-// Purpose: Constructor
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-BackupStoreContext::BackupStoreContext(int32_t ClientID,
- HousekeepingInterface &rDaemon)
- : mClientID(ClientID),
- mrDaemon(rDaemon),
- mProtocolPhase(Phase_START),
- mClientHasAccount(false),
- mStoreDiscSet(-1),
- mReadOnly(true),
- mSaveStoreInfoDelay(STORE_INFO_SAVE_DELAY),
- mpTestHook(NULL)
-{
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::~BackupStoreContext()
-// Purpose: Destructor
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-BackupStoreContext::~BackupStoreContext()
-{
- // Delete the objects in the cache
- for(std::map<int64_t, BackupStoreDirectory*>::iterator i(mDirectoryCache.begin()); i != mDirectoryCache.end(); ++i)
- {
- delete (i->second);
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::CleanUp()
-// Purpose: Clean up after a connection
-// Created: 16/12/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::CleanUp()
-{
- // Make sure the store info is saved, if it has been loaded, isn't read only and has been modified
- if(mapStoreInfo.get() && !(mapStoreInfo->IsReadOnly()) &&
- mapStoreInfo->IsModified())
- {
- mapStoreInfo->Save();
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::ReceivedFinishCommand()
-// Purpose: Called when the finish command is received by the protocol
-// Created: 16/12/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::ReceivedFinishCommand()
-{
- if(!mReadOnly && mapStoreInfo.get())
- {
- // Save the store info, not delayed
- SaveStoreInfo(false);
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::AttemptToGetWriteLock()
-// Purpose: Attempt to get a write lock for the store, and if so, unset the read only flags
-// Created: 2003/09/02
-//
-// --------------------------------------------------------------------------
-bool BackupStoreContext::AttemptToGetWriteLock()
-{
- // Make the filename of the write lock file
- std::string writeLockFile;
- StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFile);
-
- // Request the lock
- bool gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
-
- if(!gotLock)
- {
- // The housekeeping process might have the thing open -- ask it to stop
- char msg[256];
- int msgLen = sprintf(msg, "r%x\n", mClientID);
- // Send message
- mrDaemon.SendMessageToHousekeepingProcess(msg, msgLen);
-
- // Then try again a few times
- int tries = MAX_WAIT_FOR_HOUSEKEEPING_TO_RELEASE_ACCOUNT;
- do
- {
- ::sleep(1 /* second */);
- --tries;
- gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
-
- } while(!gotLock && tries > 0);
- }
-
- if(gotLock)
- {
- // Got the lock, mark as not read only
- mReadOnly = false;
- }
-
- return gotLock;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::LoadStoreInfo()
-// Purpose: Load the store info from disc
-// Created: 2003/09/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::LoadStoreInfo()
-{
- if(mapStoreInfo.get() != 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoAlreadyLoaded)
- }
-
- // Load it up!
- std::auto_ptr<BackupStoreInfo> i(BackupStoreInfo::Load(mClientID, mStoreRoot, mStoreDiscSet, mReadOnly));
-
- // Check it
- if(i->GetAccountID() != mClientID)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoForWrongAccount)
- }
-
- // Keep the pointer to it
- mapStoreInfo = i;
-
- BackupStoreAccountDatabase::Entry account(mClientID, mStoreDiscSet);
-
- // try to load the reference count database
- try
- {
- mapRefCount = BackupStoreRefCountDatabase::Load(account, false);
- }
- catch(BoxException &e)
- {
- BOX_WARNING("Reference count database is missing or corrupted, "
- "creating a new one, expect housekeeping to find and "
- "fix problems with reference counts later.");
-
- BackupStoreRefCountDatabase::CreateForRegeneration(account);
- mapRefCount = BackupStoreRefCountDatabase::Load(account, false);
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::SaveStoreInfo(bool)
-// Purpose: Potentially delayed saving of the store info
-// Created: 16/12/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::SaveStoreInfo(bool AllowDelay)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // Can delay saving it a little while?
- if(AllowDelay)
- {
- --mSaveStoreInfoDelay;
- if(mSaveStoreInfoDelay > 0)
- {
- return;
- }
- }
-
- // Want to save now
- mapStoreInfo->Save();
-
- // Set count for next delay
- mSaveStoreInfoDelay = STORE_INFO_SAVE_DELAY;
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::MakeObjectFilename(int64_t, std::string &, bool)
-// Purpose: Create the filename of an object in the store, optionally creating the
-// containing directory if it doesn't already exist.
-// Created: 2003/09/02
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists)
-{
- // Delegate to utility function
- StoreStructure::MakeObjectFilename(ObjectID, mStoreRoot, mStoreDiscSet, rOutput, EnsureDirectoryExists);
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::GetDirectoryInternal(int64_t)
-// Purpose: Return a reference to a directory. Valid only until the
-// next time a function which affects directories is called.
-// Mainly this funciton, and creation of files.
-// Private version of this, which returns non-const directories.
-// Created: 2003/09/02
-//
-// --------------------------------------------------------------------------
-BackupStoreDirectory &BackupStoreContext::GetDirectoryInternal(int64_t ObjectID)
-{
- // Get the filename
- std::string filename;
- MakeObjectFilename(ObjectID, filename);
-
- // Already in cache?
- std::map<int64_t, BackupStoreDirectory*>::iterator item(mDirectoryCache.find(ObjectID));
- if(item != mDirectoryCache.end())
- {
- // Check the revision ID of the file -- does it need refreshing?
- int64_t revID = 0;
- if(!RaidFileRead::FileExists(mStoreDiscSet, filename, &revID))
- {
- THROW_EXCEPTION(BackupStoreException, DirectoryHasBeenDeleted)
- }
-
- if(revID == item->second->GetRevisionID())
- {
- // Looks good... return the cached object
- BOX_TRACE("Returning object " <<
- BOX_FORMAT_OBJECTID(ObjectID) <<
- " from cache, modtime = " << revID);
- return *(item->second);
- }
-
- BOX_TRACE("Refreshing object " <<
- BOX_FORMAT_OBJECTID(ObjectID) <<
- " in cache, modtime changed from " <<
- item->second->GetRevisionID() << " to " << revID);
-
- // Delete this cached object
- delete item->second;
- mDirectoryCache.erase(item);
- }
-
- // Need to load it up
-
- // First check to see if the cache is too big
- if(mDirectoryCache.size() > MAX_CACHE_SIZE)
- {
- // Very simple. Just delete everything!
- for(std::map<int64_t, BackupStoreDirectory*>::iterator i(mDirectoryCache.begin()); i != mDirectoryCache.end(); ++i)
- {
- delete (i->second);
- }
- mDirectoryCache.clear();
- }
-
- // Get a RaidFileRead to read it
- int64_t revID = 0;
- std::auto_ptr<RaidFileRead> objectFile(RaidFileRead::Open(mStoreDiscSet, filename, &revID));
- ASSERT(revID != 0);
-
- // New directory object
- std::auto_ptr<BackupStoreDirectory> dir(new BackupStoreDirectory);
-
- // Read it from the stream, then set it's revision ID
- BufferedStream buf(*objectFile);
- dir->ReadFromStream(buf, IOStream::TimeOutInfinite);
- dir->SetRevisionID(revID);
-
- // Make sure the size of the directory is available for writing the dir back
- int64_t dirSize = objectFile->GetDiscUsageInBlocks();
- ASSERT(dirSize > 0);
- dir->SetUserInfo1_SizeInBlocks(dirSize);
-
- // Store in cache
- BackupStoreDirectory *pdir = dir.release();
- try
- {
- mDirectoryCache[ObjectID] = pdir;
- }
- catch(...)
- {
- delete pdir;
- throw;
- }
-
- // Return it
- return *pdir;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::AllocateObjectID()
-// Purpose: Allocate a new object ID, tolerant of failures to save store info
-// Created: 16/12/03
-//
-// --------------------------------------------------------------------------
-int64_t BackupStoreContext::AllocateObjectID()
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- // Given that the store info may not be saved for STORE_INFO_SAVE_DELAY
- // times after it has been updated, this is a reasonable number of times
- // to try for finding an unused ID.
- // (Sizes used in the store info are fixed by the housekeeping process)
- int retryLimit = (STORE_INFO_SAVE_DELAY * 2);
-
- while(retryLimit > 0)
- {
- // Attempt to allocate an ID from the store
- int64_t id = mapStoreInfo->AllocateObjectID();
-
- // Generate filename
- std::string filename;
- MakeObjectFilename(id, filename);
- // Check it doesn't exist
- if(!RaidFileRead::FileExists(mStoreDiscSet, filename))
- {
- // Success!
- return id;
- }
-
- // Decrement retry count, and try again
- --retryLimit;
-
- // Mark that the store info should be saved as soon as possible
- mSaveStoreInfoDelay = 0;
-
- BOX_WARNING("When allocating object ID, found that " <<
- BOX_FORMAT_OBJECTID(id) << " is already in use");
- }
-
- THROW_EXCEPTION(BackupStoreException, CouldNotFindUnusedIDDuringAllocation)
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::AddFile(IOStream &, int64_t,
-// int64_t, int64_t, const BackupStoreFilename &, bool)
-// Purpose: Add a file to the store, from a given stream, into
-// a specified directory. Returns object ID of the new
-// file.
-// Created: 2003/09/03
-//
-// --------------------------------------------------------------------------
-int64_t BackupStoreContext::AddFile(IOStream &rFile, int64_t InDirectory,
- int64_t ModificationTime, int64_t AttributesHash,
- int64_t DiffFromFileID, const BackupStoreFilename &rFilename,
- bool MarkFileWithSameNameAsOldVersions)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // This is going to be a bit complex to make sure it copes OK
- // with things going wrong.
- // The only thing which isn't safe is incrementing the object ID
- // and keeping the blocks used entirely accurate -- but these
- // aren't big problems if they go horribly wrong. The sizes will
- // be corrected the next time the account has a housekeeping run,
- // and the object ID allocation code is tolerant of missed IDs.
- // (the info is written lazily, so these are necessary)
-
- // Get the directory we want to modify
- BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-
- // Allocate the next ID
- int64_t id = AllocateObjectID();
-
- // Stream the file to disc
- std::string fn;
- MakeObjectFilename(id, fn, true /* make sure the directory it's in exists */);
- int64_t newObjectBlocksUsed = 0;
- RaidFileWrite *ppreviousVerStoreFile = 0;
- bool reversedDiffIsCompletelyDifferent = false;
- int64_t oldVersionNewBlocksUsed = 0;
- try
- {
- RaidFileWrite storeFile(mStoreDiscSet, fn);
- storeFile.Open(false /* no overwriting */);
-
- // size adjustment from use of patch in old file
- int64_t spaceSavedByConversionToPatch = 0;
-
- // Diff or full file?
- if(DiffFromFileID == 0)
- {
- // A full file, just store to disc
- if(!rFile.CopyStreamTo(storeFile, BACKUP_STORE_TIMEOUT))
- {
- THROW_EXCEPTION(BackupStoreException, ReadFileFromStreamTimedOut)
- }
- }
- else
- {
- // Check that the diffed from ID actually exists in the directory
- if(dir.FindEntryByID(DiffFromFileID) == 0)
- {
- THROW_EXCEPTION(BackupStoreException, DiffFromIDNotFoundInDirectory)
- }
-
- // Diff file, needs to be recreated.
- // Choose a temporary filename.
- std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(mStoreDiscSet, fn + ".difftemp",
- 1 /* NOT the same disc as the write file, to avoid using lots of space on the same disc unnecessarily */));
-
- try
- {
- // Open it twice
-#ifdef WIN32
- InvisibleTempFileStream diff(tempFn.c_str(),
- O_RDWR | O_CREAT | O_BINARY);
- InvisibleTempFileStream diff2(tempFn.c_str(),
- O_RDWR | O_BINARY);
-#else
- FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL);
- FileStream diff2(tempFn.c_str(), O_RDONLY);
-
- // Unlink it immediately, so it definitely goes away
- if(::unlink(tempFn.c_str()) != 0)
- {
- THROW_EXCEPTION(CommonException, OSFileError);
- }
-#endif
-
- // Stream the incoming diff to this temporary file
- if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT))
- {
- THROW_EXCEPTION(BackupStoreException, ReadFileFromStreamTimedOut)
- }
-
- // Verify the diff
- diff.Seek(0, IOStream::SeekType_Absolute);
- if(!BackupStoreFile::VerifyEncodedFileFormat(diff))
- {
- THROW_EXCEPTION(BackupStoreException, AddedFileDoesNotVerify)
- }
-
- // Seek to beginning of diff file
- diff.Seek(0, IOStream::SeekType_Absolute);
-
- // Filename of the old version
- std::string oldVersionFilename;
- MakeObjectFilename(DiffFromFileID, oldVersionFilename, false /* no need to make sure the directory it's in exists */);
-
- // Reassemble that diff -- open previous file, and combine the patch and file
- std::auto_ptr<RaidFileRead> from(RaidFileRead::Open(mStoreDiscSet, oldVersionFilename));
- BackupStoreFile::CombineFile(diff, diff2, *from, storeFile);
-
- // Then... reverse the patch back (open the from file again, and create a write file to overwrite it)
- std::auto_ptr<RaidFileRead> from2(RaidFileRead::Open(mStoreDiscSet, oldVersionFilename));
- ppreviousVerStoreFile = new RaidFileWrite(mStoreDiscSet, oldVersionFilename);
- ppreviousVerStoreFile->Open(true /* allow overwriting */);
- from->Seek(0, IOStream::SeekType_Absolute);
- diff.Seek(0, IOStream::SeekType_Absolute);
- BackupStoreFile::ReverseDiffFile(diff, *from, *from2, *ppreviousVerStoreFile,
- DiffFromFileID, &reversedDiffIsCompletelyDifferent);
-
- // Store disc space used
- oldVersionNewBlocksUsed = ppreviousVerStoreFile->GetDiscUsageInBlocks();
-
- // And make a space adjustment for the size calculation
- spaceSavedByConversionToPatch =
- from->GetDiscUsageInBlocks() -
- oldVersionNewBlocksUsed;
-
- // Everything cleans up here...
- }
- catch(...)
- {
- // Be very paranoid about deleting this temp file -- we could only leave a zero byte file anyway
- ::unlink(tempFn.c_str());
- throw;
- }
- }
-
- // Get the blocks used
- newObjectBlocksUsed = storeFile.GetDiscUsageInBlocks();
-
- // Exceeds the hard limit?
- int64_t newBlocksUsed = mapStoreInfo->GetBlocksUsed() +
- newObjectBlocksUsed - spaceSavedByConversionToPatch;
- if(newBlocksUsed > mapStoreInfo->GetBlocksHardLimit())
- {
- THROW_EXCEPTION(BackupStoreException, AddedFileExceedsStorageLimit)
- // The store file will be deleted automatically by the RaidFile object
- }
-
- // Commit the file
- storeFile.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
- }
- catch(...)
- {
- // Delete any previous version store file
- if(ppreviousVerStoreFile != 0)
- {
- delete ppreviousVerStoreFile;
- ppreviousVerStoreFile = 0;
- }
-
- throw;
- }
-
- // Verify the file -- only necessary for non-diffed versions
- // NOTE: No need to catch exceptions and delete ppreviousVerStoreFile, because
- // in the non-diffed code path it's never allocated.
- if(DiffFromFileID == 0)
- {
- std::auto_ptr<RaidFileRead> checkFile(RaidFileRead::Open(mStoreDiscSet, fn));
- if(!BackupStoreFile::VerifyEncodedFileFormat(*checkFile))
- {
- // Error! Delete the file
- RaidFileWrite del(mStoreDiscSet, fn);
- del.Delete();
-
- // Exception
- THROW_EXCEPTION(BackupStoreException, AddedFileDoesNotVerify)
- }
- }
-
- // Modify the directory -- first make all files with the same name
- // marked as an old version
- int64_t blocksInOldFiles = 0;
- try
- {
- if(MarkFileWithSameNameAsOldVersions)
- {
- BackupStoreDirectory::Iterator i(dir);
-
- BackupStoreDirectory::Entry *e = 0;
- while((e = i.Next()) != 0)
- {
- // First, check it's not an old version (cheaper comparison)
- if(! e->IsOld())
- {
- // Compare name
- if(e->GetName() == rFilename)
- {
- // Check that it's definately not an old version
- ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0);
- // Set old version flag
- e->AddFlags(BackupStoreDirectory::Entry::Flags_OldVersion);
- // Can safely do this, because we know we won't be here if it's already
- // an old version
- blocksInOldFiles += e->GetSizeInBlocks();
- }
- }
- }
- }
-
- // Then the new entry
- BackupStoreDirectory::Entry *pnewEntry = dir.AddEntry(rFilename,
- ModificationTime, id, newObjectBlocksUsed,
- BackupStoreDirectory::Entry::Flags_File,
- AttributesHash);
-
- // Adjust for the patch back stuff?
- if(DiffFromFileID != 0)
- {
- // Get old version entry
- BackupStoreDirectory::Entry *poldEntry = dir.FindEntryByID(DiffFromFileID);
- ASSERT(poldEntry != 0);
-
- // Adjust dependency info of file?
- if(!reversedDiffIsCompletelyDifferent)
- {
- poldEntry->SetDependsNewer(id);
- pnewEntry->SetDependsOlder(DiffFromFileID);
- }
-
- // Adjust size of old entry
- int64_t oldSize = poldEntry->GetSizeInBlocks();
- poldEntry->SetSizeInBlocks(oldVersionNewBlocksUsed);
-
- // And adjust blocks used count, for later adjustment
- newObjectBlocksUsed += (oldVersionNewBlocksUsed - oldSize);
- blocksInOldFiles += (oldVersionNewBlocksUsed - oldSize);
- }
-
- // Write the directory back to disc
- SaveDirectory(dir, InDirectory);
-
- // Commit the old version's new patched version, now that the directory safely reflects
- // the state of the files on disc.
- if(ppreviousVerStoreFile != 0)
- {
- ppreviousVerStoreFile->Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
- delete ppreviousVerStoreFile;
- ppreviousVerStoreFile = 0;
- }
- }
- catch(...)
- {
- // Back out on adding that file
- RaidFileWrite del(mStoreDiscSet, fn);
- del.Delete();
-
- // Remove this entry from the cache
- RemoveDirectoryFromCache(InDirectory);
-
- // Delete any previous version store file
- if(ppreviousVerStoreFile != 0)
- {
- delete ppreviousVerStoreFile;
- ppreviousVerStoreFile = 0;
- }
-
- // Don't worry about the incremented number in the store info
- throw;
- }
-
- // Check logic
- ASSERT(ppreviousVerStoreFile == 0);
-
- // Modify the store info
-
- if(DiffFromFileID == 0)
- {
- mapStoreInfo->AdjustNumFiles(1);
- }
- else
- {
- mapStoreInfo->AdjustNumOldFiles(1);
- }
-
- mapStoreInfo->ChangeBlocksUsed(newObjectBlocksUsed);
- mapStoreInfo->ChangeBlocksInCurrentFiles(newObjectBlocksUsed -
- blocksInOldFiles);
- mapStoreInfo->ChangeBlocksInOldFiles(blocksInOldFiles);
-
- // Increment reference count on the new directory to one
- mapRefCount->AddReference(id);
-
- // Save the store info -- can cope if this exceptions because infomation
- // will be rebuilt by housekeeping, and ID allocation can recover.
- SaveStoreInfo(false);
-
- // Return the ID to the caller
- return id;
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &)
-// Purpose: Deletes a file, returning true if the file existed. Object ID returned too, set to zero if not found.
-// Created: 2003/10/21
-//
-// --------------------------------------------------------------------------
-bool BackupStoreContext::DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut)
-{
- // Essential checks!
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // Find the directory the file is in (will exception if it fails)
- BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-
- // Setup flags
- bool fileExisted = false;
- bool madeChanges = false;
- rObjectIDOut = 0; // not found
-
- // Count of deleted blocks
- int64_t blocksDel = 0;
-
- try
- {
- // Iterate through directory, only looking at files which haven't been deleted
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *e = 0;
- while((e = i.Next(BackupStoreDirectory::Entry::Flags_File,
- BackupStoreDirectory::Entry::Flags_Deleted)) != 0)
- {
- // Compare name
- if(e->GetName() == rFilename)
- {
- // Check that it's definately not already deleted
- ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) == 0);
- // Set deleted flag
- e->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
- // Mark as made a change
- madeChanges = true;
- // Can safely do this, because we know we won't be here if it's already
- // an old version
- blocksDel += e->GetSizeInBlocks();
- // Is this the last version?
- if((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0)
- {
- // Yes. It's been found.
- rObjectIDOut = e->GetObjectID();
- fileExisted = true;
- }
- }
- }
-
- // Save changes?
- if(madeChanges)
- {
- // Save the directory back
- SaveDirectory(dir, InDirectory);
-
- // Modify the store info, and write
- // It definitely wasn't an old or deleted version
- mapStoreInfo->AdjustNumFiles(-1);
- mapStoreInfo->AdjustNumDeletedFiles(1);
- mapStoreInfo->ChangeBlocksInDeletedFiles(blocksDel);
-
- SaveStoreInfo(false);
- }
- }
- catch(...)
- {
- RemoveDirectoryFromCache(InDirectory);
- throw;
- }
-
- return fileExisted;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::UndeleteFile(int64_t, int64_t)
-// Purpose: Undeletes a file, if it exists, returning true if
-// the file existed.
-// Created: 2003/10/21
-//
-// --------------------------------------------------------------------------
-bool BackupStoreContext::UndeleteFile(int64_t ObjectID, int64_t InDirectory)
-{
- // Essential checks!
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // Find the directory the file is in (will exception if it fails)
- BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-
- // Setup flags
- bool fileExisted = false;
- bool madeChanges = false;
-
- // Count of deleted blocks
- int64_t blocksDel = 0;
-
- try
- {
- // Iterate through directory, only looking at files which have been deleted
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *e = 0;
- while((e = i.Next(BackupStoreDirectory::Entry::Flags_File |
- BackupStoreDirectory::Entry::Flags_Deleted, 0)) != 0)
- {
- // Compare name
- if(e->GetObjectID() == ObjectID)
- {
- // Check that it's definitely already deleted
- ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0);
- // Clear deleted flag
- e->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted);
- // Mark as made a change
- madeChanges = true;
- blocksDel -= e->GetSizeInBlocks();
-
- // Is this the last version?
- if((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0)
- {
- // Yes. It's been found.
- fileExisted = true;
- }
- }
- }
-
- // Save changes?
- if(madeChanges)
- {
- // Save the directory back
- SaveDirectory(dir, InDirectory);
-
- // Modify the store info, and write
- mapStoreInfo->ChangeBlocksInDeletedFiles(blocksDel);
-
- // Maybe postponed save of store info
- SaveStoreInfo();
- }
- }
- catch(...)
- {
- RemoveDirectoryFromCache(InDirectory);
- throw;
- }
-
- return fileExisted;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::RemoveDirectoryFromCache(int64_t)
-// Purpose: Remove directory from cache
-// Created: 2003/09/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::RemoveDirectoryFromCache(int64_t ObjectID)
-{
- std::map<int64_t, BackupStoreDirectory*>::iterator item(mDirectoryCache.find(ObjectID));
- if(item != mDirectoryCache.end())
- {
- // Delete this cached object
- delete item->second;
- // Erase the entry form the map
- mDirectoryCache.erase(item);
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::SaveDirectory(BackupStoreDirectory &, int64_t)
-// Purpose: Save directory back to disc, update time in cache
-// Created: 2003/09/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(rDir.GetObjectID() != ObjectID)
- {
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
-
- try
- {
- // Write to disc, adjust size in store info
- std::string dirfn;
- MakeObjectFilename(ObjectID, dirfn);
- {
- RaidFileWrite writeDir(mStoreDiscSet, dirfn);
- writeDir.Open(true /* allow overwriting */);
-
- BufferedWriteStream buffer(writeDir);
- rDir.WriteToStream(buffer);
- buffer.Flush();
-
- // get the disc usage (must do this before commiting it)
- int64_t dirSize = writeDir.GetDiscUsageInBlocks();
-
- // Commit directory
- writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
-
- // Make sure the size of the directory is available for writing the dir back
- ASSERT(dirSize > 0);
- int64_t sizeAdjustment = dirSize - rDir.GetUserInfo1_SizeInBlocks();
- mapStoreInfo->ChangeBlocksUsed(sizeAdjustment);
- mapStoreInfo->ChangeBlocksInDirectories(sizeAdjustment);
- // Update size stored in directory
- rDir.SetUserInfo1_SizeInBlocks(dirSize);
- }
- // Refresh revision ID in cache
- {
- int64_t revid = 0;
- if(!RaidFileRead::FileExists(mStoreDiscSet, dirfn, &revid))
- {
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
- rDir.SetRevisionID(revid);
- }
- }
- catch(...)
- {
- // Remove it from the cache if anything went wrong
- RemoveDirectoryFromCache(ObjectID);
- throw;
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::AddDirectory(int64_t,
-// const BackupStoreFilename &, bool &)
-// Purpose: Creates a directory (or just returns the ID of an
-// existing one). rAlreadyExists set appropraitely.
-// Created: 2003/09/04
-//
-// --------------------------------------------------------------------------
-int64_t BackupStoreContext::AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // Flags as not already existing
- rAlreadyExists = false;
-
- // Get the directory we want to modify
- BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-
- // Scan the directory for the name (only looking for directories which already exist)
- {
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *en = 0;
- while((en = i.Next(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING,
- BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)) != 0) // Ignore deleted and old directories
- {
- if(en->GetName() == rFilename)
- {
- // Already exists
- rAlreadyExists = true;
- return en->GetObjectID();
- }
- }
- }
-
- // Allocate the next ID
- int64_t id = AllocateObjectID();
-
- // Create an empty directory with the given attributes on disc
- std::string fn;
- MakeObjectFilename(id, fn, true /* make sure the directory it's in exists */);
- {
- BackupStoreDirectory emptyDir(id, InDirectory);
- // add the atttribues
- emptyDir.SetAttributes(Attributes, AttributesModTime);
-
- // Write...
- RaidFileWrite dirFile(mStoreDiscSet, fn);
- dirFile.Open(false /* no overwriting */);
- emptyDir.WriteToStream(dirFile);
- // Get disc usage, before it's commited
- int64_t dirSize = dirFile.GetDiscUsageInBlocks();
- // Commit the file
- dirFile.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
-
- // Make sure the size of the directory is added to the usage counts in the info
- ASSERT(dirSize > 0);
- mapStoreInfo->ChangeBlocksUsed(dirSize);
- mapStoreInfo->ChangeBlocksInDirectories(dirSize);
- // Not added to cache, so don't set the size in the directory
- }
-
- // Then add it into the parent directory
- try
- {
- dir.AddEntry(rFilename, 0 /* modification time */, id, 0 /* blocks used */, BackupStoreDirectory::Entry::Flags_Dir, 0 /* attributes mod time */);
- SaveDirectory(dir, InDirectory);
-
- // Increment reference count on the new directory to one
- mapRefCount->AddReference(id);
- }
- catch(...)
- {
- // Back out on adding that directory
- RaidFileWrite del(mStoreDiscSet, fn);
- del.Delete();
-
- // Remove this entry from the cache
- RemoveDirectoryFromCache(InDirectory);
-
- // Don't worry about the incremented number in the store info
- throw;
- }
-
- // Save the store info (may not be postponed)
- mapStoreInfo->AdjustNumDirectories(1);
- SaveStoreInfo(false);
-
- // tell caller what the ID was
- return id;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &, bool)
-// Purpose: Recusively deletes a directory (or undeletes if Undelete = true)
-// Created: 2003/10/21
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::DeleteDirectory(int64_t ObjectID, bool Undelete)
-{
- // Essential checks!
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // Containing directory
- int64_t InDirectory = 0;
-
- // Count of blocks deleted
- int64_t blocksDeleted = 0;
-
- try
- {
- // Get the directory that's to be deleted
- {
- // In block, because dir may not be valid after the delete directory call
- BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
-
- // Store the directory it's in for later
- InDirectory = dir.GetContainerID();
-
- // Depth first delete of contents
- DeleteDirectoryRecurse(ObjectID, blocksDeleted, Undelete);
- }
-
- // Remove the entry from the directory it's in
- ASSERT(InDirectory != 0);
- BackupStoreDirectory &parentDir(GetDirectoryInternal(InDirectory));
-
- BackupStoreDirectory::Iterator i(parentDir);
- BackupStoreDirectory::Entry *en = 0;
- while((en = i.Next(Undelete?(BackupStoreDirectory::Entry::Flags_Deleted):(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING),
- Undelete?(0):(BackupStoreDirectory::Entry::Flags_Deleted))) != 0) // Ignore deleted directories (or not deleted if Undelete)
- {
- if(en->GetObjectID() == ObjectID)
- {
- // This is the one to delete
- if(Undelete)
- {
- en->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted);
- }
- else
- {
- en->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
- }
-
- // Save it
- SaveDirectory(parentDir, InDirectory);
-
- // Done
- break;
- }
- }
-
- // Update blocks deleted count
- mapStoreInfo->ChangeBlocksInDeletedFiles(Undelete?(0 - blocksDeleted):(blocksDeleted));
- mapStoreInfo->AdjustNumDirectories(-1);
- SaveStoreInfo(false);
- }
- catch(...)
- {
- RemoveDirectoryFromCache(InDirectory);
- throw;
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::DeleteDirectoryRecurse(BackupStoreDirectory &, int64_t)
-// Purpose: Private. Deletes a directory depth-first recusively.
-// Created: 2003/10/21
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete)
-{
- try
- {
- // Does things carefully to avoid using a directory in the cache after recursive call
- // because it may have been deleted.
-
- // Do sub directories
- {
- // Get the directory...
- BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
-
- // Then scan it for directories
- std::vector<int64_t> subDirs;
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *en = 0;
- if(Undelete)
- {
- while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir | BackupStoreDirectory::Entry::Flags_Deleted, // deleted dirs
- BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING)) != 0)
- {
- // Store the directory ID.
- subDirs.push_back(en->GetObjectID());
- }
- }
- else
- {
- while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir, // dirs only
- BackupStoreDirectory::Entry::Flags_Deleted)) != 0) // but not deleted ones
- {
- // Store the directory ID.
- subDirs.push_back(en->GetObjectID());
- }
- }
-
- // Done with the directory for now. Recurse to sub directories
- for(std::vector<int64_t>::const_iterator i = subDirs.begin(); i != subDirs.end(); ++i)
- {
- DeleteDirectoryRecurse((*i), rBlocksDeletedOut, Undelete);
- }
- }
-
- // Then, delete the files. Will need to load the directory again because it might have
- // been removed from the cache.
- {
- // Get the directory...
- BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
-
- // Changes made?
- bool changesMade = false;
-
- // Run through files
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *en = 0;
-
- while((en = i.Next(Undelete?(BackupStoreDirectory::Entry::Flags_Deleted):(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING),
- Undelete?(0):(BackupStoreDirectory::Entry::Flags_Deleted))) != 0) // Ignore deleted directories (or not deleted if Undelete)
- {
- // Add/remove the deleted flags
- if(Undelete)
- {
- en->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted);
- }
- else
- {
- en->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
- }
-
- // Keep count of the deleted blocks
- if((en->GetFlags() & BackupStoreDirectory::Entry::Flags_File) != 0)
- {
- rBlocksDeletedOut += en->GetSizeInBlocks();
- }
-
- // Did something
- changesMade = true;
- }
-
- // Save the directory
- if(changesMade)
- {
- SaveDirectory(dir, ObjectID);
- }
- }
- }
- catch(...)
- {
- RemoveDirectoryFromCache(ObjectID);
- throw;
- }
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::ChangeDirAttributes(int64_t, const StreamableMemBlock &, int64_t)
-// Purpose: Change the attributes of a directory
-// Created: 2003/09/06
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- try
- {
- // Get the directory we want to modify
- BackupStoreDirectory &dir(GetDirectoryInternal(Directory));
-
- // Set attributes
- dir.SetAttributes(Attributes, AttributesModTime);
-
- // Save back
- SaveDirectory(dir, Directory);
- }
- catch(...)
- {
- RemoveDirectoryFromCache(Directory);
- throw;
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::ChangeFileAttributes(int64_t, int64_t, const StreamableMemBlock &, int64_t)
-// Purpose: Sets the attributes on a directory entry. Returns true if the object existed, false if it didn't.
-// Created: 2003/09/06
-//
-// --------------------------------------------------------------------------
-bool BackupStoreContext::ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- try
- {
- // Get the directory we want to modify
- BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-
- // Find the file entry
- BackupStoreDirectory::Entry *en = 0;
- // Iterate through current versions of files, only
- BackupStoreDirectory::Iterator i(dir);
- while((en = i.Next(
- BackupStoreDirectory::Entry::Flags_File,
- BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)
- ) != 0)
- {
- if(en->GetName() == rFilename)
- {
- // Set attributes
- en->SetAttributes(Attributes, AttributesHash);
-
- // Tell caller the object ID
- rObjectIDOut = en->GetObjectID();
-
- // Done
- break;
- }
- }
- if(en == 0)
- {
- // Didn't find it
- return false;
- }
-
- // Save back
- SaveDirectory(dir, InDirectory);
- }
- catch(...)
- {
- RemoveDirectoryFromCache(InDirectory);
- throw;
- }
-
- // Changed, everything OK
- return true;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::ObjectExists(int64_t)
-// Purpose: Test to see if an object of this ID exists in the store
-// Created: 2003/09/03
-//
-// --------------------------------------------------------------------------
-bool BackupStoreContext::ObjectExists(int64_t ObjectID, int MustBe)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- // Note that we need to allow object IDs a little bit greater than the last one in the store info,
- // because the store info may not have got saved in an error condition. Max greater ID is
- // STORE_INFO_SAVE_DELAY in this case, *2 to be safe.
- if(ObjectID <= 0 || ObjectID > (mapStoreInfo->GetLastObjectIDUsed() + (STORE_INFO_SAVE_DELAY * 2)))
- {
- // Obviously bad object ID
- return false;
- }
-
- // Test to see if it exists on the disc
- std::string filename;
- MakeObjectFilename(ObjectID, filename);
- if(!RaidFileRead::FileExists(mStoreDiscSet, filename))
- {
- // RaidFile reports no file there
- return false;
- }
-
- // Do we need to be more specific?
- if(MustBe != ObjectExists_Anything)
- {
- // Open the file
- std::auto_ptr<RaidFileRead> objectFile(RaidFileRead::Open(mStoreDiscSet, filename));
-
- // Read the first integer
- u_int32_t magic;
- if(!objectFile->ReadFullBuffer(&magic, sizeof(magic), 0 /* not interested in how many read if failure */))
- {
- // Failed to get any bytes, must have failed
- return false;
- }
-
-#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
- if(MustBe == ObjectExists_File && ntohl(magic) == OBJECTMAGIC_FILE_MAGIC_VALUE_V0)
- {
- // Old version detected
- return true;
- }
-#endif
-
- // Right one?
- u_int32_t requiredMagic = (MustBe == ObjectExists_File)?OBJECTMAGIC_FILE_MAGIC_VALUE_V1:OBJECTMAGIC_DIR_MAGIC_VALUE;
-
- // Check
- if(ntohl(magic) != requiredMagic)
- {
- return false;
- }
-
- // File is implicitly closed
- }
-
- return true;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::OpenObject(int64_t)
-// Purpose: Opens an object
-// Created: 2003/09/03
-//
-// --------------------------------------------------------------------------
-std::auto_ptr<IOStream> BackupStoreContext::OpenObject(int64_t ObjectID)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- // Attempt to open the file
- std::string fn;
- MakeObjectFilename(ObjectID, fn);
- return std::auto_ptr<IOStream>(RaidFileRead::Open(mStoreDiscSet, fn).release());
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::GetClientStoreMarker()
-// Purpose: Retrieve the client store marker
-// Created: 2003/10/29
-//
-// --------------------------------------------------------------------------
-int64_t BackupStoreContext::GetClientStoreMarker()
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- return mapStoreInfo->GetClientStoreMarker();
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::GetStoreDiscUsageInfo(int64_t &, int64_t &, int64_t &)
-// Purpose: Get disc usage info from store info
-// Created: 1/1/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- rBlocksUsed = mapStoreInfo->GetBlocksUsed();
- rBlocksSoftLimit = mapStoreInfo->GetBlocksSoftLimit();
- rBlocksHardLimit = mapStoreInfo->GetBlocksHardLimit();
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::HardLimitExceeded()
-// Purpose: Returns true if the hard limit has been exceeded
-// Created: 1/1/04
-//
-// --------------------------------------------------------------------------
-bool BackupStoreContext::HardLimitExceeded()
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- return mapStoreInfo->GetBlocksUsed() > mapStoreInfo->GetBlocksHardLimit();
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::SetClientStoreMarker(int64_t)
-// Purpose: Sets the client store marker, and commits it to disc
-// Created: 2003/10/29
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::SetClientStoreMarker(int64_t ClientStoreMarker)
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- mapStoreInfo->SetClientStoreMarker(ClientStoreMarker);
- SaveStoreInfo(false /* don't delay saving this */);
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::MoveObject(int64_t, int64_t, int64_t, const BackupStoreFilename &, bool)
-// Purpose: Move an object (and all objects with the same name) from one directory to another
-// Created: 12/11/03
-//
-// --------------------------------------------------------------------------
-void BackupStoreContext::MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject)
-{
- if(mReadOnly)
- {
- THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
- }
-
- // Should deleted files be excluded when checking for the existance of objects with the target name?
- int64_t targetSearchExcludeFlags = (AllowMoveOverDeletedObject)
- ?(BackupStoreDirectory::Entry::Flags_Deleted)
- :(BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
-
- // Special case if the directories are the same...
- if(MoveFromDirectory == MoveToDirectory)
- {
- try
- {
- // Get the first directory
- BackupStoreDirectory &dir(GetDirectoryInternal(MoveFromDirectory));
-
- // Find the file entry
- BackupStoreDirectory::Entry *en = dir.FindEntryByID(ObjectID);
-
- // Error if not found
- if(en == 0)
- {
- THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
- }
-
- // Check the new name doens't already exist (optionally ignoring deleted files)
- {
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *c = 0;
- while((c = i.Next(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, targetSearchExcludeFlags)) != 0)
- {
- if(c->GetName() == rNewFilename)
- {
- THROW_EXCEPTION(BackupStoreException, NameAlreadyExistsInDirectory)
- }
- }
- }
-
- // Need to get all the entries with the same name?
- if(MoveAllWithSameName)
- {
- // Iterate through the directory, copying all with matching names
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *c = 0;
- while((c = i.Next()) != 0)
- {
- if(c->GetName() == en->GetName())
- {
- // Rename this one
- c->SetName(rNewFilename);
- }
- }
- }
- else
- {
- // Just copy this one
- en->SetName(rNewFilename);
- }
-
- // Save the directory back
- SaveDirectory(dir, MoveFromDirectory);
- }
- catch(...)
- {
- RemoveDirectoryFromCache(MoveToDirectory); // either will do, as they're the same
- throw;
- }
-
- return;
- }
-
- // Got to be careful how this is written, as we can't guarentte that if we have two
- // directories open, the first won't be deleted as the second is opened. (cache)
-
- // List of entries to move
- std::vector<BackupStoreDirectory::Entry *> moving;
-
- // list of directory IDs which need to have containing dir id changed
- std::vector<int64_t> dirsToChangeContainingID;
-
- try
- {
- // First of all, get copies of the entries to move to the to directory.
-
- {
- // Get the first directory
- BackupStoreDirectory &from(GetDirectoryInternal(MoveFromDirectory));
-
- // Find the file entry
- BackupStoreDirectory::Entry *en = from.FindEntryByID(ObjectID);
-
- // Error if not found
- if(en == 0)
- {
- THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
- }
-
- // Need to get all the entries with the same name?
- if(MoveAllWithSameName)
- {
- // Iterate through the directory, copying all with matching names
- BackupStoreDirectory::Iterator i(from);
- BackupStoreDirectory::Entry *c = 0;
- while((c = i.Next()) != 0)
- {
- if(c->GetName() == en->GetName())
- {
- // Copy
- moving.push_back(new BackupStoreDirectory::Entry(*c));
-
- // Check for containing directory correction
- if(c->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) dirsToChangeContainingID.push_back(c->GetObjectID());
- }
- }
- ASSERT(!moving.empty());
- }
- else
- {
- // Just copy this one
- moving.push_back(new BackupStoreDirectory::Entry(*en));
-
- // Check for containing directory correction
- if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) dirsToChangeContainingID.push_back(en->GetObjectID());
- }
- }
-
- // Secondly, insert them into the to directory, and save it
-
- {
- // To directory
- BackupStoreDirectory &to(GetDirectoryInternal(MoveToDirectory));
-
- // Check the new name doens't already exist
- {
- BackupStoreDirectory::Iterator i(to);
- BackupStoreDirectory::Entry *c = 0;
- while((c = i.Next(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, targetSearchExcludeFlags)) != 0)
- {
- if(c->GetName() == rNewFilename)
- {
- THROW_EXCEPTION(BackupStoreException, NameAlreadyExistsInDirectory)
- }
- }
- }
-
- // Copy the entries into it, changing the name as we go
- for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
- {
- BackupStoreDirectory::Entry *en = (*i);
- en->SetName(rNewFilename);
- to.AddEntry(*en); // adds copy
- }
-
- // Save back
- SaveDirectory(to, MoveToDirectory);
- }
-
- // Thirdly... remove them from the first directory -- but if it fails, attempt to delete them from the to directory
- try
- {
- // Get directory
- BackupStoreDirectory &from(GetDirectoryInternal(MoveFromDirectory));
-
- // Delete each one
- for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
- {
- from.DeleteEntry((*i)->GetObjectID());
- }
-
- // Save back
- SaveDirectory(from, MoveFromDirectory);
- }
- catch(...)
- {
- // UNDO modification to To directory
-
- // Get directory
- BackupStoreDirectory &to(GetDirectoryInternal(MoveToDirectory));
-
- // Delete each one
- for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
- {
- to.DeleteEntry((*i)->GetObjectID());
- }
-
- // Save back
- SaveDirectory(to, MoveToDirectory);
-
- // Throw the error
- throw;
- }
-
- // Finally... for all the directories we moved, modify their containing directory ID
- for(std::vector<int64_t>::iterator i(dirsToChangeContainingID.begin()); i != dirsToChangeContainingID.end(); ++i)
- {
- // Load the directory
- BackupStoreDirectory &change(GetDirectoryInternal(*i));
-
- // Modify containing dir ID
- change.SetContainerID(MoveToDirectory);
-
- // Save it back
- SaveDirectory(change, *i);
- }
- }
- catch(...)
- {
- // Make sure directories aren't in the cache, as they may have been modified
- RemoveDirectoryFromCache(MoveToDirectory);
- RemoveDirectoryFromCache(MoveFromDirectory);
- for(std::vector<int64_t>::iterator i(dirsToChangeContainingID.begin()); i != dirsToChangeContainingID.end(); ++i)
- {
- RemoveDirectoryFromCache(*i);
- }
-
- while(!moving.empty())
- {
- delete moving.back();
- moving.pop_back();
- }
- throw;
- }
-
- // Clean up
- while(!moving.empty())
- {
- delete moving.back();
- moving.pop_back();
- }
-}
-
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreContext::GetBackupStoreInfo()
-// Purpose: Return the backup store info object, exception if it isn't loaded
-// Created: 19/4/04
-//
-// --------------------------------------------------------------------------
-const BackupStoreInfo &BackupStoreContext::GetBackupStoreInfo() const
-{
- if(mapStoreInfo.get() == 0)
- {
- THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
- }
-
- return *(mapStoreInfo.get());
-}
-
-
diff --git a/bin/bbstored/BackupStoreContext.h b/bin/bbstored/BackupStoreContext.h
deleted file mode 100644
index 44a05dd8..00000000
--- a/bin/bbstored/BackupStoreContext.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// --------------------------------------------------------------------------
-//
-// File
-// Name: BackupStoreContext.h
-// Purpose: Context for backup store server
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-
-#ifndef BACKUPCONTEXT__H
-#define BACKUPCONTEXT__H
-
-#include <string>
-#include <map>
-#include <memory>
-
-#include "BackupStoreRefCountDatabase.h"
-#include "NamedLock.h"
-#include "ProtocolObject.h"
-#include "Utils.h"
-
-class BackupStoreDirectory;
-class BackupStoreFilename;
-class BackupStoreDaemon;
-class BackupStoreInfo;
-class IOStream;
-class BackupProtocolObject;
-class StreamableMemBlock;
-
-class HousekeepingInterface
-{
- public:
- virtual ~HousekeepingInterface() { }
- virtual void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) = 0;
-};
-
-// --------------------------------------------------------------------------
-//
-// Class
-// Name: BackupStoreContext
-// Purpose: Context for backup store server
-// Created: 2003/08/20
-//
-// --------------------------------------------------------------------------
-class BackupStoreContext
-{
-public:
- BackupStoreContext(int32_t ClientID, HousekeepingInterface &rDaemon);
- ~BackupStoreContext();
-private:
- BackupStoreContext(const BackupStoreContext &rToCopy);
-public:
-
- void ReceivedFinishCommand();
- void CleanUp();
-
- int32_t GetClientID() {return mClientID;}
-
- enum
- {
- Phase_START = 0,
- Phase_Version = 0,
- Phase_Login = 1,
- Phase_Commands = 2
- };
-
- int GetPhase() const {return mProtocolPhase;}
- void SetPhase(int NewPhase) {mProtocolPhase = NewPhase;}
-
- // Read only locking
- bool SessionIsReadOnly() {return mReadOnly;}
- bool AttemptToGetWriteLock();
-
- void SetClientHasAccount(const std::string &rStoreRoot, int StoreDiscSet) {mClientHasAccount = true; mStoreRoot = rStoreRoot; mStoreDiscSet = StoreDiscSet;}
- bool GetClientHasAccount() const {return mClientHasAccount;}
- const std::string &GetStoreRoot() const {return mStoreRoot;}
- int GetStoreDiscSet() const {return mStoreDiscSet;}
-
- // Store info
- void LoadStoreInfo();
- void SaveStoreInfo(bool AllowDelay = true);
- const BackupStoreInfo &GetBackupStoreInfo() const;
-
- // Client marker
- int64_t GetClientStoreMarker();
- void SetClientStoreMarker(int64_t ClientStoreMarker);
-
- // Usage information
- void GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit);
- bool HardLimitExceeded();
-
- // Reading directories
- // --------------------------------------------------------------------------
- //
- // Function
- // Name: BackupStoreContext::GetDirectory(int64_t)
- // Purpose: Return a reference to a directory. Valid only until the
- // next time a function which affects directories is called.
- // Mainly this funciton, and creation of files.
- // Created: 2003/09/02
- //
- // --------------------------------------------------------------------------
- const BackupStoreDirectory &GetDirectory(int64_t ObjectID)
- {
- // External callers aren't allowed to change it -- this function
- // merely turns the the returned directory const.
- return GetDirectoryInternal(ObjectID);
- }
-
- // Manipulating files/directories
- int64_t AddFile(IOStream &rFile, int64_t InDirectory, int64_t ModificationTime, int64_t AttributesHash, int64_t DiffFromFileID, const BackupStoreFilename &rFilename, bool MarkFileWithSameNameAsOldVersions);
- int64_t AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists);
- void ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime);
- bool ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut);
- bool DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut);
- bool UndeleteFile(int64_t ObjectID, int64_t InDirectory);
- void DeleteDirectory(int64_t ObjectID, bool Undelete = false);
- void MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject);
-
- // Manipulating objects
- enum
- {
- ObjectExists_Anything = 0,
- ObjectExists_File = 1,
- ObjectExists_Directory = 2
- };
- bool ObjectExists(int64_t ObjectID, int MustBe = ObjectExists_Anything);
- std::auto_ptr<IOStream> OpenObject(int64_t ObjectID);
-
- // Info
- int32_t GetClientID() const {return mClientID;}
-
-private:
- void MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists = false);
- BackupStoreDirectory &GetDirectoryInternal(int64_t ObjectID);
- void SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID);
- void RemoveDirectoryFromCache(int64_t ObjectID);
- void DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete);
- int64_t AllocateObjectID();
-
- int32_t mClientID;
- HousekeepingInterface &mrDaemon;
- int mProtocolPhase;
- bool mClientHasAccount;
- std::string mStoreRoot; // has final directory separator
- int mStoreDiscSet;
- bool mReadOnly;
- NamedLock mWriteLock;
- int mSaveStoreInfoDelay; // how many times to delay saving the store info
-
- // Store info
- std::auto_ptr<BackupStoreInfo> mapStoreInfo;
-
- // Refcount database
- std::auto_ptr<BackupStoreRefCountDatabase> mapRefCount;
-
- // Directory cache
- std::map<int64_t, BackupStoreDirectory*> mDirectoryCache;
-
-public:
- class TestHook
- {
- public:
- virtual std::auto_ptr<ProtocolObject> StartCommand(BackupProtocolObject&
- rCommand) = 0;
- virtual ~TestHook() { }
- };
- void SetTestHook(TestHook& rTestHook)
- {
- mpTestHook = &rTestHook;
- }
- std::auto_ptr<ProtocolObject> StartCommandHook(BackupProtocolObject& rCommand)
- {
- if(mpTestHook)
- {
- return mpTestHook->StartCommand(rCommand);
- }
- return std::auto_ptr<ProtocolObject>();
- }
-
-private:
- TestHook* mpTestHook;
-};
-
-#endif // BACKUPCONTEXT__H
-
diff --git a/bin/bbstored/Makefile.extra b/bin/bbstored/Makefile.extra
deleted file mode 100644
index 6562647d..00000000
--- a/bin/bbstored/Makefile.extra
+++ /dev/null
@@ -1,9 +0,0 @@
-
-MAKEPROTOCOL = ../../lib/server/makeprotocol.pl
-
-GEN_CMD_SRV = $(MAKEPROTOCOL) Server backupprotocol.txt
-
-# AUTOGEN SEEDING
-autogen_BackupProtocolServer.cpp autogen_BackupProtocolServer.h: $(MAKEPROTOCOL) backupprotocol.txt
- $(_PERL) $(GEN_CMD_SRV)
-
diff --git a/bin/bbstored/backupprotocol.txt b/bin/bbstored/backupprotocol.txt
deleted file mode 100644
index 011458e8..00000000
--- a/bin/bbstored/backupprotocol.txt
+++ /dev/null
@@ -1,235 +0,0 @@
-#
-# backup protocol definition
-#
-
-Name Backup
-IdentString Box-Backup:v=C
-ServerContextClass BackupStoreContext BackupStoreContext.h
-
-ClientType Filename BackupStoreFilenameClear BackupStoreFilenameClear.h
-ServerType Filename BackupStoreFilename BackupStoreFilename.h
-
-ImplementLog Server syslog
-ImplementLog Client syslog
-ImplementLog Client file
-
-LogTypeToText Client Filename \"%s\" VAR.GetClearFilename().c_str()
-
-BEGIN_OBJECTS
-
-# -------------------------------------------------------------------------------------
-# Session commands
-# -------------------------------------------------------------------------------------
-
-Error 0 IsError(Type,SubType) Reply
- int32 Type
- int32 SubType
- CONSTANT ErrorType 1000
- CONSTANT Err_WrongVersion 1
- CONSTANT Err_NotInRightProtocolPhase 2
- CONSTANT Err_BadLogin 3
- CONSTANT Err_CannotLockStoreForWriting 4
- CONSTANT Err_SessionReadOnly 5
- CONSTANT Err_FileDoesNotVerify 6
- CONSTANT Err_DoesNotExist 7
- CONSTANT Err_DirectoryAlreadyExists 8
- CONSTANT Err_CannotDeleteRoot 9
- CONSTANT Err_TargetNameExists 10
- CONSTANT Err_StorageLimitExceeded 11
- CONSTANT Err_DiffFromFileDoesNotExist 12
- CONSTANT Err_DoesNotExistInDirectory 13
- CONSTANT Err_PatchConsistencyError 14
- CONSTANT Err_MultiplyReferencedObject 15
-
-Version 1 Command(Version) Reply
- int32 Version
-
-
-Login 2 Command(LoginConfirmed)
- int32 ClientID
- int32 Flags
- CONSTANT Flags_ReadOnly 1
-
-
-LoginConfirmed 3 Reply
- int64 ClientStoreMarker
- int64 BlocksUsed
- int64 BlocksSoftLimit
- int64 BlocksHardLimit
-
-
-Finished 4 Command(Finished) Reply EndsConversation
-
-
-# generic success object
-Success 5 Reply
- int64 ObjectID
-
-
-SetClientStoreMarker 6 Command(Success)
- int64 ClientStoreMarker
-
-
-# -------------------------------------------------------------------------------------
-# Generic object commands
-# -------------------------------------------------------------------------------------
-
-GetObject 10 Command(Success)
- int64 ObjectID
- CONSTANT NoObject 0
- # reply has stream following, if ObjectID != NoObject
-
-
-MoveObject 11 Command(Success)
- int64 ObjectID
- int64 MoveFromDirectory
- int64 MoveToDirectory
- int32 Flags
- Filename NewFilename
-
- CONSTANT Flags_MoveAllWithSameName 1
- CONSTANT Flags_AllowMoveOverDeletedObject 2
-
-# consider this an object command as, although it deals with directory entries,
-# it's not specific to either a file or a directory
-
-
-GetObjectName 12 Command(ObjectName)
- int64 ObjectID
- int64 ContainingDirectoryID
- CONSTANT ObjectID_DirectoryOnly 0
-
- # set ObjectID to ObjectID_DirectoryOnly to only get info on the directory
-
-
-ObjectName 13 Reply
- int32 NumNameElements
- int64 ModificationTime
- int64 AttributesHash
- int16 Flags
- # NumNameElements is zero if the object doesn't exist
- CONSTANT NumNameElements_ObjectDoesntExist 0
- # a stream of Filename objects follows, if and only if NumNameElements > 0
-
-
-# -------------------------------------------------------------------------------------
-# Directory commands
-# -------------------------------------------------------------------------------------
-
-CreateDirectory 20 Command(Success) StreamWithCommand
- int64 ContainingDirectoryID
- int64 AttributesModTime
- Filename DirectoryName
- # stream following containing attributes
-
-
-ListDirectory 21 Command(Success)
- int64 ObjectID
- int16 FlagsMustBeSet
- int16 FlagsNotToBeSet
- bool SendAttributes
- # make sure these flags are synced with those in BackupStoreDirectory
- CONSTANT Flags_INCLUDE_EVERYTHING -1
- CONSTANT Flags_EXCLUDE_NOTHING 0
- CONSTANT Flags_EXCLUDE_EVERYTHING 15
- CONSTANT Flags_File 1
- CONSTANT Flags_Dir 2
- CONSTANT Flags_Deleted 4
- CONSTANT Flags_OldVersion 8
- # make sure this is the same as in BackupStoreConstants.h
- CONSTANT RootDirectory 1
-
- # reply has stream following Success object, containing a stored BackupStoreDirectory
-
-
-ChangeDirAttributes 22 Command(Success) StreamWithCommand
- int64 ObjectID
- int64 AttributesModTime
- # stream following containing attributes
-
-
-DeleteDirectory 23 Command(Success)
- int64 ObjectID
-
-UndeleteDirectory 24 Command(Success)
- int64 ObjectID
- # may not have exactly the desired effect if files within in have been deleted before the directory was deleted.
-
-
-# -------------------------------------------------------------------------------------
-# File commands
-# -------------------------------------------------------------------------------------
-
-StoreFile 30 Command(Success) StreamWithCommand
- int64 DirectoryObjectID
- int64 ModificationTime
- int64 AttributesHash
- int64 DiffFromFileID # 0 if the file is not a diff
- Filename Filename
- # then send a stream containing the encoded file
-
-
-GetFile 31 Command(Success)
- int64 InDirectory
- int64 ObjectID
- # error returned if not a file, or does not exist
- # reply has stream following, containing an encoded file IN STREAM ORDER
- # (use GetObject to get it in file order)
-
-
-SetReplacementFileAttributes 32 Command(Success) StreamWithCommand
- int64 InDirectory
- int64 AttributesHash
- Filename Filename
- # stream follows containing attributes
-
-
-DeleteFile 33 Command(Success)
- int64 InDirectory
- Filename Filename
- # will return 0 if the object couldn't be found in the specified directory
-
-
-GetBlockIndexByID 34 Command(Success)
- int64 ObjectID
-
- # stream of the block index follows the reply
- # returns an error if the object didn't exist
-
-
-GetBlockIndexByName 35 Command(Success)
- int64 InDirectory
- Filename Filename
-
- # Success object contains the found ID -- or 0 if the entry wasn't found in the directory
- # stream of the block index follows the reply if found ID != 0
-
-
-UndeleteFile 36 Command(Success)
- int64 InDirectory
- int64 ObjectID
- # will return 0 if the object couldn't be found in the specified directory
-
-
-# -------------------------------------------------------------------------------------
-# Information commands
-# -------------------------------------------------------------------------------------
-
-GetAccountUsage 40 Command(AccountUsage)
- # no data members
-
-AccountUsage 41 Reply
- int64 BlocksUsed
- int64 BlocksInOldFiles
- int64 BlocksInDeletedFiles
- int64 BlocksInDirectories
- int64 BlocksSoftLimit
- int64 BlocksHardLimit
- int32 BlockSize
-
-GetIsAlive 42 Command(IsAlive)
- # no data members
-
-IsAlive 43 Reply
- # no data members
-