[Python-checkins] cpython: Issue #3080: case_ok() expects Unicode strings

victor.stinner python-checkins at python.org
Sun Mar 20 04:14:00 CET 2011


http://hg.python.org/cpython/rev/066b399a8477
changeset: 68734:066b399a8477
user: Victor Stinner <victor.stinner at haypocalc.com>
date: Mon Mar 14 14:34:13 2011 -0400
summary:
 Issue #3080: case_ok() expects Unicode strings
files:
 Python/import.c
diff --git a/Python/import.c b/Python/import.c
--- a/Python/import.c
+++ b/Python/import.c
@@ -1669,7 +1669,7 @@
 #endif
 
 /* Forward */
-static int case_ok(char *, Py_ssize_t, Py_ssize_t, const char *);
+static int case_ok(PyObject *, Py_ssize_t, PyObject *);
 static int find_init_module(PyObject *);
 static struct filedescr importhookdescr = {"", "", IMP_HOOK};
 
@@ -1767,12 +1767,20 @@
 if (stat(buf, &statbuf) == 0 && /* it exists */
 S_ISDIR(statbuf.st_mode)) /* it's a directory */
 {
- PyObject *bufobj = PyUnicode_DecodeFSDefault(buf);
- if (bufobj == NULL)
+ int match;
+ PyObject *filename;
+
+ filename = PyUnicode_DecodeFSDefault(buf);
+ if (filename == NULL)
 return -1;
- if (case_ok(buf, len, namelen, namestr)) { /* case matches */
- if (find_init_module(bufobj)) { /* and has __init__.py */
- Py_DECREF(bufobj);
+ match = case_ok(filename, 0, name);
+ if (match < 0) {
+ Py_DECREF(filename);
+ return -1;
+ }
+ if (match) { /* case matches */
+ if (find_init_module(filename)) { /* and has __init__.py */
+ Py_DECREF(filename);
 *p_fd = &fd_package;
 return 2;
 }
@@ -1780,14 +1788,14 @@
 int err;
 err = PyErr_WarnFormat(PyExc_ImportWarning, 1,
 "Not importing directory %R: missing __init__.py",
- bufobj);
+ filename);
 if (err) {
- Py_DECREF(bufobj);
+ Py_DECREF(filename);
 return -1;
 }
 }
 }
- Py_DECREF(bufobj);
+ Py_DECREF(filename);
 }
 #endif
 return 1;
@@ -1815,6 +1823,8 @@
 char *filemode;
 FILE *fp = NULL;
 char *namestr;
+ PyObject *filename;
+ int match;
 
 npath = PyList_Size(search_path_list);
 namestr = _PyUnicode_AsString(name);
@@ -1840,20 +1850,34 @@
 
 len = strlen(buf);
 for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
- strcpy(buf+len, fdp->suffix);
- if (Py_VerboseFlag > 1)
- PySys_WriteStderr("# trying %s\n", buf);
 filemode = fdp->mode;
 if (filemode[0] == 'U')
 filemode = "r" PY_STDIOTEXTMODE;
- fp = fopen(buf, filemode);
- if (fp == NULL)
+
+ strcpy(buf+len, fdp->suffix);
+ filename = PyUnicode_DecodeFSDefault(buf);
+ if (filename == NULL)
+ return NULL;
+
+ if (Py_VerboseFlag > 1)
+ PySys_FormatStderr("# trying %R\n", filename);
+
+ fp = _Py_fopen(filename, filemode);
+ if (fp == NULL) {
+ Py_DECREF(filename);
 continue;
-
- if (case_ok(buf, len, namelen, namestr)) {
+ }
+ match = case_ok(filename, -(Py_ssize_t)strlen(fdp->suffix), name);
+ if (match < 0) {
+ Py_DECREF(filename);
+ return NULL;
+ }
+ if (match) {
+ Py_DECREF(filename);
 *p_fp = fp;
 return fdp;
 }
+ Py_DECREF(filename);
 
 fclose(fp);
 fp = NULL;
@@ -2002,7 +2026,7 @@
 p_fp, p_loader);
 }
 
-/* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name)
+/* case_bytes(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name)
 * The arguments here are tricky, best shown by example:
 * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py0円
 * ^ ^ ^ ^
@@ -2016,18 +2040,18 @@
 * We've already done a successful stat() or fopen() on buf, so know that
 * there's some match, possibly case-insensitive.
 *
- * case_ok() is to return 1 if there's a case-sensitive match for
- * name, else 0. case_ok() is also to return 1 if envar PYTHONCASEOK
+ * case_bytes() is to return 1 if there's a case-sensitive match for
+ * name, else 0. case_bytes() is also to return 1 if envar PYTHONCASEOK
 * exists.
 *
- * case_ok() is used to implement case-sensitive import semantics even
+ * case_bytes() is used to implement case-sensitive import semantics even
 * on platforms with case-insensitive filesystems. It's trivial to implement
 * for case-sensitive filesystems. It's pretty much a cross-platform
 * nightmare for systems with case-insensitive filesystems.
 */
 
 /* First we may need a pile of platform-specific header files; the sequence
- * of #if's here should match the sequence in the body of case_ok().
+ * of #if's here should match the sequence in the body of case_bytes().
 */
 #if defined(MS_WINDOWS)
 #include <windows.h>
@@ -2046,33 +2070,24 @@
 #include <os2.h>
 #endif
 
