mirror of https://github.com/python/cpython.git
merge backout for #20621
This commit is contained in:
commit
ec91cd6040
|
@ -71,27 +71,6 @@ def tearDown(self):
|
||||||
support.modules_cleanup(*self.modules_before)
|
support.modules_cleanup(*self.modules_before)
|
||||||
|
|
||||||
|
|
||||||
def _write_zip_package(zipname, files,
|
|
||||||
data_to_prepend=b"", compression=ZIP_STORED):
|
|
||||||
z = ZipFile(zipname, "w")
|
|
||||||
try:
|
|
||||||
for name, (mtime, data) in files.items():
|
|
||||||
zinfo = ZipInfo(name, time.localtime(mtime))
|
|
||||||
zinfo.compress_type = compression
|
|
||||||
z.writestr(zinfo, data)
|
|
||||||
finally:
|
|
||||||
z.close()
|
|
||||||
|
|
||||||
if data_to_prepend:
|
|
||||||
# Prepend data to the start of the zipfile
|
|
||||||
with open(zipname, "rb") as f:
|
|
||||||
zip_data = f.read()
|
|
||||||
|
|
||||||
with open(zipname, "wb") as f:
|
|
||||||
f.write(data_to_prepend)
|
|
||||||
f.write(zip_data)
|
|
||||||
|
|
||||||
|
|
||||||
class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
|
class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
|
||||||
|
|
||||||
compression = ZIP_STORED
|
compression = ZIP_STORED
|
||||||
|
@ -104,9 +83,23 @@ def setUp(self):
|
||||||
ImportHooksBaseTestCase.setUp(self)
|
ImportHooksBaseTestCase.setUp(self)
|
||||||
|
|
||||||
def doTest(self, expected_ext, files, *modules, **kw):
|
def doTest(self, expected_ext, files, *modules, **kw):
|
||||||
_write_zip_package(TEMP_ZIP, files, data_to_prepend=kw.get("stuff"),
|
z = ZipFile(TEMP_ZIP, "w")
|
||||||
compression=self.compression)
|
|
||||||
try:
|
try:
|
||||||
|
for name, (mtime, data) in files.items():
|
||||||
|
zinfo = ZipInfo(name, time.localtime(mtime))
|
||||||
|
zinfo.compress_type = self.compression
|
||||||
|
z.writestr(zinfo, data)
|
||||||
|
z.close()
|
||||||
|
|
||||||
|
stuff = kw.get("stuff", None)
|
||||||
|
if stuff is not None:
|
||||||
|
# Prepend 'stuff' to the start of the zipfile
|
||||||
|
with open(TEMP_ZIP, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
with open(TEMP_ZIP, "wb") as f:
|
||||||
|
f.write(stuff)
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
sys.path.insert(0, TEMP_ZIP)
|
sys.path.insert(0, TEMP_ZIP)
|
||||||
|
|
||||||
mod = __import__(".".join(modules), globals(), locals(),
|
mod = __import__(".".join(modules), globals(), locals(),
|
||||||
|
@ -121,8 +114,7 @@ def doTest(self, expected_ext, files, *modules, **kw):
|
||||||
self.assertEqual(file, os.path.join(TEMP_ZIP,
|
self.assertEqual(file, os.path.join(TEMP_ZIP,
|
||||||
*modules) + expected_ext)
|
*modules) + expected_ext)
|
||||||
finally:
|
finally:
|
||||||
while TEMP_ZIP in sys.path:
|
z.close()
|
||||||
sys.path.remove(TEMP_ZIP)
|
|
||||||
os.remove(TEMP_ZIP)
|
os.remove(TEMP_ZIP)
|
||||||
|
|
||||||
def testAFakeZlib(self):
|
def testAFakeZlib(self):
|
||||||
|
@ -430,67 +422,10 @@ class CompressedZipImportTestCase(UncompressedZipImportTestCase):
|
||||||
compression = ZIP_DEFLATED
|
compression = ZIP_DEFLATED
|
||||||
|
|
||||||
|
|
||||||
class ZipFileModifiedAfterImportTestCase(ImportHooksBaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
zipimport._zip_directory_cache.clear()
|
|
||||||
zipimport._zip_stat_cache.clear()
|
|
||||||
ImportHooksBaseTestCase.setUp(self)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
ImportHooksBaseTestCase.tearDown(self)
|
|
||||||
if os.path.exists(TEMP_ZIP):
|
|
||||||
os.remove(TEMP_ZIP)
|
|
||||||
|
|
||||||
def testZipFileChangesAfterFirstImport(self):
|
|
||||||
"""Alter the zip file after caching its index and try an import."""
|
|
||||||
packdir = TESTPACK + os.sep
|
|
||||||
files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
|
|
||||||
packdir + TESTMOD + ".py": (NOW, "test_value = 38\n"),
|
|
||||||
"ziptest_a.py": (NOW, "test_value = 23\n"),
|
|
||||||
"ziptest_b.py": (NOW, "test_value = 42\n"),
|
|
||||||
"ziptest_c.py": (NOW, "test_value = 1337\n")}
|
|
||||||
zipfile_path = TEMP_ZIP
|
|
||||||
_write_zip_package(zipfile_path, files)
|
|
||||||
self.assertTrue(os.path.exists(zipfile_path))
|
|
||||||
sys.path.insert(0, zipfile_path)
|
|
||||||
|
|
||||||
# Import something out of the zipfile and confirm it is correct.
|
|
||||||
testmod = __import__(TESTPACK + "." + TESTMOD,
|
|
||||||
globals(), locals(), ["__dummy__"])
|
|
||||||
self.assertEqual(testmod.test_value, 38)
|
|
||||||
# Import something else out of the zipfile and confirm it is correct.
|
|
||||||
ziptest_b = __import__("ziptest_b", globals(), locals(), ["test_value"])
|
|
||||||
self.assertEqual(ziptest_b.test_value, 42)
|
|
||||||
|
|
||||||
# Truncate and fill the zip file with non-zip garbage.
|
|
||||||
with open(zipfile_path, "rb") as orig_zip_file:
|
|
||||||
orig_zip_file_contents = orig_zip_file.read()
|
|
||||||
with open(zipfile_path, "wb") as byebye_valid_zip_file:
|
|
||||||
byebye_valid_zip_file.write(b"Tear down this wall!\n"*1987)
|
|
||||||
# Now that the zipfile has been replaced, import something else from it
|
|
||||||
# which should fail as the file contents are now garbage.
|
|
||||||
with self.assertRaises(ImportError):
|
|
||||||
ziptest_a = __import__("ziptest_a", globals(), locals(),
|
|
||||||
["test_value"])
|
|
||||||
self.assertEqual(ziptest_a.test_value, 23)
|
|
||||||
|
|
||||||
# Now lets make it a valid zipfile that has some garbage at the start.
|
|
||||||
# This alters all of the offsets within the file
|
|
||||||
with open(zipfile_path, "wb") as new_zip_file:
|
|
||||||
new_zip_file.write(b"X"*1991) # The year Python was created.
|
|
||||||
new_zip_file.write(orig_zip_file_contents)
|
|
||||||
|
|
||||||
# Now that the zip file has been "restored" to a valid but different
|
|
||||||
# zipfile the zipimporter should *successfully* re-read the new zip
|
|
||||||
# file's end of file central index and be able to import from it again.
|
|
||||||
ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"])
|
|
||||||
self.assertEqual(ziptest_c.test_value, 1337)
|
|
||||||
|
|
||||||
|
|
||||||
class BadFileZipImportTestCase(unittest.TestCase):
|
class BadFileZipImportTestCase(unittest.TestCase):
|
||||||
def assertZipFailure(self, filename):
|
def assertZipFailure(self, filename):
|
||||||
with self.assertRaises(zipimport.ZipImportError):
|
self.assertRaises(zipimport.ZipImportError,
|
||||||
zipimport.zipimporter(filename)
|
zipimport.zipimporter, filename)
|
||||||
|
|
||||||
def testNoFile(self):
|
def testNoFile(self):
|
||||||
self.assertZipFailure('AdfjdkFJKDFJjdklfjs')
|
self.assertZipFailure('AdfjdkFJKDFJjdklfjs')
|
||||||
|
@ -564,7 +499,6 @@ def test_main():
|
||||||
UncompressedZipImportTestCase,
|
UncompressedZipImportTestCase,
|
||||||
CompressedZipImportTestCase,
|
CompressedZipImportTestCase,
|
||||||
BadFileZipImportTestCase,
|
BadFileZipImportTestCase,
|
||||||
ZipFileModifiedAfterImportTestCase,
|
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
support.unlink(TESTMOD)
|
support.unlink(TESTMOD)
|
||||||
|
|
|
@ -49,16 +49,10 @@ struct _zipimporter {
|
||||||
static PyObject *ZipImportError;
|
static PyObject *ZipImportError;
|
||||||
/* read_directory() cache */
|
/* read_directory() cache */
|
||||||
static PyObject *zip_directory_cache = NULL;
|
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 */
|
/* forward decls */
|
||||||
static FILE *fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p);
|
static PyObject *read_directory(PyObject *archive);
|
||||||
static FILE *safely_reopen_archive(ZipImporter *self);
|
static PyObject *get_data(PyObject *archive, PyObject *toc_entry);
|
||||||
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,
|
static PyObject *get_module_code(ZipImporter *self, PyObject *fullname,
|
||||||
int *p_ispackage, PyObject **p_modpath);
|
int *p_ispackage, PyObject **p_modpath);
|
||||||
|
|
||||||
|
@ -137,39 +131,11 @@ zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
files = PyDict_GetItem(zip_directory_cache, filename);
|
files = PyDict_GetItem(zip_directory_cache, filename);
|
||||||
if (files == NULL) {
|
if (files == NULL) {
|
||||||
PyObject *zip_stat = NULL;
|
files = read_directory(filename);
|
||||||
FILE *fp = fopen_rb_and_stat(filename, &zip_stat);
|
if (files == NULL)
|
||||||
if (fp == NULL) {
|
|
||||||
if (!PyErr_Occurred())
|
|
||||||
PyErr_Format(ZipImportError, "can't open Zip file: %R",
|
|
||||||
filename);
|
|
||||||
|
|
||||||
Py_XDECREF(zip_stat);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
if (PyDict_SetItem(zip_directory_cache, filename, files) != 0)
|
||||||
|
|
||||||
if (Py_VerboseFlag)
|
|
||||||
PySys_FormatStderr("# zipimport: %U not cached, "
|
|
||||||
"reading TOC.\n", filename);
|
|
||||||
|
|
||||||
files = read_directory(fp, filename);
|
|
||||||
fclose(fp);
|
|
||||||
if (files == NULL) {
|
|
||||||
Py_XDECREF(zip_stat);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
if (PyDict_SetItem(zip_directory_cache, filename, files) != 0) {
|
|
||||||
Py_DECREF(files);
|
|
||||||
Py_XDECREF(zip_stat);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (zip_stat && PyDict_SetItem(zip_stat_cache, filename,
|
|
||||||
zip_stat) != 0) {
|
|
||||||
Py_DECREF(files);
|
|
||||||
Py_DECREF(zip_stat);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
Py_XDECREF(zip_stat);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Py_INCREF(files);
|
Py_INCREF(files);
|
||||||
|
@ -594,8 +560,7 @@ zipimporter_get_data(PyObject *obj, PyObject *args)
|
||||||
{
|
{
|
||||||
ZipImporter *self = (ZipImporter *)obj;
|
ZipImporter *self = (ZipImporter *)obj;
|
||||||
PyObject *path, *key;
|
PyObject *path, *key;
|
||||||
FILE *fp;
|
PyObject *toc_entry;
|
||||||
PyObject *toc_entry, *data;
|
|
||||||
Py_ssize_t path_start, path_len, len;
|
Py_ssize_t path_start, path_len, len;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "U:zipimporter.get_data", &path))
|
if (!PyArg_ParseTuple(args, "U:zipimporter.get_data", &path))
|
||||||
|
@ -623,23 +588,15 @@ zipimporter_get_data(PyObject *obj, PyObject *args)
|
||||||
key = PyUnicode_Substring(path, path_start, path_len);
|
key = PyUnicode_Substring(path, path_start, path_len);
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
fp = safely_reopen_archive(self);
|
|
||||||
if (fp == NULL)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
toc_entry = PyDict_GetItem(self->files, key);
|
toc_entry = PyDict_GetItem(self->files, key);
|
||||||
if (toc_entry == NULL) {
|
if (toc_entry == NULL) {
|
||||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, key);
|
PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, key);
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
fclose(fp);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
Py_DECREF(path);
|
Py_DECREF(path);
|
||||||
data = get_data(fp, self->archive, toc_entry);
|
return get_data(self->archive, toc_entry);
|
||||||
fclose(fp);
|
|
||||||
return data;
|
|
||||||
error:
|
error:
|
||||||
Py_DECREF(path);
|
Py_DECREF(path);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -664,7 +621,6 @@ zipimporter_get_source(PyObject *obj, PyObject *args)
|
||||||
PyObject *toc_entry;
|
PyObject *toc_entry;
|
||||||
PyObject *fullname, *subname, *path, *fullpath;
|
PyObject *fullname, *subname, *path, *fullpath;
|
||||||
enum zi_module_info mi;
|
enum zi_module_info mi;
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname))
|
if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -694,18 +650,11 @@ zipimporter_get_source(PyObject *obj, PyObject *args)
|
||||||
if (fullpath == NULL)
|
if (fullpath == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fp = safely_reopen_archive(self);
|
|
||||||
if (fp == NULL) {
|
|
||||||
Py_DECREF(fullpath);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
toc_entry = PyDict_GetItem(self->files, fullpath);
|
toc_entry = PyDict_GetItem(self->files, fullpath);
|
||||||
Py_DECREF(fullpath);
|
Py_DECREF(fullpath);
|
||||||
if (toc_entry != NULL) {
|
if (toc_entry != NULL) {
|
||||||
PyObject *res, *bytes;
|
PyObject *res, *bytes;
|
||||||
bytes = get_data(fp, self->archive, toc_entry);
|
bytes = get_data(self->archive, toc_entry);
|
||||||
fclose(fp);
|
|
||||||
if (bytes == NULL)
|
if (bytes == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
res = PyUnicode_FromStringAndSize(PyBytes_AS_STRING(bytes),
|
res = PyUnicode_FromStringAndSize(PyBytes_AS_STRING(bytes),
|
||||||
|
@ -713,10 +662,10 @@ zipimporter_get_source(PyObject *obj, PyObject *args)
|
||||||
Py_DECREF(bytes);
|
Py_DECREF(bytes);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
/* we have the module, but no source */
|
/* we have the module, but no source */
|
||||||
Py_RETURN_NONE;
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(doc_find_module,
|
PyDoc_STRVAR(doc_find_module,
|
||||||
|
@ -882,133 +831,10 @@ get_long(unsigned char *buf) {
|
||||||
return x;
|
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;
|
|
||||||
else
|
|
||||||
problem = (PyObject_RichCompareBool(attr_a, attr_b, Py_EQ) != 1);
|
|
||||||
Py_XDECREF(attr_a);
|
|
||||||
Py_XDECREF(attr_b);
|
|
||||||
return problem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns an open FILE * on success.
|
read_directory(archive) -> files dict (new reference)
|
||||||
* Returns NULL on error with the Python error context set.
|
|
||||||
*/
|
|
||||||
static FILE *
|
|
||||||
safely_reopen_archive(ZipImporter *self)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
PyObject *stat_now = NULL;
|
|
||||||
|
|
||||||
fp = fopen_rb_and_stat(self->archive, &stat_now);
|
Given a path to a Zip archive, build a dict, mapping file names
|
||||||
if (!fp) {
|
|
||||||
PyErr_Format(ZipImportError,
|
|
||||||
"zipimport: can not open file %U", self->archive);
|
|
||||||
Py_XDECREF(stat_now);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat_now != NULL) {
|
|
||||||
int problem = 0;
|
|
||||||
PyObject *files;
|
|
||||||
PyObject *prev_stat = PyDict_GetItem(zip_stat_cache, self->archive);
|
|
||||||
/* Test stat_now vs the old cached stat on some key attributes. */
|
|
||||||
if (prev_stat != NULL) {
|
|
||||||
problem = compare_obj_attr_strings(prev_stat, stat_now,
|
|
||||||
"st_ino");
|
|
||||||
problem |= compare_obj_attr_strings(prev_stat, stat_now,
|
|
||||||
"st_size");
|
|
||||||
problem |= compare_obj_attr_strings(prev_stat, stat_now,
|
|
||||||
"st_mtime");
|
|
||||||
} else {
|
|
||||||
if (Py_VerboseFlag)
|
|
||||||
PySys_FormatStderr("# zipimport: no stat data for %U!\n",
|
|
||||||
self->archive);
|
|
||||||
problem = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (problem) {
|
|
||||||
if (Py_VerboseFlag)
|
|
||||||
PySys_FormatStderr("# zipimport: %U modified since last"
|
|
||||||
" import, rereading TOC.\n", self->archive);
|
|
||||||
files = read_directory(fp, self->archive);
|
|
||||||
if (files == NULL) {
|
|
||||||
Py_DECREF(stat_now);
|
|
||||||
fclose(fp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (PyDict_SetItem(zip_directory_cache, self->archive,
|
|
||||||
files) != 0) {
|
|
||||||
Py_DECREF(files);
|
|
||||||
Py_DECREF(stat_now);
|
|
||||||
fclose(fp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (stat_now && PyDict_SetItem(zip_stat_cache, self->archive,
|
|
||||||
stat_now) != 0) {
|
|
||||||
Py_DECREF(files);
|
|
||||||
Py_DECREF(stat_now);
|
|
||||||
fclose(fp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_XDECREF(self->files); /* free the old value. */
|
|
||||||
self->files = files;
|
|
||||||
}
|
|
||||||
Py_DECREF(stat_now);
|
|
||||||
} /* stat succeeded */
|
|
||||||
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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_obj(path, "rb");
|
|
||||||
if (fp == NULL) {
|
|
||||||
if (!PyErr_Occurred())
|
|
||||||
PyErr_Format(ZipImportError,
|
|
||||||
"zipimport: can not open file %U", path);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fstat_function) {
|
|
||||||
PyObject *stat_result = PyObject_CallFunction(fstat_function,
|
|
||||||
"i", fileno(fp));
|
|
||||||
if (stat_result == NULL) {
|
|
||||||
PyErr_Clear(); /* We can function without it. */
|
|
||||||
} else {
|
|
||||||
*py_stat_p = stat_result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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.
|
(local to the archive, using SEP as a separator) to toc entries.
|
||||||
|
|
||||||
A toc_entry is a tuple:
|
A toc_entry is a tuple:
|
||||||
|
@ -1028,9 +854,10 @@ fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p)
|
||||||
data_size and file_offset are 0.
|
data_size and file_offset are 0.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
read_directory(FILE *fp, PyObject *archive)
|
read_directory(PyObject *archive)
|
||||||
{
|
{
|
||||||
PyObject *files = NULL;
|
PyObject *files = NULL;
|
||||||
|
FILE *fp;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
short compress, time, date, name_size;
|
short compress, time, date, name_size;
|
||||||
long crc, data_size, file_size, header_size;
|
long crc, data_size, file_size, header_size;
|
||||||
|
@ -1046,18 +873,27 @@ read_directory(FILE *fp, PyObject *archive)
|
||||||
const char *charset;
|
const char *charset;
|
||||||
int bootstrap;
|
int bootstrap;
|
||||||
|
|
||||||
assert(fp != NULL);
|
fp = _Py_fopen_obj(archive, "rb");
|
||||||
|
if (fp == NULL) {
|
||||||
|
if (!PyErr_Occurred())
|
||||||
|
PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (fseek(fp, -22, SEEK_END) == -1) {
|
if (fseek(fp, -22, SEEK_END) == -1) {
|
||||||
|
fclose(fp);
|
||||||
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
header_position = ftell(fp);
|
header_position = ftell(fp);
|
||||||
if (fread(endof_central_dir, 1, 22, fp) != 22) {
|
if (fread(endof_central_dir, 1, 22, fp) != 22) {
|
||||||
|
fclose(fp);
|
||||||
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) {
|
if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) {
|
||||||
/* Bad: End of Central Dir signature */
|
/* Bad: End of Central Dir signature */
|
||||||
|
fclose(fp);
|
||||||
PyErr_Format(ZipImportError, "not a Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "not a Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1164,16 +1000,19 @@ read_directory(FILE *fp, PyObject *archive)
|
||||||
goto error;
|
goto error;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
fclose(fp);
|
||||||
if (Py_VerboseFlag)
|
if (Py_VerboseFlag)
|
||||||
PySys_FormatStderr("# zipimport: found %ld names in %R\n",
|
PySys_FormatStderr("# zipimport: found %ld names in %R\n",
|
||||||
count, archive);
|
count, archive);
|
||||||
return files;
|
return files;
|
||||||
file_error:
|
file_error:
|
||||||
|
fclose(fp);
|
||||||
Py_XDECREF(files);
|
Py_XDECREF(files);
|
||||||
Py_XDECREF(nameobj);
|
Py_XDECREF(nameobj);
|
||||||
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
error:
|
error:
|
||||||
|
fclose(fp);
|
||||||
Py_XDECREF(files);
|
Py_XDECREF(files);
|
||||||
Py_XDECREF(nameobj);
|
Py_XDECREF(nameobj);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1212,13 +1051,14 @@ get_decompress_func(void)
|
||||||
return decompress;
|
return decompress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given a FILE* to a Zip file and a toc_entry, return the (uncompressed)
|
/* Given a path to a Zip file and a toc_entry, return the (uncompressed)
|
||||||
data as a new reference. */
|
data as a new reference. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_data(FILE *fp, PyObject *archive, PyObject *toc_entry)
|
get_data(PyObject *archive, PyObject *toc_entry)
|
||||||
{
|
{
|
||||||
PyObject *raw_data, *data = NULL, *decompress;
|
PyObject *raw_data, *data = NULL, *decompress;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
FILE *fp;
|
||||||
int err;
|
int err;
|
||||||
Py_ssize_t bytes_read = 0;
|
Py_ssize_t bytes_read = 0;
|
||||||
long l;
|
long l;
|
||||||
|
@ -1232,8 +1072,17 @@ get_data(FILE *fp, PyObject *archive, PyObject *toc_entry)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fp = _Py_fopen_obj(archive, "rb");
|
||||||
|
if (!fp) {
|
||||||
|
if (!PyErr_Occurred())
|
||||||
|
PyErr_Format(PyExc_IOError,
|
||||||
|
"zipimport: can not open file %U", archive);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check to make sure the local file header is correct */
|
/* Check to make sure the local file header is correct */
|
||||||
if (fseek(fp, file_offset, 0) == -1) {
|
if (fseek(fp, file_offset, 0) == -1) {
|
||||||
|
fclose(fp);
|
||||||
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1245,9 +1094,11 @@ get_data(FILE *fp, PyObject *archive, PyObject *toc_entry)
|
||||||
PyErr_Format(ZipImportError,
|
PyErr_Format(ZipImportError,
|
||||||
"bad local file header in %U",
|
"bad local file header in %U",
|
||||||
archive);
|
archive);
|
||||||
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (fseek(fp, file_offset + 26, 0) == -1) {
|
if (fseek(fp, file_offset + 26, 0) == -1) {
|
||||||
|
fclose(fp);
|
||||||
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1255,6 +1106,7 @@ get_data(FILE *fp, PyObject *archive, PyObject *toc_entry)
|
||||||
l = 30 + PyMarshal_ReadShortFromFile(fp) +
|
l = 30 + PyMarshal_ReadShortFromFile(fp) +
|
||||||
PyMarshal_ReadShortFromFile(fp); /* local header size */
|
PyMarshal_ReadShortFromFile(fp); /* local header size */
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
file_offset += l; /* Start of file data */
|
file_offset += l; /* Start of file data */
|
||||||
|
@ -1265,6 +1117,7 @@ get_data(FILE *fp, PyObject *archive, PyObject *toc_entry)
|
||||||
raw_data = PyBytes_FromStringAndSize((char *)NULL, bytes_size);
|
raw_data = PyBytes_FromStringAndSize((char *)NULL, bytes_size);
|
||||||
|
|
||||||
if (raw_data == NULL) {
|
if (raw_data == NULL) {
|
||||||
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
buf = PyBytes_AsString(raw_data);
|
buf = PyBytes_AsString(raw_data);
|
||||||
|
@ -1273,9 +1126,11 @@ get_data(FILE *fp, PyObject *archive, PyObject *toc_entry)
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
bytes_read = fread(buf, 1, data_size, fp);
|
bytes_read = fread(buf, 1, data_size, fp);
|
||||||
} else {
|
} else {
|
||||||
|
fclose(fp);
|
||||||
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
fclose(fp);
|
||||||
if (err || bytes_read != data_size) {
|
if (err || bytes_read != data_size) {
|
||||||
PyErr_SetString(PyExc_IOError,
|
PyErr_SetString(PyExc_IOError,
|
||||||
"zipimport: can't read data");
|
"zipimport: can't read data");
|
||||||
|
@ -1496,12 +1351,12 @@ get_mtime_of_source(ZipImporter *self, PyObject *path)
|
||||||
/* Return the code object for the module named by 'fullname' from the
|
/* Return the code object for the module named by 'fullname' from the
|
||||||
Zip archive as a new reference. */
|
Zip archive as a new reference. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_code_from_data(ZipImporter *self, FILE *fp, int ispackage, int isbytecode,
|
get_code_from_data(ZipImporter *self, int ispackage, int isbytecode,
|
||||||
time_t mtime, PyObject *toc_entry)
|
time_t mtime, PyObject *toc_entry)
|
||||||
{
|
{
|
||||||
PyObject *data, *modpath, *code;
|
PyObject *data, *modpath, *code;
|
||||||
|
|
||||||
data = get_data(fp, self->archive, toc_entry);
|
data = get_data(self->archive, toc_entry);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1523,7 +1378,6 @@ get_module_code(ZipImporter *self, PyObject *fullname,
|
||||||
PyObject *code = NULL, *toc_entry, *subname;
|
PyObject *code = NULL, *toc_entry, *subname;
|
||||||
PyObject *path, *fullpath = NULL;
|
PyObject *path, *fullpath = NULL;
|
||||||
struct st_zip_searchorder *zso;
|
struct st_zip_searchorder *zso;
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
subname = get_subname(fullname);
|
subname = get_subname(fullname);
|
||||||
if (subname == NULL)
|
if (subname == NULL)
|
||||||
|
@ -1534,12 +1388,6 @@ get_module_code(ZipImporter *self, PyObject *fullname,
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fp = safely_reopen_archive(self);
|
|
||||||
if (fp == NULL) {
|
|
||||||
Py_DECREF(path);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (zso = zip_searchorder; *zso->suffix; zso++) {
|
for (zso = zip_searchorder; *zso->suffix; zso++) {
|
||||||
code = NULL;
|
code = NULL;
|
||||||
|
|
||||||
|
@ -1550,7 +1398,6 @@ get_module_code(ZipImporter *self, PyObject *fullname,
|
||||||
if (Py_VerboseFlag > 1)
|
if (Py_VerboseFlag > 1)
|
||||||
PySys_FormatStderr("# trying %U%c%U\n",
|
PySys_FormatStderr("# trying %U%c%U\n",
|
||||||
self->archive, (int)SEP, fullpath);
|
self->archive, (int)SEP, fullpath);
|
||||||
|
|
||||||
toc_entry = PyDict_GetItem(self->files, fullpath);
|
toc_entry = PyDict_GetItem(self->files, fullpath);
|
||||||
if (toc_entry != NULL) {
|
if (toc_entry != NULL) {
|
||||||
time_t mtime = 0;
|
time_t mtime = 0;
|
||||||
|
@ -1566,7 +1413,7 @@ get_module_code(ZipImporter *self, PyObject *fullname,
|
||||||
Py_CLEAR(fullpath);
|
Py_CLEAR(fullpath);
|
||||||
if (p_ispackage != NULL)
|
if (p_ispackage != NULL)
|
||||||
*p_ispackage = ispackage;
|
*p_ispackage = ispackage;
|
||||||
code = get_code_from_data(self, fp, ispackage,
|
code = get_code_from_data(self, ispackage,
|
||||||
isbytecode, mtime,
|
isbytecode, mtime,
|
||||||
toc_entry);
|
toc_entry);
|
||||||
if (code == Py_None) {
|
if (code == Py_None) {
|
||||||
|
@ -1586,7 +1433,6 @@ get_module_code(ZipImporter *self, PyObject *fullname,
|
||||||
}
|
}
|
||||||
PyErr_Format(ZipImportError, "can't find module %R", fullname);
|
PyErr_Format(ZipImportError, "can't find module %R", fullname);
|
||||||
exit:
|
exit:
|
||||||
fclose(fp);
|
|
||||||
Py_DECREF(path);
|
Py_DECREF(path);
|
||||||
Py_XDECREF(fullpath);
|
Py_XDECREF(fullpath);
|
||||||
return code;
|
return code;
|
||||||
|
@ -1604,8 +1450,6 @@ This module exports three objects:\n\
|
||||||
subclass of ImportError, so it can be caught as ImportError, too.\n\
|
subclass of ImportError, so it can be caught as ImportError, too.\n\
|
||||||
- _zip_directory_cache: a dict, mapping archive paths to zip directory\n\
|
- _zip_directory_cache: a dict, mapping archive paths to zip directory\n\
|
||||||
info dicts, as used in zipimporter._files.\n\
|
info dicts, as used in zipimporter._files.\n\
|
||||||
- _zip_stat_cache: a dict, mapping archive paths to stat_result\n\
|
|
||||||
info for the .zip the last time anything was imported from it.\n\
|
|
||||||
\n\
|
\n\
|
||||||
It is usually not needed to use the zipimport module explicitly; it is\n\
|
It is usually not needed to use the zipimport module explicitly; it is\n\
|
||||||
used by the builtin import mechanism for sys.path items that are paths\n\
|
used by the builtin import mechanism for sys.path items that are paths\n\
|
||||||
|
@ -1665,7 +1509,6 @@ PyInit_zipimport(void)
|
||||||
(PyObject *)&ZipImporter_Type) < 0)
|
(PyObject *)&ZipImporter_Type) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Py_XDECREF(zip_directory_cache); /* Avoid embedded interpreter leaks. */
|
|
||||||
zip_directory_cache = PyDict_New();
|
zip_directory_cache = PyDict_New();
|
||||||
if (zip_directory_cache == NULL)
|
if (zip_directory_cache == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1673,36 +1516,5 @@ PyInit_zipimport(void)
|
||||||
if (PyModule_AddObject(mod, "_zip_directory_cache",
|
if (PyModule_AddObject(mod, "_zip_directory_cache",
|
||||||
zip_directory_cache) < 0)
|
zip_directory_cache) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Py_XDECREF(zip_stat_cache); /* Avoid embedded interpreter leaks. */
|
|
||||||
zip_stat_cache = PyDict_New();
|
|
||||||
if (zip_stat_cache == NULL)
|
|
||||||
return NULL;
|
|
||||||
Py_INCREF(zip_stat_cache);
|
|
||||||
if (PyModule_AddObject(mod, "_zip_stat_cache", zip_stat_cache) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
{
|
|
||||||
/* We cannot import "os" here as that is a .py/.pyc file that could
|
|
||||||
* live within a zipped up standard library. Import the posix or nt
|
|
||||||
* builtin that provides the fstat() function we want instead. */
|
|
||||||
PyObject *os_like_module;
|
|
||||||
Py_CLEAR(fstat_function); /* Avoid embedded interpreter leaks. */
|
|
||||||
os_like_module = PyImport_ImportModule("posix");
|
|
||||||
if (os_like_module == NULL) {
|
|
||||||
PyErr_Clear();
|
|
||||||
os_like_module = PyImport_ImportModule("nt");
|
|
||||||
}
|
|
||||||
if (os_like_module != NULL) {
|
|
||||||
fstat_function = PyObject_GetAttrString(os_like_module, "fstat");
|
|
||||||
Py_DECREF(os_like_module);
|
|
||||||
}
|
|
||||||
if (fstat_function == NULL) {
|
|
||||||
PyErr_Clear(); /* non-fatal, we'll go on without it. */
|
|
||||||
if (Py_VerboseFlag)
|
|
||||||
PySys_WriteStderr("# zipimport unable to use os.fstat().\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue