Skip to content

Commit 121d4c5

Browse files
committed
zipfile: Support for extended_*time attributes
zipinfo now supports attributes like extended_atime, extended_ctime, extended_mtime Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
1 parent 7fb32e0 commit 121d4c5

3 files changed

Lines changed: 35 additions & 0 deletions

File tree

Doc/library/zipfile.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,23 @@ Instances have the following methods and attributes:
890890

891891
Size of the uncompressed file.
892892

893+
.. attribute:: ZipInfo.extended_mtime
894+
895+
Extended modified timestamp of the uncompressed file.
896+
897+
.. versionadded:: 3.14
898+
899+
.. attribute:: ZipInfo.extended_atime
900+
901+
Extended access timestamp of the uncompressed file.
902+
903+
.. versionadded:: 3.14
904+
905+
.. attribute:: ZipInfo.extended_ctime
906+
907+
Extended changed timestamp of the uncompressed file.
908+
909+
.. versionadded:: 3.14
893910

894911
.. _zipfile-commandline:
895912
.. program:: zipfile

Lib/test/test_zipfile/test_core.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,6 +2227,10 @@ def test_create_empty_zipinfo_default_attributes(self):
22272227
self.assertEqual(zi.file_size, 0)
22282228
self.assertEqual(zi.compress_size, 0)
22292229

2230+
self.assertEqual(zi.extended_mtime, None)
2231+
self.assertEqual(zi.extended_atime, None)
2232+
self.assertEqual(zi.extended_ctime, None)
2233+
22302234
def test_zipfile_with_short_extra_field(self):
22312235
"""If an extra field in the header is less than 4 bytes, skip it."""
22322236
zipdata = (

Lib/zipfile/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ class ZipInfo:
396396
'file_size',
397397
'_raw_time',
398398
'_end_offset',
399+
'extended_mtime',
400+
'extended_atime',
401+
'extended_ctime',
399402
)
400403

401404
def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
@@ -431,6 +434,9 @@ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
431434
self.compress_size = 0 # Size of the compressed file
432435
self.file_size = 0 # Size of the uncompressed file
433436
self._end_offset = None # Start of the next local header or central directory
437+
self.extended_mtime = None # Extended access timestamp
438+
self.extended_atime = None # Extended modified timestamp
439+
self.extended_ctime = None # Extended changed timestamp
434440
# Other attributes are set by class ZipFile:
435441
# header_offset Byte offset to the file header
436442
# CRC CRC-32 of the uncompressed file
@@ -563,6 +569,14 @@ def _decodeExtra(self, filename_crc):
563569
except UnicodeDecodeError as e:
564570
raise BadZipFile('Corrupt unicode path extra field (0x7075): invalid utf-8 bytes') from e
565571

572+
elif tp == 0x5455:
573+
flags = extra[4]
574+
if flags & 0x1 and ln >= 5:
575+
self.extended_mtime = int.from_bytes(extra[5:9], "little")
576+
if flags & 0x2 and ln >= 9:
577+
self.extended_atime = int.from_bytes(extra[9:13], "little")
578+
if flags & 0x4 and ln >= 13:
579+
self.extended_ctime = int.from_bytes(extra[13:17], "little")
566580
extra = extra[ln+4:]
567581

568582
@classmethod

0 commit comments

Comments
 (0)