From 838ffb195694abac8b64fbd6954e2d43e4b8d6af Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 31 May 2017 13:53:21 +0200 Subject: [PATCH] support PDT encrypted archives with rescue_tar.py --- rescue_tar.py | 58 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 45 insertions(+), 13 deletions(-) diff --git a/rescue_tar.py b/rescue_tar.py index 6ddd83a..ca64725 100644 --- a/rescue_tar.py +++ b/rescue_tar.py @@ -19,13 +19,15 @@ import argparse import os +import sys import tempfile from functools import partial from deltatar import tarfile +from deltatar import crypto import filesplit -def rescue(tar_files, rescue_dir=None): +def rescue(tar_files, rescue_dir=None, password=None): ''' Rescues a multivolume tarfile. Checks file name extension to detect format (compression, etc). Assumes it to be multivolume tar. @@ -50,10 +52,21 @@ def rescue(tar_files, rescue_dir=None): # autodetect file type by extension first_tar_file = tar_files[0] + + mode = "r" + decr = None + separator = None if first_tar_file.endswith(".tar.gz"): mode = "r#gz" - elif first_tar_file.endswith(".tar"): - mode = "r" + separator = tarfile.GZ_MAGIC_BYTES + elif first_tar_file.endswith(".tar.gz.pdtcrypt"): + if password is None: + print ("ERROR: tarball is encrypted but no password given", + file=sys.stderr) + return -1 + mode = "r#gz" + decr = crypto.Decrypt (password=password) + separator = crypto.PDTCRYPT_HDR_MAGIC base_name = os.path.basename(first_tar_file) extract_files = tar_files @@ -74,10 +87,12 @@ def rescue(tar_files, rescue_dir=None): return open(path, 'wb') new_gz = partial(new_gz, context, extract_files) - # split in compressed chunks + # split in compressed or encrypted chunks, respectively for f in tar_files: - filesplit.split_file(tarfile.GZ_MAGIC_BYTES, - os.path.join(rescue_dir, base_name), f, new_gz) + filesplit.split_file (separator, + os.path.join(rescue_dir, base_name), + f, + new_gz) # includes volumes already extracted with new_volume_handler already_extracted_vols = [] @@ -99,30 +114,47 @@ def rescue(tar_files, rescue_dir=None): volume_path = "%s.%d" % (base_name, next_num) already_extracted_vols.append(volume_path) - tarobj.open_volume(volume_path) + tarobj.open_volume(volume_path, encryption=decr) new_volume_handler = partial(new_volume_handler, already_extracted_vols) # extract files, as much as possible + errs = 0 for f in extract_files: if f in already_extracted_vols: continue try: - tarobj = tarfile.TarFile.open(f, mode=mode, - new_volume_handler=new_volume_handler) + tarobj = tarfile.TarFile.open \ + (f, + mode=mode, + encryption=decr, + new_volume_handler=new_volume_handler) tarobj.extractall() tarobj.close() - except: - pass + except Exception as exn: + print ("ERROR: error extracting file “%s” (%s)" % (f, exn), + file=sys.stderr) + errs += 1 + + if errs > 0: + print ("ERROR: encountered %d errors extracting %s" + % (errs, first_tar_file), file=sys.stderr) + return -1 + + return 0 if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("--rescue_dir", help="directory where rescue files " + parser.add_argument("--rescue-dir", help="directory where rescue files " "should be created. /tmp by default") + parser.add_argument("--password", + help="password; mandatory for encrypted tarballs") parser.add_argument("tar_files", nargs="+", help="list of files of a " "multitar file to rescue. Assumes format first.extension " "second.extension.0 third.extension.1 ...") args = parser.parse_args() - rescue(tar_files=args.tar_files, rescue_dir=args.rescue_dir) + sys.exit (rescue (tar_files=args.tar_files, + rescue_dir=args.rescue_dir, + password=args.password)) -- 1.7.1