summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@haypocalc.com>2010-08-16 17:54:28 (GMT)
committerVictor Stinner <victor.stinner@haypocalc.com>2010-08-16 17:54:28 (GMT)
commit2460a43a6569fbf240c5a72d0b052565617213eb (patch)
tree13d6ea2138689a623218ec25a80e26d402e7bcd0
parent79766636b6fbc7e01af160008df9cd31112716d6 (diff)
downloadcpython-2460a43a6569fbf240c5a72d0b052565617213eb.zip
cpython-2460a43a6569fbf240c5a72d0b052565617213eb.tar.gz
cpython-2460a43a6569fbf240c5a72d0b052565617213eb.tar.bz2
Issue #9425: read_directory() is fully unicode compliant
zipimport is now able to load a module with an unencodable filename.
-rw-r--r--Lib/test/test_zipimport.py14
-rw-r--r--Modules/zipimport.c49
2 files changed, 42 insertions, 21 deletions
diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py
index ba4e34a..61a6c0a 100644
--- a/Lib/test/test_zipimport.py
+++ b/Lib/test/test_zipimport.py
@@ -382,6 +382,20 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
files = {TESTMOD + ".py": (NOW, raise_src)}
self.doTest(None, files, TESTMOD, call=self.doTraceback)
+ @unittest.skipIf(support.TESTFN_UNENCODABLE is None,
+ "need an unencodable filename")
+ def testUndecodable(self):
+ filename = support.TESTFN_UNENCODABLE + ".zip"
+ z = ZipFile(filename, "w")
+ zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW))
+ zinfo.compress_type = self.compression
+ z.writestr(zinfo, test_src)
+ z.close()
+ try:
+ zipimport.zipimporter(filename)
+ finally:
+ os.remove(filename)
+
@unittest.skipUnless(zlib, "requires zlib")
class CompressedZipImportTestCase(UncompressedZipImportTestCase):
diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 519d575..49d99da 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -44,7 +44,7 @@ static PyObject *ZipImportError;
static PyObject *zip_directory_cache = NULL;
/* forward decls */
-static PyObject *read_directory(char *archive);
+static PyObject *read_directory(PyObject *archive);
static PyObject *get_data(char *archive, PyObject *toc_entry);
static PyObject *get_module_code(ZipImporter *self, char *fullname,
int *p_ispackage, char **p_modpath);
@@ -60,7 +60,7 @@ static PyObject *get_module_code(ZipImporter *self, char *fullname,
static int
zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds)
{
- PyObject *pathobj, *path_bytes, *files;
+ PyObject *pathobj, *files;
Py_UNICODE *path, *p, *prefix, buf[MAXPATHLEN+2];
Py_ssize_t len;
@@ -130,11 +130,7 @@ zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds)
files = PyDict_GetItem(zip_directory_cache, pathobj);
if (files == NULL) {
- path_bytes = PyUnicode_EncodeFSDefault(pathobj);
- if (path_bytes == NULL)
- goto error;
- files = read_directory(PyBytes_AS_STRING(path_bytes));
- Py_DECREF(path_bytes);
+ files = read_directory(pathobj);
if (files == NULL)
goto error;
if (PyDict_SetItem(zip_directory_cache, pathobj, files) != 0)
@@ -686,30 +682,33 @@ get_long(unsigned char *buf) {
data_size and file_offset are 0.
*/
static PyObject *
-read_directory(char *archive)
+read_directory(PyObject *archive_obj)
{
+ /* FIXME: work on Py_UNICODE* instead of char* */
PyObject *files = NULL;
FILE *fp;
long compress, crc, data_size, file_size, file_offset, date, time;
long header_offset, name_size, header_size, header_position;
long i, l, count;
size_t length;
- char path[MAXPATHLEN + 5];
+ Py_UNICODE path[MAXPATHLEN + 5];
char name[MAXPATHLEN + 5];
+ PyObject *nameobj = NULL;
char *p, endof_central_dir[22];
long arc_offset; /* offset from beginning of file to start of zip-archive */
+ PyObject *pathobj;
- if (strlen(archive) > MAXPATHLEN) {
+ if (PyUnicode_GET_SIZE(archive_obj) > MAXPATHLEN) {
PyErr_SetString(PyExc_OverflowError,
"Zip path name is too long");
return NULL;
}
- strcpy(path, archive);
+ Py_UNICODE_strcpy(path, PyUnicode_AS_UNICODE(archive_obj));
- fp = fopen(archive, "rb");
+ fp = _Py_fopen(archive_obj, "rb");
if (fp == NULL) {
PyErr_Format(ZipImportError, "can't open Zip file: "
- "'%.200s'", archive);
+ "'%.200U'", archive_obj);
return NULL;
}
fseek(fp, -22, SEEK_END);
@@ -717,14 +716,14 @@ read_directory(char *archive)
if (fread(endof_central_dir, 1, 22, fp) != 22) {
fclose(fp);
PyErr_Format(ZipImportError, "can't read Zip file: "
- "'%.200s'", archive);
+ "'%.200U'", archive_obj);
return NULL;
}
if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) {
/* Bad: End of Central Dir signature */
fclose(fp);
PyErr_Format(ZipImportError, "not a Zip file: "
- "'%.200s'", archive);
+ "'%.200U'", archive_obj);
return NULL;
}
@@ -737,7 +736,7 @@ read_directory(char *archive)
if (files == NULL)
goto error;
- length = (long)strlen(path);
+ length = Py_UNICODE_strlen(path);
path[length] = SEP;
/* Start of Central Directory */
@@ -776,13 +775,20 @@ read_directory(char *archive)
*p = 0; /* Add terminating null byte */
header_offset += header_size;
- strncpy(path + length + 1, name, MAXPATHLEN - length - 1);
+ nameobj = PyUnicode_DecodeFSDefaultAndSize(name, name_size);
+ if (nameobj == NULL)
+ goto error;
+ Py_UNICODE_strncpy(path + length + 1, PyUnicode_AS_UNICODE(nameobj), MAXPATHLEN - length - 1);
- t = Py_BuildValue("siiiiiii", path, compress, data_size,
+ pathobj = PyUnicode_FromUnicode(path, Py_UNICODE_strlen(path));
+ if (pathobj == NULL)
+ goto error;
+ t = Py_BuildValue("Niiiiiii", pathobj, compress, data_size,
file_size, file_offset, time, date, crc);
if (t == NULL)
goto error;
- err = PyDict_SetItemString(files, name, t);
+ err = PyDict_SetItem(files, nameobj, t);
+ Py_CLEAR(nameobj);
Py_DECREF(t);
if (err != 0)
goto error;
@@ -790,12 +796,13 @@ read_directory(char *archive)
}
fclose(fp);
if (Py_VerboseFlag)
- PySys_WriteStderr("# zipimport: found %ld names in %s\n",
- count, archive);
+ PySys_FormatStderr("# zipimport: found %ld names in %U\n",
+ count, archive_obj);
return files;
error:
fclose(fp);
Py_XDECREF(files);
+ Py_XDECREF(nameobj);
return NULL;
}