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