explicitly disable gz initalization for _Stream’s used in aux files
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Fri, 21 Apr 2017 16:03:17 +0000 (18:03 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:08 +0000 (13:34 +0200)
The process of writing an auxiliary (index, info) file differs
drastically from that of tar archives: Since files are not added
individually, the encryption must be initialized externally and
the compression layer cannot rely on being enable in the ctor
because, obviously, the latter is executed before the manual
encryption setup can be performed.

Extend the API of the _Stream ctor with a parameter to “noinit”
to request that all initialization be postponed until the
encryption has been set up. This seems to do the trick but is
quite ugly.

deltatar/deltatar.py
deltatar/tarfile.py
testing/test_deltatar.py

index 345e33f..26375e8 100644 (file)
@@ -533,9 +533,8 @@ class DeltaTar(object):
             comptype = 'tar'
 
         sink = tarfile._Stream(name=path, mode=mode, comptype=comptype,
-                               concat_stream=True, # no global zlib header
                                bufsize=tarfile.RECORDSIZE, fileobj=None,
-                               encryption=self.crypto_ctx)
+                               encryption=self.crypto_ctx, noinit=True)
         if self.crypto_ctx is not None and mode == "w":
             counter = None
             if kind == AUXILIARY_FILE_INFO:
index 84a3c12..13e092c 100644 (file)
@@ -418,7 +418,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, compresslevel=9,
+                 noinit=False):
         """Construct a _Stream object.
         """
         self._extfileobj = True
@@ -461,14 +462,14 @@ class _Stream:
                 except ImportError:
                     raise CompressionError("zlib module is not available")
                 self.zlib = zlib
-                if concat_stream is False:
-                    if mode == "r":
+                if mode == "r":
+                    self.exception = zlib.error
+                    if concat_stream is True:
                         self._init_read_gz()
-                    elif mode == "w":
+                elif mode == "w":
+                    if noinit is False:
                         self._new_gz_block()
                 self.crc = zlib.crc32(b"") & 0xFFFFffff
-                if mode == "r":
-                    self.exception = zlib.error
 
             elif comptype == "bz2":
                 if self.encryption is not None:
@@ -1975,7 +1976,6 @@ class TarFile(object):
            'r#gz'       open a stream of gzip compressed tar blocks for reading
            'w#gz'       open a stream of gzip compressed tar blocks for writing
         """
-
         if not name and not fileobj:
             raise ValueError("nothing to open")
 
@@ -2041,11 +2041,10 @@ class TarFile(object):
             if filemode not in "rw":
                 raise ValueError("mode must be 'r' or 'w'")
 
-            kwargs['concat_compression'] = True
-
             stream = _Stream(name, filemode, comptype, fileobj, bufsize,
                              concat_stream=True, encryption=encryption,
                              compresslevel=compresslevel)
+            kwargs ["concat_compression"] = True
             try:
                 t = cls(name, filemode, stream, **kwargs)
             except: # XXX except what?
index e1646be..b776d5b 100644 (file)
@@ -209,7 +209,6 @@ class DeltaTarTest(BaseTest):
         with big files bigger than the max volume size and
         restore it.
         '''
-
         if self.MODE.startswith(':') or self.MODE.startswith('|'):
             raise SkipTest('this test only works for uncompressed '
                            'or concat compressed modes')