+#if defined(DJGPP) \
+ || ((defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) \
+ && defined(HAVE_DIRENT_H)) \
+ || defined(PYOS_OS2)
+# define USE_CASE_OK_BYTES
+#endif
+
+
+#ifdef USE_CASE_OK_BYTES
 static int
-case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, const char *name)
+case_bytes(char *buf, Py_ssize_t len, Py_ssize_t namelen, const char *name)
 {
 /* Pick a platform-specific implementation; the sequence of #if's here should
 * match the sequence just above.
 */
 
-/* MS_WINDOWS */
-#if defined(MS_WINDOWS)
- WIN32_FIND_DATA data;
- HANDLE h;
-
- if (Py_GETENV("PYTHONCASEOK") != NULL)
- return 1;
-
- h = FindFirstFile(buf, &data);
- if (h == INVALID_HANDLE_VALUE) {
- PyErr_Format(PyExc_NameError,
- "Can't find file for module %.100s\n(filename %.300s)",
- name, buf);
- return 0;
- }
- FindClose(h);
- return strncmp(data.cFileName, name, namelen) == 0;
-
 /* DJGPP */
-#elif defined(DJGPP)
+#if defined(DJGPP)
 struct ffblk ffblk;
 int done;
 
@@ -2151,6 +2166,70 @@
 
 /* assuming it's a case-sensitive filesystem, so there's nothing to do! */
 #else
+# error "USE_CASE_OK_BYTES is not correctly defined"
+#endif
+}
+#endif
+
+/*
+ * Check if a filename case matchs the name case. We've already done a
+ * successful stat() or fopen() on buf, so know that there's some match,
+ * possibly case-insensitive.
+ *
+ * case_ok() is to return 1 if there's a case-sensitive match for name, 0 if it
+ * the filename doesn't match, or -1 on error. case_ok() is also to return 1
+ * if envar PYTHONCASEOK exists.
+ *
+ * case_ok() is used to implement case-sensitive import semantics even
+ * on platforms with case-insensitive filesystems. It's trivial to implement
+ * for case-sensitive filesystems. It's pretty much a cross-platform
+ * nightmare for systems with case-insensitive filesystems.
+ */
+
+static int
+case_ok(PyObject *filename, Py_ssize_t prefix_delta, PyObject *name)
+{
+#ifdef MS_WINDOWS
+ WIN32_FIND_DATAW data;
+ HANDLE h;
+ int cmp;
+
+ if (Py_GETENV("PYTHONCASEOK") != NULL)
+ return 1;
+
+ h = FindFirstFileW(PyUnicode_AS_UNICODE(filename), &data);
+ if (h == INVALID_HANDLE_VALUE) {
+ PyErr_Format(PyExc_NameError,
+ "Can't find file for module %R\n(filename %R)",
+ name, filename);
+ return 0;
+ }
+ FindClose(h);
+ cmp = wcsncmp(data.cFileName,
+ PyUnicode_AS_UNICODE(name),
+ PyUnicode_GET_SIZE(name));
+ return cmp == 0;
+#elif defined(USE_CASE_OK_BYTES)
+ int match;
+ PyObject *filebytes, *namebytes;
+ filebytes = PyUnicode_EncodeFSDefault(filename);
+ if (filebytes == NULL)
+ return -1;
+ namebytes = PyUnicode_EncodeFSDefault(name);
+ if (namebytes == NULL) {
+ Py_DECREF(filebytes);
+ return -1;
+ }
+ match = case_bytes(
+ PyBytes_AS_STRING(filebytes),
+ PyBytes_GET_SIZE(filebytes) + prefix_delta,
+ PyBytes_AS_STRING(namebytes),
+ PyBytes_GET_SIZE(namebytes));
+ Py_DECREF(filebytes);
+ Py_DECREF(namebytes);
+ return match;
+#else
+ /* assuming it's a case-sensitive filesystem, so there's nothing to do! */
 return 1;
 
 #endif
@@ -2167,8 +2246,6 @@
 struct stat statbuf;
 PyObject *filename;
 int match;
- char *filestr;
- size_t filelen;
 
 len = PyUnicode_GET_SIZE(directory);
 filename = PyUnicode_FromFormat("%U%c__init__.py", directory, SEP);
@@ -2176,9 +2253,12 @@
 return -1;
 if (_Py_stat(filename, &statbuf) == 0) {
 /* 9=len("/__init__") */
- filestr = _PyUnicode_AsString(filename);
- filelen = strlen(filestr);
- if (case_ok(filestr, filelen-9, 8, "__init__")) {
+ match = case_ok(filename, 9, initstr);
+ if (match < 0) {
+ Py_DECREF(filename);
+ return -1;
+ }
+ if (match) {
 Py_DECREF(filename);
 return 1;
 }
@@ -2191,9 +2271,12 @@
 return -1;
 if (_Py_stat(filename, &statbuf) == 0) {
 /* 9=len("/__init__") */
- filestr = _PyUnicode_AsString(filename);
- filelen = strlen(filestr);
- if (case_ok(filestr, filelen-9, 8, "__init__")) {
+ match = case_ok(filename, 9, initstr);
+ if (match < 0) {
+ Py_DECREF(filename);
+ return -1;
+ }
+ if (match) {
 Py_DECREF(filename);
 return 1;
 }
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /