From: Philipp Gesang Date: Tue, 29 Aug 2017 10:00:54 +0000 (+0200) Subject: implement volume handling for rescue mode X-Git-Tag: v2.2~7^2~36 X-Git-Url: http://developer.intra2net.com/git/?p=python-delta-tar;a=commitdiff_plain;h=27ee4dd4df48340541317123f5df348056c235ca implement volume handling for rescue mode When reconstructing the index, traverse backup volumes and set the “volume” member on the objects appropriately. --- diff --git a/deltatar/deltatar.py b/deltatar/deltatar.py index 221b7b3..f7e88c9 100644 --- a/deltatar/deltatar.py +++ b/deltatar/deltatar.py @@ -1541,10 +1541,16 @@ class DeltaTar(object): files may be corrupt; skim files for header-like information and attempt to retrieve the data. """ - backup_index = tarfile.gen_rescue_index(backup_tar_path, - self.mode, - password=self.password, - key=self.crypto_key) + def gen_volume_name (nvol): + return os.path.join (os.path.dirname (backup_tar_path), + self.volume_name_func (backup_tar_path, + True, + nvol)) + + backup_index = tarfile.gen_rescue_index (gen_volume_name, + self.mode, + password=self.password, + key=self.crypto_key) return self.restore_backup(target_path, backup_index=backup_index, diff --git a/deltatar/tarfile.py b/deltatar/tarfile.py index 31e46b9..b2de2d5 100644 --- a/deltatar/tarfile.py +++ b/deltatar/tarfile.py @@ -2750,6 +2750,7 @@ class TarFile(object): ''' Called by the user to change this tar file to point to a new volume. ''' + # open the file using either fileobj or name if not fileobj: if self.mode == "a" and not os.path.exists(name): @@ -2766,7 +2767,8 @@ class TarFile(object): fileobj=None, bufsize=self.fileobj.bufsize, encryption=encryption or self.fileobj.encryption, - concat=self.fileobj.arcmode & ARCMODE_CONCAT) + concat=self.fileobj.arcmode & ARCMODE_CONCAT, + tolerance=self.fileobj.tolerance) else: # here, we lose information about compression/encryption! self._dbg(3, 'open_volume: builtin open') @@ -3748,28 +3750,45 @@ def idxent_of_tarinfo (tarinfo): } -def gen_rescue_index (backup_tar_path, mode, password=None, key=None): +def gen_rescue_index (gen_volume_name, mode, maxvol=None, password=None, key=None): + infos = [] psidx = [] # pseudo index, return value offsets = None secret = crypto.make_secret (password=password, key=key) - if secret is not None: - offsets = crypto.reconstruct_offsets (backup_tar_path, secret) - elif mode == "#gz": - offsets = reconstruct_offsets_gz (backup_tar_path) - elif mode == "#": - offsets = reconstruct_offsets_tar (backup_tar_path) - else: - raise TarError ("no rescue handling for mode “%s”" % mode) + nvol = 0 - fileobj = bltn_open (backup_tar_path, "rb") - infos = [ (off, read_tarobj_at_offset (fileobj, off, mode, secret=secret)) - for off in offsets ] - def aux (o, ti): + def aux (o, nvol, ti): ie = idxent_of_tarinfo (ti) ie ["offset"] = o + ie ["volume"] = nvol return ie - psidx = [ aux (o, ti) for o, ti in infos ] + + while True: + vpath = gen_volume_name (nvol) + try: + if secret is not None: + offsets = crypto.reconstruct_offsets (vpath, secret) + elif mode == "#gz": + offsets = reconstruct_offsets_gz (vpath) + elif mode == "#": + offsets = reconstruct_offsets_tar (vpath) + else: + raise TarError ("no rescue handling for mode “%s”" % mode) + except FileNotFoundError as exn: + # volume does not exist + if maxvol is not None and i < maxvol: + continue # explicit volume number specified, ignore missing ones + else: + break + + fileobj = bltn_open (vpath, "rb") + infos += [ (off, nvol, read_tarobj_at_offset (fileobj, off, mode, + secret=secret)) + for off in offsets ] + nvol += 1 + + psidx = [ aux (o, nvol, ti) for o, nvol, ti in infos ] return psidx diff --git a/testing/test_recover.py b/testing/test_recover.py index a769d91..f2147dd 100644 --- a/testing/test_recover.py +++ b/testing/test_recover.py @@ -545,7 +545,12 @@ class GenIndexTest (DefectiveTest): (source_path=self.src_path, backup_path=bak_path, max_volume_size=1) - psidx = tarfile.gen_rescue_index (backup_full, mode, password=self.PASSWORD) + def gen_volume_name (nvol): + return os.path.join (bak_path, vname (backup_full, True, nvol)) + + psidx = tarfile.gen_rescue_index (gen_volume_name, + mode, + password=self.PASSWORD) assert len (psidx) == len (self.hash)