From c04e07519b40c5f8c70f7cbf5a3cbac891705901 Mon Sep 17 00:00:00 2001 From: Eduardo Robles Elvira Date: Wed, 26 Jun 2013 10:51:04 +0200 Subject: [PATCH] fixing multivolume related bugs --- deltatar/tarfile.py | 53 ++++++++++++++++++++++++++++++++++---------------- 1 files changed, 36 insertions(+), 17 deletions(-) diff --git a/deltatar/tarfile.py b/deltatar/tarfile.py index e95755d..5d356e3 100644 --- a/deltatar/tarfile.py +++ b/deltatar/tarfile.py @@ -1049,6 +1049,8 @@ class TarInfo(object): """ info["magic"] = POSIX_MAGIC pax_headers = self.pax_headers.copy() + if self.ismultivol(): + info['size'] = info['size'] - self.volume_offset # Test string fields for values that exceed the field length or cannot # be represented in ASCII encoding. @@ -1423,7 +1425,6 @@ class TarInfo(object): except HeaderError: raise SubsequentHeaderError("missing or bad subsequent header") - if self.type in (XHDTYPE, SOLARIS_XHDTYPE): # Patch the TarInfo object with the extended header info. next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) @@ -1438,12 +1439,17 @@ class TarInfo(object): offset += next._block(next.size) tarfile.offset = offset - if "GNU.volume.filename" in pax_headers and\ - pax_headers["GNU.volume.filename"] == next.name: - if "GNU.volume.size" in pax_headers: - next.size = int(pax_headers["GNU.volume.size"]) - if "GNU.volume.offset" in pax_headers: - next.volume_offset = int(pax_headers["GNU.volume.offset"]) + if next is not None: + if "GNU.volume.filename" in pax_headers: + if pax_headers["GNU.volume.filename"] == next.name: + if "GNU.volume.size" in pax_headers: + next.size = int(pax_headers["GNU.volume.size"]) + if "GNU.volume.offset" in pax_headers: + next.volume_offset = int(pax_headers["GNU.volume.offset"]) + + for key in pax_headers.keys(): + if key.startswith("GNU.volume"): + del tarfile.pax_headers[key] return next @@ -1500,7 +1506,8 @@ class TarInfo(object): def isdev(self): return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) def ismultivol(self): - return self.type == GNUTYPE_MULTIVOL or self.volume_offset > 0 + return self.type == GNUTYPE_MULTIVOL or self.volume_offset > 0 or\ + "GNU.volume.offset" in self.pax_headers # class TarInfo class TarFile(object): @@ -2083,6 +2090,10 @@ class TarFile(object): # handle multivolume support if self.max_volume_size: size_left = self._size_left() + # we only split volumes in the middle of a file, that means we have + # to write at least one block + if size_left < BLOCKSIZE: + size_left = BLOCKSIZE max_size_to_write = min(size_left, tarinfo.size - tarinfo.volume_offset) else: size_left = max_size_to_write = tarinfo.size @@ -2106,18 +2117,21 @@ class TarFile(object): if self.max_volume_size and max_size_to_write == size_left: assert remainder == 0 + self.offset += blocks * BLOCKSIZE size_left -= blocks * BLOCKSIZE tarinfo.volume_offset += blocks * BLOCKSIZE # check if creating a new volume is needed - if self.max_volume_size and size_left < BLOCKSIZE: + if tarinfo.volume_offset < tarinfo.size and\ + self.max_volume_size and size_left < 3*BLOCKSIZE: + tarinfo.type = GNUTYPE_MULTIVOL if not self.new_volume_handler or\ not callable(self.new_volume_handler): - raise Exception("We need to create a new volume and you" - " didn't supply a new_volume_handler") + raise Exception("We need to create a new volume and you " + "didn't supply a new_volume_handler") # the new volume handler should do everything needed to # start working in a new volume. usually, the handler calls @@ -2193,13 +2207,18 @@ class TarFile(object): if self.mode in "aw": self._loaded = True - self.pax_headers["GNU.volume.filename"] = unicode(self.volume_tarinfo.name) - self.pax_headers["GNU.volume.size"] = unicode(self.volume_tarinfo.size - self.volume_tarinfo.volume_offset) - self.pax_headers["GNU.volume.offset"] = unicode(self.volume_tarinfo.volume_offset) + if self.format == PAX_FORMAT: + volume_info = { + "GNU.volume.filename": unicode(self.volume_tarinfo.name), + "GNU.volume.size": unicode(self.volume_tarinfo.size - self.volume_tarinfo.volume_offset), + "GNU.volume.offset": unicode(self.volume_tarinfo.volume_offset), + } - buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) - self.fileobj.write(buf) - self.offset += len(buf) + self.pax_headers.update(volume_info) + + buf = self.tarinfo.create_pax_global_header(volume_info.copy()) + self.fileobj.write(buf) + self.offset += len(buf) except: if not self._extfileobj: self.fileobj.close() -- 1.7.1