mirror of
https://github.com/zebrajr/ansible.git
synced 2025-12-06 00:19:48 +01:00
unarchive: Clamp zip timestamps on 32-bit time_t (#84409)
Clamp zip timestamps to representible values when unpacking zip files on platforms that use 32-bit time_t (e.g. Debian i386). This is a non-issue in practice (in 2024), but should allow the test suite to pass on Debian i386. We use a round value of 2038-01-01 00:00:00 for simplicity, and to avoid running into timezone offsets closer to the actual limit. MR #81520 introduced sanity-checking tests that used dates not representable with a 32-bit time_t.
This commit is contained in:
parent
af2bb2c182
commit
d500354798
3
changelogs/fragments/unarchive_timestamp_t32.yaml
Normal file
3
changelogs/fragments/unarchive_timestamp_t32.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
bugfixes:
|
||||
- unarchive - Clamp timestamps from beyond y2038 to representible values when unpacking zip files on platforms that use 32-bit time_t (e.g. Debian i386).
|
||||
|
|
@ -241,6 +241,7 @@ uid:
|
|||
|
||||
import binascii
|
||||
import codecs
|
||||
import ctypes
|
||||
import fnmatch
|
||||
import grp
|
||||
import os
|
||||
|
|
@ -262,6 +263,13 @@ from ansible.module_utils.urls import fetch_file
|
|||
from shlex import quote
|
||||
from zipfile import BadZipFile
|
||||
|
||||
try:
|
||||
from functools import cache
|
||||
except ImportError:
|
||||
# Python < 3.9
|
||||
from functools import lru_cache
|
||||
cache = lru_cache(maxsize=None)
|
||||
|
||||
# String from tar that shows the tar contents are different from the
|
||||
# filesystem
|
||||
OWNER_DIFF_RE = re.compile(r': Uid differs$')
|
||||
|
|
@ -279,6 +287,18 @@ CONTENT_DIFF_RE = re.compile(r': Contents differ$')
|
|||
SIZE_DIFF_RE = re.compile(r': Size differs$')
|
||||
|
||||
|
||||
@cache
|
||||
def _y2038_impacted():
|
||||
"""Determine if the system has 64-bit time_t."""
|
||||
if hasattr(ctypes, "c_time_t"): # Python >= 3.12
|
||||
return ctypes.sizeof(ctypes.c_time_t) < 8
|
||||
try:
|
||||
time.gmtime(2**31)
|
||||
except OverflowError:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def crc32(path, buffer_size):
|
||||
""" Return a CRC32 checksum of a file """
|
||||
|
||||
|
|
@ -414,6 +434,8 @@ class ZipArchive(object):
|
|||
try:
|
||||
if int(match.groups()[0]) < 1980:
|
||||
date_time = epoch_date_time
|
||||
elif int(match.groups()[0]) >= 2038 and _y2038_impacted():
|
||||
date_time = (2038, 1, 1, 0, 0, 0, 0, 0, 0)
|
||||
elif int(match.groups()[0]) > 2107:
|
||||
date_time = (2107, 12, 31, 23, 59, 59, 0, 0, 0)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ def fake_ansible_module():
|
|||
return FakeAnsibleModule()
|
||||
|
||||
|
||||
def max_zip_timestamp():
|
||||
"""Return the max clamp value that will be selected."""
|
||||
try:
|
||||
return time.mktime(time.struct_time((2107, 12, 31, 23, 59, 59, 0, 0, 0)))
|
||||
except OverflowError:
|
||||
return time.mktime(time.struct_time((2038, 1, 1, 0, 0, 0, 0, 0, 0)))
|
||||
|
||||
|
||||
class FakeAnsibleModule:
|
||||
def __init__(self):
|
||||
self.params = {}
|
||||
|
|
@ -68,7 +76,7 @@ class TestCaseZipArchive:
|
|||
),
|
||||
pytest.param(
|
||||
"21081231.000000",
|
||||
time.mktime(time.struct_time((2107, 12, 31, 23, 59, 59, 0, 0, 0))),
|
||||
max_zip_timestamp(),
|
||||
id="invalid-year-2108",
|
||||
),
|
||||
pytest.param(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user