Skip to content

Commit 29c3340

Browse files
committed
gh-153625: rewrite with original filename
1 parent 65585ca commit 29c3340

2 files changed

Lines changed: 37 additions & 4 deletions

File tree

Lib/test/test_zipfile/test_core.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4827,6 +4827,28 @@ def test_overlap_with_archive_comment(self):
48274827
with self.assertRaisesRegex(zipfile.BadZipFile, 'Overlapped entries'):
48284828
zipf.read('a')
48294829

4830+
def test_append_keep_filename(self):
4831+
"""Files loaded from an archive should keep original filename when
4832+
rewritten to central directory in append mode."""
4833+
with zipfile.ZipFile(TESTFN, mode="w") as zipfp:
4834+
zinfo = zipfile.ZipInfo('MyFolder/My\\File.txt')
4835+
zinfo._orig_filename = 'MyFolder/My\\File.txt'
4836+
zipfp.writestr(zinfo, 'foo')
4837+
4838+
with zipfile.ZipFile(TESTFN, "a") as zipfp:
4839+
self.assertIsNone(zipfp.testzip())
4840+
zi = zipfp.infolist()[0]
4841+
self.assertEqual(zi.orig_filename, 'MyFolder/My\\File.txt')
4842+
self.assertEqual(zi.filename, 'MyFolder/My/File.txt')
4843+
# trigger archive rewriting
4844+
zipfp.comment = b''
4845+
4846+
with zipfile.ZipFile(TESTFN, "r") as zipfp:
4847+
self.assertIsNone(zipfp.testzip())
4848+
zi = zipfp.infolist()[0]
4849+
self.assertEqual(zi.orig_filename, 'MyFolder/My\\File.txt')
4850+
self.assertEqual(zi.filename, 'MyFolder/My/File.txt')
4851+
48304852
def tearDown(self):
48314853
unlink(TESTFN)
48324854
unlink(TESTFN2)

Lib/zipfile/__init__.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ class ZipInfo:
432432
"""Class with attributes describing each file in the ZIP archive."""
433433

434434
__slots__ = (
435-
'orig_filename',
435+
'_orig_filename',
436436
'filename',
437437
'date_time',
438438
'compress_type',
@@ -456,7 +456,7 @@ class ZipInfo:
456456
)
457457

458458
def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
459-
self.orig_filename = filename # Original file name in archive
459+
self.orig_filename = None # Original file name in archive
460460

461461
# Terminate the file name at the first null byte and
462462
# ensure paths always use forward slashes as the directory separator.
@@ -492,6 +492,16 @@ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
492492
# header_offset Byte offset to the file header
493493
# CRC CRC-32 of the uncompressed file
494494

495+
@property
496+
def orig_filename(self):
497+
return (self._orig_filename if self._orig_filename is not None
498+
else self.filename)
499+
500+
# Maintain backward compatibility in case someone sets it.
501+
@orig_filename.setter
502+
def orig_filename(self, value):
503+
self._orig_filename = value
504+
495505
# Maintain backward compatibility with the old protected attribute name.
496506
@property
497507
def _compresslevel(self):
@@ -579,9 +589,9 @@ def _encodeFilenameFlags(self):
579589
else:
580590
encoding = 'cp437'
581591
try:
582-
return self.filename.encode(encoding), self.flag_bits & ~_MASK_UTF_FILENAME
592+
return self.orig_filename.encode(encoding), self.flag_bits & ~_MASK_UTF_FILENAME
583593
except UnicodeEncodeError:
584-
return self.filename.encode('utf-8'), self.flag_bits | _MASK_UTF_FILENAME
594+
return self.orig_filename.encode('utf-8'), self.flag_bits | _MASK_UTF_FILENAME
585595

586596
def _decodeExtra(self, filename_crc):
587597
# Try to decode the extra field.
@@ -2056,6 +2066,7 @@ def _RealGetContents(self):
20562066
filename = filename.decode(self.metadata_encoding or 'cp437')
20572067
# Create ZipInfo instance to store file information
20582068
x = ZipInfo(filename)
2069+
x._orig_filename = filename
20592070
x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
20602071
x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
20612072
x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET]

0 commit comments

Comments
 (0)