Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Doc/library/gzip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,13 @@ The module defines the following items:
is no compression. The default is ``9``.

The optional *mtime* argument is the timestamp requested by gzip. The time
is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970.
If *mtime* is omitted or ``None``, the current time is used. Use *mtime* = 0
to generate a compressed stream that does not depend on creation time.
is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970. Set
*mtime* to ``0`` to generate a compressed stream that does not depend on
creation time. If *mtime* is omitted or ``None``, the current time is used;
however, if the current time is outside the range 00:00:00 UTC, January 1,
1970 through 06:28:15 UTC, February 7, 2106, or explicitly passed *mtime*
argument is outside the range ``0`` to ``2**32-1``, then the value ``0``
is used instead.

See below for the :attr:`mtime` attribute that is set when decompressing.

Expand Down
10 changes: 8 additions & 2 deletions Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ def __init__(self, filename=None, mode=None,

The optional mtime argument is the timestamp requested by gzip. The time
is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970.
If mtime is omitted or None, the current time is used. Use mtime = 0
to generate a compressed stream that does not depend on creation time.
Set mtime to 0 to generate a compressed stream that does not depend on
creation time. If mtime is omitted or None, the current time is used.
If the resulting mtime is outside the range 0 to 2**32-1, then the
value 0 is used instead.

"""

Expand Down Expand Up @@ -295,6 +297,8 @@ def _write_gzip_header(self, compresslevel):
mtime = self._write_mtime
if mtime is None:
mtime = time.time()
if not 0 <= mtime < 2**32:
mtime = 0
write32u(self.fileobj, int(mtime))
if compresslevel == _COMPRESS_LEVEL_BEST:
xfl = b'\002'
Expand Down Expand Up @@ -663,6 +667,8 @@ def compress(data, compresslevel=_COMPRESS_LEVEL_TRADEOFF, *, mtime=0):
gzip_data = zlib.compress(data, level=compresslevel, wbits=31)
if mtime is None:
mtime = time.time()
if not 0 <= mtime < 2**32:
mtime = 0
# Reuse gzip header created by zlib, replace mtime and OS byte for
# consistency.
header = struct.pack("<4sLBB", gzip_data, int(mtime), gzip_data[8], 255)
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import sys
import unittest
from subprocess import PIPE, Popen
from unittest import mock
from test.support import catch_unraisable_exception
from test.support import force_not_colorized_test_class, import_helper
from test.support import os_helper
Expand Down Expand Up @@ -350,6 +351,26 @@ def test_mtime(self):
self.assertEqual(dataRead, data1)
self.assertEqual(fRead.mtime, mtime)

def test_mtime_out_of_range(self):
for mtime in (-1, 2**32):
with gzip.GzipFile(self.filename, 'w', mtime=mtime) as fWrite:
fWrite.write(data1)
with gzip.GzipFile(self.filename) as fRead:
fRead.read(1)
self.assertEqual(fRead.mtime, 0)
datac = gzip.compress(data1, mtime=mtime)
with gzip.GzipFile(fileobj=io.BytesIO(datac)) as fRead:
fRead.read(1)
self.assertEqual(fRead.mtime, 0)

for mtime in (-1, 2**32):
with mock.patch('time.time', return_value=float(mtime)):
with gzip.GzipFile(self.filename, 'w') as fWrite:
fWrite.write(data1)
with gzip.GzipFile(self.filename) as fRead:
fRead.read(1)
self.assertEqual(fRead.mtime, 0)

def test_metadata(self):
mtime = 123456789

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fix :exc:`struct.error` exception when creating a file with
:class:`gzip.GzipFile` or compressing data with :func:`gzip.compress`
if the system time is outside the range 00:00:00 UTC, January 1, 1970
through 06:28:15 UTC, February 7, 2106, or explicitly passed *mtime*
argument is outside the range ``0`` to ``2**32-1``.
Loading