Skip to content

Commit 6f130f2

Browse files
[3.12] gh-102956: Fix returning of empty byte strings after seek in zipfile … (GH-103565) (#111289)
gh-102956: Fix returning of empty byte strings after seek in zipfile … (GH-103565) (cherry picked from commit c73b0f3) 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. Co-authored-by: Jokimax <[email protected]>
1 parent a4eb2e3 commit 6f130f2

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
@@ -1122,8 +1122,12 @@ def seek(self, offset, whence=os.SEEK_SET):
11221122
read_offset = new_pos - curr_pos
11231123
buff_offset = read_offset + self._offset
11241124

1125+
if buff_offset >= 0 and buff_offset < len(self._readbuffer):
1126+
# Just move the _offset index if the new position is in the _readbuffer
1127+
self._offset = buff_offset
1128+
read_offset = 0
11251129
# Fast seek uncompressed unencrypted file
1126-
if self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0:
1130+
elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0:
11271131
# disable CRC checking after first seeking - it would be invalid
11281132
self._expected_crc = None
11291133
# seek actual file taking already buffered data into account
@@ -1134,10 +1138,6 @@ def seek(self, offset, whence=os.SEEK_SET):
11341138
# flush read buffer
11351139
self._readbuffer = b''
11361140
self._offset = 0
1137-
elif buff_offset >= 0 and buff_offset < len(self._readbuffer):
1138-
# Just move the _offset index if the new position is in the _readbuffer
1139-
self._offset = buff_offset
1140-
read_offset = 0
11411141
elif read_offset < 0:
11421142
# Position is before the current position. Reset the ZipExtFile
11431143
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)