From 7eba897f6da8b1a993f0d40251af1748b5c793ea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 May 2008 14:44:38 +0000 Subject: Add restore -f option to force restore to continue after an error. --- bin/bbackupquery/BackupQueries.cpp | 18 +++- bin/bbackupquery/documentation.txt | 3 +- lib/backupclient/BackupClientRestore.cpp | 152 +++++++++++++++++++++++++++---- lib/backupclient/BackupClientRestore.h | 19 ++-- 4 files changed, 162 insertions(+), 30 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 61b7e85b..7a7eb5cc 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -217,7 +217,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) { "getobject", "" }, { "get", "i" }, { "compare", "alcqAEQ" }, - { "restore", "dri" }, + { "restore", "drif" }, { "help", "" }, { "usage", "" }, { "undelete", "" }, @@ -1966,7 +1966,7 @@ void BackupQueries::CommandRestore(const std::vector &args, const b // Check arguments if(args.size() != 2) { - BOX_ERROR("Incorrect usage. restore [-d] [-r] [-i] "); + BOX_ERROR("Incorrect usage. restore [-drif] "); return; } @@ -2029,7 +2029,8 @@ void BackupQueries::CommandRestore(const std::vector &args, const b localName.c_str(), true /* print progress dots */, restoreDeleted, false /* don't undelete after restore! */, - opts['r'] /* resume? */); + opts['r'] /* resume? */, + opts['f'] /* force continue after errors */); } catch(std::exception &e) { @@ -2050,13 +2051,20 @@ void BackupQueries::CommandRestore(const std::vector &args, const b BOX_INFO("Restore complete."); break; + case Restore_CompleteWithErrors: + BOX_WARNING("Restore complete, but some files could not be " + "restored."); + break; + case Restore_ResumePossible: - BOX_ERROR("Resume possible -- repeat command with -r flag to resume"); + BOX_ERROR("Resume possible -- repeat command with -r flag " + "to resume."); SetReturnCode(COMMAND_RETURN_ERROR); break; case Restore_TargetExists: - BOX_ERROR("The target directory exists. You cannot restore over an existing directory."); + BOX_ERROR("The target directory exists. You cannot restore " + "over an existing directory."); SetReturnCode(COMMAND_RETURN_ERROR); break; diff --git a/bin/bbackupquery/documentation.txt b/bin/bbackupquery/documentation.txt index 42217edc..84126bee 100644 --- a/bin/bbackupquery/documentation.txt +++ b/bin/bbackupquery/documentation.txt @@ -116,7 +116,7 @@ compare This can be used for automated tests. < -> restore [-d] [-r] [-i] +> restore [-drif] Restores a directory to the local disc. The local directory specified must not exist (unless a previous restore is being restarted). @@ -126,6 +126,7 @@ compare -d -- restore a deleted directory or deleted files inside -r -- resume an interrupted restoration -i -- directory name is actually an ID + -f -- force restore to continue if errors are encountered If a restore operation is interrupted for any reason, it can be restarted using the -r switch. Restore progress information is saved in a file at diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 336952be..605fe30a 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; @@ -387,7 +389,15 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, { BOX_LOG_SYS_ERROR("Failed to create directory '" << rLocalDirectoryName << "'"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } // Save the restore info, in case it's needed later @@ -400,14 +410,30 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, 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 @@ -435,13 +461,29 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, { 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; @@ -473,7 +515,15 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, BOX_LOG_SYS_ERROR("Failed to delete " "file '" << localFilename << "'"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } // Request it from the store @@ -507,14 +557,30 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, 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? @@ -545,7 +611,15 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, "whether file exists: '" << localFilename << "': " << e.what()); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } catch(...) { @@ -553,7 +627,15 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, "whether file exists: '" << localFilename << "': " "unknown error"); - return Restore_UnknownError; + + if (Params.ContinueAfterErrors) + { + Params.ContinuedAfterError = true; + } + else + { + return Restore_UnknownError; + } } if(exists) @@ -606,14 +688,28 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, 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; @@ -670,13 +766,27 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, { 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; @@ -687,7 +797,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, // // Function // Name: BackupClientRestore(BackupProtocolClient &, int64_t, -// const char *, bool, bool) +// 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. @@ -707,19 +817,24 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, // (Won't attempt to overwrite things.) // // Returns Restore_Complete on success. (Exceptions -// on error.) +// 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) + 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"; @@ -782,6 +897,7 @@ int BackupClientRestore(BackupProtocolClient &rConnection, // Delete the resume information file ::unlink(params.mRestoreResumeInfoFilename.c_str()); - return Restore_Complete; + return params.ContinuedAfterError ? Restore_CompleteWithErrors + : Restore_Complete; } diff --git a/lib/backupclient/BackupClientRestore.h b/lib/backupclient/BackupClientRestore.h index f7724030..7e492238 100644 --- a/lib/backupclient/BackupClientRestore.h +++ b/lib/backupclient/BackupClientRestore.h @@ -15,14 +15,21 @@ class BackupProtocolClient; enum { Restore_Complete = 0, - Restore_ResumePossible = 1, - Restore_TargetExists = 2, - Restore_TargetPathNotFound = 3, - Restore_UnknownError = 4, + Restore_ResumePossible, + Restore_TargetExists, + Restore_TargetPathNotFound, + Restore_UnknownError, + Restore_CompleteWithErrors, }; -int BackupClientRestore(BackupProtocolClient &rConnection, int64_t DirectoryID, const char *LocalDirectoryName, - bool PrintDots = false, bool RestoreDeleted = false, bool UndeleteAfterRestoreDeleted = false, bool Resume = false); +int BackupClientRestore(BackupProtocolClient &rConnection, + int64_t DirectoryID, + const char *LocalDirectoryName, + bool PrintDots = false, + bool RestoreDeleted = false, + bool UndeleteAfterRestoreDeleted = false, + bool Resume = false, + bool ContinueAfterErrors = false); #endif // BACKUPSCLIENTRESTORE__H -- cgit v1.2.3