From: Eduardo Robles Elvira Date: Fri, 21 Jun 2013 11:52:41 +0000 (+0200) Subject: fixing remaining issues with PAX compress/extract X-Git-Tag: v2.2~183 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=0eb5048fc42ad1fd6664b6c586ddcd7091653d5a;p=python-delta-tar fixing remaining issues with PAX compress/extract --- diff --git a/deltatar/tarfile.py b/deltatar/tarfile.py index 657404e..4a93b80 100644 --- a/deltatar/tarfile.py +++ b/deltatar/tarfile.py @@ -939,6 +939,8 @@ class TarInfo(object): self.offset = 0 # the tar header starts here self.offset_data = 0 # the file's data starts here + self.volume_offset = 0 # the file's data corresponds with the data + # starting at this position self.pax_headers = {} # pax header information @@ -976,7 +978,8 @@ class TarInfo(object): "gname": self.gname, "devmajor": self.devmajor, "devminor": self.devminor, - "offset_data": self.offset_data + "offset_data": self.offset_data, + "volume_offset": self.volume_offset } if info["type"] == DIRTYPE and not info["name"].endswith("/"): @@ -1024,11 +1027,11 @@ class TarInfo(object): prefix = [ itn(info.get("atime", 0), 12, GNU_FORMAT), itn(info.get("ctime", 0), 12, GNU_FORMAT), - itn(self.offset_data, 12, GNU_FORMAT), + itn(self.volume_offset, 12, GNU_FORMAT), itn(0, 119, GNU_FORMAT), # stuff unused in this tar implementation, set to zero ] info['prefix'] = "".join(prefix) - info['size'] = info['size'] - self.offset_data + info['size'] = info['size'] - self.volume_offset buf = "" if len(info["linkname"]) > LENGTH_LINK: @@ -1071,11 +1074,6 @@ class TarInfo(object): if len(info[name]) > length: pax_headers[hname] = val - if self.ismultivol(): - pax_headers["GNU.volume.filename"] = unicode(self.name) - pax_headers["GNU.volume.size"] = unicode(info['size'] - self.offset_data) - pax_headers["GNU.volume.offset"] = unicode(self.offset_data) - # Test number fields for values that exceed the field limit or values # that like to be stored as float. for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): @@ -1425,13 +1423,6 @@ class TarInfo(object): except HeaderError: raise SubsequentHeaderError("missing or bad subsequent header") - if next and next.type == GNUTYPE_MULTIVOL: - if "GNU.volume.filename" in pax_headers: - next.name = pax_headers["GNU.volume.filename"] - if "GNU.volume.size" in pax_headers: - next.size = int(pax_headers["GNU.volume.size"]) - #if "GNU.volume.offset" in pax_headers: - #next.offset_data = int(pax_headers["GNU.volume.offset"]) if self.type in (XHDTYPE, SOLARIS_XHDTYPE): # Patch the TarInfo object with the extended header info. @@ -1447,6 +1438,13 @@ 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"]) + return next def _apply_pax_info(self, pax_headers, encoding, errors): @@ -1502,7 +1500,7 @@ class TarInfo(object): def isdev(self): return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) def ismultivol(self): - return self.type == GNUTYPE_MULTIVOL or 'GNU.volume.offset' in self.pax_headers + return self.type == GNUTYPE_MULTIVOL or self.volume_offset > 0 # class TarInfo class TarFile(object): @@ -2085,14 +2083,14 @@ class TarFile(object): # handle multivolume support if self.max_volume_size: size_left = self._size_left() - max_size_to_write = min(size_left, tarinfo.size - tarinfo.offset_data) + max_size_to_write = min(size_left, tarinfo.size - tarinfo.volume_offset) else: size_left = max_size_to_write = tarinfo.size data_written = 0 # iterate, one iteration per volume (usually only one volume) - while tarinfo.offset_data < tarinfo.size: + while tarinfo.volume_offset < tarinfo.size: copyfileobj(fileobj, self.fileobj, max_size_to_write) blocks, remainder = divmod(max_size_to_write, BLOCKSIZE) @@ -2112,7 +2110,7 @@ class TarFile(object): self.offset += blocks * BLOCKSIZE size_left -= blocks * BLOCKSIZE - tarinfo.offset_data += blocks * BLOCKSIZE + tarinfo.volume_offset += blocks * BLOCKSIZE # check if creating a new volume is needed if self.max_volume_size and size_left < BLOCKSIZE: @@ -2127,20 +2125,27 @@ class TarFile(object): # start working in a new volume. usually, the handler calls # to self.open_volume self.volume_number += 1 + + # set to be used by open_volume, becuase in the case of a PAX + # tar it needs to write information about the volume and offset + # in the global header + self.volume_tarinfo = tarinfo self.new_volume_handler(self, self.base_name, self.volume_number) + self.volume_tarinfo = None + # write new volume header buf = tarinfo.tobuf(self.format, self.encoding, self.errors) self.offset += len(buf) self.fileobj.write(buf) size_left = self._size_left() - max_size_to_write = min(size_left, tarinfo.size - tarinfo.offset_data) + max_size_to_write = min(size_left, tarinfo.size - tarinfo.volume_offset) self.members.append(tarinfo) def open_volume(self, name="", fileobj=None): ''' - Called by the user to change this tar file to point to a new volume + Called by the user to change this tar file to point to a new volume. ''' # open the file using either fileobj or name if not fileobj: @@ -2190,10 +2195,13 @@ class TarFile(object): if self.mode in "aw": self._loaded = True - if self.pax_headers: - buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) - self.fileobj.write(buf) - self.offset += len(buf) + 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) + + buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) + self.fileobj.write(buf) + self.offset += len(buf) except: if not self._extfileobj: self.fileobj.close()