Commit 767dc3f1 authored by bescoto's avatar bescoto

When data gets deleted from dest, try not to exit as easily


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@401 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent 961a625b
......@@ -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)
---------------------------
......
......@@ -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"))
......
......@@ -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([])
......
......@@ -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()
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