summaryrefslogtreecommitdiff
path: root/rdiff-backup/rdiff_backup/restore.py
diff options
context:
space:
mode:
Diffstat (limited to 'rdiff-backup/rdiff_backup/restore.py')
-rw-r--r--rdiff-backup/rdiff_backup/restore.py84
1 files changed, 81 insertions, 3 deletions
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index 2e8bf35..8d64c36 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -48,6 +48,7 @@ def Restore(mirror_rp, inc_rpath, target, restore_to_time):
target_iter = TargetS.get_initial_iter(target)
diff_iter = MirrorS.get_diffs(target_iter)
TargetS.patch(target, diff_iter)
+ MirrorS.close_rf_cache()
def get_inclist(inc_rpath):
"""Returns increments with given base"""
@@ -87,7 +88,7 @@ def ListChangedSince(mirror_rp, inc_rp, restore_to_time):
path_desc = (old_rorp and old_rorp.get_indexpath() or
cur_rorp.get_indexpath())
yield rpath.RORPath(("%-7s %s" % (change, path_desc),))
-
+ MirrorStruct.close_rf_cache()
def ListAtTime(mirror_rp, inc_rp, time):
"""List the files in archive at the given time
@@ -158,6 +159,10 @@ class MirrorStruct:
cls.root_rf = rf
cls.rf_cache = CachedRF(rf)
+ def close_rf_cache(cls):
+ """Run anything remaining on CachedRF object"""
+ cls.rf_cache.close()
+
def get_mirror_rorp_iter(cls, rest_time = None, require_metadata = None):
"""Return iter of mirror rps at given restore time
@@ -195,7 +200,9 @@ class MirrorStruct:
rorp = rf.get_attribs()
yield rorp
if rorp.isdir():
- for sub_rf in rf.yield_sub_rfs(): yield sub_rf.get_attribs()
+ for sub_rf in rf.yield_sub_rfs():
+ for attribs in cls.get_rorp_iter_from_rf(sub_rf):
+ yield attribs
def subtract_indicies(cls, index, rorp_iter):
"""Subtract index from index of each rorp in rorp_iter
@@ -295,6 +302,8 @@ class CachedRF:
"""Initialize CachedRF, self.rf_list variable"""
self.root_rf = root_rf
self.rf_list = [] # list should filled in index order
+ if Globals.process_uid != 0:
+ self.perm_changer = PermissionChanger(root_rf.mirror_rp)
def list_rfs_in_cache(self, index):
"""Used for debugging, return indicies of cache rfs for printing"""
@@ -309,7 +318,9 @@ class CachedRF:
if not self.rf_list:
if not self.add_rfs(index): return None
rf = self.rf_list[0]
- if rf.index == index: return rf
+ if rf.index == index:
+ if Globals.process_uid != 0: self.perm_changer(rf.mirror_rp)
+ return rf
elif rf.index > index:
# Try to add earlier indicies. But if first is
# already from same directory, or we can't find any
@@ -339,6 +350,7 @@ The cause is probably data loss from the destination directory.""" %
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), [])
+ if Globals.process_uid != 0: self.perm_changer(temp_rf.mirror_rp)
new_rfs = list(temp_rf.yield_sub_rfs())
if not new_rfs:
log.Log("Warning: No RFs added for index %s" % (index,), 2)
@@ -346,6 +358,10 @@ The cause is probably data loss from the destination directory.""" %
self.rf_list[0:0] = new_rfs
return 1
+ def close(self):
+ """Finish remaining rps in PermissionChanger"""
+ if Globals.process_uid != 0: self.perm_changer.finish()
+
class RestoreFile:
"""Hold data about a single mirror file and its related increments
@@ -617,3 +633,65 @@ class PatchITRB(rorpiter.ITRBranch):
self.base_rp.rmdir()
if self.dir_replacement.lstat():
rpath.rename(self.dir_replacement, self.base_rp)
+
+
+class PermissionChanger:
+ """Change the permission of mirror files and directories
+
+ The problem is that mirror files and directories may need their
+ permissions changed in order to be read and listed, and then
+ changed back when we are done. This class hooks into the CachedRF
+ object to know when an rp is needed.
+
+ """
+ def __init__(self, root_rp):
+ self.root_rp = root_rp
+ self.current_index = ()
+ # Below is a list of (index, rp, old_perm) triples in reverse
+ # order that need clearing
+ self.open_index_list = []
+
+ def __call__(self, rp):
+ """Given rpath, change permissions up and including rp"""
+ index, old_index = rp.index, self.current_index
+ self.current_index = index
+ if not index or index == old_index: return
+ assert index > old_index, (index, old_index)
+ self.restore_old(rp, index)
+ self.add_new(rp, old_index, index)
+
+ def restore_old(self, rp, index):
+ """Restore permissions for indicies we are done with"""
+ while self.open_index_list:
+ old_index, old_rp, old_perms = self.open_index_list[0]
+ if index[:len(old_index)] > old_index: old_rp.chmod(old_perms)
+ else: break
+ del self.open_index_list[0]
+
+ def add_new(self, rp, old_index, index):
+ """Change permissions of directories between old_index and index"""
+ for rp in self.get_new_rp_list(rp, old_index, index):
+ if ((rp.isreg() and not rp.readable()) or
+ (rp.isdir() and not rp.hasfullperms())):
+ old_perms = rp.getperms()
+ self.open_index_list.insert(0, (index, rp, old_perms))
+ if rp.isreg(): rp.chmod(0400 | old_perms)
+ else: rp.chmod(0700 | old_perms)
+
+ def get_new_rp_list(self, rp, old_index, index):
+ """Return list of new rp's between old_index and index"""
+ for i in range(len(index)-1, -1, -1):
+ if old_index[:i] == index[:i]:
+ common_prefix_len = i
+ break
+ else: assert 0
+
+ new_rps = []
+ for total_len in range(common_prefix_len+1, len(index)):
+ new_rps.append(self.root_rp.new_index(index[:total_len]))
+ new_rps.append(rp)
+ return new_rps
+
+ def finish(self):
+ """Restore any remaining rps"""
+ for index, rp, perms in self.open_index_list: rp.chmod(perms)