LCOV - code coverage report
Current view: top level - Modules - getpath.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 265 377 70.3 %
Date: 2022-07-07 18:19:46 Functions: 19 22 86.4 %

          Line data    Source code
       1             : /* Return the initial module search path. */
       2             : 
       3             : #include "Python.h"
       4             : #include "marshal.h"              // PyMarshal_ReadObjectFromString
       5             : #include "osdefs.h"               // DELIM
       6             : #include "pycore_initconfig.h"
       7             : #include "pycore_fileutils.h"
       8             : #include "pycore_pathconfig.h"
       9             : #include "pycore_pymem.h"         // _PyMem_SetDefaultAllocator()
      10             : #include <wchar.h>
      11             : 
      12             : #ifdef MS_WINDOWS
      13             : #  include <windows.h>            // GetFullPathNameW(), MAX_PATH
      14             : #  include <pathcch.h>
      15             : #endif
      16             : 
      17             : #ifdef __APPLE__
      18             : #  include <mach-o/dyld.h>
      19             : #endif
      20             : 
      21             : /* Reference the precompiled getpath.py */
      22             : #include "../Python/frozen_modules/getpath.h"
      23             : 
      24             : #if (!defined(PREFIX) || !defined(EXEC_PREFIX) \
      25             :         || !defined(VERSION) || !defined(VPATH) \
      26             :         || !defined(PLATLIBDIR))
      27             : #error "PREFIX, EXEC_PREFIX, VERSION, VPATH and PLATLIBDIR macros must be defined"
      28             : #endif
      29             : 
      30             : #if !defined(PYTHONPATH)
      31             : #define PYTHONPATH NULL
      32             : #endif
      33             : 
      34             : #if !defined(PYDEBUGEXT)
      35             : #define PYDEBUGEXT NULL
      36             : #endif
      37             : 
      38             : #if !defined(PYWINVER)
      39             : #ifdef MS_DLL_ID
      40             : #define PYWINVER MS_DLL_ID
      41             : #else
      42             : #define PYWINVER NULL
      43             : #endif
      44             : #endif
      45             : 
      46             : #if !defined(EXE_SUFFIX)
      47             : #if defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(__MINGW32__)
      48             : #define EXE_SUFFIX L".exe"
      49             : #else
      50             : #define EXE_SUFFIX NULL
      51             : #endif
      52             : #endif
      53             : 
      54             : 
      55             : /* HELPER FUNCTIONS for getpath.py */
      56             : 
      57             : static PyObject *
      58        2986 : getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args)
      59             : {
      60        2986 :     PyObject *r = NULL;
      61             :     PyObject *pathobj;
      62             :     wchar_t *path;
      63        2986 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
      64           0 :         return NULL;
      65             :     }
      66             :     Py_ssize_t len;
      67        2986 :     path = PyUnicode_AsWideCharString(pathobj, &len);
      68        2986 :     if (path) {
      69             :         wchar_t *abs;
      70        2986 :         if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) {
      71        2986 :             r = PyUnicode_FromWideChar(abs, -1);
      72        2986 :             PyMem_RawFree((void *)abs);
      73             :         } else {
      74           0 :             PyErr_SetString(PyExc_OSError, "failed to make path absolute");
      75             :         }
      76        2986 :         PyMem_Free((void *)path);
      77             :     }
      78        2986 :     return r;
      79             : }
      80             : 
      81             : 
      82             : static PyObject *
      83          25 : getpath_basename(PyObject *Py_UNUSED(self), PyObject *args)
      84             : {
      85             :     const char *path;
      86          25 :     if (!PyArg_ParseTuple(args, "s", &path)) {
      87           0 :         return NULL;
      88             :     }
      89          25 :     const char *name = strrchr(path, SEP);
      90          25 :     return PyUnicode_FromString(name ? name + 1 : path);
      91             : }
      92             : 
      93             : 
      94             : static PyObject *
      95        9476 : getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args)
      96             : {
      97             :     const char *path;
      98        9476 :     if (!PyArg_ParseTuple(args, "s", &path)) {
      99           0 :         return NULL;
     100             :     }
     101        9476 :     const char *name = strrchr(path, SEP);
     102        9476 :     if (!name) {
     103          10 :         return PyUnicode_FromStringAndSize(NULL, 0);
     104             :     }
     105        9466 :     return PyUnicode_FromStringAndSize(path, (name - path));
     106             : }
     107             : 
     108             : 
     109             : static PyObject *
     110           0 : getpath_isabs(PyObject *Py_UNUSED(self), PyObject *args)
     111             : {
     112           0 :     PyObject *r = NULL;
     113             :     PyObject *pathobj;
     114             :     const wchar_t *path;
     115           0 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
     116           0 :         return NULL;
     117             :     }
     118           0 :     path = PyUnicode_AsWideCharString(pathobj, NULL);
     119           0 :     if (path) {
     120           0 :         r = _Py_isabs(path) ? Py_True : Py_False;
     121           0 :         PyMem_Free((void *)path);
     122             :     }
     123           0 :     Py_XINCREF(r);
     124           0 :     return r;
     125             : }
     126             : 
     127             : 
     128             : static PyObject *
     129           0 : getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args)
     130             : {
     131           0 :     PyObject *r = NULL;
     132             :     PyObject *pathobj;
     133             :     PyObject *suffixobj;
     134             :     const wchar_t *path;
     135             :     const wchar_t *suffix;
     136           0 :     if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) {
     137           0 :         return NULL;
     138             :     }
     139             :     Py_ssize_t len, suffixLen;
     140           0 :     path = PyUnicode_AsWideCharString(pathobj, &len);
     141           0 :     if (path) {
     142           0 :         suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen);
     143           0 :         if (suffix) {
     144           0 :             if (suffixLen > len ||
     145             : #ifdef MS_WINDOWS
     146             :                 wcsicmp(&path[len - suffixLen], suffix) != 0
     147             : #else
     148           0 :                 wcscmp(&path[len - suffixLen], suffix) != 0
     149             : #endif
     150             :             ) {
     151           0 :                 r = Py_False;
     152             :             } else {
     153           0 :                 r = Py_True;
     154             :             }
     155           0 :             Py_INCREF(r);
     156           0 :             PyMem_Free((void *)suffix);
     157             :         }
     158           0 :         PyMem_Free((void *)path);
     159             :     }
     160           0 :     return r;
     161             : }
     162             : 
     163             : 
     164             : static PyObject *
     165           1 : getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args)
     166             : {
     167           1 :     PyObject *r = NULL;
     168             :     PyObject *pathobj;
     169             :     const wchar_t *path;
     170           1 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
     171           0 :         return NULL;
     172             :     }
     173           1 :     path = PyUnicode_AsWideCharString(pathobj, NULL);
     174           1 :     if (path) {
     175             : #ifdef MS_WINDOWS
     176             :         DWORD attr = GetFileAttributesW(path);
     177             :         r = (attr != INVALID_FILE_ATTRIBUTES) &&
     178             :             (attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
     179             : #else
     180             :         struct stat st;
     181           1 :         r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False;
     182             : #endif
     183           1 :         PyMem_Free((void *)path);
     184             :     }
     185           1 :     Py_XINCREF(r);
     186           1 :     return r;
     187             : }
     188             : 
     189             : 
     190             : static PyObject *
     191        3212 : getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args)
     192             : {
     193        3212 :     PyObject *r = NULL;
     194             :     PyObject *pathobj;
     195             :     const wchar_t *path;
     196        3212 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
     197           0 :         return NULL;
     198             :     }
     199        3212 :     path = PyUnicode_AsWideCharString(pathobj, NULL);
     200        3212 :     if (path) {
     201             : #ifdef MS_WINDOWS
     202             :         DWORD attr = GetFileAttributesW(path);
     203             :         r = (attr != INVALID_FILE_ATTRIBUTES) &&
     204             :             !(attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
     205             : #else
     206             :         struct stat st;
     207        3212 :         r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False;
     208             : #endif
     209        3212 :         PyMem_Free((void *)path);
     210             :     }
     211        3212 :     Py_XINCREF(r);
     212        3212 :     return r;
     213             : }
     214             : 
     215             : 
     216             : static PyObject *
     217         124 : getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args)
     218             : {
     219         124 :     PyObject *r = NULL;
     220             :     PyObject *pathobj;
     221             :     const wchar_t *path;
     222             :     Py_ssize_t cchPath;
     223         124 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
     224           0 :         return NULL;
     225             :     }
     226         124 :     path = PyUnicode_AsWideCharString(pathobj, &cchPath);
     227         124 :     if (path) {
     228             : #ifdef MS_WINDOWS
     229             :         const wchar_t *ext;
     230             :         DWORD attr = GetFileAttributesW(path);
     231             :         r = (attr != INVALID_FILE_ATTRIBUTES) &&
     232             :             !(attr & FILE_ATTRIBUTE_DIRECTORY) &&
     233             :             SUCCEEDED(PathCchFindExtension(path, cchPath + 1, &ext)) &&
     234             :             (CompareStringOrdinal(ext, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL)
     235             :             ? Py_True : Py_False;
     236             : #else
     237             :         struct stat st;
     238         124 :         r = (_Py_wstat(path, &st) == 0) &&
     239           3 :             S_ISREG(st.st_mode) &&
     240           3 :             (st.st_mode & 0111)
     241         127 :             ? Py_True : Py_False;
     242             : #endif
     243         124 :         PyMem_Free((void *)path);
     244             :     }
     245         124 :     Py_XINCREF(r);
     246         124 :     return r;
     247             : }
     248             : 
     249             : 
     250             : static PyObject *
     251       25699 : getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args)
     252             : {
     253       25699 :     if (!PyTuple_Check(args)) {
     254           0 :         PyErr_SetString(PyExc_TypeError, "requires tuple of arguments");
     255           0 :         return NULL;
     256             :     }
     257       25699 :     Py_ssize_t n = PyTuple_GET_SIZE(args);
     258       25699 :     if (n == 0) {
     259           0 :         return PyUnicode_FromString(NULL);
     260             :     }
     261             :     /* Convert all parts to wchar and accumulate max final length */
     262       25699 :     wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *));
     263       25699 :     memset(parts, 0, n * sizeof(wchar_t *));
     264       25699 :     Py_ssize_t cchFinal = 0;
     265       25699 :     Py_ssize_t first = 0;
     266             : 
     267       77097 :     for (Py_ssize_t i = 0; i < n; ++i) {
     268       51398 :         PyObject *s = PyTuple_GET_ITEM(args, i);
     269             :         Py_ssize_t cch;
     270       51398 :         if (s == Py_None) {
     271        3164 :             cch = 0;
     272       48234 :         } else if (PyUnicode_Check(s)) {
     273       48234 :             parts[i] = PyUnicode_AsWideCharString(s, &cch);
     274       48234 :             if (!parts[i]) {
     275           0 :                 cchFinal = -1;
     276           0 :                 break;
     277             :             }
     278       48234 :             if (_Py_isabs(parts[i])) {
     279       26094 :                 first = i;
     280             :             }
     281             :         } else {
     282           0 :             PyErr_SetString(PyExc_TypeError, "all arguments to joinpath() must be str or None");
     283           0 :             cchFinal = -1;
     284           0 :             break;
     285             :         }
     286       51398 :         cchFinal += cch + 1;
     287             :     }
     288             : 
     289       25699 :     wchar_t *final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL;
     290       25699 :     if (!final) {
     291           0 :         for (Py_ssize_t i = 0; i < n; ++i) {
     292           0 :             PyMem_Free(parts[i]);
     293             :         }
     294           0 :         PyMem_Free(parts);
     295           0 :         if (cchFinal) {
     296           0 :             PyErr_NoMemory();
     297           0 :             return NULL;
     298             :         }
     299           0 :         return PyUnicode_FromStringAndSize(NULL, 0);
     300             :     }
     301             : 
     302       25699 :     final[0] = '\0';
     303             :     /* Now join all the paths. The final result should be shorter than the buffer */
     304       77097 :     for (Py_ssize_t i = 0; i < n; ++i) {
     305       51398 :         if (!parts[i]) {
     306        3164 :             continue;
     307             :         }
     308       48234 :         if (i >= first && final) {
     309       47829 :             if (!final[0]) {
     310             :                 /* final is definitely long enough to fit any individual part */
     311       25707 :                 wcscpy(final, parts[i]);
     312       22122 :             } else if (_Py_add_relfile(final, parts[i], cchFinal) < 0) {
     313             :                 /* if we fail, keep iterating to free memory, but stop adding parts */
     314           0 :                 PyMem_Free(final);
     315           0 :                 final = NULL;
     316             :             }
     317             :         }
     318       48234 :         PyMem_Free(parts[i]);
     319             :     }
     320       25699 :     PyMem_Free(parts);
     321       25699 :     if (!final) {
     322           0 :         PyErr_SetString(PyExc_SystemError, "failed to join paths");
     323           0 :         return NULL;
     324             :     }
     325       25699 :     PyObject *r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1);
     326       25699 :     PyMem_Free(final);
     327       25699 :     return r;
     328             : }
     329             : 
     330             : 
     331             : static PyObject *
     332       15778 : getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args)
     333             : {
     334       15778 :     PyObject *r = NULL;
     335             :     PyObject *pathobj;
     336             :     const wchar_t *path;
     337       15778 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
     338           0 :         return NULL;
     339             :     }
     340       15778 :     path = PyUnicode_AsWideCharString(pathobj, NULL);
     341       15778 :     if (!path) {
     342           0 :         return NULL;
     343             :     }
     344       15778 :     FILE *fp = _Py_wfopen(path, L"rb");
     345       15778 :     PyMem_Free((void *)path);
     346       15778 :     if (!fp) {
     347       12595 :         PyErr_SetFromErrno(PyExc_OSError);
     348       12595 :         return NULL;
     349             :     }
     350             : 
     351        3183 :     r = PyList_New(0);
     352        3183 :     if (!r) {
     353           0 :         fclose(fp);
     354           0 :         return NULL;
     355             :     }
     356        3183 :     const size_t MAX_FILE = 32 * 1024;
     357        3183 :     char *buffer = (char *)PyMem_Malloc(MAX_FILE);
     358        3183 :     if (!buffer) {
     359           0 :         Py_DECREF(r);
     360           0 :         fclose(fp);
     361           0 :         return NULL;
     362             :     }
     363             : 
     364        3183 :     size_t cb = fread(buffer, 1, MAX_FILE, fp);
     365        3183 :     fclose(fp);
     366        3183 :     if (!cb) {
     367           0 :         return r;
     368             :     }
     369        3183 :     if (cb >= MAX_FILE) {
     370           0 :         Py_DECREF(r);
     371           0 :         PyErr_SetString(PyExc_MemoryError,
     372             :             "cannot read file larger than 32KB during initialization");
     373           0 :         return NULL;
     374             :     }
     375        3183 :     buffer[cb] = '\0';
     376             : 
     377             :     size_t len;
     378        3183 :     wchar_t *wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len);
     379        3183 :     PyMem_Free((void *)buffer);
     380        3183 :     if (!wbuffer) {
     381           0 :         Py_DECREF(r);
     382           0 :         PyErr_NoMemory();
     383           0 :         return NULL;
     384             :     }
     385             : 
     386        3183 :     wchar_t *p1 = wbuffer;
     387        3183 :     wchar_t *p2 = p1;
     388        3782 :     while ((p2 = wcschr(p1, L'\n')) != NULL) {
     389         599 :         Py_ssize_t cb = p2 - p1;
     390        1198 :         while (cb >= 0 && (p1[cb] == L'\n' || p1[cb] == L'\r')) {
     391         599 :             --cb;
     392             :         }
     393         599 :         PyObject *u = PyUnicode_FromWideChar(p1, cb >= 0 ? cb + 1 : 0);
     394         599 :         if (!u || PyList_Append(r, u) < 0) {
     395           0 :             Py_XDECREF(u);
     396           0 :             Py_CLEAR(r);
     397           0 :             break;
     398             :         }
     399         599 :         Py_DECREF(u);
     400         599 :         p1 = p2 + 1;
     401             :     }
     402        3183 :     if (r && p1 && *p1) {
     403        3142 :         PyObject *u = PyUnicode_FromWideChar(p1, -1);
     404        3142 :         if (!u || PyList_Append(r, u) < 0) {
     405           0 :             Py_CLEAR(r);
     406             :         }
     407        3142 :         Py_XDECREF(u);
     408             :     }
     409        3183 :     PyMem_RawFree(wbuffer);
     410        3183 :     return r;
     411             : }
     412             : 
     413             : 
     414             : static PyObject *
     415        3209 : getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args)
     416             : {
     417             :     PyObject *pathobj;
     418        3209 :     if (!PyArg_ParseTuple(args, "U", &pathobj)) {
     419           0 :         return NULL;
     420             :     }
     421             : #if defined(HAVE_READLINK)
     422             :     /* This readlink calculation only resolves a symlinked file, and
     423             :        does not resolve any path segments. This is consistent with
     424             :        prior releases, however, the realpath implementation below is
     425             :        potentially correct in more cases. */
     426        3209 :     PyObject *r = NULL;
     427        3209 :     int nlink = 0;
     428        3209 :     wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
     429        3209 :     if (!path) {
     430           0 :         goto done;
     431             :     }
     432        3209 :     wchar_t *path2 = _PyMem_RawWcsdup(path);
     433        3209 :     PyMem_Free((void *)path);
     434        3209 :     path = path2;
     435        3242 :     while (path) {
     436             :         wchar_t resolved[MAXPATHLEN + 1];
     437        3242 :         int linklen = _Py_wreadlink(path, resolved, Py_ARRAY_LENGTH(resolved));
     438        3242 :         if (linklen == -1) {
     439        3209 :             r = PyUnicode_FromWideChar(path, -1);
     440        3209 :             break;
     441             :         }
     442          33 :         if (_Py_isabs(resolved)) {
     443          31 :             PyMem_RawFree((void *)path);
     444          31 :             path = _PyMem_RawWcsdup(resolved);
     445             :         } else {
     446           2 :             wchar_t *s = wcsrchr(path, SEP);
     447           2 :             if (s) {
     448           2 :                 *s = L'\0';
     449             :             }
     450           2 :             path2 = _Py_normpath(_Py_join_relfile(path, resolved), -1);
     451           2 :             PyMem_RawFree((void *)path);
     452           2 :             path = path2;
     453             :         }
     454          33 :         nlink++;
     455             :         /* 40 is the Linux kernel 4.2 limit */
     456          33 :         if (nlink >= 40) {
     457           0 :             PyErr_SetString(PyExc_OSError, "maximum number of symbolic links reached");
     458           0 :             break;
     459             :         }
     460             :     }
     461        3209 :     if (!path) {
     462           0 :         PyErr_NoMemory();
     463             :     }
     464        3209 : done:
     465        3209 :     PyMem_RawFree((void *)path);
     466        3209 :     return r;
     467             : 
     468             : #elif defined(HAVE_REALPATH)
     469             :     PyObject *r = NULL;
     470             :     struct stat st;
     471             :     const char *narrow = NULL;
     472             :     wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
     473             :     if (!path) {
     474             :         goto done;
     475             :     }
     476             :     narrow = Py_EncodeLocale(path, NULL);
     477             :     if (!narrow) {
     478             :         PyErr_NoMemory();
     479             :         goto done;
     480             :     }
     481             :     if (lstat(narrow, &st)) {
     482             :         PyErr_SetFromErrno(PyExc_OSError);
     483             :         goto done;
     484             :     }
     485             :     if (!S_ISLNK(st.st_mode)) {
     486             :         Py_INCREF(pathobj);
     487             :         r = pathobj;
     488             :         goto done;
     489             :     }
     490             :     wchar_t resolved[MAXPATHLEN+1];
     491             :     if (_Py_wrealpath(path, resolved, MAXPATHLEN) == NULL) {
     492             :         PyErr_SetFromErrno(PyExc_OSError);
     493             :     } else {
     494             :         r = PyUnicode_FromWideChar(resolved, -1);
     495             :     }
     496             : done:
     497             :     PyMem_Free((void *)path);
     498             :     PyMem_Free((void *)narrow);
     499             :     return r;
     500             : #endif
     501             : 
     502             :     Py_INCREF(pathobj);
     503             :     return pathobj;
     504             : }
     505             : 
     506             : 
     507             : static PyMethodDef getpath_methods[] = {
     508             :     {"abspath", getpath_abspath, METH_VARARGS, NULL},
     509             :     {"basename", getpath_basename, METH_VARARGS, NULL},
     510             :     {"dirname", getpath_dirname, METH_VARARGS, NULL},
     511             :     {"hassuffix", getpath_hassuffix, METH_VARARGS, NULL},
     512             :     {"isabs", getpath_isabs, METH_VARARGS, NULL},
     513             :     {"isdir", getpath_isdir, METH_VARARGS, NULL},
     514             :     {"isfile", getpath_isfile, METH_VARARGS, NULL},
     515             :     {"isxfile", getpath_isxfile, METH_VARARGS, NULL},
     516             :     {"joinpath", getpath_joinpath, METH_VARARGS, NULL},
     517             :     {"readlines", getpath_readlines, METH_VARARGS, NULL},
     518             :     {"realpath", getpath_realpath, METH_VARARGS, NULL},
     519             :     {NULL, NULL, 0, NULL}
     520             : };
     521             : 
     522             : 
     523             : /* Two implementations of warn() to use depending on whether warnings
     524             :    are enabled or not. */
     525             : 
     526             : static PyObject *
     527           2 : getpath_warn(PyObject *Py_UNUSED(self), PyObject *args)
     528             : {
     529             :     PyObject *msgobj;
     530           2 :     if (!PyArg_ParseTuple(args, "U", &msgobj)) {
     531           0 :         return NULL;
     532             :     }
     533           2 :     fprintf(stderr, "%s\n", PyUnicode_AsUTF8(msgobj));
     534           2 :     Py_RETURN_NONE;
     535             : }
     536             : 
     537             : 
     538             : static PyObject *
     539           0 : getpath_nowarn(PyObject *Py_UNUSED(self), PyObject *args)
     540             : {
     541           0 :     Py_RETURN_NONE;
     542             : }
     543             : 
     544             : 
     545             : static PyMethodDef getpath_warn_method = {"warn", getpath_warn, METH_VARARGS, NULL};
     546             : static PyMethodDef getpath_nowarn_method = {"warn", getpath_nowarn, METH_VARARGS, NULL};
     547             : 
     548             : /* Add the helper functions to the dict */
     549             : static int
     550        3172 : funcs_to_dict(PyObject *dict, int warnings)
     551             : {
     552       38064 :     for (PyMethodDef *m = getpath_methods; m->ml_name; ++m) {
     553       34892 :         PyObject *f = PyCFunction_NewEx(m, NULL, NULL);
     554       34892 :         if (!f) {
     555           0 :             return 0;
     556             :         }
     557       34892 :         if (PyDict_SetItemString(dict, m->ml_name, f) < 0) {
     558           0 :             Py_DECREF(f);
     559           0 :             return 0;
     560             :         }
     561       34892 :         Py_DECREF(f);
     562             :     }
     563        3172 :     PyMethodDef *m2 = warnings ? &getpath_warn_method : &getpath_nowarn_method;
     564        3172 :     PyObject *f = PyCFunction_NewEx(m2, NULL, NULL);
     565        3172 :     if (!f) {
     566           0 :         return 0;
     567             :     }
     568        3172 :     if (PyDict_SetItemString(dict, m2->ml_name, f) < 0) {
     569           0 :         Py_DECREF(f);
     570           0 :         return 0;
     571             :     }
     572        3172 :     Py_DECREF(f);
     573        3172 :     return 1;
     574             : }
     575             : 
     576             : 
     577             : /* Add a wide-character string constant to the dict */
     578             : static int
     579        9516 : wchar_to_dict(PyObject *dict, const char *key, const wchar_t *s)
     580             : {
     581             :     PyObject *u;
     582             :     int r;
     583        9516 :     if (s && s[0]) {
     584           2 :         u = PyUnicode_FromWideChar(s, -1);
     585           2 :         if (!u) {
     586           0 :             return 0;
     587             :         }
     588             :     } else {
     589        9514 :         u = Py_None;
     590        9514 :         Py_INCREF(u);
     591             :     }
     592        9516 :     r = PyDict_SetItemString(dict, key, u) == 0;
     593        9516 :     Py_DECREF(u);
     594        9516 :     return r;
     595             : }
     596             : 
     597             : 
     598             : /* Add a narrow string constant to the dict, using default locale decoding */
     599             : static int
     600       25376 : decode_to_dict(PyObject *dict, const char *key, const char *s)
     601             : {
     602       25376 :     PyObject *u = NULL;
     603             :     int r;
     604       38064 :     if (s && s[0]) {
     605             :         size_t len;
     606       12688 :         const wchar_t *w = Py_DecodeLocale(s, &len);
     607       12688 :         if (w) {
     608       12688 :             u = PyUnicode_FromWideChar(w, len);
     609       12688 :             PyMem_RawFree((void *)w);
     610             :         }
     611       12688 :         if (!u) {
     612           0 :             return 0;
     613             :         }
     614             :     } else {
     615       12688 :         u = Py_None;
     616       12688 :         Py_INCREF(u);
     617             :     }
     618       25376 :     r = PyDict_SetItemString(dict, key, u) == 0;
     619       25376 :     Py_DECREF(u);
     620       25376 :     return r;
     621             : }
     622             : 
     623             : /* Add an environment variable to the dict, optionally clearing it afterwards */
     624             : static int
     625       12688 : env_to_dict(PyObject *dict, const char *key, int and_clear)
     626             : {
     627       12688 :     PyObject *u = NULL;
     628       12688 :     int r = 0;
     629       12688 :     assert(strncmp(key, "ENV_", 4) == 0);
     630       12688 :     assert(strlen(key) < 64);
     631             : #ifdef MS_WINDOWS
     632             :     wchar_t wkey[64];
     633             :     // Quick convert to wchar_t, since we know key is ASCII
     634             :     wchar_t *wp = wkey;
     635             :     for (const char *p = &key[4]; *p; ++p) {
     636             :         assert(*p < 128);
     637             :         *wp++ = *p;
     638             :     }
     639             :     *wp = L'\0';
     640             :     const wchar_t *v = _wgetenv(wkey);
     641             :     if (v) {
     642             :         u = PyUnicode_FromWideChar(v, -1);
     643             :         if (!u) {
     644             :             PyErr_Clear();
     645             :         }
     646             :     }
     647             : #else
     648       12688 :     const char *v = getenv(&key[4]);
     649       12688 :     if (v) {
     650             :         size_t len;
     651        3170 :         const wchar_t *w = Py_DecodeLocale(v, &len);
     652        3170 :         if (w) {
     653        3170 :             u = PyUnicode_FromWideChar(w, len);
     654        3170 :             if (!u) {
     655           0 :                 PyErr_Clear();
     656             :             }
     657        3170 :             PyMem_RawFree((void *)w);
     658             :         }
     659             :     }
     660             : #endif
     661       12688 :     if (u) {
     662        3170 :         r = PyDict_SetItemString(dict, key, u) == 0;
     663        3170 :         Py_DECREF(u);
     664             :     } else {
     665        9518 :         r = PyDict_SetItemString(dict, key, Py_None) == 0;
     666             :     }
     667       12688 :     if (r && and_clear) {
     668             : #ifdef MS_WINDOWS
     669             :         _wputenv_s(wkey, L"");
     670             : #else
     671        3172 :         unsetenv(&key[4]);
     672             : #endif
     673             :     }
     674       12688 :     return r;
     675             : }
     676             : 
     677             : 
     678             : /* Add an integer constant to the dict */
     679             : static int
     680        9516 : int_to_dict(PyObject *dict, const char *key, int v)
     681             : {
     682             :     PyObject *o;
     683             :     int r;
     684        9516 :     o = PyLong_FromLong(v);
     685        9516 :     if (!o) {
     686           0 :         return 0;
     687             :     }
     688        9516 :     r = PyDict_SetItemString(dict, key, o) == 0;
     689        9516 :     Py_DECREF(o);
     690        9516 :     return r;
     691             : }
     692             : 
     693             : 
     694             : #ifdef MS_WINDOWS
     695             : static int
     696             : winmodule_to_dict(PyObject *dict, const char *key, HMODULE mod)
     697             : {
     698             :     wchar_t *buffer = NULL;
     699             :     for (DWORD cch = 256; buffer == NULL && cch < (1024 * 1024); cch *= 2) {
     700             :         buffer = (wchar_t*)PyMem_RawMalloc(cch * sizeof(wchar_t));
     701             :         if (buffer) {
     702             :             if (GetModuleFileNameW(mod, buffer, cch) == cch) {
     703             :                 PyMem_RawFree(buffer);
     704             :                 buffer = NULL;
     705             :             }
     706             :         }
     707             :     }
     708             :     int r = wchar_to_dict(dict, key, buffer);
     709             :     PyMem_RawFree(buffer);
     710             :     return r;
     711             : }
     712             : #endif
     713             : 
     714             : 
     715             : /* Add the current executable's path to the dict */
     716             : static int
     717        3172 : progname_to_dict(PyObject *dict, const char *key)
     718             : {
     719             : #ifdef MS_WINDOWS
     720             :     return winmodule_to_dict(dict, key, NULL);
     721             : #elif defined(__APPLE__)
     722             :     char *path;
     723             :     uint32_t pathLen = 256;
     724             :     while (pathLen) {
     725             :         path = PyMem_RawMalloc((pathLen + 1) * sizeof(char));
     726             :         if (!path) {
     727             :             return 0;
     728             :         }
     729             :         if (_NSGetExecutablePath(path, &pathLen) != 0) {
     730             :             PyMem_RawFree(path);
     731             :             continue;
     732             :         }
     733             :         // Only keep if the path is absolute
     734             :         if (path[0] == SEP) {
     735             :             int r = decode_to_dict(dict, key, path);
     736             :             PyMem_RawFree(path);
     737             :             return r;
     738             :         }
     739             :         // Fall back and store None
     740             :         PyMem_RawFree(path);
     741             :         break;
     742             :     }
     743             : #endif
     744        3172 :     return PyDict_SetItemString(dict, key, Py_None) == 0;
     745             : }
     746             : 
     747             : 
     748             : /* Add the runtime library's path to the dict */
     749             : static int
     750        3172 : library_to_dict(PyObject *dict, const char *key)
     751             : {
     752             : #ifdef MS_WINDOWS
     753             :     extern HMODULE PyWin_DLLhModule;
     754             :     if (PyWin_DLLhModule) {
     755             :         return winmodule_to_dict(dict, key, PyWin_DLLhModule);
     756             :     }
     757             : #elif defined(WITH_NEXT_FRAMEWORK)
     758             :     static char modPath[MAXPATHLEN + 1];
     759             :     static int modPathInitialized = -1;
     760             :     if (modPathInitialized < 0) {
     761             :         modPathInitialized = 0;
     762             : 
     763             :         /* On Mac OS X we have a special case if we're running from a framework.
     764             :            This is because the python home should be set relative to the library,
     765             :            which is in the framework, not relative to the executable, which may
     766             :            be outside of the framework. Except when we're in the build
     767             :            directory... */
     768             :         NSSymbol symbol = NSLookupAndBindSymbol("_Py_Initialize");
     769             :         if (symbol != NULL) {
     770             :             NSModule pythonModule = NSModuleForSymbol(symbol);
     771             :             if (pythonModule != NULL) {
     772             :                 /* Use dylib functions to find out where the framework was loaded from */
     773             :                 const char *path = NSLibraryNameForModule(pythonModule);
     774             :                 if (path) {
     775             :                     strncpy(modPath, path, MAXPATHLEN);
     776             :                     modPathInitialized = 1;
     777             :                 }
     778             :             }
     779             :         }
     780             :     }
     781             :     if (modPathInitialized > 0) {
     782             :         return decode_to_dict(dict, key, modPath);
     783             :     }
     784             : #endif
     785        3172 :     return PyDict_SetItemString(dict, key, Py_None) == 0;
     786             : }
     787             : 
     788             : 
     789             : PyObject *
     790        3172 : _Py_Get_Getpath_CodeObject(void)
     791             : {
     792        3172 :     return PyMarshal_ReadObjectFromString(
     793             :         (const char*)_Py_M__getpath, sizeof(_Py_M__getpath));
     794             : }
     795             : 
     796             : 
     797             : /* Perform the actual path calculation.
     798             : 
     799             :    When compute_path_config is 0, this only reads any initialised path
     800             :    config values into the PyConfig struct. For example, Py_SetHome() or
     801             :    Py_SetPath(). The only error should be due to failed memory allocation.
     802             : 
     803             :    When compute_path_config is 1, full path calculation is performed.
     804             :    The GIL must be held, and there may be filesystem access, side
     805             :    effects, and potential unraisable errors that are reported directly
     806             :    to stderr.
     807             : 
     808             :    Calling this function multiple times on the same PyConfig is only
     809             :    safe because already-configured values are not recalculated. To
     810             :    actually recalculate paths, you need a clean PyConfig.
     811             : */
     812             : PyStatus
     813        6155 : _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
     814             : {
     815        6155 :     PyStatus status = _PyPathConfig_ReadGlobal(config);
     816             : 
     817        6155 :     if (_PyStatus_EXCEPTION(status) || !compute_path_config) {
     818        2983 :         return status;
     819             :     }
     820             : 
     821        3172 :     if (!_PyThreadState_UncheckedGet()) {
     822           0 :         return PyStatus_Error("cannot calculate path configuration without GIL");
     823             :     }
     824             : 
     825        3172 :     PyObject *configDict = _PyConfig_AsDict(config);
     826        3172 :     if (!configDict) {
     827           0 :         PyErr_Clear();
     828           0 :         return PyStatus_NoMemory();
     829             :     }
     830             : 
     831        3172 :     PyObject *dict = PyDict_New();
     832        3172 :     if (!dict) {
     833           0 :         PyErr_Clear();
     834           0 :         Py_DECREF(configDict);
     835           0 :         return PyStatus_NoMemory();
     836             :     }
     837             : 
     838        3172 :     if (PyDict_SetItemString(dict, "config", configDict) < 0) {
     839           0 :         PyErr_Clear();
     840           0 :         Py_DECREF(configDict);
     841           0 :         Py_DECREF(dict);
     842           0 :         return PyStatus_NoMemory();
     843             :     }
     844             :     /* reference now held by dict */
     845        3172 :     Py_DECREF(configDict);
     846             : 
     847        3172 :     PyObject *co = _Py_Get_Getpath_CodeObject();
     848        3172 :     if (!co || !PyCode_Check(co)) {
     849           0 :         PyErr_Clear();
     850           0 :         Py_XDECREF(co);
     851           0 :         Py_DECREF(dict);
     852           0 :         return PyStatus_Error("error reading frozen getpath.py");
     853             :     }
     854             : 
     855             : #ifdef MS_WINDOWS
     856             :     PyObject *winreg = PyImport_ImportModule("winreg");
     857             :     if (!winreg || PyDict_SetItemString(dict, "winreg", winreg) < 0) {
     858             :         PyErr_Clear();
     859             :         Py_XDECREF(winreg);
     860             :         if (PyDict_SetItemString(dict, "winreg", Py_None) < 0) {
     861             :             PyErr_Clear();
     862             :             Py_DECREF(co);
     863             :             Py_DECREF(dict);
     864             :             return PyStatus_Error("error importing winreg module");
     865             :         }
     866             :     } else {
     867             :         Py_DECREF(winreg);
     868             :     }
     869             : #endif
     870             : 
     871        3172 :     if (
     872             : #ifdef MS_WINDOWS
     873             :         !decode_to_dict(dict, "os_name", "nt") ||
     874             : #elif defined(__APPLE__)
     875             :         !decode_to_dict(dict, "os_name", "darwin") ||
     876             : #else
     877        6344 :         !decode_to_dict(dict, "os_name", "posix") ||
     878             : #endif
     879             : #ifdef WITH_NEXT_FRAMEWORK
     880             :         !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 1) ||
     881             : #else
     882        6344 :         !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 0) ||
     883             : #endif
     884        6344 :         !decode_to_dict(dict, "PREFIX", PREFIX) ||
     885        6344 :         !decode_to_dict(dict, "EXEC_PREFIX", EXEC_PREFIX) ||
     886        6344 :         !decode_to_dict(dict, "PYTHONPATH", PYTHONPATH) ||
     887        6344 :         !decode_to_dict(dict, "VPATH", VPATH) ||
     888        6344 :         !decode_to_dict(dict, "PLATLIBDIR", PLATLIBDIR) ||
     889        6344 :         !decode_to_dict(dict, "PYDEBUGEXT", PYDEBUGEXT) ||
     890        6344 :         !int_to_dict(dict, "VERSION_MAJOR", PY_MAJOR_VERSION) ||
     891        6344 :         !int_to_dict(dict, "VERSION_MINOR", PY_MINOR_VERSION) ||
     892        6344 :         !decode_to_dict(dict, "PYWINVER", PYWINVER) ||
     893        6344 :         !wchar_to_dict(dict, "EXE_SUFFIX", EXE_SUFFIX) ||
     894        6344 :         !env_to_dict(dict, "ENV_PATH", 0) ||
     895        6344 :         !env_to_dict(dict, "ENV_PYTHONHOME", 0) ||
     896        6344 :         !env_to_dict(dict, "ENV_PYTHONEXECUTABLE", 0) ||
     897        6344 :         !env_to_dict(dict, "ENV___PYVENV_LAUNCHER__", 1) ||
     898        6344 :         !progname_to_dict(dict, "real_executable") ||
     899        6344 :         !library_to_dict(dict, "library") ||
     900        6344 :         !wchar_to_dict(dict, "executable_dir", NULL) ||
     901        6344 :         !wchar_to_dict(dict, "py_setpath", _PyPathConfig_GetGlobalModuleSearchPath()) ||
     902        6344 :         !funcs_to_dict(dict, config->pathconfig_warnings) ||
     903             : #ifndef MS_WINDOWS
     904        6344 :         PyDict_SetItemString(dict, "winreg", Py_None) < 0 ||
     905             : #endif
     906        3172 :         PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0
     907             :     ) {
     908           0 :         Py_DECREF(co);
     909           0 :         Py_DECREF(dict);
     910           0 :         _PyErr_WriteUnraisableMsg("error evaluating initial values", NULL);
     911           0 :         return PyStatus_Error("error evaluating initial values");
     912             :     }
     913             : 
     914        3172 :     PyObject *r = PyEval_EvalCode(co, dict, dict);
     915        3172 :     Py_DECREF(co);
     916             : 
     917        3172 :     if (!r) {
     918           0 :         Py_DECREF(dict);
     919           0 :         _PyErr_WriteUnraisableMsg("error evaluating path", NULL);
     920           0 :         return PyStatus_Error("error evaluating path");
     921             :     }
     922        3172 :     Py_DECREF(r);
     923             : 
     924             : #if 0
     925             :     PyObject *it = PyObject_GetIter(configDict);
     926             :     for (PyObject *k = PyIter_Next(it); k; k = PyIter_Next(it)) {
     927             :         if (!strcmp("__builtins__", PyUnicode_AsUTF8(k))) {
     928             :             Py_DECREF(k);
     929             :             continue;
     930             :         }
     931             :         fprintf(stderr, "%s = ", PyUnicode_AsUTF8(k));
     932             :         PyObject *o = PyDict_GetItem(configDict, k);
     933             :         o = PyObject_Repr(o);
     934             :         fprintf(stderr, "%s\n", PyUnicode_AsUTF8(o));
     935             :         Py_DECREF(o);
     936             :         Py_DECREF(k);
     937             :     }
     938             :     Py_DECREF(it);
     939             : #endif
     940             : 
     941        3172 :     if (_PyConfig_FromDict(config, configDict) < 0) {
     942           0 :         _PyErr_WriteUnraisableMsg("reading getpath results", NULL);
     943           0 :         Py_DECREF(dict);
     944           0 :         return PyStatus_Error("error getting getpath results");
     945             :     }
     946             : 
     947        3172 :     Py_DECREF(dict);
     948             : 
     949        3172 :     return _PyStatus_OK();
     950             : }
     951             : 

Generated by: LCOV version 1.14