summaryrefslogtreecommitdiff
path: root/rdiff-backup/rdiff_backup
diff options
context:
space:
mode:
authorowsla <owsla@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2008-10-12 02:21:30 +0000
committerowsla <owsla@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2008-10-12 02:21:30 +0000
commit3852649621c640e01ee4077f2dd77b506fe6be7f (patch)
tree2d3773ec7265cfe5c1baa861c4f75065479373fd /rdiff-backup/rdiff_backup
parent8e4eacb461cee6ee8b15822185553bc42e508263 (diff)
downloadrdiff-backup-3852649621c640e01ee4077f2dd77b506fe6be7f.tar.gz
Automatically resume after a failed initial backup. (Patch from Josh Nisly)
git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/trunk@950 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
Diffstat (limited to 'rdiff-backup/rdiff_backup')
-rw-r--r--rdiff-backup/rdiff_backup/Main.py40
-rw-r--r--rdiff-backup/rdiff_backup/Security.py4
-rw-r--r--rdiff-backup/rdiff_backup/rpath.py23
3 files changed, 66 insertions, 1 deletions
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index a286842..9ba0dce 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -380,6 +380,44 @@ def backup_check_dirs(rpin, rpout):
Log.FatalError("Source %s is not a directory" % rpin.path)
Globals.rbdir = rpout.append_path("rdiff-backup-data")
+def check_failed_initial_backup():
+ """Returns true if it looks like initial backup failed."""
+ if Globals.rbdir.lstat():
+ rbdir_files = Globals.rbdir.listdir()
+ mirror_markers = filter(lambda x: x.startswith("current_mirror"),
+ rbdir_files)
+ error_logs = filter(lambda x: x.startswith("error_log"),
+ rbdir_files)
+ metadata_mirrors = filter(lambda x: x.startswith("mirror_metadata"),
+ rbdir_files)
+ # If we have no current_mirror marker, and the increments directory
+ # is empty, we most likely have a failed backup.
+ return not mirror_markers and len(error_logs) <= 1 and \
+ len(metadata_mirrors) <= 1
+ return False
+
+def fix_failed_initial_backup():
+ """Clear Globals.rbdir after a failed initial backup"""
+ Log("Found interrupted initial backup. Removing...", 2)
+ rbdir_files = Globals.rbdir.listdir()
+ # Try to delete the increments dir first
+ if 'increments' in rbdir_files:
+ rbdir_files.remove('increments')
+ rp = Globals.rbdir.append('increments')
+ try:
+ rp.conn.rpath.delete_dir_no_files(rp)
+ except rpath.RPathException:
+ Log("Increments dir contains files.", 4)
+ return
+ except Security.Violation:
+ Log("Server doesn't support resuming.", 2)
+ return
+
+ for file_name in rbdir_files:
+ rp = Globals.rbdir.append_path(file_name)
+ if not rp.isdir(): # Only remove files, not folders
+ rp.delete()
+
def backup_set_rbdir(rpin, rpout):
"""Initialize data dir and logging"""
global incdir
@@ -400,6 +438,8 @@ exists, but does not look like a rdiff-backup directory. Running
rdiff-backup like this could mess up what is currently in it. If you
want to update or overwrite it, run rdiff-backup with the --force
option.""" % rpout.path)
+ elif check_failed_initial_backup():
+ fix_failed_initial_backup()
if not Globals.rbdir.lstat(): Globals.rbdir.mkdir()
SetConnections.UpdateGlobal('rbdir', Globals.rbdir)
diff --git a/rdiff-backup/rdiff_backup/Security.py b/rdiff-backup/rdiff_backup/Security.py
index 8dc26bc..a259221 100644
--- a/rdiff-backup/rdiff_backup/Security.py
+++ b/rdiff-backup/rdiff_backup/Security.py
@@ -45,7 +45,8 @@ file_requests = {'os.listdir':0, 'rpath.make_file_dict':0, 'os.chmod':0,
'os.chown':0, 'os.remove':0, 'os.removedirs':0,
'os.rename':0, 'os.renames':0, 'os.rmdir':0, 'os.unlink':0,
'os.utime':0, 'os.lchown':0, 'os.link':1, 'os.symlink':1,
- 'os.mkdir':0, 'os.makedirs':0}
+ 'os.mkdir':0, 'os.makedirs':0,
+ 'rpath.delete_dir_no_files':0}
def initialize(action, cmdpairs):
"""Initialize allowable request list and chroot"""
@@ -180,6 +181,7 @@ def set_allowed_requests(sec_level):
if sec_level == "all":
l.extend(["os.mkdir", "os.chown", "os.lchown", "os.rename",
"os.unlink", "os.remove", "os.chmod", "os.makedirs",
+ "rpath.delete_dir_no_files",
"backup.DestinationStruct.patch",
"restore.TargetStruct.get_initial_iter",
"restore.TargetStruct.patch",
diff --git a/rdiff-backup/rdiff_backup/rpath.py b/rdiff-backup/rdiff_backup/rpath.py
index b3efc8c..a75cc0e 100644
--- a/rdiff-backup/rdiff_backup/rpath.py
+++ b/rdiff-backup/rdiff_backup/rpath.py
@@ -372,6 +372,14 @@ def get_incfile_info(basename):
else: basestr = ".".join(dotsplit[:-2])
return (compressed, timestring, ext, basestr)
+def delete_dir_no_files(rp):
+ """Deletes the directory at rp.path if empty. Raises if the
+ directory contains files."""
+ assert rp.isdir()
+ if rp.contains_files():
+ raise RPathException("Directory contains files.")
+ rp.delete()
+
class RORPath:
"""Read Only RPath - carry information about a path
@@ -1047,6 +1055,21 @@ class RPath(RORPath):
else: self.conn.os.unlink(self.path)
self.setdata()
+ def contains_files(self):
+ """Returns true if self (or subdir) contains any regular files."""
+ log.Log("Determining if directory contains files: %s" % self.path, 7)
+ if not self.isdir():
+ return False
+ dir_entries = self.listdir()
+ for entry in dir_entries:
+ child_rp = self.append(entry)
+ if not child_rp.isdir():
+ return True
+ else:
+ if child_rp.contains_files():
+ return True
+ return False
+
def quote(self):
"""Return quoted self.path for use with os.system()"""
return '"%s"' % self.regex_chars_to_quote.sub(