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