summaryrefslogtreecommitdiff
path: root/lib/backupclient/BackupClientRestore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/backupclient/BackupClientRestore.cpp')
-rw-r--r--lib/backupclient/BackupClientRestore.cpp289
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;
}
-
-
-