cleanly perform block transition in non-concat mode
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Fri, 28 Apr 2017 12:04:42 +0000 (14:04 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:08 +0000 (13:34 +0200)
deltatar/deltatar.py
deltatar/tarfile.py

index d28617a..180745c 100644 (file)
@@ -559,21 +559,20 @@ class DeltaTar(object):
             comptype = 'tar'
 
         crypto_ctx = None
+        enccounter = None
         if mode == "w":
             self.initialize_encryption (CRYPTO_MODE_ENCRYPT)
             crypto_ctx = self.encryptor
+            if crypto_ctx is not None and \
+                    kind == AUXILIARY_FILE_INFO:
+                enccounter = crypto.AES_GCM_IV_CNT_INFOFILE
         elif mode == "r":
             self.initialize_encryption (CRYPTO_MODE_DECRYPT)
             crypto_ctx = self.decryptor
 
         sink = tarfile._Stream(name=path, mode=mode, comptype=comptype,
                                bufsize=tarfile.RECORDSIZE, fileobj=None,
-                               encryption=crypto_ctx)
-        if self.encryptor is not None and mode == "w":
-            counter = None
-            if kind == AUXILIARY_FILE_INFO:
-                counter = crypto.AES_GCM_IV_CNT_INFOFILE
-            sink._init_write_encrypt (path, counter)
+                               encryption=crypto_ctx, enccounter=enccounter)
 
         return sink
 
index 6bd3a42..59f9c9e 100644 (file)
@@ -420,7 +420,8 @@ class _Stream:
     remainder = -1 # track size in encrypted entries
 
     def __init__(self, name, mode, comptype, fileobj, bufsize,
-                 concat_stream=False, encryption=None, compresslevel=9):
+                 concat_stream=False, encryption=None, enccounter=None,
+                 compresslevel=9):
         """Construct a _Stream object.
         """
         self._extfileobj = True
@@ -466,7 +467,9 @@ class _Stream:
                     self.exception = zlib.error
                     self._init_read_gz()
                 elif mode == "w":
-                    if concat_stream is False and self.encryption is None:
+                    if concat_stream is False:
+                        if self.encryption is not None:
+                            self._init_write_encrypt (name, enccounter)
                         self._init_write_gz ()
                 self.crc = zlib.crc32(b"") & 0xFFFFffff
 
@@ -500,7 +503,13 @@ class _Stream:
                 else:
                     self.cmp = lzma.LZMACompressor()
 
-            elif comptype != "tar":
+            elif comptype == "tar":
+                if concat_stream is False \
+                        and mode == "w" \
+                        and self.encryption is not None:
+                    self._init_write_encrypt (name, enccounter)
+
+            else:
                 if self.encryption is not None:
                     raise InvalidEncryptionError("encryption not available for "
                                                  "compression %s" % comptype)
@@ -517,7 +526,8 @@ class _Stream:
             self.close()
 
 
-    def _init_write_encrypt (self, entry=None, counter=None):
+    def _init_write_encrypt (self, entry=None, counter=None,
+                             set_last_block_offset=False):
         """Save position for delayed write of header; fill the header location
         with dummy bytes."""
         if self.encryption is not None:
@@ -531,6 +541,8 @@ class _Stream:
 
             self.lasthdr = self.fileobj.tell()
             self.__write_to_file(dummyhdr)
+            if set_last_block_offset is True:
+                self.last_block_offset = self.lasthdr
 
 
     def _finalize_write_encrypt (self):
@@ -580,9 +592,7 @@ class _Stream:
         '''
         self.concat_pos = 0
         self.crc = self.zlib.crc32(b"") & 0xFFFFffff
-        first = False
-        if self.cmp is None:
-            first = True
+        first = self.cmp is None
         self.cmp = self.zlib.compressobj(self.compresslevel,
                                          self.zlib.DEFLATED,
                                          -self.zlib.MAX_WBITS,
@@ -590,7 +600,7 @@ class _Stream:
                                          0)
 
         # if aes, we encrypt after compression
-        if self.encryption is None and set_last_block_offset:
+        if set_last_block_offset is True:
             self.last_block_offset = self.fileobj.tell()
 
         self.__write(gz_header (self.name if first is True else None))
@@ -2431,16 +2441,15 @@ class TarFile(object):
 
         tarinfo = copy.copy(tarinfo)
 
-        if self.concat_compression is True and \
-                getattr (self.fileobj, "cmp", None) is not None:
-            self.fileobj._finalize_write_gz ()
-
-        if getattr (self.fileobj, "encryption", None) is not None:
-            self.fileobj._finalize_write_encrypt ()
-            self.fileobj._init_write_encrypt (tarinfo.name)
-
-        if self.concat_compression:
-            self.fileobj._init_write_gz (True)
+        if self.concat_compression is True:
+            if getattr (self.fileobj, "cmp", None) is not None:
+                self.fileobj._finalize_write_gz ()
+            encrypt = getattr (self.fileobj, "encryption", None) is not None
+            if encrypt is True:
+                self.fileobj._finalize_write_encrypt ()
+                self.fileobj._init_write_encrypt (tarinfo.name,
+                                                  set_last_block_offset=True)
+            self.fileobj._init_write_gz (set_last_block_offset=not encrypt)
             self.last_block_offset = self.fileobj.last_block_offset
         else:
             self.last_block_offset = self.fileobj.tell()
@@ -2516,16 +2525,17 @@ class TarFile(object):
                 # the “new_volume_handler” is supposed to call .close() on the
                 # “fileobj” _Stream
                 self.new_volume_handler(self, self.base_name, self.volume_number)
-                if self.concat_compression and \
-                        getattr (self.fileobj, "cmp", None) is not None:
-                    # e. g. compressed PAX header written
-                    self.fileobj._finalize_write_gz ()
 
                 self.volume_tarinfo = None
 
-                if getattr (self.fileobj, "encryption", None) is not None:
-                    self.fileobj._init_write_encrypt (tarinfo.name)
                 if self.concat_compression is True:
+                    # with non-concat modes, this is taken care by the _Stream
+                    # ctor as invoked by the newvol handler
+                    if getattr (self.fileobj, "cmp", None) is not None:
+                        # e. g. compressed PAX header written
+                        self.fileobj._finalize_write_gz ()
+                    if getattr (self.fileobj, "encryption", None) is not None:
+                        self.fileobj._init_write_encrypt (tarinfo.name)
                     self.fileobj._init_write_gz ()
 
                 # write new volume header