[Box Backup-commit] COMMIT r1273 - box/chris/merge/lib/backupclient
boxbackup-dev@fluffy.co.uk
boxbackup-dev@fluffy.co.uk
Fri, 09 Feb 2007 22:34:21 +0000
Author: chris
Date: 2007-02-09 22:34:21 +0000 (Fri, 09 Feb 2007)
New Revision: 1273
Modified:
box/chris/merge/lib/backupclient/BackupClientRestore.cpp
Log:
Check whether the restore target parent directory exists before trying
to create the target directory or save restore info in the parent (refs #3)
Modified: box/chris/merge/lib/backupclient/BackupClientRestore.cpp
===================================================================
--- box/chris/merge/lib/backupclient/BackupClientRestore.cpp 2007-02-09 22:30:15 UTC (rev 1272)
+++ box/chris/merge/lib/backupclient/BackupClientRestore.cpp 2007-02-09 22:34:21 UTC (rev 1273)
@@ -224,9 +224,6 @@
rLevel.RemoveLevel();
}
- // Save the resumption information
- Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
-
// Create the local directory, if not already done.
// Path and owner set later, just use restrictive owner mode.
@@ -270,18 +267,106 @@
}
TRACE1("In restore, directory name collision with file %s", rLocalDirectoryName.c_str());
}
- // follow through to... (no break)
+ break;
case ObjectExists_NoObject:
- if(::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0)
- {
- THROW_EXCEPTION(CommonException, OSFileError);
- }
+ // we'll create it in a second, after checking
+ // whether the parent directory exists
break;
default:
ASSERT(false);
break;
}
+
+ std::string parentDirectoryName(rLocalDirectoryName);
+ if(parentDirectoryName[parentDirectoryName.size() - 1] ==
+ DIRECTORY_SEPARATOR_ASCHAR)
+ {
+ parentDirectoryName.resize(parentDirectoryName.size() - 1);
+ }
+
+ int lastSlash = parentDirectoryName.rfind(DIRECTORY_SEPARATOR_ASCHAR);
+
+ if(lastSlash == std::string::npos)
+ {
+ // might be a forward slash separator,
+ // especially in the unit tests!
+ lastSlash = parentDirectoryName.rfind('/');
+ }
+
+ if(lastSlash != std::string::npos)
+ {
+ // the target directory is a deep path, remove the last
+ // directory name and check that the resulting parent
+ // exists, otherwise the restore should fail.
+ parentDirectoryName.resize(lastSlash);
+
+ int parentExists;
+
+ try
+ {
+ parentExists = ObjectExists(parentDirectoryName.c_str());
+ }
+ catch (BoxException &e)
+ {
+ ::syslog(LOG_ERR, "Failed to check existence for %s: "
+ "%s", parentDirectoryName.c_str(), e.what());
+ return Restore_UnknownError;
+ }
+ catch(std::exception &e)
+ {
+ ::syslog(LOG_ERR, "Failed to check existence for %s: "
+ "%s", parentDirectoryName.c_str(), e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ ::syslog(LOG_ERR, "Failed to check existence for %s: "
+ "unknown error", parentDirectoryName.c_str());
+ return Restore_UnknownError;
+ }
+
+ switch(parentExists)
+ {
+ case ObjectExists_Dir:
+ // this is fine, do nothing
+ break;
+
+ case ObjectExists_File:
+ fprintf(stderr, "Failed to restore: '%s' "
+ "is a file, but should be a "
+ "directory.\n",
+ parentDirectoryName.c_str());
+ return Restore_TargetPathNotFound;
+
+ case ObjectExists_NoObject:
+ fprintf(stderr, "Failed to restore: "
+ "parent '%s' of target directory "
+ "does not exist.\n",
+ parentDirectoryName.c_str());
+ return Restore_TargetPathNotFound;
+
+ default:
+ fprintf(stderr, "Failed to restore: "
+ "unknown result from "
+ "ObjectExists('%s').\n",
+ parentDirectoryName.c_str());
+ return Restore_UnknownError;
+ }
+ }
+
+ if((exists == ObjectExists_NoObject ||
+ exists == ObjectExists_File) &&
+ ::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0)
+ {
+ ::syslog(LOG_ERR, "Failed to create directory %s: %s",
+ rLocalDirectoryName.c_str(),
+ strerror(errno));
+ return Restore_UnknownError;
+ }
+ // Save the resumption information
+ Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+
// Fetch the directory listing from the server -- getting a list
// of files which is appropriate to the restore type
rConnection.QueryListDirectory(