Skip to content

Commit c73b0f3

Browse files
authored
gh-102956: Fix returning of empty byte strings after seek in zipfile … (#103565)
gh-102956: Fix returning of empty byte strings after seek in zipfile module. This was a regression in 3.12.0 due to a performance enhancement.
1 parent e5168ff commit c73b0f3

File tree

3 files changed

+22
-5
lines changed

3 files changed

+22
-5
lines changed

Lib/test/test_zipfile/test_core.py

+16
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,22 @@ def test_seek_tell(self):
22462246
fp.seek(0, os.SEEK_SET)
22472247
self.assertEqual(fp.tell(), 0)
22482248

2249+
def test_read_after_seek(self):
2250+
# Issue 102956: Make sure seek(x, os.SEEK_CUR) doesn't break read()
2251+
txt = b"Charge men!"
2252+
bloc = txt.find(b"men")
2253+
with zipfile.ZipFile(TESTFN, "w") as zipf:
2254+
zipf.writestr("foo.txt", txt)
2255+
with zipfile.ZipFile(TESTFN, mode="r") as zipf:
2256+
with zipf.open("foo.txt", "r") as fp:
2257+
fp.seek(bloc, os.SEEK_CUR)
2258+
self.assertEqual(fp.read(-1), b'men!')
2259+
with zipfile.ZipFile(TESTFN, mode="r") as zipf:
2260+
with zipf.open("foo.txt", "r") as fp:
2261+
fp.read(6)
2262+
fp.seek(1, os.SEEK_CUR)
2263+
self.assertEqual(fp.read(-1), b'men!')
2264+
22492265
@requires_bz2()
22502266
def test_decompress_without_3rd_party_library(self):
22512267
data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Lib/zipfile/__init__.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1136,8 +1136,12 @@ def seek(self, offset, whence=os.SEEK_SET):
11361136
read_offset = new_pos - curr_pos
11371137
buff_offset = read_offset + self._offset
11381138

1139+
if buff_offset >= 0 and buff_offset < len(self._readbuffer):
1140+
# Just move the _offset index if the new position is in the _readbuffer
1141+
self._offset = buff_offset
1142+
read_offset = 0
11391143
# Fast seek uncompressed unencrypted file
1140-
if self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0:
1144+
elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0:
11411145
# disable CRC checking after first seeking - it would be invalid
11421146
self._expected_crc = None
11431147
# seek actual file taking already buffered data into account
@@ -1148,10 +1152,6 @@ def seek(self, offset, whence=os.SEEK_SET):
11481152
# flush read buffer
11491153
self._readbuffer = b''
11501154
self._offset = 0
1151-
elif buff_offset >= 0 and buff_offset < len(self._readbuffer):
1152-
# Just move the _offset index if the new position is in the _readbuffer
1153-
self._offset = buff_offset
1154-
read_offset = 0
11551155
elif read_offset < 0:
11561156
# Position is before the current position. Reset the ZipExtFile
11571157
self._fileobj.seek(self._orig_compress_start)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix returning of empty byte strings after seek in zipfile module

0 commit comments

Comments
 (0)