[Box Backup-dev] COMMIT r516 - box/chris/general/lib/backupclient

boxbackup-dev@fluffy.co.uk boxbackup-dev@fluffy.co.uk
Sun, 26 Feb 2006 00:28:24 +0000 (GMT)


Author: chris
Date: 2006-02-26 00:28:22 +0000 (Sun, 26 Feb 2006)
New Revision: 516

Modified:
   box/chris/general/lib/backupclient/BackupClientRestore.cpp
Log:
* BackupClientRestore.cpp
- Detect when the user tries to restore to a directory whose parent does not
  exist, and return an appropriate error


Modified: box/chris/general/lib/backupclient/BackupClientRestore.cpp
===================================================================
--- box/chris/general/lib/backupclient/BackupClientRestore.cpp	2006-02-26 00:27:45 UTC (rev 515)
+++ box/chris/general/lib/backupclient/BackupClientRestore.cpp	2006-02-26 00:28:22 UTC (rev 516)
@@ -206,7 +206,7 @@
 //		Created: 23/11/03
 //
 // --------------------------------------------------------------------------
-static void 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
@@ -222,12 +222,11 @@
 		// Remove the level for the recursed directory
 		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
-	switch(ObjectExists(rLocalDirectoryName.c_str()))
+	int exists = ObjectExists(rLocalDirectoryName.c_str());
+
+	switch(exists)
 	{
 		case ObjectExists_Dir:
 			// Do nothing
@@ -244,16 +243,64 @@
 			}
 			// follow through to... (no break)
 		case ObjectExists_NoObject:
-			if(::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0)
-			{
-				THROW_EXCEPTION(CommonException, OSFileError);
-			}
 			break;
 		default:
 			ASSERT(false);
 			break;
 	}
+
+	std::string parentDirectoryName(rLocalDirectoryName);
+	if(parentDirectoryName[parentDirectoryName.size() - 1] == '/')
+	{
+		parentDirectoryName.resize(parentDirectoryName.size() - 1);
+	}
+
+	int lastSlash = parentDirectoryName.rfind(DIRECTORY_SEPARATOR_ASCHAR);
+	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);
+		switch(ObjectExists(parentDirectoryName.c_str()))
+		{
+			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)
+	{
+		THROW_EXCEPTION(CommonException, OSFileError);
+	}
 	
+	// Save the resumption information
+	Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+	
 	// Fetch the directory listing from the server -- getting a list of files which is approparite to the restore type
 	rConnection.QueryListDirectory(
 			DirectoryID,
@@ -347,7 +394,7 @@
 	}
 
 	
-	// Recuse to directories
+	// Recurse to directories
 	{
 		BackupStoreDirectory::Iterator i(dir);
 		BackupStoreDirectory::Entry *en = 0;
@@ -364,7 +411,14 @@
 				RestoreResumeInfo &rnextLevel(rLevel.AddLevel(en->GetObjectID(), nm.GetClearFilename()));
 				
 				// Recurse
-				BackupClientRestoreDir(rConnection, en->GetObjectID(), localDirname, Params, rnextLevel);
+				int result = BackupClientRestoreDir(
+					rConnection, en->GetObjectID(), 
+					localDirname, Params, rnextLevel);
+
+				if (result != Restore_Complete)
+				{
+					return result;
+				}
 				
 				// Remove the level for the above call
 				rLevel.RemoveLevel();
@@ -373,7 +427,9 @@
 				rLevel.mRestoredObjects.insert(en->GetObjectID());
 			}
 		}
-	}	
+	}
+
+	return Restore_Complete;
 }
 
 
@@ -444,7 +500,12 @@
 	
 	// Restore the directory
 	std::string localName(LocalDirectoryName);
-	BackupClientRestoreDir(rConnection, DirectoryID, localName, params, params.mResumeInfo);
+	int result = BackupClientRestoreDir(rConnection, DirectoryID, 
+		localName, params, params.mResumeInfo);
+	if (result != Restore_Complete)
+	{
+		return result;
+	}
 
 	// Undelete the directory on the server?
 	if(RestoreDeleted && UndeleteAfterRestoreDeleted)