read tar objects at predetermined offsets for rescue index
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Thu, 24 Aug 2017 09:57:53 +0000 (11:57 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:09 +0000 (13:34 +0200)
Leverage the tarobj to read the object headers at the determined
offsets. Currently only implemented for encrypted archives whose
offsets are located with *crypto.py*.

deltatar/tarfile.py

index ef4fca0..4f9e033 100644 (file)
@@ -2218,6 +2218,19 @@ class TarFile(object):
 
         raise ValueError("undiscernible mode %r" % mode)
 
+
+    @classmethod
+    def open_at_offset(cls, offset, *a, **kwa):
+        """
+        Same as ``.open()``, but start reading at the given offset. Assumes a
+        seekable file object.
+        """
+        fileobj = kwa.get ("fileobj")
+        if fileobj is not None:
+            fileobj.seek (offset)
+        return cls.open (*a, **kwa)
+
+
     @classmethod
     def taropen(cls, name, mode="r", fileobj=None, **kwargs):
         """Open uncompressed tar archive name for reading or writing.
@@ -3295,10 +3308,36 @@ class TarIter:
 # support functionality for rescue mode
 #---------------------------------------------------------
 
-def gen_rescue_index (backup_tar_path, password=None, key=None):
+def read_tarobj_at_offset (fileobj, offset, mode, secret=None):
+    decr = None
+    ks   = secret [0]
+
+    if ks == crypto.PDTCRYPT_SECRET_PW:
+        decr = crypto.Decrypt (password=secret [1])
+    elif ks == crypto.PDTCRYPT_SECRET_KEY:
+        key = binascii.unhexlify (secret [1])
+        decr = crypto.Decrypt (key=key)
+    else:
+        raise RuntimeError
+
+    tarobj = \
+        TarFile.open_at_offset (offset,
+                                mode=mode,
+                                fileobj=fileobj,
+                                format=GNU_FORMAT,
+                                concat='#' in mode,
+                                encryption=decr,
+                                save_to_members=False,
+                                tolerance=TOLERANCE_RESCUE)
+
+    return tarobj.next ()
+
+
+def gen_rescue_index (backup_tar_path, mode, password=None, key=None):
     psidx   = [] # pseudo index, return value
     offsets = None
     secret  = None
+    mode    = "r" + mode
 
     if password is not None:
         secret = (crypto.PDTCRYPT_SECRET_PW, password)
@@ -3307,6 +3346,9 @@ def gen_rescue_index (backup_tar_path, password=None, key=None):
 
     if secret is not None:
         offsets = crypto.reconstruct_offsets (backup_tar_path, secret)
+        fileobj = bltn_open (backup_tar_path, "rb")
+        psinfos = [ read_tarobj_at_offset (fileobj, off, mode, secret=secret)
+                    for off in offsets ]
 
     return psidx