summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbescoto <bescoto@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2003-08-24 03:46:13 +0000
committerbescoto <bescoto@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2003-08-24 03:46:13 +0000
commit5eb272cab822b4f8ec54605c562c554223faad18 (patch)
tree2a1b4f042e5fdbe8338b41c8dbe337f260425637
parent188794d438954505a5c2effb74ddea5105b8b40e (diff)
downloadrdiff-backup-5eb272cab822b4f8ec54605c562c554223faad18.tar.gz
Make restoring from broken archive easier
git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/branches/r0-12@402 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
-rw-r--r--rdiff-backup/CHANGELOG4
-rw-r--r--rdiff-backup/rdiff_backup/Main.py6
-rw-r--r--rdiff-backup/rdiff_backup/restore.py33
-rw-r--r--rdiff-backup/testing/finaltest.py45
4 files changed, 79 insertions, 9 deletions
diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG
index 0946d3b..11f3035 100644
--- a/rdiff-backup/CHANGELOG
+++ b/rdiff-backup/CHANGELOG
@@ -8,6 +8,10 @@ Fixed bug backing up unreadable regular files when rdiff-backup is run
by root on the source site and non-root on the destination side.
(Reported by Troels Arvin and Arkadiusz Miskiewicz.)
+If there is data missing from the destination dir (for instance if a
+user mistakenly deletes it), only warn when restoring, instead of
+exiting with error.
+
New in v0.12.3 (2003/08/08)
---------------------------
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index 7edfdc3..da1e596 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -527,7 +527,7 @@ def CalculateAverage(rps):
def RemoveOlderThan(rootrp):
"""Remove all increment files older than a certain time"""
- rom_check_dir(rootrp)
+ rot_check_dir(rootrp)
try: time = Time.genstrtotime(remove_older_than_string)
except Time.TimeException, exc: Log.FatalError(str(exc))
timep = Time.timetopretty(time)
@@ -552,13 +552,13 @@ def RemoveOlderThan(rootrp):
else: Log("Deleting increments at times:\n" + inc_pretty_time, 3)
manage.delete_earlier_than(Globals.rbdir, time)
-def rom_check_dir(rootrp):
+def rot_check_dir(rootrp):
"""Check destination dir before RemoveOlderThan"""
SetConnections.UpdateGlobal('rbdir',
rootrp.append_path("rdiff-backup-data"))
if not Globals.rbdir.isdir():
Log.FatalError("Unable to open rdiff-backup-data dir %s" %
- (datadir.path,))
+ (Globals.rbdir.path,))
checkdest_if_necessary(rootrp)
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index 26bc499..f73dbc1 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -287,28 +287,43 @@ class CachedRF:
return "\n".join((s1, s2, s3))
def get_rf(self, index):
- """Return RestoreFile of given index"""
+ """Return RestoreFile of given index, or None"""
while 1:
- if not self.rf_list: self.add_rfs(index)
+ if not self.rf_list:
+ if not self.add_rfs(index): return None
rf = self.rf_list.pop(0)
if rf.index < index: continue
elif rf.index == index: return rf
self.rf_list.insert(0, rf)
- self.add_rfs(index)
+ if not self.add_rfs(index): return None
def get_fp(self, index):
"""Return the file object (for reading) of given index"""
+ rf = self.get_rf(index)
+ if not rf:
+ log.Log("""Error: Unable to retrieve data for file %s!
+The cause is probably data loss from the destination directory.""" %
+ (index and "/".join(index) or '.',), 2)
+ return cStringIO.StringIO('')
return self.get_rf(index).get_restore_fp()
def add_rfs(self, index):
- """Given index, add the rfs in that same directory"""
+ """Given index, add the rfs in that same directory
+
+ Returns false if no rfs are available, which usually indicates
+ an error.
+
+ """
if not index: return self.root_rf
parent_index = index[:-1]
temp_rf = RestoreFile(self.root_rf.mirror_rp.new_index(parent_index),
self.root_rf.inc_rp.new_index(parent_index), [])
new_rfs = list(temp_rf.yield_sub_rfs())
- assert new_rfs, "No RFs added for index %s" % index
+ if not new_rfs:
+ log.Log("Warning: No RFs added for index %s" % (index,), 2)
+ return 0
self.rf_list[0:0] = new_rfs
+ return 1
class RestoreFile:
@@ -432,7 +447,13 @@ rdiff-backup destination directory, or a bug in rdiff-backup""" %
def yield_sub_rfs(self):
"""Return RestoreFiles under current RestoreFile (which is dir)"""
- assert self.mirror_rp.isdir() or self.inc_rp.isdir()
+ if not self.mirror_rp.isdir() and not self.inc_rp.isdir():
+ log.Log("""Warning: directory %s seems to be missing from backup!
+
+This is probably due to files being deleted manually from the
+rdiff-backup destination directory. In general you shouldn't do this,
+as data loss may result.\n""" % (self.mirror_rp.get_indexpath(),), 2)
+ return
if self.mirror_rp.isdir():
mirror_iter = self.yield_mirrorrps(self.mirror_rp)
else: mirror_iter = iter([])
diff --git a/rdiff-backup/testing/finaltest.py b/rdiff-backup/testing/finaltest.py
index c45bd62..82d03a7 100644
--- a/rdiff-backup/testing/finaltest.py
+++ b/rdiff-backup/testing/finaltest.py
@@ -410,5 +410,50 @@ testfiles/increment2/changed_dir""")
self.assertRaises(OSError, os.lstat,
'testfiles/restoretarget1/executable2')
+
+class FinalCorrupt(PathSetter):
+ """Test messing with things a bit and making sure they still work"""
+ def make_dir(self):
+ self.delete_tmpdirs()
+ rp1 = rpath.RPath(Globals.local_connection, 'testfiles/final_deleted1')
+ if rp1.lstat(): Myrm(rp1.path)
+ rp1.mkdir()
+ rp1_1 = rp1.append('regfile')
+ rp1_1.touch()
+ rp1_2 = rp1.append('dir')
+ rp1_2.mkdir()
+ rp1_2_1 = rp1_2.append('regfile2')
+ rp1_2_1.write_string('foo')
+
+ rp2 = rpath.RPath(Globals.local_connection, 'testfiles/final_deleted2')
+ if rp2.lstat(): Myrm(rp2.path)
+ os.system('cp -a %s %s' % (rp1.path, rp2.path))
+ rp2_2_1 = rp2.append('dir').append('regfile2')
+ assert rp2_2_1.lstat()
+ rp2_2_1.delete()
+ rp2_2_1.touch()
+ return rp1, rp1_2, rp2
+
+ def test_dest_delete(self):
+ """Test deleting a directory from the destination dir
+
+ Obviously that directory can no longer be restored, but the
+ rest of the files should be OK. Just runs locally for now.
+
+ """
+ in_dir1, in_subdir, in_dir2 = self.make_dir()
+ self.set_connections(None, None, None, None)
+ self.exec_rb(10000, in_dir1.path, 'testfiles/output')
+
+ out_subdir = rpath.RPath(Globals.local_connection,
+ 'testfiles/output/%s' %
+ (in_subdir.index[-1],))
+ log.Log("Deleting %s" % (out_subdir.path,), 3)
+ out_subdir.delete()
+ self.exec_rb(20000, in_dir2.path, 'testfiles/output')
+
+ self.exec_rb_restore(10000, 'testfiles/output',
+ 'testfiles/restoretarget1')
+
if __name__ == "__main__": unittest.main()