diff options
Diffstat (limited to 'lib/backupclient/BackupClientRestore.cpp')
-rw-r--r-- | lib/backupclient/BackupClientRestore.cpp | 289 |
1 files changed, 216 insertions, 73 deletions
diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index b5a54964..b1c5cd0f 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -193,6 +193,8 @@ typedef struct { bool PrintDots; bool RestoreDeleted; + bool ContinueAfterErrors; + bool ContinuedAfterError; std::string mRestoreResumeInfoFilename; RestoreResumeInfo mResumeInfo; } RestoreParams; @@ -202,20 +204,26 @@ typedef struct // -------------------------------------------------------------------------- // // Function -// Name: BackupClientRestoreDir(BackupProtocolClient &, int64_t, const char *, bool) +// Name: BackupClientRestoreDir(BackupProtocolClient &, +// int64_t, const char *, bool) // Purpose: Restore a directory // Created: 23/11/03 // // -------------------------------------------------------------------------- -static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t DirectoryID, std::string &rLocalDirectoryName, +static int BackupClientRestoreDir(BackupProtocolClient &rConnection, + int64_t DirectoryID, std::string &rLocalDirectoryName, RestoreParams &Params, RestoreResumeInfo &rLevel) { - // If we're resuming... check that we haven't got a next level to look at + // If we're resuming... check that we haven't got a next level to + // look at if(rLevel.mpNextLevel != 0) { // Recurse immediately - std::string localDirname(rLocalDirectoryName + DIRECTORY_SEPARATOR_ASCHAR + rLevel.mNextLevelLocalName); - BackupClientRestoreDir(rConnection, rLevel.mNextLevelID, localDirname, Params, *rLevel.mpNextLevel); + std::string localDirname(rLocalDirectoryName + + DIRECTORY_SEPARATOR_ASCHAR + + rLevel.mNextLevelLocalName); + BackupClientRestoreDir(rConnection, rLevel.mNextLevelID, + localDirname, Params, *rLevel.mpNextLevel); // Add it to the list of done itmes rLevel.mRestoredObjects.insert(rLevel.mNextLevelID); @@ -259,22 +267,23 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir break; case ObjectExists_File: { - // File exists with this name, which is fun. Get rid of it. + // File exists with this name, which is fun. + // Get rid of it. BOX_WARNING("File present with name '" << - rLocalDirectoryName << "', removing " << + rLocalDirectoryName << "', removing " "out of the way of restored directory. " "Use specific restore with ID to " "restore this object."); if(::unlink(rLocalDirectoryName.c_str()) != 0) { - BOX_ERROR("Failed to delete file " << - rLocalDirectoryName << ": " << - strerror(errno)); + BOX_LOG_SYS_ERROR("Failed to delete " + "file '" << + rLocalDirectoryName << "'"); return Restore_UnknownError; } BOX_TRACE("In restore, directory name " - "collision with file " << - rLocalDirectoryName); + "collision with file '" << + rLocalDirectoryName << "'"); } break; case ObjectExists_NoObject: @@ -378,10 +387,17 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir exists == ObjectExists_File) && ::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0) { - BOX_ERROR("Failed to create directory '" << - rLocalDirectoryName << "': " << - strerror(errno)); - return Restore_UnknownError; + BOX_LOG_SYS_ERROR("Failed to create directory '" << + rLocalDirectoryName << "'"); + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } // Save the restore info, in case it's needed later @@ -394,23 +410,39 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir BOX_ERROR("Failed to save resume info file '" << Params.mRestoreResumeInfoFilename << "': " << e.what()); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { BOX_ERROR("Failed to save resume info file '" << Params.mRestoreResumeInfoFilename << "': unknown error"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } // Fetch the directory listing from the server -- getting a // list of files which is appropriate to the restore type rConnection.QueryListDirectory( - DirectoryID, - Params.RestoreDeleted?(BackupProtocolClientListDirectory::Flags_Deleted):(BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING), - BackupProtocolClientListDirectory::Flags_OldVersion | (Params.RestoreDeleted?(0):(BackupProtocolClientListDirectory::Flags_Deleted)), - true /* want attributes */); + DirectoryID, + Params.RestoreDeleted?(BackupProtocolClientListDirectory::Flags_Deleted):(BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING), + BackupProtocolClientListDirectory::Flags_OldVersion | (Params.RestoreDeleted?(0):(BackupProtocolClientListDirectory::Flags_Deleted)), + true /* want attributes */); // Retrieve the directory from the stream following BackupStoreDirectory dir; @@ -429,13 +461,29 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { BOX_ERROR("Failed to restore attributes for '" << rLocalDirectoryName << "': " << e.what()); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { BOX_ERROR("Failed to restore attributes for '" << rLocalDirectoryName << "': unknown error"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } int64_t bytesWrittenSinceLastRestoreInfoSave = 0; @@ -444,35 +492,51 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = 0; - while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0) + while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) + != 0) { // Check ID hasn't already been done - if(rLevel.mRestoredObjects.find(en->GetObjectID()) == rLevel.mRestoredObjects.end()) + if(rLevel.mRestoredObjects.find(en->GetObjectID()) + == rLevel.mRestoredObjects.end()) { // Local name BackupStoreFilenameClear nm(en->GetName()); - std::string localFilename(rLocalDirectoryName + DIRECTORY_SEPARATOR_ASCHAR + nm.GetClearFilename()); + std::string localFilename(rLocalDirectoryName + + DIRECTORY_SEPARATOR_ASCHAR + + nm.GetClearFilename()); // Unlink anything which already exists: // For resuming restores, we can't overwrite // files already there. - if(ObjectExists(localFilename) != ObjectExists_NoObject && + if(ObjectExists(localFilename) + != ObjectExists_NoObject && ::unlink(localFilename.c_str()) != 0) { - BOX_ERROR("Failed to delete file '" << - localFilename << "': " << - strerror(errno)); - return Restore_UnknownError; + BOX_LOG_SYS_ERROR("Failed to delete " + "file '" << localFilename << + "'"); + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } // Request it from the store - rConnection.QueryGetFile(DirectoryID, en->GetObjectID()); + rConnection.QueryGetFile(DirectoryID, + en->GetObjectID()); // Stream containing encoded file - std::auto_ptr<IOStream> objectStream(rConnection.ReceiveStream()); + std::auto_ptr<IOStream> objectStream( + rConnection.ReceiveStream()); - // Decode the file -- need to do different things depending on whether - // the directory entry has additional attributes + // Decode the file -- need to do different + // things depending on whether the directory + // entry has additional attributes try { if(en->HasAttributes()) @@ -493,14 +557,30 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir BOX_ERROR("Failed to restore file '" << localFilename << "': " << e.what()); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { BOX_ERROR("Failed to restore file '" << localFilename << "': unknown error"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } // Progress display? @@ -515,7 +595,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // Save restore info? int64_t fileSize; - int exists; + bool exists = false; try { @@ -531,7 +611,15 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir "whether file exists: '" << localFilename << "': " << e.what()); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { @@ -539,17 +627,27 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir "whether file exists: '" << localFilename << "': " "unknown error"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } if(exists) { // File exists... - bytesWrittenSinceLastRestoreInfoSave += fileSize; + bytesWrittenSinceLastRestoreInfoSave + += fileSize; if(bytesWrittenSinceLastRestoreInfoSave > MAX_BYTES_WRITTEN_BETWEEN_RESTORE_INFO_SAVES) { - // Save the restore info, in case it's needed later + // Save the restore info, in + // case it's needed later try { Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename); @@ -590,14 +688,28 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir BOX_ERROR("Failed to save resume info file '" << Params.mRestoreResumeInfoFilename << "': " << e.what()); - return Restore_UnknownError; + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { BOX_ERROR("Failed to save resume info file '" << Params.mRestoreResumeInfoFilename << "': unknown error"); - return Restore_UnknownError; + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } bytesWrittenSinceLastRestoreInfoSave = 0; @@ -608,17 +720,23 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = 0; - while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir)) != 0) + while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir)) + != 0) { // Check ID hasn't already been done - if(rLevel.mRestoredObjects.find(en->GetObjectID()) == rLevel.mRestoredObjects.end()) + if(rLevel.mRestoredObjects.find(en->GetObjectID()) + == rLevel.mRestoredObjects.end()) { // Local name BackupStoreFilenameClear nm(en->GetName()); - std::string localDirname(rLocalDirectoryName + DIRECTORY_SEPARATOR_ASCHAR + nm.GetClearFilename()); + std::string localDirname(rLocalDirectoryName + + DIRECTORY_SEPARATOR_ASCHAR + + nm.GetClearFilename()); // Add the level for the next entry - RestoreResumeInfo &rnextLevel(rLevel.AddLevel(en->GetObjectID(), nm.GetClearFilename())); + RestoreResumeInfo &rnextLevel( + rLevel.AddLevel(en->GetObjectID(), + nm.GetClearFilename())); // Recurse int result = BackupClientRestoreDir( @@ -648,13 +766,27 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { BOX_ERROR("Failed to restore attributes for '" << rLocalDirectoryName << "': " << e.what()); - return Restore_UnknownError; + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { BOX_ERROR("Failed to restore attributes for '" << rLocalDirectoryName << "': unknown error"); - return Restore_UnknownError; + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } return Restore_Complete; @@ -664,33 +796,45 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // -------------------------------------------------------------------------- // // Function -// Name: BackupClientRestore(BackupProtocolClient &, int64_t, const char *, bool, bool) -// Purpose: Restore a directory on the server to a local directory on the disc. -// -// The local directory must not already exist. +// Name: BackupClientRestore(BackupProtocolClient &, int64_t, +// const char *, bool, bool, bool, bool, bool) +// Purpose: Restore a directory on the server to a local +// directory on the disc. The local directory must not +// already exist. // -// If a restore is aborted for any reason, then it may be resumed if -// Resume == true. If Resume == false and resumption is possible, then -// Restore_ResumePossible is returned. +// If a restore is aborted for any reason, then it may +// be resumed if Resume == true. If Resume == false +// and resumption is possible, then +// Restore_ResumePossible is returned. // -// Set RestoreDeleted to restore a deleted directory. This may not give the -// directory structure when it was deleted, because files may have been deleted -// within it before it was deleted. +// Set RestoreDeleted to restore a deleted directory. +// This may not give the directory structure when it +// was deleted, because files may have been deleted +// within it before it was deleted. // -// Returns Restore_TargetExists if the target directory exists, but -// there is no restore possible. (Won't attempt to overwrite things.) +// Returns Restore_TargetExists if the target +// directory exists, but there is no restore possible. +// (Won't attempt to overwrite things.) // -// Returns Restore_Complete on success. (Exceptions on error.) +// Returns Restore_Complete on success. (Exceptions +// on error, unless ContinueAfterError is true and +// the error is recoverable, in which case it returns +// Restore_CompleteWithErrors) // Created: 23/11/03 // // -------------------------------------------------------------------------- -int BackupClientRestore(BackupProtocolClient &rConnection, int64_t DirectoryID, const char *LocalDirectoryName, - bool PrintDots, bool RestoreDeleted, bool UndeleteAfterRestoreDeleted, bool Resume) +int BackupClientRestore(BackupProtocolClient &rConnection, + int64_t DirectoryID, const char *LocalDirectoryName, + bool PrintDots, bool RestoreDeleted, + bool UndeleteAfterRestoreDeleted, bool Resume, + bool ContinueAfterErrors) { // Parameter block RestoreParams params; params.PrintDots = PrintDots; params.RestoreDeleted = RestoreDeleted; + params.ContinueAfterErrors = ContinueAfterErrors; + params.ContinuedAfterError = false; params.mRestoreResumeInfoFilename = LocalDirectoryName; params.mRestoreResumeInfoFilename += ".boxbackupresume"; @@ -699,12 +843,13 @@ int BackupClientRestore(BackupProtocolClient &rConnection, int64_t DirectoryID, // Does any resumption information exist? bool doingResume = false; - if(FileExists(params.mRestoreResumeInfoFilename.c_str()) && targetExistance == ObjectExists_Dir) + if(FileExists(params.mRestoreResumeInfoFilename.c_str()) && + targetExistance == ObjectExists_Dir) { if(!Resume) { - // Caller didn't specify that resume should be done, so refuse to do it - // but say why. + // Caller didn't specify that resume should be done, + // so refuse to do it but say why. return Restore_ResumePossible; } @@ -752,9 +897,7 @@ int BackupClientRestore(BackupProtocolClient &rConnection, int64_t DirectoryID, // Delete the resume information file ::unlink(params.mRestoreResumeInfoFilename.c_str()); - return Restore_Complete; + return params.ContinuedAfterError ? Restore_CompleteWithErrors + : Restore_Complete; } - - - |