Issue #3080: zipimport has a full unicode suppport

- Use Unicode for module paths and names, self->archive and self->prefix
 - Format module names and paths use %R instead of '%U' to escape surrogate
   characters (PEP 383)
 - Use PyImport_ExecCodeModuleObject() instead of PyImport_ExecCodeModuleEx()
 - Use PyImport_AddModuleObject() instead of PyImport_AddModule()
This commit is contained in:
Victor Stinner 2011-03-14 20:46:50 -04:00
parent 942003ccf9
commit f6b563af2d

View file

@ -49,7 +49,7 @@ static PyObject *zip_directory_cache = NULL;
/* forward decls */ /* forward decls */
static PyObject *read_directory(PyObject *archive); static PyObject *read_directory(PyObject *archive);
static PyObject *get_data(PyObject *archive, PyObject *toc_entry); static PyObject *get_data(PyObject *archive, PyObject *toc_entry);
static PyObject *get_module_code(ZipImporter *self, char *fullname, static PyObject *get_module_code(ZipImporter *self, PyObject *fullname,
int *p_ispackage, PyObject **p_modpath); int *p_ispackage, PyObject **p_modpath);
@ -202,49 +202,50 @@ zipimporter_repr(ZipImporter *self)
} }
/* return fullname.split(".")[-1] */ /* return fullname.split(".")[-1] */
static char * static PyObject *
get_subname(char *fullname) get_subname(PyObject *fullname)
{ {
char *subname = strrchr(fullname, '.'); Py_ssize_t len;
if (subname == NULL) Py_UNICODE *subname;
subname = fullname; subname = Py_UNICODE_strrchr(PyUnicode_AS_UNICODE(fullname), '.');
else if (subname == NULL) {
Py_INCREF(fullname);
return fullname;
} else {
subname++; subname++;
return subname; len = PyUnicode_GET_SIZE(fullname);
len -= subname - PyUnicode_AS_UNICODE(fullname);
return PyUnicode_FromUnicode(subname, len);
}
} }
/* Given a (sub)modulename, write the potential file path in the /* Given a (sub)modulename, write the potential file path in the
archive (without extension) to the path buffer. Return the archive (without extension) to the path buffer. Return the
length of the resulting string. */ length of the resulting string.
static int
make_filename(PyObject *prefix_obj, char *name, char *path, size_t pathsize) return self.prefix + name.replace('.', os.sep) */
static PyObject*
make_filename(PyObject *prefix, PyObject *name)
{ {
size_t len; PyObject *pathobj;
char *p; Py_UNICODE *p;
PyObject *prefix;
prefix = PyUnicode_EncodeFSDefault(prefix_obj); pathobj = PyUnicode_FromUnicode(NULL,
if (prefix == NULL) PyUnicode_GET_SIZE(prefix)
return -1; + PyUnicode_GET_SIZE(name));
len = PyBytes_GET_SIZE(prefix); if (pathobj == NULL)
return NULL;
/* self.prefix + name [+ SEP + "__init__"] + ".py[co]" */ p = PyUnicode_AS_UNICODE(pathobj);
if (len + strlen(name) + 13 >= pathsize - 1) {
PyErr_SetString(ZipImportError, "path too long");
Py_DECREF(prefix);
return -1;
}
strcpy(path, PyBytes_AS_STRING(prefix)); Py_UNICODE_strcpy(p, PyUnicode_AS_UNICODE(prefix));
Py_DECREF(prefix); p += PyUnicode_GET_SIZE(prefix);
strcpy(path + len, name); Py_UNICODE_strcpy(p, PyUnicode_AS_UNICODE(name));
for (p = path + len; *p; p++) { for (; *p; p++) {
if (*p == '.') if (*p == '.')
*p = SEP; *p = SEP;
} }
len += strlen(name); return pathobj;
assert(len < INT_MAX);
return (int)len;
} }
enum zi_module_info { enum zi_module_info {
@ -256,27 +257,38 @@ enum zi_module_info {
/* Return some information about a module. */ /* Return some information about a module. */
static enum zi_module_info static enum zi_module_info
get_module_info(ZipImporter *self, char *fullname) get_module_info(ZipImporter *self, PyObject *fullname)
{ {
char *subname, path[MAXPATHLEN + 1]; PyObject *subname;
int len; PyObject *path, *fullpath, *item;
struct st_zip_searchorder *zso; struct st_zip_searchorder *zso;
subname = get_subname(fullname); subname = get_subname(fullname);
if (subname == NULL)
return MI_ERROR;
len = make_filename(self->prefix, subname, path, sizeof(path)); path = make_filename(self->prefix, subname);
if (len < 0) Py_DECREF(subname);
if (path == NULL)
return MI_ERROR; return MI_ERROR;
for (zso = zip_searchorder; *zso->suffix; zso++) { for (zso = zip_searchorder; *zso->suffix; zso++) {
strcpy(path + len, zso->suffix); fullpath = PyUnicode_FromFormat("%U%s", path, zso->suffix);
if (PyDict_GetItemString(self->files, path) != NULL) { if (fullpath == NULL) {
Py_DECREF(path);
return MI_ERROR;
}
item = PyDict_GetItem(self->files, fullpath);
Py_DECREF(fullpath);
if (item != NULL) {
Py_DECREF(path);
if (zso->type & IS_PACKAGE) if (zso->type & IS_PACKAGE)
return MI_PACKAGE; return MI_PACKAGE;
else else
return MI_MODULE; return MI_MODULE;
} }
} }
Py_DECREF(path);
return MI_NOT_FOUND; return MI_NOT_FOUND;
} }
@ -287,10 +299,10 @@ zipimporter_find_module(PyObject *obj, PyObject *args)
{ {
ZipImporter *self = (ZipImporter *)obj; ZipImporter *self = (ZipImporter *)obj;
PyObject *path = NULL; PyObject *path = NULL;
char *fullname; PyObject *fullname;
enum zi_module_info mi; enum zi_module_info mi;
if (!PyArg_ParseTuple(args, "s|O:zipimporter.find_module", if (!PyArg_ParseTuple(args, "U|O:zipimporter.find_module",
&fullname, &path)) &fullname, &path))
return NULL; return NULL;
@ -311,11 +323,11 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
{ {
ZipImporter *self = (ZipImporter *)obj; ZipImporter *self = (ZipImporter *)obj;
PyObject *code = NULL, *mod, *dict; PyObject *code = NULL, *mod, *dict;
char *fullname; PyObject *fullname;
PyObject *modpath = NULL, *modpath_bytes; PyObject *modpath = NULL;
int ispackage; int ispackage;
if (!PyArg_ParseTuple(args, "s:zipimporter.load_module", if (!PyArg_ParseTuple(args, "U:zipimporter.load_module",
&fullname)) &fullname))
return NULL; return NULL;
@ -323,7 +335,7 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
if (code == NULL) if (code == NULL)
goto error; goto error;
mod = PyImport_AddModule(fullname); mod = PyImport_AddModuleObject(fullname);
if (mod == NULL) if (mod == NULL)
goto error; goto error;
dict = PyModule_GetDict(mod); dict = PyModule_GetDict(mod);
@ -336,17 +348,17 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
/* add __path__ to the module *before* the code gets /* add __path__ to the module *before* the code gets
executed */ executed */
PyObject *pkgpath, *fullpath; PyObject *pkgpath, *fullpath;
char *subname = get_subname(fullname); PyObject *subname = get_subname(fullname);
int err; int err;
fullpath = PyUnicode_FromFormat("%U%c%U%s", fullpath = PyUnicode_FromFormat("%U%c%U%U",
self->archive, SEP, self->archive, SEP,
self->prefix, subname); self->prefix, subname);
Py_DECREF(subname);
if (fullpath == NULL) if (fullpath == NULL)
goto error; goto error;
pkgpath = Py_BuildValue("[O]", fullpath); pkgpath = Py_BuildValue("[N]", fullpath);
Py_DECREF(fullpath);
if (pkgpath == NULL) if (pkgpath == NULL)
goto error; goto error;
err = PyDict_SetItemString(dict, "__path__", pkgpath); err = PyDict_SetItemString(dict, "__path__", pkgpath);
@ -354,18 +366,13 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
if (err != 0) if (err != 0)
goto error; goto error;
} }
modpath_bytes = PyUnicode_EncodeFSDefault(modpath); mod = PyImport_ExecCodeModuleObject(fullname, code, modpath, NULL);
if (modpath_bytes == NULL)
goto error;
mod = PyImport_ExecCodeModuleEx(fullname, code,
PyBytes_AS_STRING(modpath_bytes));
Py_DECREF(modpath_bytes);
Py_CLEAR(code); Py_CLEAR(code);
if (mod == NULL) if (mod == NULL)
goto error; goto error;
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_FormatStderr("import %s # loaded from Zip %U\n", PySys_FormatStderr("import %U # loaded from Zip %U\n",
fullname, modpath); fullname, modpath);
Py_DECREF(modpath); Py_DECREF(modpath);
return mod; return mod;
@ -380,12 +387,10 @@ static PyObject *
zipimporter_get_filename(PyObject *obj, PyObject *args) zipimporter_get_filename(PyObject *obj, PyObject *args)
{ {
ZipImporter *self = (ZipImporter *)obj; ZipImporter *self = (ZipImporter *)obj;
PyObject *code; PyObject *fullname, *code, *modpath;
char *fullname;
PyObject *modpath;
int ispackage; int ispackage;
if (!PyArg_ParseTuple(args, "s:zipimporter.get_filename", if (!PyArg_ParseTuple(args, "U:zipimporter.get_filename",
&fullname)) &fullname))
return NULL; return NULL;
@ -404,10 +409,10 @@ static PyObject *
zipimporter_is_package(PyObject *obj, PyObject *args) zipimporter_is_package(PyObject *obj, PyObject *args)
{ {
ZipImporter *self = (ZipImporter *)obj; ZipImporter *self = (ZipImporter *)obj;
char *fullname; PyObject *fullname;
enum zi_module_info mi; enum zi_module_info mi;
if (!PyArg_ParseTuple(args, "s:zipimporter.is_package", if (!PyArg_ParseTuple(args, "U:zipimporter.is_package",
&fullname)) &fullname))
return NULL; return NULL;
@ -415,7 +420,7 @@ zipimporter_is_package(PyObject *obj, PyObject *args)
if (mi == MI_ERROR) if (mi == MI_ERROR)
return NULL; return NULL;
if (mi == MI_NOT_FOUND) { if (mi == MI_NOT_FOUND) {
PyErr_Format(ZipImportError, "can't find module '%s'", fullname); PyErr_Format(ZipImportError, "can't find module %R", fullname);
return NULL; return NULL;
} }
return PyBool_FromLong(mi == MI_PACKAGE); return PyBool_FromLong(mi == MI_PACKAGE);
@ -477,9 +482,9 @@ static PyObject *
zipimporter_get_code(PyObject *obj, PyObject *args) zipimporter_get_code(PyObject *obj, PyObject *args)
{ {
ZipImporter *self = (ZipImporter *)obj; ZipImporter *self = (ZipImporter *)obj;
char *fullname; PyObject *fullname;
if (!PyArg_ParseTuple(args, "s:zipimporter.get_code", &fullname)) if (!PyArg_ParseTuple(args, "U:zipimporter.get_code", &fullname))
return NULL; return NULL;
return get_module_code(self, fullname, NULL, NULL); return get_module_code(self, fullname, NULL, NULL);
@ -490,34 +495,39 @@ zipimporter_get_source(PyObject *obj, PyObject *args)
{ {
ZipImporter *self = (ZipImporter *)obj; ZipImporter *self = (ZipImporter *)obj;
PyObject *toc_entry; PyObject *toc_entry;
char *fullname, *subname, path[MAXPATHLEN+1]; PyObject *fullname, *subname, *path, *fullpath;
int len;
enum zi_module_info mi; enum zi_module_info mi;
if (!PyArg_ParseTuple(args, "s:zipimporter.get_source", &fullname)) if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname))
return NULL; return NULL;
mi = get_module_info(self, fullname); mi = get_module_info(self, fullname);
if (mi == MI_ERROR) if (mi == MI_ERROR)
return NULL; return NULL;
if (mi == MI_NOT_FOUND) { if (mi == MI_NOT_FOUND) {
PyErr_Format(ZipImportError, "can't find module '%s'", fullname); PyErr_Format(ZipImportError, "can't find module %R", fullname);
return NULL; return NULL;
} }
subname = get_subname(fullname); subname = get_subname(fullname);
if (subname == NULL)
len = make_filename(self->prefix, subname, path, sizeof(path));
if (len < 0)
return NULL; return NULL;
if (mi == MI_PACKAGE) { path = make_filename(self->prefix, subname);
path[len] = SEP; Py_DECREF(subname);
strcpy(path + len + 1, "__init__.py"); if (path == NULL)
} return NULL;
else
strcpy(path + len, ".py");
toc_entry = PyDict_GetItemString(self->files, path); if (mi == MI_PACKAGE)
fullpath = PyUnicode_FromFormat("%U%c__init__.py", path, SEP);
else
fullpath = PyUnicode_FromFormat("%U.py", path);
Py_DECREF(path);
if (fullpath == NULL)
return NULL;
toc_entry = PyDict_GetItem(self->files, fullpath);
Py_DECREF(fullpath);
if (toc_entry != NULL) { if (toc_entry != NULL) {
PyObject *res, *bytes; PyObject *res, *bytes;
bytes = get_data(self->archive, toc_entry); bytes = get_data(self->archive, toc_entry);
@ -708,9 +718,8 @@ get_long(unsigned char *buf) {
data_size and file_offset are 0. data_size and file_offset are 0.
*/ */
static PyObject * static PyObject *
read_directory(PyObject *archive_obj) read_directory(PyObject *archive)
{ {
/* FIXME: work on Py_UNICODE* instead of char* */
PyObject *files = NULL; PyObject *files = NULL;
FILE *fp; FILE *fp;
unsigned short flags; unsigned short flags;
@ -727,29 +736,29 @@ read_directory(PyObject *archive_obj)
const char *charset; const char *charset;
int bootstrap; int bootstrap;
if (PyUnicode_GET_SIZE(archive_obj) > MAXPATHLEN) { if (PyUnicode_GET_SIZE(archive) > MAXPATHLEN) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"Zip path name is too long"); "Zip path name is too long");
return NULL; return NULL;
} }
Py_UNICODE_strcpy(path, PyUnicode_AS_UNICODE(archive_obj)); Py_UNICODE_strcpy(path, PyUnicode_AS_UNICODE(archive));
fp = _Py_fopen(archive_obj, "rb"); fp = _Py_fopen(archive, "rb");
if (fp == NULL) { if (fp == NULL) {
PyErr_Format(ZipImportError, "can't open Zip file: '%U'", archive_obj); PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);
return NULL; return NULL;
} }
fseek(fp, -22, SEEK_END); fseek(fp, -22, SEEK_END);
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); fclose(fp);
PyErr_Format(ZipImportError, "can't read Zip file: '%U'", archive_obj); 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); fclose(fp);
PyErr_Format(ZipImportError, "not a Zip file: '%U'", archive_obj); PyErr_Format(ZipImportError, "not a Zip file: %R", archive);
return NULL; return NULL;
} }
@ -826,7 +835,9 @@ read_directory(PyObject *archive_obj)
PY_MAJOR_VERSION, PY_MINOR_VERSION); PY_MAJOR_VERSION, PY_MINOR_VERSION);
goto error; goto error;
} }
Py_UNICODE_strncpy(path + length + 1, PyUnicode_AS_UNICODE(nameobj), MAXPATHLEN - length - 1); Py_UNICODE_strncpy(path + length + 1,
PyUnicode_AS_UNICODE(nameobj),
MAXPATHLEN - length - 1);
pathobj = PyUnicode_FromUnicode(path, Py_UNICODE_strlen(path)); pathobj = PyUnicode_FromUnicode(path, Py_UNICODE_strlen(path));
if (pathobj == NULL) if (pathobj == NULL)
@ -844,8 +855,8 @@ read_directory(PyObject *archive_obj)
} }
fclose(fp); fclose(fp);
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_FormatStderr("# zipimport: found %ld names in %U\n", PySys_FormatStderr("# zipimport: found %ld names in %R\n",
count, archive_obj); count, archive);
return files; return files;
error: error:
fclose(fp); fclose(fp);
@ -999,7 +1010,7 @@ eq_mtime(time_t t1, time_t t2)
to .py if available and we don't want to mask other errors). to .py if available and we don't want to mask other errors).
Returns a new reference. */ Returns a new reference. */
static PyObject * static PyObject *
unmarshal_code(char *pathname, PyObject *data, time_t mtime) unmarshal_code(PyObject *pathname, PyObject *data, time_t mtime)
{ {
PyObject *code; PyObject *code;
char *buf = PyBytes_AsString(data); char *buf = PyBytes_AsString(data);
@ -1013,8 +1024,8 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
if (get_long((unsigned char *)buf) != PyImport_GetMagicNumber()) { if (get_long((unsigned char *)buf) != PyImport_GetMagicNumber()) {
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_WriteStderr("# %s has bad magic\n", PySys_FormatStderr("# %R has bad magic\n",
pathname); pathname);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; /* signal caller to try alternative */ return Py_None; /* signal caller to try alternative */
} }
@ -1022,8 +1033,8 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
if (mtime != 0 && !eq_mtime(get_long((unsigned char *)buf + 4), if (mtime != 0 && !eq_mtime(get_long((unsigned char *)buf + 4),
mtime)) { mtime)) {
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_WriteStderr("# %s has bad mtime\n", PySys_FormatStderr("# %R has bad mtime\n",
pathname); pathname);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; /* signal caller to try alternative */ return Py_None; /* signal caller to try alternative */
} }
@ -1034,7 +1045,7 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
if (!PyCode_Check(code)) { if (!PyCode_Check(code)) {
Py_DECREF(code); Py_DECREF(code);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"compiled module %s is not a code object", "compiled module %R is not a code object",
pathname); pathname);
return NULL; return NULL;
} }
@ -1048,11 +1059,12 @@ unmarshal_code(char *pathname, PyObject *data, time_t mtime)
static PyObject * static PyObject *
normalize_line_endings(PyObject *source) normalize_line_endings(PyObject *source)
{ {
char *buf, *q, *p = PyBytes_AsString(source); char *buf, *q, *p;
PyObject *fixed_source; PyObject *fixed_source;
int len = 0; int len = 0;
if (!p) { p = PyBytes_AsString(source);
if (p == NULL) {
return PyBytes_FromStringAndSize("\n\0", 2); return PyBytes_FromStringAndSize("\n\0", 2);
} }
@ -1085,16 +1097,24 @@ normalize_line_endings(PyObject *source)
/* Given a string buffer containing Python source code, compile it /* Given a string buffer containing Python source code, compile it
return and return a code object as a new reference. */ return and return a code object as a new reference. */
static PyObject * static PyObject *
compile_source(char *pathname, PyObject *source) compile_source(PyObject *pathname, PyObject *source)
{ {
PyObject *code, *fixed_source; PyObject *code, *fixed_source, *pathbytes;
fixed_source = normalize_line_endings(source); pathbytes = PyUnicode_EncodeFSDefault(pathname);
if (fixed_source == NULL) if (pathbytes == NULL)
return NULL; return NULL;
code = Py_CompileString(PyBytes_AsString(fixed_source), pathname, fixed_source = normalize_line_endings(source);
if (fixed_source == NULL) {
Py_DECREF(pathbytes);
return NULL;
}
code = Py_CompileString(PyBytes_AsString(fixed_source),
PyBytes_AsString(pathbytes),
Py_file_input); Py_file_input);
Py_DECREF(pathbytes);
Py_DECREF(fixed_source); Py_DECREF(fixed_source);
return code; return code;
} }
@ -1123,14 +1143,19 @@ parse_dostime(int dostime, int dosdate)
modification time of the matching .py file, or 0 if no source modification time of the matching .py file, or 0 if no source
is available. */ is available. */
static time_t static time_t
get_mtime_of_source(ZipImporter *self, char *path) get_mtime_of_source(ZipImporter *self, PyObject *path)
{ {
PyObject *toc_entry; PyObject *toc_entry, *stripped;
time_t mtime = 0; time_t mtime;
Py_ssize_t lastchar = strlen(path) - 1;
char savechar = path[lastchar]; /* strip 'c' or 'o' from *.py[co] */
path[lastchar] = '\0'; /* strip 'c' or 'o' from *.py[co] */ stripped = PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(path),
toc_entry = PyDict_GetItemString(self->files, path); PyUnicode_GET_SIZE(path) - 1);
if (stripped == NULL)
return (time_t)-1;
toc_entry = PyDict_GetItem(self->files, stripped);
Py_DECREF(stripped);
if (toc_entry != NULL && PyTuple_Check(toc_entry) && if (toc_entry != NULL && PyTuple_Check(toc_entry) &&
PyTuple_Size(toc_entry) == 8) { PyTuple_Size(toc_entry) == 8) {
/* fetch the time stamp of the .py file for comparison /* fetch the time stamp of the .py file for comparison
@ -1139,8 +1164,8 @@ get_mtime_of_source(ZipImporter *self, char *path)
time = PyLong_AsLong(PyTuple_GetItem(toc_entry, 5)); time = PyLong_AsLong(PyTuple_GetItem(toc_entry, 5));
date = PyLong_AsLong(PyTuple_GetItem(toc_entry, 6)); date = PyLong_AsLong(PyTuple_GetItem(toc_entry, 6));
mtime = parse_dostime(time, date); mtime = parse_dostime(time, date);
} } else
path[lastchar] = savechar; mtime = 0;
return mtime; return mtime;
} }
@ -1150,24 +1175,17 @@ static PyObject *
get_code_from_data(ZipImporter *self, 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, *code; PyObject *data, *modpath, *code;
PyObject *modpath;
data = get_data(self->archive, toc_entry); data = get_data(self->archive, toc_entry);
if (data == NULL) if (data == NULL)
return NULL; return NULL;
modpath = PyUnicode_EncodeFSDefault(PyTuple_GetItem(toc_entry, 0)); modpath = PyTuple_GetItem(toc_entry, 0);
if (modpath == NULL) {
Py_DECREF(data);
return NULL;
}
if (isbytecode) if (isbytecode)
code = unmarshal_code(PyBytes_AS_STRING(modpath), data, mtime); code = unmarshal_code(modpath, data, mtime);
else else
code = compile_source(PyBytes_AS_STRING(modpath), data); code = compile_source(modpath, data);
Py_DECREF(modpath);
Py_DECREF(data); Py_DECREF(data);
return code; return code;
} }
@ -1175,35 +1193,45 @@ get_code_from_data(ZipImporter *self, int ispackage, int isbytecode,
/* Get the code object associated with the module specified by /* Get the code object associated with the module specified by
'fullname'. */ 'fullname'. */
static PyObject * static PyObject *
get_module_code(ZipImporter *self, char *fullname, get_module_code(ZipImporter *self, PyObject *fullname,
int *p_ispackage, PyObject **p_modpath) int *p_ispackage, PyObject **p_modpath)
{ {
PyObject *toc_entry; PyObject *code, *toc_entry, *subname;
char *subname, path[MAXPATHLEN + 1]; PyObject *path, *fullpath;
int len;
struct st_zip_searchorder *zso; struct st_zip_searchorder *zso;
subname = get_subname(fullname); subname = get_subname(fullname);
if (subname == NULL)
return NULL;
len = make_filename(self->prefix, subname, path, sizeof(path)); path = make_filename(self->prefix, subname);
if (len < 0) Py_DECREF(subname);
if (path == NULL)
return NULL; return NULL;
for (zso = zip_searchorder; *zso->suffix; zso++) { for (zso = zip_searchorder; *zso->suffix; zso++) {
PyObject *code = NULL; code = NULL;
fullpath = PyUnicode_FromFormat("%U%s", path, zso->suffix);
if (fullpath == NULL)
goto exit;
strcpy(path + len, zso->suffix);
if (Py_VerboseFlag > 1) if (Py_VerboseFlag > 1)
PySys_FormatStderr("# trying %U%c%s\n", PySys_FormatStderr("# trying %U%c%U\n",
self->archive, (int)SEP, path); self->archive, (int)SEP, fullpath);
toc_entry = PyDict_GetItemString(self->files, path); toc_entry = PyDict_GetItem(self->files, fullpath);
if (toc_entry != NULL) { if (toc_entry != NULL) {
time_t mtime = 0; time_t mtime = 0;
int ispackage = zso->type & IS_PACKAGE; int ispackage = zso->type & IS_PACKAGE;
int isbytecode = zso->type & IS_BYTECODE; int isbytecode = zso->type & IS_BYTECODE;
if (isbytecode) if (isbytecode) {
mtime = get_mtime_of_source(self, path); mtime = get_mtime_of_source(self, fullpath);
if (mtime == (time_t)-1 && PyErr_Occurred()) {
goto exit;
}
}
Py_CLEAR(fullpath);
if (p_ispackage != NULL) if (p_ispackage != NULL)
*p_ispackage = ispackage; *p_ispackage = ispackage;
code = get_code_from_data(self, ispackage, code = get_code_from_data(self, ispackage,
@ -1219,11 +1247,16 @@ get_module_code(ZipImporter *self, char *fullname,
*p_modpath = PyTuple_GetItem(toc_entry, 0); *p_modpath = PyTuple_GetItem(toc_entry, 0);
Py_INCREF(*p_modpath); Py_INCREF(*p_modpath);
} }
return code; goto exit;
} }
else
Py_CLEAR(fullpath);
} }
PyErr_Format(ZipImportError, "can't find module '%s'", fullname); PyErr_Format(ZipImportError, "can't find module %R", fullname);
return NULL; exit:
Py_DECREF(path);
Py_XDECREF(fullpath);
return code;
} }