Skip to content

Commit ec6fec2

Browse files
authored
Update some libs and tests to 3.14.7 (#8603)
* `typing.py` * tempfile * tarfile * imaplib
1 parent 86e7ede commit ec6fec2

8 files changed

Lines changed: 1717 additions & 148 deletions

File tree

‎Lib/imaplib.py‎

Lines changed: 172 additions & 54 deletions
Large diffs are not rendered by default.

‎Lib/tarfile.py‎

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,32 @@ def copyfileobj(src, dst, length=None, exception=OSError, bufsize=None):
258258
dst.write(buf)
259259
return
260260

261+
# Maximum number of bytes read in a single call when reading a member's
262+
# extended header (a GNU long name/link or a pax header). The size of such
263+
# a header is taken from the archive and is not trustworthy, so it is read in
264+
# bounded chunks to avoid a huge up-front allocation when a crafted or
265+
# truncated archive claims far more data than the file actually contains
266+
# (gh-151497).
267+
_EXTHEADER_READ_CHUNK = 1024 * 1024 # 1 MiB
268+
269+
def _safe_read(fileobj, size):
270+
"""Read up to *size* bytes from *fileobj* in bounded chunks.
271+
272+
Returns the same bytes as ``fileobj.read(size)`` would (including a short
273+
result at end of file), but limits pre-allocation, so an
274+
oversized size field in a crafted header cannot force a huge allocation.
275+
"""
276+
if size <= _EXTHEADER_READ_CHUNK:
277+
return fileobj.read(size)
278+
chunks = []
279+
while size > 0:
280+
chunk = fileobj.read(min(size, _EXTHEADER_READ_CHUNK))
281+
if not chunk:
282+
break
283+
chunks.append(chunk)
284+
size -= len(chunk)
285+
return b"".join(chunks)
286+
261287
def _safe_print(s):
262288
encoding = getattr(sys.stdout, 'encoding', None)
263289
if encoding is not None:
@@ -524,7 +550,9 @@ def seek(self, pos=0):
524550
if pos - self.pos >= 0:
525551
blocks, remainder = divmod(pos - self.pos, self.bufsize)
526552
for i in range(blocks):
527-
self.read(self.bufsize)
553+
data = self.read(self.bufsize)
554+
if not data:
555+
break
528556
self.read(remainder)
529557
else:
530558
raise StreamError("seeking backwards is not allowed")
@@ -1429,7 +1457,7 @@ def _proc_gnulong(self, tarfile):
14291457
"""Process the blocks that hold a GNU longname
14301458
or longlink member.
14311459
"""
1432-
buf = tarfile.fileobj.read(self._block(self.size))
1460+
buf = _safe_read(tarfile.fileobj, self._block(self.size))
14331461

14341462
# Fetch the next header and process it.
14351463
try:
@@ -1485,7 +1513,7 @@ def _proc_pax(self, tarfile):
14851513
POSIX.1-2008.
14861514
"""
14871515
# Read the header information.
1488-
buf = tarfile.fileobj.read(self._block(self.size))
1516+
buf = _safe_read(tarfile.fileobj, self._block(self.size))
14891517

14901518
# A pax header stores supplemental information for either
14911519
# the following file (extended) or all following files
@@ -2510,7 +2538,8 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False,
25102538
tarinfo, unfiltered = self._get_extract_tarinfo(
25112539
member, filter_function, path)
25122540
if tarinfo is not None:
2513-
self._extract_one(tarinfo, path, set_attrs, numeric_owner)
2541+
self._extract_one(tarinfo, path, set_attrs, numeric_owner,
2542+
filter_function=filter_function)
25142543

25152544
def _get_extract_tarinfo(self, member, filter_function, path):
25162545
"""Get (filtered, unfiltered) TarInfos from *member*
@@ -2782,6 +2811,9 @@ def makelink_with_filter(self, tarinfo, targetpath,
27822811
"makelink_with_filter: if filter_function is not None, "
27832812
+ "extraction_root must also not be None")
27842813
try:
2814+
filter_function(
2815+
unfiltered.replace(name=tarinfo.name, deep=False),
2816+
extraction_root)
27852817
filtered = filter_function(unfiltered, extraction_root)
27862818
except _FILTER_ERRORS as cause:
27872819
raise LinkFallbackError(tarinfo, unfiltered.name) from cause

‎Lib/tempfile.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,8 @@ def __init__(self, suffix=None, prefix=None, dir=None,
915915
@classmethod
916916
def _rmtree(cls, name, ignore_errors=False, repeated=False):
917917
def onexc(func, path, exc):
918-
if isinstance(exc, PermissionError):
918+
# On DragonFly BSD, UF_NOUNLINK removal fails with EISDIR, not EPERM.
919+
if isinstance(exc, (PermissionError, IsADirectoryError)):
919920
if repeated and path == name:
920921
if ignore_errors:
921922
return

0 commit comments

Comments
 (0)