Commit 26d64222 authored by owsla's avatar owsla

Automatically resume after a failed initial backup. (Patch from Josh Nisly)


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@950 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent ea1060c2
New in v1.2.2 (????/??/??) New in v1.2.2 (????/??/??)
--------------------------- ---------------------------
Automatically resume after a failed initial backup. (Patch from Josh Nisly)
Improve compatibility between Unix and remote native Windows client. It is now Improve compatibility between Unix and remote native Windows client. It is now
possible to use SSH daemons other than Putty on Windows. (Andrew Ferguson) possible to use SSH daemons other than Putty on Windows. (Andrew Ferguson)
......
...@@ -380,6 +380,44 @@ def backup_check_dirs(rpin, rpout): ...@@ -380,6 +380,44 @@ def backup_check_dirs(rpin, rpout):
Log.FatalError("Source %s is not a directory" % rpin.path) Log.FatalError("Source %s is not a directory" % rpin.path)
Globals.rbdir = rpout.append_path("rdiff-backup-data") 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): def backup_set_rbdir(rpin, rpout):
"""Initialize data dir and logging""" """Initialize data dir and logging"""
global incdir global incdir
...@@ -400,6 +438,8 @@ exists, but does not look like a rdiff-backup directory. Running ...@@ -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 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 want to update or overwrite it, run rdiff-backup with the --force
option.""" % rpout.path) option.""" % rpout.path)
elif check_failed_initial_backup():
fix_failed_initial_backup()
if not Globals.rbdir.lstat(): Globals.rbdir.mkdir() if not Globals.rbdir.lstat(): Globals.rbdir.mkdir()
SetConnections.UpdateGlobal('rbdir', Globals.rbdir) SetConnections.UpdateGlobal('rbdir', Globals.rbdir)
......
...@@ -45,7 +45,8 @@ file_requests = {'os.listdir':0, 'rpath.make_file_dict':0, 'os.chmod':0, ...@@ -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.chown':0, 'os.remove':0, 'os.removedirs':0,
'os.rename':0, 'os.renames':0, 'os.rmdir':0, 'os.unlink':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.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): def initialize(action, cmdpairs):
"""Initialize allowable request list and chroot""" """Initialize allowable request list and chroot"""
...@@ -180,6 +181,7 @@ def set_allowed_requests(sec_level): ...@@ -180,6 +181,7 @@ def set_allowed_requests(sec_level):
if sec_level == "all": if sec_level == "all":
l.extend(["os.mkdir", "os.chown", "os.lchown", "os.rename", l.extend(["os.mkdir", "os.chown", "os.lchown", "os.rename",
"os.unlink", "os.remove", "os.chmod", "os.makedirs", "os.unlink", "os.remove", "os.chmod", "os.makedirs",
"rpath.delete_dir_no_files",
"backup.DestinationStruct.patch", "backup.DestinationStruct.patch",
"restore.TargetStruct.get_initial_iter", "restore.TargetStruct.get_initial_iter",
"restore.TargetStruct.patch", "restore.TargetStruct.patch",
......
...@@ -372,6 +372,14 @@ def get_incfile_info(basename): ...@@ -372,6 +372,14 @@ def get_incfile_info(basename):
else: basestr = ".".join(dotsplit[:-2]) else: basestr = ".".join(dotsplit[:-2])
return (compressed, timestring, ext, basestr) 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: class RORPath:
"""Read Only RPath - carry information about a path """Read Only RPath - carry information about a path
...@@ -1047,6 +1055,21 @@ class RPath(RORPath): ...@@ -1047,6 +1055,21 @@ class RPath(RORPath):
else: self.conn.os.unlink(self.path) else: self.conn.os.unlink(self.path)
self.setdata() 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): def quote(self):
"""Return quoted self.path for use with os.system()""" """Return quoted self.path for use with os.system()"""
return '"%s"' % self.regex_chars_to_quote.sub( return '"%s"' % self.regex_chars_to_quote.sub(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment