draft rescue mode through all layers
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Wed, 23 Aug 2017 08:49:36 +0000 (10:49 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:09 +0000 (13:34 +0200)
The strategy is for rescue mode to reconstruct the relevant [*]
information from the index by inspecting the passed tar object,
then continue from there. On the crypto side, this boils down to
a streamlined (and silent) version of the “scan” mode. The
tarfile side is still WIP.

[*] Omitting the useless parts like inode number.

deltatar/crypto.py
deltatar/deltatar.py
deltatar/tarfile.py

index 538e4db..a5d08c4 100755 (executable)
@@ -637,6 +637,36 @@ def try_decrypt (ifd, off, hdr, secret, ofd=-1):
     return pos - off
 
 
+def readable_objects_offsets (ifd, secret, cands):
+    """
+    From a list of candidates, locate the ones that mark the start of actual
+    readable PDTCRYPT objects.
+    """
+    good = []
+    nobj = 0
+    for cand in cands:
+        nobj += 1
+        vdt, hdr = inspect_hdr (ifd, cand)
+        if vdt == HDR_CAND_JUNK:
+            pass # ignore unreadable ones
+        elif vdt in [HDR_CAND_GOOD, HDR_CAND_FISHY]:
+            off0 = cand + PDTCRYPT_HDR_SIZE
+            ok = try_decrypt (ifd, off0, hdr, secret) == hdr ["ctsize"]
+            if ok is True:
+                good.append (cand)
+    return good
+
+
+def reconstruct_offsets (fname, secret):
+    ifd = os.open (fname, os.O_RDONLY)
+
+    try:
+        cands = locate_hdr_candidates (ifd)
+        return readable_objects_offsets (ifd, secret, cands)
+    finally:
+        os.close (ifd)
+
+
 ###############################################################################
 ## passthrough / null encryption
 ###############################################################################
@@ -1364,7 +1394,7 @@ def open2_dump_file (fname, dir_fd, force=False):
     outfd = -1
 
     oflags = os.O_CREAT | os.O_WRONLY
-    if PDTCRYPT_OVERWRITE is True:
+    if force is True:
         oflags |= os.O_TRUNC
     else:
         oflags |= os.O_EXCL
@@ -1874,6 +1904,7 @@ def bail (msg):
 
 
 def parse_argv (argv):
+    global PDTCRYPT_OVERWRITE
     global SELF
     mode          = PDTCRYPT_DECRYPT
     secret        = None
@@ -1931,7 +1962,6 @@ def parse_argv (argv):
                     outsspec = checked_arg ()
                     if PDTCRYPT_VERBOSE is True: noise ("PDT: decrypt to %s" % outsspec)
                 elif arg in [ "-f", "--force" ]:
-                    global PDTCRYPT_OVERWRITE
                     PDTCRYPT_OVERWRITE = True
                     if PDTCRYPT_VERBOSE is True: noise ("PDT: overwrite existing files")
                 elif arg in [ "-S", "--split" ]:
@@ -1965,7 +1995,6 @@ def parse_argv (argv):
                     outsspec = checked_arg ()
                     if PDTCRYPT_VERBOSE is True: noise ("PDT: decrypt to %s" % outsspec)
                 elif arg in [ "-f", "--force" ]:
-                    global PDTCRYPT_OVERWRITE
                     PDTCRYPT_OVERWRITE = True
                     if PDTCRYPT_VERBOSE is True: noise ("PDT: overwrite existing files")
                 else:
index b1b8ccc..02670da 100644 (file)
@@ -1490,15 +1490,19 @@ class DeltaTar(object):
                                    disaster=tarfile.TOLERANCE_RECOVER)
 
 
-    def rescue_backup(self, target_path, backup_indexes_paths=[],
+    def rescue_backup(self, target_path, backup_tar_path,
                       restore_callback=None):
         """
         More aggressive “unfsck” mode: do not rely on the index data as the
         files may be corrupt; skim files for header-like information and
         attempt to retrieve the data.
         """
+        faux_index = tarfile.gen_rescue_index(backup_tar_path,
+                                              password=self.password,
+                                              key=self.crypto_key)
+
         return self.restore_backup(target_path,
-                                   backup_indexes_paths=backup_indexes_paths,
+                                   backup_index=faux_index,
                                    disaster=tarfile.TOLERANCE_RESCUE)
 
 
index cc74e92..ef4fca0 100644 (file)
@@ -3291,6 +3291,24 @@ class TarIter:
 
         return tarinfo
 
+#---------------------------------------------------------
+# support functionality for rescue mode
+#---------------------------------------------------------
+
+def gen_rescue_index (backup_tar_path, password=None, key=None):
+    psidx   = [] # pseudo index, return value
+    offsets = None
+    secret  = None
+
+    if password is not None:
+        secret = (crypto.PDTCRYPT_SECRET_PW, password)
+    elif key is not None:
+        secret = (crypto.PDTCRYPT_SECRET_KEY, key)
+
+    if secret is not None:
+        offsets = crypto.reconstruct_offsets (backup_tar_path, secret)
+
+    return psidx
 
 #--------------------
 # exported functions