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.py137
1 files changed, 100 insertions, 37 deletions
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index 0e0d62e..6e51b81 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -20,7 +20,6 @@ class Restore:
and rptarget is the rpath that will be written with the restored file.
"""
- inclist = Restore.sortincseq(rest_time, inclist)
if not inclist and not (rpbase and rpbase.lstat()):
return # no increments were applicable
Log("Restoring %s with increments %s to %s" %
@@ -58,7 +57,7 @@ class Restore:
i = i+1
incpairs = incpairs[:i+1]
- # Return increments in reversed order
+ # Return increments in reversed order (latest first)
incpairs.reverse()
return map(lambda pair: pair[1], incpairs)
@@ -106,44 +105,106 @@ class Restore:
"""
assert isinstance(target_base, DSRPath)
- collated = RORPIter.CollateIterators(
- DestructiveStepping.Iterate_from(mirror_base, None),
- Restore.yield_inc_tuples(baseinc_tup))
+ baseinc_tup = IndexedTuple(baseinc_tup.index, (baseinc_tup[0],
+ Restore.sortincseq(rest_time, baseinc_tup[1])))
+
+ collated = Restore.yield_collated_tuples((), mirror_base,
+ baseinc_tup, target_base, rest_time)
mirror_finalizer = DestructiveStepping.Finalizer()
target_finalizer = DestructiveStepping.Finalizer()
- for mirror, inc_tup in collated:
- if not inc_tup:
- inclist = []
- target = target_base.new_index(mirror.index)
- else:
- inclist = inc_tup[1]
- target = target_base.new_index(inc_tup.index)
+ for mirror, inc_tup, target in collated:
+ inclist = inc_tup and inc_tup[1] or []
DestructiveStepping.initialize(target, None)
Restore.RestoreFile(rest_time, mirror, mirror_rel_index,
inclist, target)
target_finalizer(target)
if mirror: mirror_finalizer(mirror)
target_finalizer.getresult()
- mirror_finalizer.getresult()
+ mirror_finalizer.getresult()
+
+ def yield_collated_tuples(index, mirrorrp, inc_tup, target, rest_time):
+ """Iterate collated tuples starting with given args
- def yield_inc_tuples(inc_tuple):
- """Iterate increment tuples starting with inc_tuple
+ A collated tuple is an IndexedTuple (mirrorrp, inc_tuple, target).
+ inc_tuple is itself an IndexedTuple. target is an rpath where
+ the created file should go.
- An increment tuple is an IndexedTuple (pair). The first will
- be the rpath of a directory, and the second is a list of all
- the increments associated with that directory. If there are
- increments that do not correspond to a directory, the first
- element will be None. All the rpaths involved correspond to
- files in the increment directory.
+ In this case the "mirror" directory is treated as the source,
+ and we are actually copying stuff onto what Select considers
+ the source directory.
"""
- oldindex, rpath = inc_tuple.index, inc_tuple[0]
- yield inc_tuple
- if not rpath or not rpath.isdir(): return
+ select_result = Globals.select_mirror.Select(target)
+ if select_result == 0: return
+
+ inc_base = inc_tup and inc_tup[0]
+ if mirrorrp and (not Globals.select_source.Select(mirrorrp) or
+ DestructiveStepping.initialize(mirrorrp, None)):
+ mirrorrp = None
+ collated_tuple = IndexedTuple(index, (mirrorrp, inc_tup, target))
+ if mirrorrp and mirrorrp.isdir() or inc_base and inc_base.isdir():
+ depth_tuples = Restore.yield_collated_tuples_dir(index, mirrorrp,
+ inc_tup, target, rest_time)
+ else: depth_tuples = None
+
+ if select_result == 1:
+ yield collated_tuple
+ if depth_tuples:
+ for tup in depth_tuples: yield tup
+ elif select_result == 2:
+ if depth_tuples:
+ try: first = depth_tuples.next()
+ except StopIteration: return # no tuples found inside, skip
+ yield collated_tuple
+ yield first
+ for tup in depth_tuples: yield tup
+
+ def yield_collated_tuples_dir(index, mirrorrp, inc_tup, target, rest_time):
+ """Yield collated tuples from inside given args"""
+ if not Restore.check_dir_exists(mirrorrp, inc_tup): return
+ if mirrorrp and mirrorrp.isdir():
+ dirlist = mirrorrp.listdir()
+ dirlist.sort()
+ mirror_list = map(lambda x: IndexedTuple(x, (mirrorrp.append(x),)),
+ dirlist)
+ else: mirror_list = []
+ inc_list = Restore.get_inc_tuples(inc_tup, rest_time)
+
+ for indexed_tup in RORPIter.CollateIterators(iter(mirror_list),
+ iter(inc_list)):
+ filename = indexed_tup.index
+ new_inc_tup = indexed_tup[1]
+ new_mirrorrp = indexed_tup[0] and indexed_tup[0][0]
+ for new_col_tup in Restore.yield_collated_tuples(
+ index + (filename,), new_mirrorrp, new_inc_tup,
+ target.append(filename), rest_time): yield new_col_tup
+
+ def check_dir_exists(mirrorrp, inc_tuple):
+ """Return true if target should be a directory"""
+ if inc_tuple and inc_tuple[1]:
+ # Incs say dir if last (earliest) one is a dir increment
+ return inc_tuple[1][-1].getinctype() == "dir"
+ elif mirrorrp: return mirrorrp.isdir() # if no incs, copy mirror
+ else: return None
+
+ def get_inc_tuples(inc_tuple, rest_time):
+ """Return list of inc tuples in given rpath of increment directory
+
+ An increment tuple is an IndexedTuple (pair). The second
+ element in the pair is a list of increments with the same
+ base. The first element is the rpath of the corresponding
+ base. Usually this base is a directory, otherwise it is
+ ignored. If there are increments whose corresponding base
+ doesn't exist, the first element will be None. All the rpaths
+ involved correspond to files in the increment directory.
+ """
+ if not inc_tuple: return []
+ oldindex, incdir = inc_tuple.index, inc_tuple[0]
+ if not incdir.isdir(): return []
inc_list_dict = {} # Index tuple lists by index
- dirlist = rpath.listdir()
+ dirlist = incdir.listdir()
def affirm_dict_indexed(index):
"""Make sure the inc_list_dict has given index"""
@@ -152,7 +213,7 @@ class Restore:
def add_to_dict(filename):
"""Add filename to the inc tuple dictionary"""
- rp = rpath.append(filename)
+ rp = incdir.append(filename)
if rp.isincfile():
basename = rp.getincbase_str()
affirm_dict_indexed(basename)
@@ -161,20 +222,22 @@ class Restore:
affirm_dict_indexed(filename)
inc_list_dict[filename][0] = rp
- def list2tuple(index):
- """Return inc_tuple version of dictionary entry by index"""
- inclist = inc_list_dict[index]
- if not inclist[1]: return None # no increments, so ignore
- return IndexedTuple(oldindex + (index,), inclist)
+ def index2tuple(index):
+ """Return inc_tuple version of dictionary entry by index
+
+ Also runs sortincseq to sort the increments and remove
+ irrelevant ones. This is done here so we can avoid
+ descending into .missing directories.
+
+ """
+ incbase, inclist = inc_list_dict[index]
+ inclist = Restore.sortincseq(rest_time, inclist)
+ if not inclist: return None # no relevant increments, so ignore
+ return IndexedTuple(index, (incbase, inclist))
for filename in dirlist: add_to_dict(filename)
keys = inc_list_dict.keys()
keys.sort()
- for index in keys:
- new_inc_tuple = list2tuple(index)
- if not new_inc_tuple: continue
- elif new_inc_tuple[0]: # corresponds to directory
- for i in Restore.yield_inc_tuples(new_inc_tuple): yield i
- else: yield new_inc_tuple
+ return filter(lambda x: x, map(index2tuple, keys))
MakeStatic(Restore)