cpython: 2807a5f011e4 (original) (raw)
--- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -46,6 +46,27 @@ pyc_file = imp.cache_from_source(TESTMOD pyc_ext = ('.pyc' if debug else '.pyo') +def _write_zip_package(zipname, files,
data_to_prepend=b"", compression=ZIP_STORED):[](#l1.8)
- z = ZipFile(zipname, "w")
- try:
for name, (mtime, data) in files.items():[](#l1.11)
zinfo = ZipInfo(name, time.localtime(mtime))[](#l1.12)
zinfo.compress_type = compression[](#l1.13)
z.writestr(zinfo, data)[](#l1.14)
- finally:
z.close()[](#l1.16)
- if data_to_prepend:
# Prepend data to the start of the zipfile[](#l1.19)
with open(zipname, "rb") as f:[](#l1.20)
zip_data = f.read()[](#l1.21)
with open(zipname, "wb") as f:[](#l1.23)
f.write(data_to_prepend)[](#l1.24)
f.write(zip_data)[](#l1.25)
+ + class UncompressedZipImportTestCase(ImportHooksBaseTestCase): compression = ZIP_STORED @@ -58,23 +79,9 @@ class UncompressedZipImportTestCase(Impo ImportHooksBaseTestCase.setUp(self) def doTest(self, expected_ext, files, *modules, **kw):
z = ZipFile(TEMP_ZIP, "w")[](#l1.35)
_write_zip_package(TEMP_ZIP, files, data_to_prepend=kw.get("stuff"),[](#l1.36)
compression=self.compression)[](#l1.37) try:[](#l1.38)
for name, (mtime, data) in files.items():[](#l1.39)
zinfo = ZipInfo(name, time.localtime(mtime))[](#l1.40)
zinfo.compress_type = self.compression[](#l1.41)
z.writestr(zinfo, data)[](#l1.42)
z.close()[](#l1.43)
stuff = kw.get("stuff", None)[](#l1.45)
if stuff is not None:[](#l1.46)
# Prepend 'stuff' to the start of the zipfile[](#l1.47)
with open(TEMP_ZIP, "rb") as f:[](#l1.48)
data = f.read()[](#l1.49)
with open(TEMP_ZIP, "wb") as f:[](#l1.50)
f.write(stuff)[](#l1.51)
f.write(data)[](#l1.52)
- sys.path.insert(0, TEMP_ZIP) mod = import(".".join(modules), globals(), locals(), @@ -89,7 +96,8 @@ class UncompressedZipImportTestCase(Impo self.assertEqual(file, os.path.join(TEMP_ZIP, *modules) + expected_ext) finally:
z.close()[](#l1.61)
while TEMP_ZIP in sys.path:[](#l1.62)
sys.path.remove(TEMP_ZIP)[](#l1.63) os.remove(TEMP_ZIP)[](#l1.64)
def testAFakeZlib(self): @@ -395,10 +403,67 @@ class CompressedZipImportTestCase(Uncomp compression = ZIP_DEFLATED +class ZipFileModifiedAfterImportTestCase(ImportHooksBaseTestCase):
- def setUp(self):
zipimport._zip_directory_cache.clear()[](#l1.73)
zipimport._zip_stat_cache.clear()[](#l1.74)
ImportHooksBaseTestCase.setUp(self)[](#l1.75)
- def tearDown(self):
ImportHooksBaseTestCase.tearDown(self)[](#l1.78)
if os.path.exists(TEMP_ZIP):[](#l1.79)
os.remove(TEMP_ZIP)[](#l1.80)
- def testZipFileChangesAfterFirstImport(self):
"""Alter the zip file after caching its index and try an import."""[](#l1.83)
packdir = TESTPACK + os.sep[](#l1.84)
files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),[](#l1.85)
packdir + TESTMOD + ".py": (NOW, "test_value = 38\n"),[](#l1.86)
"ziptest_a.py": (NOW, "test_value = 23\n"),[](#l1.87)
"ziptest_b.py": (NOW, "test_value = 42\n"),[](#l1.88)
"ziptest_c.py": (NOW, "test_value = 1337\n")}[](#l1.89)
zipfile_path = TEMP_ZIP[](#l1.90)
_write_zip_package(zipfile_path, files)[](#l1.91)
self.assertTrue(os.path.exists(zipfile_path))[](#l1.92)
sys.path.insert(0, zipfile_path)[](#l1.93)
# Import something out of the zipfile and confirm it is correct.[](#l1.95)
testmod = __import__(TESTPACK + "." + TESTMOD,[](#l1.96)
globals(), locals(), ["__dummy__"])[](#l1.97)
self.assertEqual(testmod.test_value, 38)[](#l1.98)
# Import something else out of the zipfile and confirm it is correct.[](#l1.99)
ziptest_b = __import__("ziptest_b", globals(), locals(), ["test_value"])[](#l1.100)
self.assertEqual(ziptest_b.test_value, 42)[](#l1.101)
# Truncate and fill the zip file with non-zip garbage.[](#l1.103)
with open(zipfile_path, "rb") as orig_zip_file:[](#l1.104)
orig_zip_file_contents = orig_zip_file.read()[](#l1.105)
with open(zipfile_path, "wb") as byebye_valid_zip_file:[](#l1.106)
byebye_valid_zip_file.write(b"Tear down this wall!\n"*1987)[](#l1.107)
# Now that the zipfile has been replaced, import something else from it[](#l1.108)
# which should fail as the file contents are now garbage.[](#l1.109)
with self.assertRaises(ImportError):[](#l1.110)
ziptest_a = __import__("ziptest_a", globals(), locals(),[](#l1.111)
["test_value"])[](#l1.112)
self.assertEqual(ziptest_a.test_value, 23)[](#l1.113)
# Now lets make it a valid zipfile that has some garbage at the start.[](#l1.115)
# This alters all of the offsets within the file[](#l1.116)
with open(zipfile_path, "wb") as new_zip_file:[](#l1.117)
new_zip_file.write(b"X"*1991) # The year Python was created.[](#l1.118)
new_zip_file.write(orig_zip_file_contents)[](#l1.119)
# Now that the zip file has been "restored" to a valid but different[](#l1.121)
# zipfile the zipimporter should *successfully* re-read the new zip[](#l1.122)
# file's end of file central index and be able to import from it again.[](#l1.123)
ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"])[](#l1.124)
self.assertEqual(ziptest_c.test_value, 1337)[](#l1.125)
+ + class BadFileZipImportTestCase(unittest.TestCase): def assertZipFailure(self, filename):
self.assertRaises(zipimport.ZipImportError,[](#l1.130)
zipimport.zipimporter, filename)[](#l1.131)
with self.assertRaises(zipimport.ZipImportError):[](#l1.132)
zipimport.zipimporter(filename)[](#l1.133)
def testNoFile(self): self.assertZipFailure('AdfjdkFJKDFJjdklfjs') @@ -472,6 +537,7 @@ def test_main(): UncompressedZipImportTestCase, CompressedZipImportTestCase, BadFileZipImportTestCase,
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ What's New in Python 3.3.4 release candi Core and Builtins ----------------- +- Issue #19081: When a zipimport .zip file in sys.path being imported from
- is modified during the lifetime of the Python process after zipimport has
- already cached the zip's table of contents we detect this and recover
- rather than read bad data from the .zip (causing odd import errors). +
- Issue #17432: Drop UCS2 from names of Unicode functions in python3.def.
- Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c"
--- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -45,10 +45,16 @@ struct _zipimporter { static PyObject ZipImportError; / read_directory() cache */ static PyObject *zip_directory_cache = NULL; +static PyObject zip_stat_cache = NULL; +/ posix.fstat or nt.fstat function. Used due to posixmodule.c's
- superior fstat implementation over libc's on Windows. */ +static PyObject fstat_function = NULL; / posix.fstat() or nt.fstat() / / forward decls */ -static PyObject *read_directory(PyObject *archive); -static PyObject *get_data(PyObject *archive, PyObject *toc_entry); +static FILE *fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p); +static FILE *safely_reopen_archive(ZipImporter *self); +static PyObject *read_directory(FILE *fp, PyObject *archive); +static PyObject *get_data(FILE *fp, PyObject *archive, PyObject *toc_entry); static PyObject *get_module_code(ZipImporter *self, PyObject *fullname, int *p_ispackage, PyObject **p_modpath);
@@ -128,11 +134,39 @@ zipimporter_init(ZipImporter *self, PyOb files = PyDict_GetItem(zip_directory_cache, filename); if (files == NULL) {
files = read_directory(filename);[](#l3.26)
if (files == NULL)[](#l3.27)
PyObject *zip_stat = NULL;[](#l3.28)
FILE *fp = fopen_rb_and_stat(filename, &zip_stat);[](#l3.29)
if (fp == NULL) {[](#l3.30)
if (!PyErr_Occurred())[](#l3.31)
PyErr_Format(ZipImportError, "can't open Zip file: %R",[](#l3.32)
filename);[](#l3.33)
Py_XDECREF(zip_stat);[](#l3.35) goto error;[](#l3.36)
if (PyDict_SetItem(zip_directory_cache, filename, files) != 0)[](#l3.37)
}[](#l3.38)
if (Py_VerboseFlag)[](#l3.40)
PySys_FormatStderr("# zipimport: %U not cached, "[](#l3.41)
"reading TOC.\n", filename);[](#l3.42)
files = read_directory(fp, filename);[](#l3.44)
fclose(fp);[](#l3.45)
if (files == NULL) {[](#l3.46)
Py_XDECREF(zip_stat);[](#l3.47) goto error;[](#l3.48)
}[](#l3.49)
if (PyDict_SetItem(zip_directory_cache, filename, files) != 0) {[](#l3.50)
Py_DECREF(files);[](#l3.51)
Py_XDECREF(zip_stat);[](#l3.52)
goto error;[](#l3.53)
}[](#l3.54)
if (zip_stat && PyDict_SetItem(zip_stat_cache, filename,[](#l3.55)
zip_stat) != 0) {[](#l3.56)
Py_DECREF(files);[](#l3.57)
Py_DECREF(zip_stat);[](#l3.58)
goto error;[](#l3.59)
}[](#l3.60)
} else Py_INCREF(files);Py_XDECREF(zip_stat);[](#l3.61)
@@ -554,10 +588,11 @@ zipimporter_get_data(PyObject *obj, PyOb { ZipImporter *self = (ZipImporter *)obj; PyObject *path, *key;
#ifdef ALTSEP _Py_IDENTIFIER(replace); #endif
- PyObject *toc_entry, *data; Py_ssize_t path_start, path_len, len; if (!PyArg_ParseTuple(args, "U:zipimporter.get_data", &path)) @@ -585,15 +620,23 @@ zipimporter_get_data(PyObject *obj, PyOb key = PyUnicode_Substring(path, path_start, path_len); if (key == NULL) goto error;
+ toc_entry = PyDict_GetItem(self->files, key); if (toc_entry == NULL) { PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, key); Py_DECREF(key);
error: Py_DECREF(path); return NULL; @@ -618,6 +661,7 @@ zipimporter_get_source(PyObject *obj, Py PyObject *toc_entry; PyObject *fullname, *subname, *path, *fullpath; enum zi_module_info mi;
if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname)) return NULL; @@ -647,11 +691,18 @@ zipimporter_get_source(PyObject *obj, Py if (fullpath == NULL) return NULL;
- fp = safely_reopen_archive(self);
- if (fp == NULL) {
Py_DECREF(fullpath);[](#l3.117)
return NULL;[](#l3.118)
- }
+ toc_entry = PyDict_GetItem(self->files, fullpath); Py_DECREF(fullpath); if (toc_entry != NULL) { PyObject *res, *bytes;
bytes = get_data(self->archive, toc_entry);[](#l3.125)
bytes = get_data(fp, self->archive, toc_entry);[](#l3.126)
fclose(fp);[](#l3.127) if (bytes == NULL)[](#l3.128) return NULL;[](#l3.129) res = PyUnicode_FromStringAndSize(PyBytes_AS_STRING(bytes),[](#l3.130)
@@ -659,10 +710,10 @@ zipimporter_get_source(PyObject *obj, Py Py_DECREF(bytes); return res; }
/* we have the module, but no source */
} PyDoc_STRVAR(doc_find_module, @@ -828,10 +879,135 @@ get_long(unsigned char buf) { return x; } +/ Return 1 if objects a and b fail a Py_EQ test for an attr. */ +static int +compare_obj_attr_strings(PyObject *obj_a, PyObject *obj_b, char *attr_name) +{
- int problem = 0;
- PyObject *attr_a = PyObject_GetAttrString(obj_a, attr_name);
- PyObject *attr_b = PyObject_GetAttrString(obj_b, attr_name);
- if (attr_a == NULL || attr_b == NULL)
problem = 1;[](#l3.156)
- else
problem = (PyObject_RichCompareBool(attr_a, attr_b, Py_EQ) != 1);[](#l3.158)
- Py_XDECREF(attr_a);
- Py_XDECREF(attr_b);
- return problem;
- fp = fopen_rb_and_stat(self->archive, &stat_now);
- if (!fp) {
PyErr_Format(ZipImportError,[](#l3.177)
"zipimport: can not open file %U", self->archive);[](#l3.178)
Py_XDECREF(stat_now);[](#l3.179)
return NULL;[](#l3.180)
- }
- if (stat_now != NULL) {
int problem = 0;[](#l3.184)
PyObject *files;[](#l3.185)
PyObject *prev_stat = PyDict_GetItem(zip_stat_cache, self->archive);[](#l3.186)
/* Test stat_now vs the old cached stat on some key attributes. */[](#l3.187)
if (prev_stat != NULL) {[](#l3.188)
problem = compare_obj_attr_strings(prev_stat, stat_now,[](#l3.189)
"st_ino");[](#l3.190)
problem |= compare_obj_attr_strings(prev_stat, stat_now,[](#l3.191)
"st_size");[](#l3.192)
problem |= compare_obj_attr_strings(prev_stat, stat_now,[](#l3.193)
"st_mtime");[](#l3.194)
} else {[](#l3.195)
if (Py_VerboseFlag)[](#l3.196)
PySys_FormatStderr("# zipimport: no stat data for %U!\n",[](#l3.197)
self->archive);[](#l3.198)
problem = 1;[](#l3.199)
}[](#l3.200)
if (problem) {[](#l3.203)
if (Py_VerboseFlag)[](#l3.204)
PySys_FormatStderr("# zipimport: %U modified since last"[](#l3.205)
" import, rereading TOC.\n", self->archive);[](#l3.206)
files = read_directory(fp, self->archive);[](#l3.207)
if (files == NULL) {[](#l3.208)
Py_DECREF(stat_now);[](#l3.209)
fclose(fp);[](#l3.210)
return NULL;[](#l3.211)
}[](#l3.212)
if (PyDict_SetItem(zip_directory_cache, self->archive,[](#l3.213)
files) != 0) {[](#l3.214)
Py_DECREF(files);[](#l3.215)
Py_DECREF(stat_now);[](#l3.216)
fclose(fp);[](#l3.217)
return NULL;[](#l3.218)
}[](#l3.219)
if (stat_now && PyDict_SetItem(zip_stat_cache, self->archive,[](#l3.220)
stat_now) != 0) {[](#l3.221)
Py_DECREF(files);[](#l3.222)
Py_DECREF(stat_now);[](#l3.223)
fclose(fp);[](#l3.224)
return NULL;[](#l3.225)
}[](#l3.226)
Py_XDECREF(self->files); /* free the old value. */[](#l3.227)
self->files = files;[](#l3.228)
} else {[](#l3.229)
/* No problem, discard the new stat data. */[](#l3.230)
Py_DECREF(stat_now);[](#l3.231)
}[](#l3.232)
- } /* stat succeeded */
- fopen_rb_and_stat(path, &py_stat) -> FILE * +
- Opens path in "rb" mode and populates the Python py_stat stat_result
- with information about the opened file. *py_stat may not be changed
- if there is no fstat_function or if fstat_function fails. +
- Returns NULL and does nothing to py_stat if the open failed. +/ +static FILE * +fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p) +{
- FILE *fp;
- assert(py_stat_p != NULL);
- assert(*py_stat_p == NULL);
- fp = _Py_fopen(path, "rb");
- if (fp == NULL) {
if (!PyErr_Occurred())[](#l3.256)
PyErr_Format(ZipImportError,[](#l3.257)
"zipimport: can not open file %U", path);[](#l3.258)
return NULL;[](#l3.259)
- }
- if (fstat_function) {
PyObject *stat_result = PyObject_CallFunction(fstat_function,[](#l3.263)
"i", fileno(fp));[](#l3.264)
if (stat_result == NULL) {[](#l3.265)
PyErr_Clear(); /* We can function without it. */[](#l3.266)
} else {[](#l3.267)
*py_stat_p = stat_result;[](#l3.268)
}[](#l3.269)
- }
- read_directory(fp, archive) -> files dict (new reference) +
- Given an open Zip archive, build a dict, mapping file names (local to the archive, using SEP as a separator) to toc entries. A toc_entry is a tuple: @@ -851,10 +1027,9 @@ get_long(unsigned char *buf) { data_size and file_offset are 0. */ static PyObject * -read_directory(PyObject *archive) +read_directory(FILE *fp, PyObject *archive) { PyObject *files = NULL;
- FILE *fp; unsigned short flags; short compress, time, date, name_size; long crc, data_size, file_size, header_size; @@ -869,27 +1044,18 @@ read_directory(PyObject *archive) const char *charset; int bootstrap;
- fp = _Py_fopen(archive, "rb");
- if (fp == NULL) {
if (!PyErr_Occurred())[](#l3.300)
PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);[](#l3.301)
return NULL;[](#l3.302)
- }
} header_position = ftell(fp); if (fread(endof_central_dir, 1, 22, fp) != 22) {fclose(fp);[](#l3.307) PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);[](#l3.308) return NULL;[](#l3.309)
} if (get_long((unsigned char )endof_central_dir) != 0x06054B50) { / Bad: End of Central Dir signature */fclose(fp);[](#l3.313) PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);[](#l3.314) return NULL;[](#l3.315)
} @@ -983,19 +1149,16 @@ read_directory(PyObject *archive) goto error; count++; }fclose(fp);[](#l3.319) PyErr_Format(ZipImportError, "not a Zip file: %R", archive);[](#l3.320) return NULL;[](#l3.321)
- fclose(fp); if (Py_VerboseFlag) PySys_FormatStderr("# zipimport: found %ld names in %R\n", count, archive); return files; fseek_error:
- fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; error:
- fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); return NULL; @@ -1034,14 +1197,13 @@ get_decompress_func(void) return decompress; }
-/* Given a path to a Zip file and a toc_entry, return the (uncompressed) +/* Given a FILE* to a Zip file and a toc_entry, return the (uncompressed) data as a new reference. */ static PyObject * -get_data(PyObject *archive, PyObject *toc_entry) +get_data(FILE *fp, PyObject *archive, PyObject *toc_entry) { PyObject *raw_data, *data = NULL, *decompress; char *buf;
- FILE *fp; int err; Py_ssize_t bytes_read = 0; long l; @@ -1055,17 +1217,8 @@ get_data(PyObject *archive, PyObject *to return NULL; }
- fp = _Py_fopen(archive, "rb");
- if (!fp) {
if (!PyErr_Occurred())[](#l3.366)
PyErr_Format(PyExc_IOError,[](#l3.367)
"zipimport: can not open file %U", archive);[](#l3.368)
return NULL;[](#l3.369)
- }
- /* Check to make sure the local file header is correct */ if (fseek(fp, file_offset, 0) == -1) {
} @@ -1076,11 +1229,9 @@ get_data(PyObject *archive, PyObject *to PyErr_Format(ZipImportError, "bad local file header in %U", archive);fclose(fp);[](#l3.374) PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);[](#l3.375) return NULL;[](#l3.376)
} if (fseek(fp, file_offset + 26, 0) == -1) {fclose(fp);[](#l3.382) return NULL;[](#l3.383)
} @@ -1095,7 +1246,6 @@ get_data(PyObject *archive, PyObject *to raw_data = PyBytes_FromStringAndSize((char *)NULL, bytes_size); if (raw_data == NULL) {fclose(fp);[](#l3.386) PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);[](#l3.387) return NULL;[](#l3.388)
} buf = PyBytes_AsString(raw_data); @@ -1104,11 +1254,9 @@ get_data(PyObject *archive, PyObject *to if (err == 0) { bytes_read = fread(buf, 1, data_size, fp); } else {fclose(fp);[](#l3.394) return NULL;[](#l3.395)
}fclose(fp);[](#l3.402) PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);[](#l3.403) return NULL;[](#l3.404)
- fclose(fp); if (err || bytes_read != data_size) { PyErr_SetString(PyExc_IOError, "zipimport: can't read data");
@@ -1329,12 +1477,12 @@ get_mtime_of_source(ZipImporter self, P / Return the code object for the module named by 'fullname' from the Zip archive as a new reference. */ static PyObject * -get_code_from_data(ZipImporter *self, int ispackage, int isbytecode, +get_code_from_data(ZipImporter *self, FILE *fp, int ispackage, int isbytecode, time_t mtime, PyObject *toc_entry) { PyObject *data, *modpath, *code;
@@ -1356,6 +1504,7 @@ get_module_code(ZipImporter *self, PyObj PyObject *code = NULL, *toc_entry, *subname; PyObject *path, *fullpath = NULL; struct st_zip_searchorder *zso;
subname = get_subname(fullname); if (subname == NULL) @@ -1366,6 +1515,12 @@ get_module_code(ZipImporter *self, PyObj if (path == NULL) return NULL;
- fp = safely_reopen_archive(self);
- if (fp == NULL) {
Py_DECREF(path);[](#l3.439)
return NULL;[](#l3.440)
- }
+ for (zso = zip_searchorder; *zso->suffix; zso++) { code = NULL; @@ -1376,6 +1531,7 @@ get_module_code(ZipImporter *self, PyObj if (Py_VerboseFlag > 1) PySys_FormatStderr("# trying %U%c%U\n", self->archive, (int)SEP, fullpath); + toc_entry = PyDict_GetItem(self->files, fullpath); if (toc_entry != NULL) { time_t mtime = 0; @@ -1391,7 +1547,7 @@ get_module_code(ZipImporter *self, PyObj Py_CLEAR(fullpath); if (p_ispackage != NULL) *p_ispackage = ispackage;
code = get_code_from_data(self, ispackage,[](#l3.458)
code = get_code_from_data(self, fp, ispackage,[](#l3.459) isbytecode, mtime,[](#l3.460) toc_entry);[](#l3.461) if (code == Py_None) {[](#l3.462)
@@ -1411,6 +1567,7 @@ get_module_code(ZipImporter *self, PyObj } PyErr_Format(ZipImportError, "can't find module %R", fullname); exit:
- fclose(fp); Py_DECREF(path); Py_XDECREF(fullpath); return code; @@ -1428,6 +1585,8 @@ This module exports three objects:\n[](#l3.471) subclass of ImportError, so it can be caught as ImportError, too.\n[](#l3.472)
- _zip_directory_cache: a dict, mapping archive paths to zip directory\n[](#l3.473) info dicts, as used in zipimporter._files.\n[](#l3.474) +- _zip_stat_cache: a dict, mapping archive paths to stat_result\n[](#l3.475)
- info for the .zip the last time anything was imported from it.\n[](#l3.476) \n[](#l3.477) It is usually not needed to use the zipimport module explicitly; it is\n[](#l3.478) used by the builtin import mechanism for sys.path items that are paths\n[](#l3.479) @@ -1487,6 +1646,7 @@ PyInit_zipimport(void) (PyObject *)&ZipImporter_Type) < 0) return NULL;
- Py_XDECREF(zip_directory_cache); /* Avoid embedded interpreter leaks. */ zip_directory_cache = PyDict_New(); if (zip_directory_cache == NULL) return NULL;
@@ -1494,5 +1654,36 @@ PyInit_zipimport(void) if (PyModule_AddObject(mod, "_zip_directory_cache", zip_directory_cache) < 0) return NULL; +
- Py_XDECREF(zip_stat_cache); /* Avoid embedded interpreter leaks. */
- zip_stat_cache = PyDict_New();
- if (zip_stat_cache == NULL)
return NULL;[](#l3.496)
- Py_INCREF(zip_stat_cache);
- if (PyModule_AddObject(mod, "_zip_stat_cache", zip_stat_cache) < 0)
return NULL;[](#l3.499)
- {
/* We cannot import "os" here as that is a .py/.pyc file that could[](#l3.502)
* live within a zipped up standard library. Import the posix or nt[](#l3.503)
* builtin that provides the fstat() function we want instead. */[](#l3.504)
PyObject *os_like_module;[](#l3.505)
Py_CLEAR(fstat_function); /* Avoid embedded interpreter leaks. */[](#l3.506)
os_like_module = PyImport_ImportModule("posix");[](#l3.507)
if (os_like_module == NULL) {[](#l3.508)
PyErr_Clear();[](#l3.509)
os_like_module = PyImport_ImportModule("nt");[](#l3.510)
}[](#l3.511)
if (os_like_module != NULL) {[](#l3.512)
fstat_function = PyObject_GetAttrString(os_like_module, "fstat");[](#l3.513)
Py_DECREF(os_like_module);[](#l3.514)
}[](#l3.515)
if (fstat_function == NULL) {[](#l3.516)
PyErr_Clear(); /* non-fatal, we'll go on without it. */[](#l3.517)
if (Py_VerboseFlag)[](#l3.518)
PySys_WriteStderr("# zipimport unable to use os.fstat().\n");[](#l3.519)
}[](#l3.520)
- }