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
"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("/"):
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:
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)):
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.
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):
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):
# 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)
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:
# 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:
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()