diff options
author | ben <ben@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109> | 2002-05-10 23:14:35 +0000 |
---|---|---|
committer | ben <ben@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109> | 2002-05-10 23:14:35 +0000 |
commit | 807241bc4f322edc6f95782291900362484263df (patch) | |
tree | 95dc93d87081ab901e31844867d4facca6207aac /rdiff-backup/rdiff_backup/restore.py | |
parent | 5c059e737511644b0056b8326b52763c82efcac4 (diff) | |
download | rdiff-backup-807241bc4f322edc6f95782291900362484263df.tar.gz |
Lots of changes, see changelog for 0.7.4.
git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/trunk@72 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
Diffstat (limited to 'rdiff-backup/rdiff_backup/restore.py')
-rw-r--r-- | rdiff-backup/rdiff_backup/restore.py | 172 |
1 files changed, 120 insertions, 52 deletions
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py index dcba7f3..0faa9b2 100644 --- a/rdiff-backup/rdiff_backup/restore.py +++ b/rdiff-backup/rdiff_backup/restore.py @@ -24,32 +24,78 @@ class Restore: same index as mirror. """ - if not isinstance(mirror, DSRPath): - mirror = DSRPath(source = 1, mirror) - if not isinstance(target, DSRPath): - target = DSRPath(source = None, target) + if not isinstance(mirror, DSRPath): mirror = DSRPath(1, mirror) + if not isinstance(target, DSRPath): target = DSRPath(None, target) + + mirror_time = Restore.get_mirror_time() + rest_time = Restore.get_rest_time(rest_time) + inc_list = Restore.get_inclist(inc_rpath) + rid = RestoreIncrementData(inc_rpath.index, inc_rpath, inc_list) + rid.sortincseq(rest_time, mirror_time) + Restore.check_hardlinks(rest_time) + Restore.restore_recursive(inc_rpath.index, mirror, rid, target, + rest_time, mirror_time) + + def get_mirror_time(): + """Return the time (in seconds) of latest mirror""" + current_mirror_incs = \ + Restore.get_inclist(Globals.rbdir.append("current_mirror")) + if not current_mirror_incs: + Log.FatalError("Could not get time of current mirror") + elif len(current_mirror_incs) > 1: + Log("Warning, two different dates for current mirror found", 2) + return Time.stringtotime(current_mirror_incs[0].getinctime()) + + def get_rest_time(old_rest_time): + """If old_rest_time is between two increments, return older time + + There is a slightly tricky reason for doing this: The rest of + the code just ignores increments that are older than + rest_time. But sometimes we want to consider the very next + increment older than rest time, because rest_time will be + between two increments, and what was actually on the mirror + side will correspond to the older one. + + So here we assume all rdiff-backup events were recorded in + "increments" increments, and if its in-between we pick the + older one here. + """ + base_incs = Restore.get_inclist(Globals.rbdir.append("increments")) + if not base_incs: return old_rest_time + inctimes = [Time.stringtotime(inc.getinctime()) for inc in base_incs] + return max(filter(lambda time: time <= old_rest_time, inctimes)) + + def get_inclist(inc_rpath): + """Returns increments with given base""" dirname, basename = inc_rpath.dirsplit() parent_dir = RPath(inc_rpath.conn, dirname, ()) index = inc_rpath.index - if inc_rpath.index: + if index: get_inc_ext = lambda filename: \ RPath(inc_rpath.conn, inc_rpath.base, inc_rpath.index[:-1] + (filename,)) else: get_inc_ext = lambda filename: \ - RPath(inc_rpath.conn, os.join(dirname, filename)) + RPath(inc_rpath.conn, os.path.join(dirname, filename)) inc_list = [] for filename in parent_dir.listdir(): inc = get_inc_ext(filename) - if inc.getincbase_str() == basename: inc_list.append(inc) - - rid = RestoreIncrementData(index, inc_rpath, inc_list) - rid.sortincseq(rest_time) - Restore.restore_recursive(index, mirror, rid, target, rest_time) - - def restore_recursive(index, mirror, rid, target, time): + if inc.isincfile() and inc.getincbase_str() == basename: + inc_list.append(inc) + return inc_list + + def check_hardlinks(rest_time): + """Check for hard links and enable hard link support if found""" + if (Globals.preserve_hardlinks != 0 and + Hardlink.retrieve_final(rest_time)): + Log("Hard link information found, attempting to preserve " + "hard links.", 5) + SetConnections.UpdateGlobal('preserve_hardlinks', 1) + else: SetConnections.UpdateGlobal('preserve_hardlinks', None) + + def restore_recursive(index, mirror, rid, target, time, mirror_time): """Recursive restore function. rid is a RestoreIncrementData object whose inclist is already @@ -66,14 +112,15 @@ class Restore: mirror_finalizer = DestructiveSteppingFinalizer() target_finalizer = DestructiveSteppingFinalizer() - for rcd in Restore.yield_rcds(rid.index, mirror, rid, target, time): + for rcd in Restore.yield_rcds(rid.index, mirror, rid, + target, time, mirror_time): rcd.RestoreFile() - if rcd.mirror: mirror_finalizer(rcd.mirror) - target_finalizer(rcd.target) + if rcd.mirror: mirror_finalizer(rcd.index, rcd.mirror) + target_finalizer(rcd.target.index, rcd.target) target_finalizer.Finish() mirror_finalizer.Finish() - def yield_rcds(index, mirrorrp, rid, target, rest_time): + def yield_rcds(index, mirrorrp, rid, target, rest_time, mirror_time): """Iterate RestoreCombinedData objects starting with given args rid is a RestoreCombinedData object. target is an rpath where @@ -91,9 +138,10 @@ class Restore: mirrorrp = None rcd = RestoreCombinedData(rid, mirrorrp, target) - if mirrorrp and mirrorrp.isdir() or rid and rid.inc_rpath.isdir(): + if mirrorrp and mirrorrp.isdir() or \ + rid and rid.inc_rpath and rid.inc_rpath.isdir(): sub_rcds = Restore.yield_sub_rcds(index, mirrorrp, rid, - target, rest_time) + target, rest_time, mirror_time) else: sub_rcds = None if select_result == 1: @@ -108,35 +156,39 @@ class Restore: yield first for sub_rcd in sub_rcds: yield sub_rcd - def yield_collated_tuples_dir(index, mirrorrp, rid, target, rest_time): + def yield_sub_rcds(index, mirrorrp, rid, target, rest_time, mirror_time): """Yield collated tuples from inside given args""" - if not Restore.check_dir_exists(mirrorrp, inc_tup): return + if not Restore.check_dir_exists(mirrorrp, rid): return mirror_iter = Restore.yield_mirrorrps(mirrorrp) - rid_iter = Restore.get_rids(rid, rest_time) + rid_iter = Restore.yield_rids(rid, rest_time, mirror_time) for indexed_tup in RORPIter.CollateIterators(mirror_iter, rid_iter): index = indexed_tup.index new_mirrorrp, new_rid = indexed_tup - for rcd in Restore.yield_collated_tuples(index, new_mirrorrp, - new_rid, target.new_index(index), rest_time): + for rcd in Restore.yield_rcds(index, new_mirrorrp, + new_rid, target.append(index[-1]), rest_time, mirror_time): yield rcd - def check_dir_exists(mirrorrp, inc_tuple): + def check_dir_exists(mirrorrp, rid): """Return true if target should be a directory""" - if inc_tuple and inc_tuple[1]: + if rid and rid.inc_list: # Incs say dir if last (earliest) one is a dir increment - return inc_tuple[1][-1].getinctype() == "dir" + return rid.inc_list[-1].getinctype() == "dir" elif mirrorrp: return mirrorrp.isdir() # if no incs, copy mirror else: return None def yield_mirrorrps(mirrorrp): """Yield mirrorrps underneath given mirrorrp""" if mirrorrp and mirrorrp.isdir(): - dirlist = mirrorrp.listdir() - dirlist.sort() - for filename in dirlist: yield mirrorrp.append(filename) - - def yield_rids(rid, rest_time): + if Globals.quoting_enabled: + for rp in FilenameMapping.get_quoted_dir_children(mirrorrp): + yield rp + else: + dirlist = mirrorrp.listdir() + dirlist.sort() + for filename in dirlist: yield mirrorrp.append(filename) + + def yield_rids(rid, rest_time, mirror_time): """Yield RestoreIncrementData objects within given rid dir If the rid doesn't correspond to a directory, don't yield any @@ -148,16 +200,19 @@ class Restore: if not rid or not rid.inc_rpath or not rid.inc_rpath.isdir(): return rid_dict = {} # dictionary of basenames:rids dirlist = rid.inc_rpath.listdir() + if Globals.quoting_enabled: + dirlist = [FilenameMapping.unquote(fn) for fn in dirlist] def affirm_dict_indexed(basename): """Make sure the rid dictionary has given basename as key""" - if not inc_list_dict.has_key(basename): + if not rid_dict.has_key(basename): rid_dict[basename] = RestoreIncrementData( rid.index + (basename,), None, []) # init with empty rid def add_to_dict(filename): """Add filename to the inc tuple dictionary""" rp = rid.inc_rpath.append(filename) + if Globals.quoting_enabled: rp.quote_path() if rp.isincfile(): basename = rp.getincbase_str() affirm_dict_indexed(basename) @@ -167,14 +222,14 @@ class Restore: rid_dict[filename].inc_rpath = rp for filename in dirlist: add_to_dict(filename) - keys = inc_list_dict.keys() + keys = rid_dict.keys() keys.sort() # sortincseq now to avoid descending .missing directories later for key in keys: rid = rid_dict[key] if rid.inc_rpath or rid.inc_list: - rid.sortincseq(rest_time) + rid.sortincseq(rest_time, mirror_time) yield rid MakeStatic(Restore) @@ -192,26 +247,36 @@ class RestoreIncrementData: self.inc_rpath = inc_rpath self.inc_list = inc_list - def sortincseq(self, rest_time): + def sortincseq(self, rest_time, mirror_time): """Sort self.inc_list sequence, throwing away irrelevant increments""" - incpairs = map(lambda rp: (Time.stringtotime(rp.getinctime()), rp), - self.inc_list) - # Only consider increments at or after the time being restored - incpairs = filter(lambda pair: pair[0] >= rest_time, incpairs) + if not self.inc_list or rest_time >= mirror_time: + self.inc_list = [] + return - # Now throw away older unnecessary increments - incpairs.sort() + newer_incs = self.get_newer_incs(rest_time, mirror_time) i = 0 - while(i < len(incpairs)): + while(i < len(newer_incs)): # Only diff type increments require later versions - if incpairs[i][1].getinctype() != "diff": break + if newer_incs[i].getinctype() != "diff": break i = i+1 - incpairs = incpairs[:i+1] + self.inc_list = newer_incs[:i+1] + self.inc_list.reverse() # return in reversed order (latest first) + + def get_newer_incs(self, rest_time, mirror_time): + """Return list of newer incs sorted by time (increasing) - # Return increments in reversed order (latest first) - incpairs.reverse() - self.inc_list = map(lambda pair: pair[1], incpairs) + Also discard increments older than rest_time (rest_time we are + assuming is the exact time rdiff-backup was run, so no need to + consider the next oldest increment or any of that) + """ + incpairs = [] + for inc in self.inc_list: + time = Time.stringtotime(inc.getinctime()) + if time >= rest_time: incpairs.append((time, inc)) + incpairs.sort() + return [pair[1] for pair in incpairs] + class RestoreCombinedData: """Combine index information from increment and mirror directories @@ -235,9 +300,12 @@ class RestoreCombinedData: if mirror: self.mirror = mirror assert mirror.index == self.index + else: self.mirror = None elif mirror: self.index = mirror.index self.mirror = mirror + self.inc_list = [] + self.inc_rpath = None else: assert None, "neither rid nor mirror given" self.target = target @@ -249,15 +317,15 @@ class RestoreCombinedData: if self.restore_hardlink(): return - if not inclist or inclist[0].getinctype() == "diff": + if not self.inc_list or self.inc_list[0].getinctype() == "diff": assert self.mirror and self.mirror.lstat(), \ "No base to go with incs for %s" % self.target.path RPath.copy_with_attribs(self.mirror, self.target) for inc in self.inc_list: self.applyinc(inc, self.target) - def log(self) + def log(self): """Log current restore action""" - inc_string = ','.join(map(lambda x: x.path, self.inc_list)) + inc_string = ','.join([inc.path for inc in self.inc_list]) Log("Restoring %s with increments %s to %s" % (self.mirror and self.mirror.path, inc_string, self.target.path), 5) @@ -266,7 +334,7 @@ class RestoreCombinedData: """Hard link target and return true if hard linking appropriate""" if (Globals.preserve_hardlinks and Hardlink.restore_link(self.index, self.target)): - RPath.copy_attribs(self.inc_list and inc_list[-1] or + RPath.copy_attribs(self.inc_list and self.inc_list[-1] or self.mirror, self.target) return 1 return None |