]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Merge 3.2: Issue #7732: Don't open a directory as a file anymore while
authorVictor Stinner <victor.stinner@haypocalc.com>
Fri, 23 Sep 2011 16:59:08 +0000 (18:59 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Fri, 23 Sep 2011 16:59:08 +0000 (18:59 +0200)
importing a module. Ignore the direcotry if its name matchs the module name
(e.g.  "__init__.py") and raise a ImportError instead.

1  2 
Lib/test/test_import.py
Misc/NEWS
Python/import.c

Simple merge
diff --cc Misc/NEWS
index 571db4b2f1b2c610a055761de4ecd9f3082e4969,fd98d021e501d0eea7d930b00c12f73783f1b016..0e18621d2399fe5385c97f85ff8049461889b351
+++ b/Misc/NEWS
@@@ -283,25 -108,6 +287,25 @@@ Core and Builtin
  Library
  -------
  
-  
 +- Issue #9871: Prevent IDLE 3 crash when given byte stings
 +  with invalid hex escape sequences, like b'\x0'.
 +  (Original patch by Claudiu Popa.)
 +
 +- Issue #12306: Expose the runtime version of the zlib C library as a constant,
 +  ZLIB_RUNTIME_VERSION, in the zlib module. Patch by Torsten Landschoff.
 +
 +- Issue #12959: Add collections.ChainMap to collections.__all__.
++
 +- Issue #8933: distutils' PKG-INFO files and packaging's METADATA files will
 +  now correctly report Metadata-Version: 1.1 instead of 1.0 if a Classifier or
 +  Download-URL field is present.
 +
 +- Issue #12567: Add curses.unget_wch() function. Push a character so the next
 +  get_wch() will return it.
 +
 +- Issue #9561: distutils and packaging now writes egg-info files using UTF-8,
 +  instead of the locale encoding.
 +
  - Issue #8286: The distutils command sdist will print a warning message instead
    of crashing when an invalid path is given in the manifest template.
  
diff --cc Python/import.c
index adfd2cc5df9d6fd191badb65426678d30bb1b1e9,2adcb04674113b0de3b68fdb1402347fab7b26f9..24df985d46465553b92541fa155fc6a9573c90e3
@@@ -1789,282 -1612,232 +1789,291 @@@ find_module_path(PyObject *fullname, Py
              if (loader != Py_None) {
                  /* a loader was found */
                  *p_loader = loader;
 -                Py_DECREF(meta_path);
 -                return &importhookdescr;
 +                *p_fd = &importhookdescr;
 +                return 2;
              }
              Py_DECREF(loader);
 +            return 0;
          }
 -        Py_DECREF(meta_path);
 -    }
 -
 -    if (find_frozen(fullname) != NULL) {
 -        strcpy(buf, fullname);
 -        return &fd_frozen;
      }
 +    /* no hook was found, use builtin import */
  
 -    if (path == NULL) {
 -        if (is_builtin(name)) {
 -            strcpy(buf, name);
 -            return &fd_builtin;
 -        }
 -#ifdef MS_COREDLL
 -        fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen);
 -        if (fp != NULL) {
 -            *p_fp = fp;
 -            return fdp;
 -        }
 +    if (len > 0 && buf[len-1] != SEP
 +#ifdef ALTSEP
 +        && buf[len-1] != ALTSEP
  #endif
 -        path = PySys_GetObject("path");
 -    }
 -
 -    if (path == NULL || !PyList_Check(path)) {
 -        PyErr_SetString(PyExc_RuntimeError,
 -                        "sys.path must be a list of directory names");
 -        return NULL;
 -    }
 +        )
 +        buf[len++] = SEP;
 +    Py_UNICODE_strcpy(buf+len, PyUnicode_AS_UNICODE(name));
 +    len += PyUnicode_GET_SIZE(name);
  
 -    path_hooks = PySys_GetObject("path_hooks");
 -    if (path_hooks == NULL || !PyList_Check(path_hooks)) {
 -        PyErr_SetString(PyExc_RuntimeError,
 -                        "sys.path_hooks must be a list of "
 -                        "import hooks");
 -        return NULL;
 -    }
 -    path_importer_cache = PySys_GetObject("path_importer_cache");
 -    if (path_importer_cache == NULL ||
 -        !PyDict_Check(path_importer_cache)) {
 -        PyErr_SetString(PyExc_RuntimeError,
 -                        "sys.path_importer_cache must be a dict");
 -        return NULL;
 -    }
 +    filename = PyUnicode_FromUnicode(buf, len);
 +    if (filename == NULL)
 +        return -1;
  
 -    npath = PyList_Size(path);
 -    namelen = strlen(name);
 -    for (i = 0; i < npath; i++) {
 -        PyObject *v = PyList_GetItem(path, i);
 -        PyObject *origv = v;
 -        const char *base;
 -        Py_ssize_t size;
 -        if (!v)
 -            return NULL;
 -        if (PyUnicode_Check(v)) {
 -            v = PyUnicode_EncodeFSDefault(v);
 -            if (v == NULL)
 -                return NULL;
 -        }
 -        else if (!PyBytes_Check(v))
 -            continue;
 -        else
 -            Py_INCREF(v);
 -
 -        base = PyBytes_AS_STRING(v);
 -        size = PyBytes_GET_SIZE(v);
 -        len = size;
 -        if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) {
 -            Py_DECREF(v);
 -            continue; /* Too long */
 -        }
 -        strcpy(buf, base);
 -        Py_DECREF(v);
 +    /* Check for package import (buf holds a directory name,
 +       and there's an __init__ module in that directory */
 +#ifdef HAVE_STAT
 +    if (_Py_stat(filename, &statbuf) == 0 &&         /* it exists */
 +        S_ISDIR(statbuf.st_mode))           /* it's a directory */
 +    {
 +        int match;
  
 -        if (strlen(buf) != len) {
 -            continue; /* v contains '\0' */
 +        match = case_ok(filename, 0, name);
 +        if (match < 0) {
 +            Py_DECREF(filename);
 +            return -1;
          }
 -
 -        /* sys.path_hooks import hook */
 -        if (p_loader != NULL) {
 -            PyObject *importer;
 -
 -            importer = get_path_importer(path_importer_cache,
 -                                         path_hooks, origv);
 -            if (importer == NULL) {
 -                return NULL;
 +        if (match) { /* case matches */
 +            if (find_init_module(filename)) { /* and has __init__.py */
 +                *p_path = filename;
 +                *p_fd = &fd_package;
 +                return 2;
              }
 -            /* Note: importer is a borrowed reference */
 -            if (importer != Py_None) {
 -                PyObject *loader;
 -                loader = PyObject_CallMethod(importer,
 -                                             "find_module",
 -                                             "s", fullname);
 -                if (loader == NULL)
 -                    return NULL;  /* error */
 -                if (loader != Py_None) {
 -                    /* a loader was found */
 -                    *p_loader = loader;
 -                    return &importhookdescr;
 +            else {
 +                int err;
 +                err = PyErr_WarnFormat(PyExc_ImportWarning, 1,
 +                    "Not importing directory %R: missing __init__.py",
 +                    filename);
 +                if (err) {
 +                    Py_DECREF(filename);
 +                    return -1;
                  }
 -                Py_DECREF(loader);
 -                continue;
              }
          }
 -        /* no hook was found, use builtin import */
 -
 -        if (len > 0 && buf[len-1] != SEP
 -#ifdef ALTSEP
 -            && buf[len-1] != ALTSEP
 +    }
  #endif
 -            )
 -            buf[len++] = SEP;
 -        strcpy(buf+len, name);
 -        len += namelen;
 +    *p_path = filename;
 +    return 1;
 +}
  
 -        /* Check for package import (buf holds a directory name,
 -           and there's an __init__ module in that directory */
 -#ifdef HAVE_STAT
 -        if (stat(buf, &statbuf) == 0 &&         /* it exists */
 -            S_ISDIR(statbuf.st_mode) &&         /* it's a directory */
 -            case_ok(buf, len, namelen, name)) { /* case matches */
 -            if (find_init_module(buf)) { /* and has __init__.py */
 -                return &fd_package;
 -            }
 -            else {
 -                int err;
 -                PyObject *unicode = PyUnicode_DecodeFSDefault(buf);
 -                if (unicode == NULL)
 -                    return NULL;
 -                err = PyErr_WarnFormat(PyExc_ImportWarning, 1,
 -                    "Not importing directory '%U': missing __init__.py",
 -                    unicode);
 -                Py_DECREF(unicode);
 -                if (err)
 -                    return NULL;
 -            }
 +/* Find a module in search_path_list. For each path, try
 +   find_module_path() or try each _PyImport_Filetab suffix.
 +
 +   If the module is found, return a file descriptor, write the path in
 +   *p_filename, write the pointer to the file object into *p_fp, and (if
 +   p_loader is not NULL) the loader into *p_loader.
 +
 +   Otherwise, raise an exception and return NULL. */
 +
 +static struct filedescr*
 +find_module_path_list(PyObject *fullname, PyObject *name,
 +                      PyObject *search_path_list, PyObject *path_hooks,
 +                      PyObject *path_importer_cache,
 +                      PyObject **p_path, FILE **p_fp, PyObject **p_loader)
 +{
 +    Py_ssize_t i, npath;
 +    struct filedescr *fdp = NULL;
 +    char *filemode;
 +    FILE *fp = NULL;
 +    PyObject *prefix, *filename;
 +    int match;
 +
 +    npath = PyList_Size(search_path_list);
 +    for (i = 0; i < npath; i++) {
 +        PyObject *path;
 +        int ok;
 +
 +        path = PyList_GetItem(search_path_list, i);
 +        if (path == NULL)
 +            return NULL;
 +
 +        prefix = NULL;
 +        ok = find_module_path(fullname, name, path,
 +                              path_hooks, path_importer_cache,
 +                              &prefix, p_loader, &fdp);
 +        if (ok < 0)
 +            return NULL;
 +        if (ok == 0)
 +            continue;
 +        if (ok == 2) {
 +            *p_path = prefix;
 +            return fdp;
          }
 -#endif
 -#if defined(PYOS_OS2)
 -        /* take a snapshot of the module spec for restoration
 -         * after the 8 character DLL hackery
 -         */
 -        saved_buf = strdup(buf);
 -        saved_len = len;
 -        saved_namelen = namelen;
 -#endif /* PYOS_OS2 */
 +
          for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
 -#if defined(PYOS_OS2) && defined(HAVE_DYNAMIC_LOADING)
 -            /* OS/2 limits DLLs to 8 character names (w/o
 -               extension)
 -             * so if the name is longer than that and its a
 -             * dynamically loaded module we're going to try,
 -             * truncate the name before trying
 -             */
 -            if (strlen(subname) > 8) {
 -                /* is this an attempt to load a C extension? */
 -                const struct filedescr *scan;
 -                scan = _PyImport_DynLoadFiletab;
 -                while (scan->suffix != NULL) {
 -                    if (!strcmp(scan->suffix, fdp->suffix))
 -                        break;
 -                    else
 -                        scan++;
 -                }
 -                if (scan->suffix != NULL) {
 -                    /* yes, so truncate the name */
 -                    namelen = 8;
 -                    len -= strlen(subname) - namelen;
 -                    buf[len] = '\0';
 -                }
 -            }
 -#endif /* PYOS_OS2 */
 -            strcpy(buf+len, fdp->suffix);
 -            if (Py_VerboseFlag > 1)
 -                PySys_WriteStderr("# trying %s\n", buf);
+             struct stat statbuf;
              filemode = fdp->mode;
              if (filemode[0] == 'U')
                  filemode = "r" PY_STDIOTEXTMODE;
  
 -            if (stat(buf, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
 -                /* it's a directory */
 -                fp = NULL;
 -            else
 -                fp = fopen(buf, filemode);
 -            if (fp != NULL) {
 -                if (case_ok(buf, len, namelen, name))
 -                    break;
 -                else {                   /* continue search */
 -                    fclose(fp);
 -                    fp = NULL;
 +            filename = PyUnicode_FromFormat("%U%s", prefix, fdp->suffix);
 +            if (filename == NULL) {
 +                Py_DECREF(prefix);
 +                return NULL;
 +            }
 +
 +            if (Py_VerboseFlag > 1)
 +                PySys_FormatStderr("# trying %R\n", filename);
 +
++            if (_Py_stat(filename, &statbuf) == 0 &&         /* it exists */
++                S_ISDIR(statbuf.st_mode))           /* it's a directory */
++            {
++                Py_DECREF(filename);
++                continue;
++            }
++
 +            fp = _Py_fopen(filename, filemode);
 +            if (fp == NULL) {
 +                Py_DECREF(filename);
 +                if (PyErr_Occurred()) {
 +                    Py_DECREF(prefix);
 +                    return NULL;
                  }
 +                continue;
              }
 -#if defined(PYOS_OS2)
 -            /* restore the saved snapshot */
 -            strcpy(buf, saved_buf);
 -            len = saved_len;
 -            namelen = saved_namelen;
 -#endif
 +            match = case_ok(filename, -(Py_ssize_t)strlen(fdp->suffix), name);
 +            if (match < 0) {
 +                Py_DECREF(prefix);
 +                Py_DECREF(filename);
 +                return NULL;
 +            }
 +            if (match) {
 +                Py_DECREF(prefix);
 +                *p_path = filename;
 +                *p_fp = fp;
 +                return fdp;
 +            }
 +            Py_DECREF(filename);
 +
 +            fclose(fp);
 +            fp = NULL;
          }
 -#if defined(PYOS_OS2)
 -        /* don't need/want the module name snapshot anymore */
 -        if (saved_buf)
 -        {
 -            free(saved_buf);
 -            saved_buf = NULL;
 +        Py_DECREF(prefix);
 +    }
 +    PyErr_Format(PyExc_ImportError,
 +                 "No module named %R", name);
 +    return NULL;
 +}
 +
 +/* Find a module:
 +
 +   - try find_module() of each sys.meta_path hook
 +   - try find_frozen()
 +   - try is_builtin()
 +   - try _PyWin_FindRegisteredModule() (Windows only)
 +   - otherwise, call find_module_path_list() with search_path_list (if not
 +     NULL) or sys.path
 +
 +   fullname can be NULL, but only if p_loader is NULL.
 +
 +   Return:
 +
 +   - &fd_builtin (C_BUILTIN) if it is a builtin
 +   - &fd_frozen (PY_FROZEN) if it is frozen
 +   - &fd_package (PKG_DIRECTORY) and write the filename into *p_path
 +     if it is a package
 +   - &importhookdescr (IMP_HOOK) and write the loader into *p_loader if a
 +     importer loader was found
 +   - a file descriptor (PY_SOURCE, PY_COMPILED, C_EXTENSION, PY_RESOURCE or
 +     PY_CODERESOURCE: see _PyImport_Filetab), write the filename into
 +     *p_path and the pointer to the open file into *p_fp
 +   - NULL on error
 +
 +   By default, *p_path, *p_fp and *p_loader (if set) are set to NULL.
 +   Eg. *p_path is set to NULL for a builtin package.
 +*/
 +
 +static struct filedescr *
 +find_module(PyObject *fullname, PyObject *name, PyObject *search_path_list,
 +            PyObject **p_path, FILE **p_fp, PyObject **p_loader)
 +{
 +    Py_ssize_t i, npath;
 +    static struct filedescr fd_frozen = {"", "", PY_FROZEN};
 +    static struct filedescr fd_builtin = {"", "", C_BUILTIN};
 +    PyObject *path_hooks, *path_importer_cache;
 +
 +    *p_path = NULL;
 +    *p_fp = NULL;
 +    if (p_loader != NULL)
 +        *p_loader = NULL;
 +
 +    /* sys.meta_path import hook */
 +    if (p_loader != NULL) {
 +        PyObject *meta_path;
 +
 +        meta_path = PySys_GetObject("meta_path");
 +        if (meta_path == NULL || !PyList_Check(meta_path)) {
 +            PyErr_SetString(PyExc_RuntimeError,
 +                            "sys.meta_path must be a list of "
 +                            "import hooks");
 +            return NULL;
 +        }
 +        Py_INCREF(meta_path);  /* zap guard */
 +        npath = PyList_Size(meta_path);
 +        for (i = 0; i < npath; i++) {
 +            PyObject *loader;
 +            PyObject *hook = PyList_GetItem(meta_path, i);
 +            loader = PyObject_CallMethod(hook, "find_module",
 +                                         "OO", fullname,
 +                                         search_path_list != NULL ?
 +                                         search_path_list : Py_None);
 +            if (loader == NULL) {
 +                Py_DECREF(meta_path);
 +                return NULL;  /* true error */
 +            }
 +            if (loader != Py_None) {
 +                /* a loader was found */
 +                *p_loader = loader;
 +                Py_DECREF(meta_path);
 +                return &importhookdescr;
 +            }
 +            Py_DECREF(loader);
          }
 +        Py_DECREF(meta_path);
 +    }
 +
 +    if (find_frozen(fullname) != NULL)
 +        return &fd_frozen;
 +
 +    if (search_path_list == NULL) {
 +#ifdef MS_COREDLL
 +        FILE *fp;
 +        struct filedescr *fdp;
  #endif
 -        if (fp != NULL)
 -            break;
 +        if (is_builtin(name))
 +            return &fd_builtin;
 +#ifdef MS_COREDLL
 +        fp = _PyWin_FindRegisteredModule(name, &fdp, p_path);
 +        if (fp != NULL) {
 +            *p_fp = fp;
 +            return fdp;
 +        }
 +        else if (PyErr_Occurred())
 +            return NULL;
 +#endif
 +        search_path_list = PySys_GetObject("path");
      }
 -    if (fp == NULL) {
 -        PyErr_Format(PyExc_ImportError,
 -                     "No module named %.200s", name);
 +
 +    if (search_path_list == NULL || !PyList_Check(search_path_list)) {
 +        PyErr_SetString(PyExc_RuntimeError,
 +                        "sys.path must be a list of directory names");
          return NULL;
      }
 -    *p_fp = fp;
 -    return fdp;
 +
 +    path_hooks = PySys_GetObject("path_hooks");
 +    if (path_hooks == NULL || !PyList_Check(path_hooks)) {
 +        PyErr_SetString(PyExc_RuntimeError,
 +                        "sys.path_hooks must be a list of "
 +                        "import hooks");
 +        return NULL;
 +    }
 +    path_importer_cache = PySys_GetObject("path_importer_cache");
 +    if (path_importer_cache == NULL ||
 +        !PyDict_Check(path_importer_cache)) {
 +        PyErr_SetString(PyExc_RuntimeError,
 +                        "sys.path_importer_cache must be a dict");
 +        return NULL;
 +    }
 +
 +    return find_module_path_list(fullname, name,
 +                                 search_path_list, path_hooks,
 +                                 path_importer_cache,
 +                                 p_path, 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.py\0
   *    ^                      ^                   ^    ^