summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbescoto <bescoto@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2003-08-24 03:39:56 +0000
committerbescoto <bescoto@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2003-08-24 03:39:56 +0000
commit6a48fc6c34e3d2f8fcaf791a847aebb6854557e7 (patch)
treedfd7331259298750b49f7493ba52219acd647164
parent94da66c4015094e2c5a71e945ef3562644543c0f (diff)
downloadrdiff-backup-6a48fc6c34e3d2f8fcaf791a847aebb6854557e7.tar.gz
When data gets deleted from dest, try not to exit as easily
git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/trunk@401 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
-rw-r--r--rdiff-backup/CHANGELOG4
-rw-r--r--rdiff-backup/rdiff_backup/Main.py4
-rw-r--r--rdiff-backup/rdiff_backup/restore.py33
-rw-r--r--rdiff-backup/testing/finaltest.py45
4 files changed, 78 insertions, 8 deletions
diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG
index 71c1e07..02c093c 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.13.1 (2003/08/08)
---------------------------
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index 638f137..f9cb252 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -571,7 +571,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)
@@ -596,7 +596,7 @@ 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"))
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index 7094a3b..f4add16 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -289,28 +289,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:
@@ -434,7 +449,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 593570f..4f1caf9 100644
--- a/rdiff-backup/testing/finaltest.py
+++ b/rdiff-backup/testing/finaltest.py
@@ -471,5 +471,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()