diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/bbstored/BackupCommands.cpp | 959 | ||||
-rw-r--r-- | bin/bbstored/BackupConstants.h | 21 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreContext.cpp | 1808 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreContext.h | 186 | ||||
-rw-r--r-- | bin/bbstored/Makefile.extra | 9 | ||||
-rw-r--r-- | bin/bbstored/backupprotocol.txt | 235 |
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 - |