(root)/
Python-3.11.7/
Python/
pathconfig.c
       1  /* Path configuration like module_search_path (sys.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  #ifdef MS_WINDOWS
      12  #  include <windows.h>            // GetFullPathNameW(), MAX_PATH
      13  #  include <pathcch.h>
      14  #  include <shlwapi.h>
      15  #endif
      16  
      17  #ifdef __cplusplus
      18  extern "C" {
      19  #endif
      20  
      21  
      22  /* External interface */
      23  
      24  /* Stored values set by C API functions */
      25  typedef struct _PyPathConfig {
      26      /* Full path to the Python program */
      27      wchar_t *program_full_path;
      28      wchar_t *prefix;
      29      wchar_t *exec_prefix;
      30      wchar_t *stdlib_dir;
      31      /* Set by Py_SetPath */
      32      wchar_t *module_search_path;
      33      /* Set by _PyPathConfig_UpdateGlobal */
      34      wchar_t *calculated_module_search_path;
      35      /* Python program name */
      36      wchar_t *program_name;
      37      /* Set by Py_SetPythonHome() or PYTHONHOME environment variable */
      38      wchar_t *home;
      39      int _is_python_build;
      40  } _PyPathConfig;
      41  
      42  #  define _PyPathConfig_INIT \
      43        {.module_search_path = NULL, ._is_python_build = 0}
      44  
      45  
      46  _PyPathConfig _Py_path_config = _PyPathConfig_INIT;
      47  
      48  
      49  const wchar_t *
      50  _PyPathConfig_GetGlobalModuleSearchPath(void)
      51  {
      52      return _Py_path_config.module_search_path;
      53  }
      54  
      55  
      56  void
      57  _PyPathConfig_ClearGlobal(void)
      58  {
      59      PyMemAllocatorEx old_alloc;
      60      _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
      61  
      62  #define CLEAR(ATTR) \
      63      do { \
      64          PyMem_RawFree(_Py_path_config.ATTR); \
      65          _Py_path_config.ATTR = NULL; \
      66      } while (0)
      67  
      68      CLEAR(program_full_path);
      69      CLEAR(prefix);
      70      CLEAR(exec_prefix);
      71      CLEAR(stdlib_dir);
      72      CLEAR(module_search_path);
      73      CLEAR(calculated_module_search_path);
      74      CLEAR(program_name);
      75      CLEAR(home);
      76      _Py_path_config._is_python_build = 0;
      77  
      78  #undef CLEAR
      79  
      80      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
      81  }
      82  
      83  PyStatus
      84  _PyPathConfig_ReadGlobal(PyConfig *config)
      85  {
      86      PyStatus status = _PyStatus_OK();
      87  
      88  #define COPY(ATTR) \
      89      do { \
      90          if (_Py_path_config.ATTR && !config->ATTR) { \
      91              status = PyConfig_SetString(config, &config->ATTR, _Py_path_config.ATTR); \
      92              if (_PyStatus_EXCEPTION(status)) goto done; \
      93          } \
      94      } while (0)
      95  
      96  #define COPY2(ATTR, SRCATTR) \
      97      do { \
      98          if (_Py_path_config.SRCATTR && !config->ATTR) { \
      99              status = PyConfig_SetString(config, &config->ATTR, _Py_path_config.SRCATTR); \
     100              if (_PyStatus_EXCEPTION(status)) goto done; \
     101          } \
     102      } while (0)
     103  
     104  #define COPY_INT(ATTR) \
     105      do { \
     106          assert(_Py_path_config.ATTR >= 0); \
     107          if ((_Py_path_config.ATTR >= 0) && (config->ATTR <= 0)) { \
     108              config->ATTR = _Py_path_config.ATTR; \
     109          } \
     110      } while (0)
     111  
     112      COPY(prefix);
     113      COPY(exec_prefix);
     114      COPY(stdlib_dir);
     115      COPY(program_name);
     116      COPY(home);
     117      COPY2(executable, program_full_path);
     118      COPY_INT(_is_python_build);
     119      // module_search_path must be initialised - not read
     120  #undef COPY
     121  #undef COPY2
     122  #undef COPY_INT
     123  
     124  done:
     125      return status;
     126  }
     127  
     128  PyStatus
     129  _PyPathConfig_UpdateGlobal(const PyConfig *config)
     130  {
     131      PyMemAllocatorEx old_alloc;
     132      _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     133  
     134  #define COPY(ATTR) \
     135      do { \
     136          if (config->ATTR) { \
     137              PyMem_RawFree(_Py_path_config.ATTR); \
     138              _Py_path_config.ATTR = _PyMem_RawWcsdup(config->ATTR); \
     139              if (!_Py_path_config.ATTR) goto error; \
     140          } \
     141      } while (0)
     142  
     143  #define COPY2(ATTR, SRCATTR) \
     144      do { \
     145          if (config->SRCATTR) { \
     146              PyMem_RawFree(_Py_path_config.ATTR); \
     147              _Py_path_config.ATTR = _PyMem_RawWcsdup(config->SRCATTR); \
     148              if (!_Py_path_config.ATTR) goto error; \
     149          } \
     150      } while (0)
     151  
     152  #define COPY_INT(ATTR) \
     153      do { \
     154          if (config->ATTR > 0) { \
     155              _Py_path_config.ATTR = config->ATTR; \
     156          } \
     157      } while (0)
     158  
     159      COPY(prefix);
     160      COPY(exec_prefix);
     161      COPY(stdlib_dir);
     162      COPY(program_name);
     163      COPY(home);
     164      COPY2(program_full_path, executable);
     165      COPY_INT(_is_python_build);
     166  #undef COPY
     167  #undef COPY2
     168  #undef COPY_INT
     169  
     170      PyMem_RawFree(_Py_path_config.module_search_path);
     171      _Py_path_config.module_search_path = NULL;
     172      PyMem_RawFree(_Py_path_config.calculated_module_search_path);
     173      _Py_path_config.calculated_module_search_path = NULL;
     174  
     175      do {
     176          size_t cch = 1;
     177          for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i) {
     178              cch += 1 + wcslen(config->module_search_paths.items[i]);
     179          }
     180  
     181          wchar_t *path = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t) * cch);
     182          if (!path) {
     183              goto error;
     184          }
     185          wchar_t *p = path;
     186          for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i) {
     187              wcscpy(p, config->module_search_paths.items[i]);
     188              p = wcschr(p, L'\0');
     189              *p++ = DELIM;
     190              *p = L'\0';
     191          }
     192  
     193          do {
     194              *p = L'\0';
     195          } while (p != path && *--p == DELIM);
     196          _Py_path_config.calculated_module_search_path = path;
     197      } while (0);
     198  
     199      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     200      return _PyStatus_OK();
     201  
     202  error:
     203      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     204      return _PyStatus_NO_MEMORY();
     205  }
     206  
     207  
     208  static void _Py_NO_RETURN
     209  path_out_of_memory(const char *func)
     210  {
     211      _Py_FatalErrorFunc(func, "out of memory");
     212  }
     213  
     214  void
     215  Py_SetPath(const wchar_t *path)
     216  {
     217      if (path == NULL) {
     218          _PyPathConfig_ClearGlobal();
     219          return;
     220      }
     221  
     222      PyMemAllocatorEx old_alloc;
     223      _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     224  
     225      PyMem_RawFree(_Py_path_config.prefix);
     226      PyMem_RawFree(_Py_path_config.exec_prefix);
     227      PyMem_RawFree(_Py_path_config.stdlib_dir);
     228      PyMem_RawFree(_Py_path_config.module_search_path);
     229      PyMem_RawFree(_Py_path_config.calculated_module_search_path);
     230  
     231      _Py_path_config.prefix = _PyMem_RawWcsdup(L"");
     232      _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L"");
     233      // XXX Copy this from the new module_search_path?
     234      if (_Py_path_config.home != NULL) {
     235          _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(_Py_path_config.home);
     236      }
     237      else {
     238          _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(L"");
     239      }
     240      _Py_path_config.module_search_path = _PyMem_RawWcsdup(path);
     241      _Py_path_config.calculated_module_search_path = NULL;
     242  
     243      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     244  
     245      if (_Py_path_config.prefix == NULL
     246          || _Py_path_config.exec_prefix == NULL
     247          || _Py_path_config.stdlib_dir == NULL
     248          || _Py_path_config.module_search_path == NULL)
     249      {
     250          path_out_of_memory(__func__);
     251      }
     252  }
     253  
     254  
     255  void
     256  Py_SetPythonHome(const wchar_t *home)
     257  {
     258      int has_value = home && home[0];
     259  
     260      PyMemAllocatorEx old_alloc;
     261      _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     262  
     263      PyMem_RawFree(_Py_path_config.home);
     264      _Py_path_config.home = NULL;
     265  
     266      if (has_value) {
     267          _Py_path_config.home = _PyMem_RawWcsdup(home);
     268      }
     269  
     270      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     271  
     272      if (has_value && _Py_path_config.home == NULL) {
     273          path_out_of_memory(__func__);
     274      }
     275  }
     276  
     277  
     278  void
     279  Py_SetProgramName(const wchar_t *program_name)
     280  {
     281      int has_value = program_name && program_name[0];
     282  
     283      PyMemAllocatorEx old_alloc;
     284      _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     285  
     286      PyMem_RawFree(_Py_path_config.program_name);
     287      _Py_path_config.program_name = NULL;
     288  
     289      if (has_value) {
     290          _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
     291      }
     292  
     293      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     294  
     295      if (has_value && _Py_path_config.program_name == NULL) {
     296          path_out_of_memory(__func__);
     297      }
     298  }
     299  
     300  void
     301  _Py_SetProgramFullPath(const wchar_t *program_full_path)
     302  {
     303      int has_value = program_full_path && program_full_path[0];
     304  
     305      PyMemAllocatorEx old_alloc;
     306      _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     307  
     308      PyMem_RawFree(_Py_path_config.program_full_path);
     309      _Py_path_config.program_full_path = NULL;
     310  
     311      if (has_value) {
     312          _Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path);
     313      }
     314  
     315      PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     316  
     317      if (has_value && _Py_path_config.program_full_path == NULL) {
     318          path_out_of_memory(__func__);
     319      }
     320  }
     321  
     322  
     323  wchar_t *
     324  Py_GetPath(void)
     325  {
     326      /* If the user has provided a path, return that */
     327      if (_Py_path_config.module_search_path) {
     328          return _Py_path_config.module_search_path;
     329      }
     330      /* If we have already done calculations, return the calculated path */
     331      return _Py_path_config.calculated_module_search_path;
     332  }
     333  
     334  
     335  wchar_t *
     336  _Py_GetStdlibDir(void)
     337  {
     338      wchar_t *stdlib_dir = _Py_path_config.stdlib_dir;
     339      if (stdlib_dir != NULL && stdlib_dir[0] != L'\0') {
     340          return stdlib_dir;
     341      }
     342      return NULL;
     343  }
     344  
     345  
     346  wchar_t *
     347  Py_GetPrefix(void)
     348  {
     349      return _Py_path_config.prefix;
     350  }
     351  
     352  
     353  wchar_t *
     354  Py_GetExecPrefix(void)
     355  {
     356      return _Py_path_config.exec_prefix;
     357  }
     358  
     359  
     360  wchar_t *
     361  Py_GetProgramFullPath(void)
     362  {
     363      return _Py_path_config.program_full_path;
     364  }
     365  
     366  
     367  wchar_t*
     368  Py_GetPythonHome(void)
     369  {
     370      return _Py_path_config.home;
     371  }
     372  
     373  
     374  wchar_t *
     375  Py_GetProgramName(void)
     376  {
     377      return _Py_path_config.program_name;
     378  }
     379  
     380  
     381  
     382  /* Compute module search path from argv[0] or the current working
     383     directory ("-m module" case) which will be prepended to sys.argv:
     384     sys.path[0].
     385  
     386     Return 1 if the path is correctly resolved and written into *path0_p.
     387  
     388     Return 0 if it fails to resolve the full path. For example, return 0 if the
     389     current working directory has been removed (bpo-36236) or if argv is empty.
     390  
     391     Raise an exception and return -1 on error.
     392     */
     393  int
     394  _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p)
     395  {
     396      assert(_PyWideStringList_CheckConsistency(argv));
     397  
     398      if (argv->length == 0) {
     399          /* Leave sys.path unchanged if sys.argv is empty */
     400          return 0;
     401      }
     402  
     403      wchar_t *argv0 = argv->items[0];
     404      int have_module_arg = (wcscmp(argv0, L"-m") == 0);
     405      int have_script_arg = (!have_module_arg && (wcscmp(argv0, L"-c") != 0));
     406  
     407      wchar_t *path0 = argv0;
     408      Py_ssize_t n = 0;
     409  
     410  #ifdef HAVE_REALPATH
     411      wchar_t fullpath[MAXPATHLEN];
     412  #elif defined(MS_WINDOWS)
     413      wchar_t fullpath[MAX_PATH];
     414  #endif
     415  
     416      if (have_module_arg) {
     417  #if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
     418          if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) {
     419              return 0;
     420          }
     421          path0 = fullpath;
     422  #else
     423          path0 = L".";
     424  #endif
     425          n = wcslen(path0);
     426      }
     427  
     428  #ifdef HAVE_READLINK
     429      wchar_t link[MAXPATHLEN + 1];
     430      int nr = 0;
     431      wchar_t path0copy[2 * MAXPATHLEN + 1];
     432  
     433      if (have_script_arg) {
     434          nr = _Py_wreadlink(path0, link, Py_ARRAY_LENGTH(link));
     435      }
     436      if (nr > 0) {
     437          /* It's a symlink */
     438          link[nr] = '\0';
     439          if (link[0] == SEP) {
     440              path0 = link; /* Link to absolute path */
     441          }
     442          else if (wcschr(link, SEP) == NULL) {
     443              /* Link without path */
     444          }
     445          else {
     446              /* Must join(dirname(path0), link) */
     447              wchar_t *q = wcsrchr(path0, SEP);
     448              if (q == NULL) {
     449                  /* path0 without path */
     450                  path0 = link;
     451              }
     452              else {
     453                  /* Must make a copy, path0copy has room for 2 * MAXPATHLEN */
     454                  wcsncpy(path0copy, path0, MAXPATHLEN);
     455                  q = wcsrchr(path0copy, SEP);
     456                  wcsncpy(q+1, link, MAXPATHLEN);
     457                  q[MAXPATHLEN + 1] = L'\0';
     458                  path0 = path0copy;
     459              }
     460          }
     461      }
     462  #endif /* HAVE_READLINK */
     463  
     464      wchar_t *p = NULL;
     465  
     466  #if SEP == '\\'
     467      /* Special case for Microsoft filename syntax */
     468      if (have_script_arg) {
     469          wchar_t *q;
     470  #if defined(MS_WINDOWS)
     471          /* Replace the first element in argv with the full path. */
     472          wchar_t *ptemp;
     473          if (GetFullPathNameW(path0,
     474                             Py_ARRAY_LENGTH(fullpath),
     475                             fullpath,
     476                             &ptemp)) {
     477              path0 = fullpath;
     478          }
     479  #endif
     480          p = wcsrchr(path0, SEP);
     481          /* Test for alternate separator */
     482          q = wcsrchr(p ? p : path0, '/');
     483          if (q != NULL)
     484              p = q;
     485          if (p != NULL) {
     486              n = p + 1 - path0;
     487              if (n > 1 && p[-1] != ':')
     488                  n--; /* Drop trailing separator */
     489          }
     490      }
     491  #else
     492      /* All other filename syntaxes */
     493      if (have_script_arg) {
     494  #if defined(HAVE_REALPATH)
     495          if (_Py_wrealpath(path0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
     496              path0 = fullpath;
     497          }
     498  #endif
     499          p = wcsrchr(path0, SEP);
     500      }
     501      if (p != NULL) {
     502          n = p + 1 - path0;
     503  #if SEP == '/' /* Special case for Unix filename syntax */
     504          if (n > 1) {
     505              /* Drop trailing separator */
     506              n--;
     507          }
     508  #endif /* Unix */
     509      }
     510  #endif /* All others */
     511  
     512      PyObject *path0_obj = PyUnicode_FromWideChar(path0, n);
     513      if (path0_obj == NULL) {
     514          return -1;
     515      }
     516  
     517      *path0_p = path0_obj;
     518      return 1;
     519  }
     520  
     521  
     522  #ifdef __cplusplus
     523  }
     524  #endif