-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (C) 2013 Intra2net AG
#
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.
# 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
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(b'\x1f\x8b',
- 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 = []
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))