|
|
|
@ -1118,8 +1118,6 @@ unchanged: |
|
|
|
} |
|
|
|
|
|
|
|
/* Forward */ |
|
|
|
static struct filedescr *find_module(PyObject *, PyObject *, PyObject *, |
|
|
|
PyObject **, FILE **, PyObject **); |
|
|
|
static struct _frozen * find_frozen(PyObject *); |
|
|
|
|
|
|
|
|
|
|
|
@ -1220,678 +1218,12 @@ PyImport_GetImporter(PyObject *path) { |
|
|
|
return importer; |
|
|
|
} |
|
|
|
|
|
|
|
/* Search the path (default sys.path) for a module. Return the |
|
|
|
corresponding filedescr struct, and (via return arguments) the |
|
|
|
pathname and an open file. Return NULL if the module is not found. */ |
|
|
|
|
|
|
|
#ifdef MS_COREDLL |
|
|
|
extern FILE *_PyWin_FindRegisteredModule(PyObject *, struct filedescr **, |
|
|
|
PyObject **p_path); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Forward */ |
|
|
|
static int case_ok(PyObject *, Py_ssize_t, PyObject *); |
|
|
|
static int find_init_module(PyObject *); |
|
|
|
static struct filedescr importhookdescr = {"", "", IMP_HOOK}; |
|
|
|
|
|
|
|
/* Get the path of a module: get its importer and call importer.find_module() |
|
|
|
hook, or check if the module if a package (if path/__init__.py exists). |
|
|
|
|
|
|
|
-1: error: a Python error occurred |
|
|
|
0: ignore: an error occurred because of invalid data, but the error is not |
|
|
|
important enough to be reported. |
|
|
|
1: get path: module not found, but *buf contains its path |
|
|
|
2: found: *p_fd is the file descriptor (IMP_HOOK or PKG_DIRECTORY) |
|
|
|
and *buf is the path */ |
|
|
|
|
|
|
|
static int |
|
|
|
find_module_path(PyObject *fullname, PyObject *name, PyObject *path, |
|
|
|
PyObject *path_hooks, PyObject *path_importer_cache, |
|
|
|
PyObject **p_path, PyObject **p_loader, struct filedescr **p_fd) |
|
|
|
{ |
|
|
|
PyObject *path_unicode, *filename = NULL; |
|
|
|
Py_ssize_t len, pos; |
|
|
|
struct stat statbuf; |
|
|
|
static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; |
|
|
|
int err, result, addsep; |
|
|
|
|
|
|
|
if (PyUnicode_Check(path)) { |
|
|
|
Py_INCREF(path); |
|
|
|
path_unicode = path; |
|
|
|
} |
|
|
|
else if (PyBytes_Check(path)) { |
|
|
|
path_unicode = PyUnicode_DecodeFSDefaultAndSize( |
|
|
|
PyBytes_AS_STRING(path), PyBytes_GET_SIZE(path)); |
|
|
|
if (path_unicode == NULL) |
|
|
|
return -1; |
|
|
|
} |
|
|
|
else |
|
|
|
return 0; |
|
|
|
|
|
|
|
if (PyUnicode_READY(path_unicode)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
len = PyUnicode_GET_LENGTH(path_unicode); |
|
|
|
if (PyUnicode_FindChar(path_unicode, 0, 0, len, 1) != -1) { |
|
|
|
result = 0; |
|
|
|
goto out; /* path contains '\0' */ |
|
|
|
} |
|
|
|
|
|
|
|
/* sys.path_hooks import hook */ |
|
|
|
if (p_loader != NULL) { |
|
|
|
_Py_IDENTIFIER(find_module); |
|
|
|
PyObject *importer; |
|
|
|
|
|
|
|
importer = get_path_importer(path_importer_cache, |
|
|
|
path_hooks, path); |
|
|
|
if (importer == NULL) { |
|
|
|
result = -1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
/* Note: importer is a borrowed reference */ |
|
|
|
if (importer != Py_None) { |
|
|
|
PyObject *loader; |
|
|
|
loader = _PyObject_CallMethodId(importer, |
|
|
|
&PyId_find_module, "O", fullname); |
|
|
|
if (loader == NULL) { |
|
|
|
result = -1; /* error */ |
|
|
|
goto out; |
|
|
|
} |
|
|
|
if (loader != Py_None) { |
|
|
|
/* a loader was found */ |
|
|
|
*p_loader = loader; |
|
|
|
*p_fd = &importhookdescr; |
|
|
|
result = 2; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
Py_DECREF(loader); |
|
|
|
result = 0; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
} |
|
|
|
/* no hook was found, use builtin import */ |
|
|
|
|
|
|
|
addsep = 0; |
|
|
|
if (len > 0 && PyUnicode_READ_CHAR(path_unicode, len-1) != SEP |
|
|
|
#ifdef ALTSEP |
|
|
|
&& PyUnicode_READ_CHAR(path_unicode, len-1) != ALTSEP |
|
|
|
#endif |
|
|
|
) |
|
|
|
addsep = 1; |
|
|
|
filename = PyUnicode_New(len + PyUnicode_GET_LENGTH(name) + addsep, |
|
|
|
Py_MAX(PyUnicode_MAX_CHAR_VALUE(path_unicode), |
|
|
|
PyUnicode_MAX_CHAR_VALUE(name))); |
|
|
|
if (filename == NULL) { |
|
|
|
result = -1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
PyUnicode_CopyCharacters(filename, 0, path_unicode, 0, len); |
|
|
|
pos = len; |
|
|
|
if (addsep) |
|
|
|
PyUnicode_WRITE(PyUnicode_KIND(filename), |
|
|
|
PyUnicode_DATA(filename), |
|
|
|
pos++, SEP); |
|
|
|
PyUnicode_CopyCharacters(filename, pos, name, 0, |
|
|
|
PyUnicode_GET_LENGTH(name)); |
|
|
|
|
|
|
|
/* Check for package import (buf holds a directory name, |
|
|
|
and there's an __init__ module in that directory */ |
|
|
|
#ifdef HAVE_STAT |
|
|
|
err = _Py_stat(filename, &statbuf); |
|
|
|
if (err == -2) { |
|
|
|
result = -1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
if (err == 0 && /* it exists */ |
|
|
|
S_ISDIR(statbuf.st_mode)) /* it's a directory */ |
|
|
|
{ |
|
|
|
int match; |
|
|
|
|
|
|
|
match = case_ok(filename, 0, name); |
|
|
|
if (match < 0) { |
|
|
|
result = -1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
if (match) { /* case matches */ |
|
|
|
if (find_init_module(filename)) { /* and has __init__.py */ |
|
|
|
*p_path = filename; |
|
|
|
filename = NULL; |
|
|
|
*p_fd = &fd_package; |
|
|
|
result = 2; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
else { |
|
|
|
int err; |
|
|
|
err = PyErr_WarnFormat(PyExc_ImportWarning, 1, |
|
|
|
"Not importing directory %R: missing __init__.py", |
|
|
|
filename); |
|
|
|
if (err) { |
|
|
|
result = -1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
*p_path = filename; |
|
|
|
filename = NULL; |
|
|
|
result = 1; |
|
|
|
out: |
|
|
|
Py_DECREF(path_unicode); |
|
|
|
Py_XDECREF(filename); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/* 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; |
|
|
|
int err; |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { |
|
|
|
struct stat statbuf; |
|
|
|
|
|
|
|
filemode = fdp->mode; |
|
|
|
if (filemode[0] == 'U') |
|
|
|
filemode = "r" PY_STDIOTEXTMODE; |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
err = _Py_stat(filename, &statbuf); |
|
|
|
if (err == -2) { |
|
|
|
Py_DECREF(prefix); |
|
|
|
Py_DECREF(filename); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
if (err != 0 || S_ISDIR(statbuf.st_mode)) { |
|
|
|
/* it doesn't exist, or 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; |
|
|
|
} |
|
|
|
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; |
|
|
|
} |
|
|
|
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) { |
|
|
|
_Py_IDENTIFIER(find_module); |
|
|
|
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_CallMethodId(hook, &PyId_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 (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 (search_path_list == NULL || !PyList_Check(search_path_list)) { |
|
|
|
PyErr_SetString(PyExc_RuntimeError, |
|
|
|
"sys.path must be a list of directory names"); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
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_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 |
|
|
|
* ^ ^ ^ ^ |
|
|
|
* |--------------------- buf ---------------------| |
|
|
|
* |------------------- len ------------------| |
|
|
|
* |------ name -------| |
|
|
|
* |----- namelen -----| |
|
|
|
* buf is the full path, but len only counts up to (& exclusive of) the |
|
|
|
* extension. name is the module name, also exclusive of extension. |
|
|
|
* |
|
|
|
* We've already done a successful stat() or fopen() on buf, so know that |
|
|
|
* there's some match, possibly case-insensitive. |
|
|
|
* |
|
|
|
* 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_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_bytes(). |
|
|
|
*/ |
|
|
|
#if defined(MS_WINDOWS) |
|
|
|
#include <windows.h> |
|
|
|
|
|
|
|
#elif defined(DJGPP) |
|
|
|
#include <dir.h> |
|
|
|
|
|
|
|
#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) |
|
|
|
#include <sys/types.h> |
|
|
|
#include <dirent.h> |
|
|
|
|
|
|
|
#elif defined(PYOS_OS2) |
|
|
|
#define INCL_DOS |
|
|
|
#define INCL_DOSERRORS |
|
|
|
#define INCL_NOPMAPI |
|
|
|
#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_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. |
|
|
|
*/ |
|
|
|
|
|
|
|
/* DJGPP */ |
|
|
|
#if defined(DJGPP) |
|
|
|
struct ffblk ffblk; |
|
|
|
int done; |
|
|
|
|
|
|
|
if (Py_GETENV("PYTHONCASEOK") != NULL) |
|
|
|
return 1; |
|
|
|
|
|
|
|
done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC); |
|
|
|
if (done) { |
|
|
|
PyErr_Format(PyExc_NameError, |
|
|
|
"Can't find file for module %.100s\n(filename %.300s)", |
|
|
|
name, buf); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return strncmp(ffblk.ff_name, name, namelen) == 0; |
|
|
|
|
|
|
|
/* new-fangled macintosh (macosx) or Cygwin */ |
|
|
|
#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) |
|
|
|
DIR *dirp; |
|
|
|
struct dirent *dp; |
|
|
|
char dirname[MAXPATHLEN + 1]; |
|
|
|
const int dirlen = len - namelen - 1; /* don't want trailing SEP */ |
|
|
|
|
|
|
|
if (Py_GETENV("PYTHONCASEOK") != NULL) |
|
|
|
return 1; |
|
|
|
|
|
|
|
/* Copy the dir component into dirname; substitute "." if empty */ |
|
|
|
if (dirlen <= 0) { |
|
|
|
dirname[0] = '.'; |
|
|
|
dirname[1] = '\0'; |
|
|
|
} |
|
|
|
else { |
|
|
|
assert(dirlen <= MAXPATHLEN); |
|
|
|
memcpy(dirname, buf, dirlen); |
|
|
|
dirname[dirlen] = '\0'; |
|
|
|
} |
|
|
|
/* Open the directory and search the entries for an exact match. */ |
|
|
|
dirp = opendir(dirname); |
|
|
|
if (dirp) { |
|
|
|
char *nameWithExt = buf + len - namelen; |
|
|
|
while ((dp = readdir(dirp)) != NULL) { |
|
|
|
const int thislen = |
|
|
|
#ifdef _DIRENT_HAVE_D_NAMELEN |
|
|
|
dp->d_namlen; |
|
|
|
#else |
|
|
|
strlen(dp->d_name); |
|
|
|
#endif |
|
|
|
if (thislen >= namelen && |
|
|
|
strcmp(dp->d_name, nameWithExt) == 0) { |
|
|
|
(void)closedir(dirp); |
|
|
|
return 1; /* Found */ |
|
|
|
} |
|
|
|
} |
|
|
|
(void)closedir(dirp); |
|
|
|
} |
|
|
|
return 0 ; /* Not found */ |
|
|
|
|
|
|
|
/* OS/2 */ |
|
|
|
#elif defined(PYOS_OS2) |
|
|
|
HDIR hdir = 1; |
|
|
|
ULONG srchcnt = 1; |
|
|
|
FILEFINDBUF3 ffbuf; |
|
|
|
APIRET rc; |
|
|
|
|
|
|
|
if (Py_GETENV("PYTHONCASEOK") != NULL) |
|
|
|
return 1; |
|
|
|
|
|
|
|
rc = DosFindFirst(buf, |
|
|
|
&hdir, |
|
|
|
FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, |
|
|
|
&ffbuf, sizeof(ffbuf), |
|
|
|
&srchcnt, |
|
|
|
FIL_STANDARD); |
|
|
|
if (rc != NO_ERROR) |
|
|
|
return 0; |
|
|
|
return strncmp(ffbuf.achName, name, namelen) == 0; |
|
|
|
|
|
|
|
/* 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; |
|
|
|
wchar_t *wfilename, *wname; |
|
|
|
Py_ssize_t wname_len; |
|
|
|
|
|
|
|
if (Py_GETENV("PYTHONCASEOK") != NULL) |
|
|
|
return 1; |
|
|
|
|
|
|
|
wfilename = PyUnicode_AsUnicode(filename); |
|
|
|
if (wfilename == NULL) |
|
|
|
return -1; |
|
|
|
|
|
|
|
h = FindFirstFileW(wfilename, &data); |
|
|
|
if (h == INVALID_HANDLE_VALUE) { |
|
|
|
PyErr_Format(PyExc_NameError, |
|
|
|
"Can't find file for module %R\n(filename %R)", |
|
|
|
name, filename); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
FindClose(h); |
|
|
|
|
|
|
|
wname = PyUnicode_AsUnicodeAndSize(name, &wname_len); |
|
|
|
if (wname == NULL) |
|
|
|
return -1; |
|
|
|
|
|
|
|
cmp = wcsncmp(data.cFileName, wname, wname_len); |
|
|
|
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_GET_SIZE(namebytes), |
|
|
|
PyBytes_AS_STRING(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 |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef HAVE_STAT |
|
|
|
|
|
|
|
/* Helper to look for __init__.py or __init__.py[co] in potential package. |
|
|
|
Return 1 if __init__ was found, 0 if not, or -1 on error. */ |
|
|
|
static int |
|
|
|
find_init_module(PyObject *directory) |
|
|
|
{ |
|
|
|
struct stat statbuf; |
|
|
|
PyObject *filename; |
|
|
|
int match; |
|
|
|
int err; |
|
|
|
|
|
|
|
filename = PyUnicode_FromFormat("%U%c__init__.py", directory, SEP); |
|
|
|
if (filename == NULL) |
|
|
|
return -1; |
|
|
|
err = _Py_stat(filename, &statbuf); |
|
|
|
if (err == -2) |
|
|
|
return -1; |
|
|
|
if (err == 0) { |
|
|
|
/* 3=len(".py") */ |
|
|
|
match = case_ok(filename, -3, initstr); |
|
|
|
if (match < 0) { |
|
|
|
Py_DECREF(filename); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (match) { |
|
|
|
Py_DECREF(filename); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
Py_DECREF(filename); |
|
|
|
|
|
|
|
filename = PyUnicode_FromFormat("%U%c__init__.py%c", |
|
|
|
directory, SEP, Py_OptimizeFlag ? 'o' : 'c'); |
|
|
|
if (filename == NULL) |
|
|
|
return -1; |
|
|
|
err = _Py_stat(filename, &statbuf); |
|
|
|
if (err == -2) { |
|
|
|
Py_DECREF(filename); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (err == 0) { |
|
|
|
/* 4=len(".pyc") */ |
|
|
|
match = case_ok(filename, -4, initstr); |
|
|
|
if (match < 0) { |
|
|
|
Py_DECREF(filename); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (match) { |
|
|
|
Py_DECREF(filename); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
Py_DECREF(filename); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
#endif /* HAVE_STAT */ |
|
|
|
|
|
|
|
|
|
|
|
static int init_builtin(PyObject *); /* Forward */ |
|
|
|
|
|
|
|
@ -2688,81 +2020,6 @@ imp_get_suffixes(PyObject *self, PyObject *noargs) |
|
|
|
return list; |
|
|
|
} |
|
|
|
|
|
|
|
static PyObject * |
|
|
|
call_find_module(PyObject *name, PyObject *path_list) |
|
|
|
{ |
|
|
|
extern int fclose(FILE *); |
|
|
|
PyObject *fob, *ret; |
|
|
|
PyObject *pathobj; |
|
|
|
struct filedescr *fdp; |
|
|
|
FILE *fp; |
|
|
|
int fd = -1; |
|
|
|
char *found_encoding = NULL; |
|
|
|
char *encoding = NULL; |
|
|
|
|
|
|
|
if (path_list == Py_None) |
|
|
|
path_list = NULL; |
|
|
|
fdp = find_module(NULL, name, path_list, |
|
|
|
&pathobj, &fp, NULL); |
|
|
|
if (fdp == NULL) |
|
|
|
return NULL; |
|
|
|
if (fp != NULL) { |
|
|
|
fd = fileno(fp); |
|
|
|
if (fd != -1) |
|
|
|
fd = dup(fd); |
|
|
|
fclose(fp); |
|
|
|
fp = NULL; |
|
|
|
if (fd == -1) |
|
|
|
return PyErr_SetFromErrno(PyExc_OSError); |
|
|
|
} |
|
|
|
if (fd != -1) { |
|
|
|
if (strchr(fdp->mode, 'b') == NULL) { |
|
|
|
/* PyTokenizer_FindEncodingFilename() returns PyMem_MALLOC'ed |
|
|
|
memory. */ |
|
|
|
found_encoding = PyTokenizer_FindEncodingFilename(fd, pathobj); |
|
|
|
lseek(fd, 0, 0); /* Reset position */ |
|
|
|
if (found_encoding == NULL && PyErr_Occurred()) { |
|
|
|
Py_XDECREF(pathobj); |
|
|
|
close(fd); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
encoding = (found_encoding != NULL) ? found_encoding : |
|
|
|
(char*)PyUnicode_GetDefaultEncoding(); |
|
|
|
} |
|
|
|
fob = PyFile_FromFd(fd, NULL, fdp->mode, -1, |
|
|
|
(char*)encoding, NULL, NULL, 1); |
|
|
|
if (fob == NULL) { |
|
|
|
Py_XDECREF(pathobj); |
|
|
|
close(fd); |
|
|
|
PyMem_FREE(found_encoding); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
fob = Py_None; |
|
|
|
Py_INCREF(fob); |
|
|
|
} |
|
|
|
if (pathobj == NULL) { |
|
|
|
Py_INCREF(Py_None); |
|
|
|
pathobj = Py_None; |
|
|
|
} |
|
|
|
ret = Py_BuildValue("NN(ssi)", |
|
|
|
fob, pathobj, fdp->suffix, fdp->mode, fdp->type); |
|
|
|
PyMem_FREE(found_encoding); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static PyObject * |
|
|
|
imp_find_module(PyObject *self, PyObject *args) |
|
|
|
{ |
|
|
|
PyObject *name, *path_list = NULL; |
|
|
|
if (!PyArg_ParseTuple(args, "U|O:find_module", |
|
|
|
&name, &path_list)) |
|
|
|
return NULL; |
|
|
|
return call_find_module(name, path_list); |
|
|
|
} |
|
|
|
|
|
|
|
static PyObject * |
|
|
|
imp_init_builtin(PyObject *self, PyObject *args) |
|
|
|
{ |
|
|
|
@ -2931,13 +2188,6 @@ Reload the module. The module must have been successfully imported before."); |
|
|
|
PyDoc_STRVAR(doc_imp, |
|
|
|
"(Extremely) low-level import machinery bits as used by importlib and imp."); |
|
|
|
|
|
|
|
PyDoc_STRVAR(doc_find_module, |
|
|
|
"find_module(name, [path]) -> (file, filename, (suffix, mode, type))\n\ |
|
|
|
Search for a module. If path is omitted or None, search for a\n\ |
|
|
|
built-in, frozen or special module and continue search in sys.path.\n\ |
|
|
|
The module name cannot contain '.'; to search for a submodule of a\n\ |
|
|
|
package, pass the submodule name and the package's __path__."); |
|
|
|
|
|
|
|
PyDoc_STRVAR(doc_get_magic, |
|
|
|
"get_magic() -> string\n\ |
|
|
|
Return the magic number for .pyc or .pyo files."); |
|
|
|
@ -2969,7 +2219,6 @@ Release the interpreter's import lock.\n\ |
|
|
|
On platforms without threads, this function does nothing."); |
|
|
|
|
|
|
|
static PyMethodDef imp_methods[] = { |
|
|
|
{"find_module", imp_find_module, METH_VARARGS, doc_find_module}, |
|
|
|
{"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic}, |
|
|
|
{"get_tag", imp_get_tag, METH_NOARGS, doc_get_tag}, |
|
|
|
{"get_suffixes", imp_get_suffixes, METH_NOARGS, doc_get_suffixes}, |
|
|
|
|