mirror of
https://github.com/python/cpython.git
synced 2025-12-05 00:52:25 +00:00
[Patch 988444]
Read multiple special headers - fixed/improved handling of extended/special headers in read-mode (adding new extended headers should be less painful now). - improved nts() function. - removed TarFile.chunks datastructure which is not (and was never) needed. - fixed TarInfo.tobuf(), fields could overflow with too large values, values are now clipped.
This commit is contained in:
parent
f027ca8167
commit
864bba1981
1 changed files with 31 additions and 34 deletions
|
|
@ -135,7 +135,7 @@ TOEXEC = 0001 # execute/search by other
|
||||||
def nts(s):
|
def nts(s):
|
||||||
"""Convert a null-terminated string buffer to a python string.
|
"""Convert a null-terminated string buffer to a python string.
|
||||||
"""
|
"""
|
||||||
return s.split(NUL, 1)[0]
|
return s.rstrip(NUL)
|
||||||
|
|
||||||
def calc_chksum(buf):
|
def calc_chksum(buf):
|
||||||
"""Calculate the checksum for a member's header. It's a simple addition
|
"""Calculate the checksum for a member's header. It's a simple addition
|
||||||
|
|
@ -713,7 +713,7 @@ class TarInfo(object):
|
||||||
(self.prefix, 155)
|
(self.prefix, 155)
|
||||||
):
|
):
|
||||||
l = len(value)
|
l = len(value)
|
||||||
parts.append(value + (fieldsize - l) * NUL)
|
parts.append(value[:fieldsize] + (fieldsize - l) * NUL)
|
||||||
|
|
||||||
buf = "".join(parts)
|
buf = "".join(parts)
|
||||||
chksum = calc_chksum(buf)
|
chksum = calc_chksum(buf)
|
||||||
|
|
@ -796,7 +796,6 @@ class TarFile(object):
|
||||||
self.closed = False
|
self.closed = False
|
||||||
self.members = [] # list of members as TarInfo objects
|
self.members = [] # list of members as TarInfo objects
|
||||||
self.membernames = [] # names of members
|
self.membernames = [] # names of members
|
||||||
self.chunks = [0] # chunk cache
|
|
||||||
self._loaded = False # flag if all members have been read
|
self._loaded = False # flag if all members have been read
|
||||||
self.offset = 0L # current position in the archive file
|
self.offset = 0L # current position in the archive file
|
||||||
self.inodes = {} # dictionary caching the inodes of
|
self.inodes = {} # dictionary caching the inodes of
|
||||||
|
|
@ -1281,9 +1280,7 @@ class TarFile(object):
|
||||||
blocks += 1
|
blocks += 1
|
||||||
self.offset += blocks * BLOCKSIZE
|
self.offset += blocks * BLOCKSIZE
|
||||||
|
|
||||||
self.members.append(tarinfo)
|
self._record_member(tarinfo)
|
||||||
self.membernames.append(tarinfo.name)
|
|
||||||
self.chunks.append(self.offset)
|
|
||||||
|
|
||||||
def extract(self, member, path=""):
|
def extract(self, member, path=""):
|
||||||
"""Extract a member from the archive to the current working directory,
|
"""Extract a member from the archive to the current working directory,
|
||||||
|
|
@ -1551,7 +1548,7 @@ class TarFile(object):
|
||||||
return m
|
return m
|
||||||
|
|
||||||
# Read the next block.
|
# Read the next block.
|
||||||
self.fileobj.seek(self.chunks[-1])
|
self.fileobj.seek(self.offset)
|
||||||
while True:
|
while True:
|
||||||
buf = self.fileobj.read(BLOCKSIZE)
|
buf = self.fileobj.read(BLOCKSIZE)
|
||||||
if not buf:
|
if not buf:
|
||||||
|
|
@ -1569,7 +1566,7 @@ class TarFile(object):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
# Block is empty or unreadable.
|
# Block is empty or unreadable.
|
||||||
if self.chunks[-1] == 0:
|
if self.offset == 0:
|
||||||
# If the first block is invalid. That does not
|
# If the first block is invalid. That does not
|
||||||
# look like a tar archive we can handle.
|
# look like a tar archive we can handle.
|
||||||
raise ReadError,"empty, unreadable or compressed file"
|
raise ReadError,"empty, unreadable or compressed file"
|
||||||
|
|
@ -1592,20 +1589,18 @@ class TarFile(object):
|
||||||
# Check if the TarInfo object has a typeflag for which a callback
|
# Check if the TarInfo object has a typeflag for which a callback
|
||||||
# method is registered in the TYPE_METH. If so, then call it.
|
# method is registered in the TYPE_METH. If so, then call it.
|
||||||
if tarinfo.type in self.TYPE_METH:
|
if tarinfo.type in self.TYPE_METH:
|
||||||
tarinfo = self.TYPE_METH[tarinfo.type](self, tarinfo)
|
return self.TYPE_METH[tarinfo.type](self, tarinfo)
|
||||||
else:
|
|
||||||
tarinfo.offset_data = self.offset
|
tarinfo.offset_data = self.offset
|
||||||
if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
|
if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
|
||||||
# Skip the following data blocks.
|
# Skip the following data blocks.
|
||||||
self.offset += self._block(tarinfo.size)
|
self.offset += self._block(tarinfo.size)
|
||||||
|
|
||||||
if tarinfo.isreg() and tarinfo.name[:-1] == "/":
|
if tarinfo.isreg() and tarinfo.name[:-1] == "/":
|
||||||
# some old tar programs don't know DIRTYPE
|
# some old tar programs don't know DIRTYPE
|
||||||
tarinfo.type = DIRTYPE
|
tarinfo.type = DIRTYPE
|
||||||
|
|
||||||
self.members.append(tarinfo)
|
self._record_member(tarinfo)
|
||||||
self.membernames.append(tarinfo.name)
|
|
||||||
self.chunks.append(self.offset)
|
|
||||||
return tarinfo
|
return tarinfo
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
|
@ -1620,7 +1615,9 @@ class TarFile(object):
|
||||||
# if there is data to follow.
|
# if there is data to follow.
|
||||||
# 2. set self.offset to the position where the next member's header will
|
# 2. set self.offset to the position where the next member's header will
|
||||||
# begin.
|
# begin.
|
||||||
# 3. return a valid TarInfo object.
|
# 3. call self._record_member() if the tarinfo object is supposed to
|
||||||
|
# appear as a member of the TarFile object.
|
||||||
|
# 4. return tarinfo or another valid TarInfo object.
|
||||||
|
|
||||||
def proc_gnulong(self, tarinfo):
|
def proc_gnulong(self, tarinfo):
|
||||||
"""Evaluate the blocks that hold a GNU longname
|
"""Evaluate the blocks that hold a GNU longname
|
||||||
|
|
@ -1636,24 +1633,16 @@ class TarFile(object):
|
||||||
self.offset += BLOCKSIZE
|
self.offset += BLOCKSIZE
|
||||||
count -= BLOCKSIZE
|
count -= BLOCKSIZE
|
||||||
|
|
||||||
|
# Fetch the next header
|
||||||
|
next = self.next()
|
||||||
|
|
||||||
|
next.offset = tarinfo.offset
|
||||||
if tarinfo.type == GNUTYPE_LONGNAME:
|
if tarinfo.type == GNUTYPE_LONGNAME:
|
||||||
name = nts(buf)
|
next.name = nts(buf)
|
||||||
if tarinfo.type == GNUTYPE_LONGLINK:
|
elif tarinfo.type == GNUTYPE_LONGLINK:
|
||||||
linkname = nts(buf)
|
next.linkname = nts(buf)
|
||||||
|
|
||||||
buf = self.fileobj.read(BLOCKSIZE)
|
return next
|
||||||
|
|
||||||
tarinfo = TarInfo.frombuf(buf)
|
|
||||||
tarinfo.offset = self.offset
|
|
||||||
self.offset += BLOCKSIZE
|
|
||||||
tarinfo.offset_data = self.offset
|
|
||||||
tarinfo.name = name or tarinfo.name
|
|
||||||
tarinfo.linkname = linkname or tarinfo.linkname
|
|
||||||
|
|
||||||
if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
|
|
||||||
# Skip the following data blocks.
|
|
||||||
self.offset += self._block(tarinfo.size)
|
|
||||||
return tarinfo
|
|
||||||
|
|
||||||
def proc_sparse(self, tarinfo):
|
def proc_sparse(self, tarinfo):
|
||||||
"""Analyze a GNU sparse header plus extra headers.
|
"""Analyze a GNU sparse header plus extra headers.
|
||||||
|
|
@ -1709,6 +1698,8 @@ class TarFile(object):
|
||||||
tarinfo.offset_data = self.offset
|
tarinfo.offset_data = self.offset
|
||||||
self.offset += self._block(tarinfo.size)
|
self.offset += self._block(tarinfo.size)
|
||||||
tarinfo.size = origsize
|
tarinfo.size = origsize
|
||||||
|
|
||||||
|
self._record_member(tarinfo)
|
||||||
return tarinfo
|
return tarinfo
|
||||||
|
|
||||||
# The type mapping for the next() method. The keys are single character
|
# The type mapping for the next() method. The keys are single character
|
||||||
|
|
@ -1745,6 +1736,12 @@ class TarFile(object):
|
||||||
if name == self.membernames[i]:
|
if name == self.membernames[i]:
|
||||||
return self.members[i]
|
return self.members[i]
|
||||||
|
|
||||||
|
def _record_member(self, tarinfo):
|
||||||
|
"""Record a tarinfo object in the internal datastructures.
|
||||||
|
"""
|
||||||
|
self.members.append(tarinfo)
|
||||||
|
self.membernames.append(tarinfo.name)
|
||||||
|
|
||||||
def _load(self):
|
def _load(self):
|
||||||
"""Read through the entire archive file and look for readable
|
"""Read through the entire archive file and look for readable
|
||||||
members.
|
members.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue