LCOV - code coverage report
Current view: top level - Python - pathconfig.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 139 177 78.5 %
Date: 2022-07-07 18:19:46 Functions: 15 17 88.2 %

          Line data    Source code
       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        3172 : _PyPathConfig_GetGlobalModuleSearchPath(void)
      51             : {
      52        3172 :     return _Py_path_config.module_search_path;
      53             : }
      54             : 
      55             : 
      56             : void
      57        2174 : _PyPathConfig_ClearGlobal(void)
      58             : {
      59             :     PyMemAllocatorEx old_alloc;
      60        2174 :     _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        2174 :     CLEAR(program_full_path);
      69        2174 :     CLEAR(prefix);
      70        2174 :     CLEAR(exec_prefix);
      71        2174 :     CLEAR(stdlib_dir);
      72        2174 :     CLEAR(module_search_path);
      73        2174 :     CLEAR(calculated_module_search_path);
      74        2174 :     CLEAR(program_name);
      75        2174 :     CLEAR(home);
      76        2174 :     _Py_path_config._is_python_build = 0;
      77             : 
      78             : #undef CLEAR
      79             : 
      80        2174 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
      81        2174 : }
      82             : 
      83             : PyStatus
      84        6155 : _PyPathConfig_ReadGlobal(PyConfig *config)
      85             : {
      86        6155 :     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        6155 :     COPY(prefix);
     113        6155 :     COPY(exec_prefix);
     114        6155 :     COPY(stdlib_dir);
     115        6155 :     COPY(program_name);
     116        6155 :     COPY(home);
     117        6155 :     COPY2(executable, program_full_path);
     118        6155 :     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         241 : done:
     125        6155 :     return status;
     126             : }
     127             : 
     128             : PyStatus
     129        5880 : _PyPathConfig_UpdateGlobal(const PyConfig *config)
     130             : {
     131             :     PyMemAllocatorEx old_alloc;
     132        5880 :     _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        5880 :     COPY(prefix);
     160        5880 :     COPY(exec_prefix);
     161        5880 :     COPY(stdlib_dir);
     162        5880 :     COPY(program_name);
     163        5880 :     COPY(home);
     164        5880 :     COPY2(program_full_path, executable);
     165        5880 :     COPY_INT(_is_python_build);
     166             : #undef COPY
     167             : #undef COPY2
     168             : #undef COPY_INT
     169             : 
     170        5880 :     PyMem_RawFree(_Py_path_config.module_search_path);
     171        5880 :     _Py_path_config.module_search_path = NULL;
     172        5880 :     PyMem_RawFree(_Py_path_config.calculated_module_search_path);
     173        5880 :     _Py_path_config.calculated_module_search_path = NULL;
     174             : 
     175             :     do {
     176        5880 :         size_t cch = 1;
     177       24394 :         for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i) {
     178       18514 :             cch += 1 + wcslen(config->module_search_paths.items[i]);
     179             :         }
     180             : 
     181        5880 :         wchar_t *path = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t) * cch);
     182        5880 :         if (!path) {
     183           0 :             goto error;
     184             :         }
     185        5880 :         wchar_t *p = path;
     186       24394 :         for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i) {
     187       18514 :             wcscpy(p, config->module_search_paths.items[i]);
     188       18514 :             p = wcschr(p, L'\0');
     189       18514 :             *p++ = DELIM;
     190       18514 :             *p = L'\0';
     191             :         }
     192             : 
     193             :         do {
     194       11757 :             *p = L'\0';
     195       11757 :         } while (p != path && *--p == DELIM);
     196        5880 :         _Py_path_config.calculated_module_search_path = path;
     197             :     } while (0);
     198             : 
     199        5880 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     200        5880 :     return _PyStatus_OK();
     201             : 
     202           0 : error:
     203           0 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     204           0 :     return _PyStatus_NO_MEMORY();
     205             : }
     206             : 
     207             : 
     208             : static void _Py_NO_RETURN
     209           0 : path_out_of_memory(const char *func)
     210             : {
     211           0 :     _Py_FatalErrorFunc(func, "out of memory");
     212             : }
     213             : 
     214             : void
     215           2 : Py_SetPath(const wchar_t *path)
     216             : {
     217           2 :     if (path == NULL) {
     218           0 :         _PyPathConfig_ClearGlobal();
     219           0 :         return;
     220             :     }
     221             : 
     222             :     PyMemAllocatorEx old_alloc;
     223           2 :     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     224             : 
     225           2 :     PyMem_RawFree(_Py_path_config.prefix);
     226           2 :     PyMem_RawFree(_Py_path_config.exec_prefix);
     227           2 :     PyMem_RawFree(_Py_path_config.stdlib_dir);
     228           2 :     PyMem_RawFree(_Py_path_config.module_search_path);
     229           2 :     PyMem_RawFree(_Py_path_config.calculated_module_search_path);
     230             : 
     231           2 :     _Py_path_config.prefix = _PyMem_RawWcsdup(L"");
     232           2 :     _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L"");
     233             :     // XXX Copy this from the new module_search_path?
     234           2 :     if (_Py_path_config.home != NULL) {
     235           0 :         _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(_Py_path_config.home);
     236             :     }
     237             :     else {
     238           2 :         _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(L"");
     239             :     }
     240           2 :     _Py_path_config.module_search_path = _PyMem_RawWcsdup(path);
     241           2 :     _Py_path_config.calculated_module_search_path = NULL;
     242             : 
     243           2 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     244             : 
     245           2 :     if (_Py_path_config.prefix == NULL
     246           2 :         || _Py_path_config.exec_prefix == NULL
     247           2 :         || _Py_path_config.stdlib_dir == NULL
     248           2 :         || _Py_path_config.module_search_path == NULL)
     249             :     {
     250           0 :         path_out_of_memory(__func__);
     251             :     }
     252             : }
     253             : 
     254             : 
     255             : void
     256           1 : Py_SetPythonHome(const wchar_t *home)
     257             : {
     258           1 :     int has_value = home && home[0];
     259             : 
     260             :     PyMemAllocatorEx old_alloc;
     261           1 :     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     262             : 
     263           1 :     PyMem_RawFree(_Py_path_config.home);
     264           1 :     if (has_value) {
     265           1 :         _Py_path_config.home = _PyMem_RawWcsdup(home);
     266             :     }
     267             : 
     268           1 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     269             : 
     270           1 :     if (has_value && _Py_path_config.home == NULL) {
     271           0 :         path_out_of_memory(__func__);
     272             :     }
     273           1 : }
     274             : 
     275             : 
     276             : void
     277           3 : Py_SetProgramName(const wchar_t *program_name)
     278             : {
     279           3 :     int has_value = program_name && program_name[0];
     280             : 
     281             :     PyMemAllocatorEx old_alloc;
     282           3 :     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     283             : 
     284           3 :     PyMem_RawFree(_Py_path_config.program_name);
     285           3 :     if (has_value) {
     286           3 :         _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
     287             :     }
     288             : 
     289           3 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     290             : 
     291           3 :     if (has_value && _Py_path_config.program_name == NULL) {
     292           0 :         path_out_of_memory(__func__);
     293             :     }
     294           3 : }
     295             : 
     296             : void
     297           0 : _Py_SetProgramFullPath(const wchar_t *program_full_path)
     298             : {
     299           0 :     int has_value = program_full_path && program_full_path[0];
     300             : 
     301             :     PyMemAllocatorEx old_alloc;
     302           0 :     _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     303             : 
     304           0 :     PyMem_RawFree(_Py_path_config.program_full_path);
     305           0 :     if (has_value) {
     306           0 :         _Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path);
     307             :     }
     308             : 
     309           0 :     PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
     310             : 
     311           0 :     if (has_value && _Py_path_config.program_full_path == NULL) {
     312           0 :         path_out_of_memory(__func__);
     313             :     }
     314           0 : }
     315             : 
     316             : 
     317             : wchar_t *
     318           1 : Py_GetPath(void)
     319             : {
     320             :     /* If the user has provided a path, return that */
     321           1 :     if (_Py_path_config.module_search_path) {
     322           0 :         return _Py_path_config.module_search_path;
     323             :     }
     324             :     /* If we have already done calculations, return the calculated path */
     325           1 :     return _Py_path_config.calculated_module_search_path;
     326             : }
     327             : 
     328             : 
     329             : wchar_t *
     330        3173 : _Py_GetStdlibDir(void)
     331             : {
     332        3173 :     wchar_t *stdlib_dir = _Py_path_config.stdlib_dir;
     333        3173 :     if (stdlib_dir != NULL && stdlib_dir[0] != L'\0') {
     334        3171 :         return stdlib_dir;
     335             :     }
     336           2 :     return NULL;
     337             : }
     338             : 
     339             : 
     340             : wchar_t *
     341           1 : Py_GetPrefix(void)
     342             : {
     343           1 :     return _Py_path_config.prefix;
     344             : }
     345             : 
     346             : 
     347             : wchar_t *
     348           1 : Py_GetExecPrefix(void)
     349             : {
     350           1 :     return _Py_path_config.exec_prefix;
     351             : }
     352             : 
     353             : 
     354             : wchar_t *
     355           1 : Py_GetProgramFullPath(void)
     356             : {
     357           1 :     return _Py_path_config.program_full_path;
     358             : }
     359             : 
     360             : 
     361             : wchar_t*
     362           1 : Py_GetPythonHome(void)
     363             : {
     364           1 :     return _Py_path_config.home;
     365             : }
     366             : 
     367             : 
     368             : wchar_t *
     369          11 : Py_GetProgramName(void)
     370             : {
     371          11 :     return _Py_path_config.program_name;
     372             : }
     373             : 
     374             : 
     375             : 
     376             : /* Compute module search path from argv[0] or the current working
     377             :    directory ("-m module" case) which will be prepended to sys.argv:
     378             :    sys.path[0].
     379             : 
     380             :    Return 1 if the path is correctly resolved and written into *path0_p.
     381             : 
     382             :    Return 0 if it fails to resolve the full path. For example, return 0 if the
     383             :    current working directory has been removed (bpo-36236) or if argv is empty.
     384             : 
     385             :    Raise an exception and return -1 on error.
     386             :    */
     387             : int
     388        2154 : _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p)
     389             : {
     390        2154 :     assert(_PyWideStringList_CheckConsistency(argv));
     391             : 
     392        2154 :     if (argv->length == 0) {
     393             :         /* Leave sys.path unchanged if sys.argv is empty */
     394           0 :         return 0;
     395             :     }
     396             : 
     397        2154 :     wchar_t *argv0 = argv->items[0];
     398        2154 :     int have_module_arg = (wcscmp(argv0, L"-m") == 0);
     399        2154 :     int have_script_arg = (!have_module_arg && (wcscmp(argv0, L"-c") != 0));
     400             : 
     401        2154 :     wchar_t *path0 = argv0;
     402        2154 :     Py_ssize_t n = 0;
     403             : 
     404             : #ifdef HAVE_REALPATH
     405             :     wchar_t fullpath[MAXPATHLEN];
     406             : #elif defined(MS_WINDOWS)
     407             :     wchar_t fullpath[MAX_PATH];
     408             : #endif
     409             : 
     410        2154 :     if (have_module_arg) {
     411             : #if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
     412         624 :         if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) {
     413           0 :             return 0;
     414             :         }
     415         624 :         path0 = fullpath;
     416             : #else
     417             :         path0 = L".";
     418             : #endif
     419         624 :         n = wcslen(path0);
     420             :     }
     421             : 
     422             : #ifdef HAVE_READLINK
     423             :     wchar_t link[MAXPATHLEN + 1];
     424        2154 :     int nr = 0;
     425             :     wchar_t path0copy[2 * MAXPATHLEN + 1];
     426             : 
     427        2154 :     if (have_script_arg) {
     428         228 :         nr = _Py_wreadlink(path0, link, Py_ARRAY_LENGTH(link));
     429             :     }
     430        2154 :     if (nr > 0) {
     431             :         /* It's a symlink */
     432           0 :         link[nr] = '\0';
     433           0 :         if (link[0] == SEP) {
     434           0 :             path0 = link; /* Link to absolute path */
     435             :         }
     436           0 :         else if (wcschr(link, SEP) == NULL) {
     437             :             /* Link without path */
     438             :         }
     439             :         else {
     440             :             /* Must join(dirname(path0), link) */
     441           0 :             wchar_t *q = wcsrchr(path0, SEP);
     442           0 :             if (q == NULL) {
     443             :                 /* path0 without path */
     444           0 :                 path0 = link;
     445             :             }
     446             :             else {
     447             :                 /* Must make a copy, path0copy has room for 2 * MAXPATHLEN */
     448           0 :                 wcsncpy(path0copy, path0, MAXPATHLEN);
     449           0 :                 q = wcsrchr(path0copy, SEP);
     450           0 :                 wcsncpy(q+1, link, MAXPATHLEN);
     451           0 :                 q[MAXPATHLEN + 1] = L'\0';
     452           0 :                 path0 = path0copy;
     453             :             }
     454             :         }
     455             :     }
     456             : #endif /* HAVE_READLINK */
     457             : 
     458        2154 :     wchar_t *p = NULL;
     459             : 
     460             : #if SEP == '\\'
     461             :     /* Special case for Microsoft filename syntax */
     462             :     if (have_script_arg) {
     463             :         wchar_t *q;
     464             : #if defined(MS_WINDOWS)
     465             :         /* Replace the first element in argv with the full path. */
     466             :         wchar_t *ptemp;
     467             :         if (GetFullPathNameW(path0,
     468             :                            Py_ARRAY_LENGTH(fullpath),
     469             :                            fullpath,
     470             :                            &ptemp)) {
     471             :             path0 = fullpath;
     472             :         }
     473             : #endif
     474             :         p = wcsrchr(path0, SEP);
     475             :         /* Test for alternate separator */
     476             :         q = wcsrchr(p ? p : path0, '/');
     477             :         if (q != NULL)
     478             :             p = q;
     479             :         if (p != NULL) {
     480             :             n = p + 1 - path0;
     481             :             if (n > 1 && p[-1] != ':')
     482             :                 n--; /* Drop trailing separator */
     483             :         }
     484             :     }
     485             : #else
     486             :     /* All other filename syntaxes */
     487        2154 :     if (have_script_arg) {
     488             : #if defined(HAVE_REALPATH)
     489         228 :         if (_Py_wrealpath(path0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
     490         208 :             path0 = fullpath;
     491             :         }
     492             : #endif
     493         228 :         p = wcsrchr(path0, SEP);
     494             :     }
     495        2154 :     if (p != NULL) {
     496         208 :         n = p + 1 - path0;
     497             : #if SEP == '/' /* Special case for Unix filename syntax */
     498         208 :         if (n > 1) {
     499             :             /* Drop trailing separator */
     500         208 :             n--;
     501             :         }
     502             : #endif /* Unix */
     503             :     }
     504             : #endif /* All others */
     505             : 
     506        2154 :     PyObject *path0_obj = PyUnicode_FromWideChar(path0, n);
     507        2154 :     if (path0_obj == NULL) {
     508           0 :         return -1;
     509             :     }
     510             : 
     511        2154 :     *path0_p = path0_obj;
     512        2154 :     return 1;
     513             : }
     514             : 
     515             : 
     516             : #ifdef __cplusplus
     517             : }
     518             : #endif

Generated by: LCOV version 1.14