diff options
Diffstat (limited to 'PC/getpathp.c')
-rw-r--r-- | PC/getpathp.c | 593 |
1 files changed, 385 insertions, 208 deletions
diff --git a/PC/getpathp.c b/PC/getpathp.c index 4756dc8abb..e0cb9a2575 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -116,14 +116,34 @@ #define LANDMARK L"lib\\os.py" #endif -static wchar_t prefix[MAXPATHLEN+1]; -static wchar_t progpath[MAXPATHLEN+1]; -static wchar_t dllpath[MAXPATHLEN+1]; -static wchar_t *module_search_path = NULL; +typedef struct { + wchar_t prefix[MAXPATHLEN+1]; + wchar_t progpath[MAXPATHLEN+1]; + wchar_t dllpath[MAXPATHLEN+1]; + wchar_t *module_search_path; +} PyPathConfig; + +typedef struct { + wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ + wchar_t *path_env; /* PATH environment variable */ + wchar_t *home; /* PYTHONHOME environment variable */ + + /* Registry key "Software\Python\PythonCore\PythonPath" */ + wchar_t *machine_path; /* from HKEY_LOCAL_MACHINE */ + wchar_t *user_path; /* from HKEY_CURRENT_USER */ + + wchar_t *prog; /* Program name */ + wchar_t argv0_path[MAXPATHLEN+1]; + wchar_t zip_path[MAXPATHLEN+1]; +} PyCalculatePath; + +static PyPathConfig path_config = {.module_search_path = NULL}; + +/* determine if "ch" is a separator character */ static int -is_sep(wchar_t ch) /* determine if "ch" is a separator character */ +is_sep(wchar_t ch) { #ifdef ALTSEP return ch == SEP || ch == ALTSEP; @@ -132,28 +152,31 @@ is_sep(wchar_t ch) /* determine if "ch" is a separator character */ #endif } + /* assumes 'dir' null terminated in bounds. Never writes - beyond existing terminator. -*/ + beyond existing terminator. */ static void reduce(wchar_t *dir) { size_t i = wcsnlen_s(dir, MAXPATHLEN+1); - if (i >= MAXPATHLEN+1) + if (i >= MAXPATHLEN+1) { Py_FatalError("buffer overflow in getpathp.c's reduce()"); + } while (i > 0 && !is_sep(dir[i])) --i; dir[i] = '\0'; } + static int change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) { size_t src_len = wcsnlen_s(src, MAXPATHLEN+1); size_t i = src_len; - if (i >= MAXPATHLEN+1) + if (i >= MAXPATHLEN+1) { Py_FatalError("buffer overflow in getpathp.c's reduce()"); + } while (i > 0 && src[i] != '.' && !is_sep(src[i])) --i; @@ -163,11 +186,13 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) return -1; } - if (is_sep(src[i])) + if (is_sep(src[i])) { i = src_len; + } if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) || - wcscat_s(dest, MAXPATHLEN+1, ext)) { + wcscat_s(dest, MAXPATHLEN+1, ext)) + { dest[0] = '\0'; return -1; } @@ -175,22 +200,25 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) return 0; } + static int exists(wchar_t *filename) { return GetFileAttributesW(filename) != 0xFFFFFFFF; } -/* Assumes 'filename' MAXPATHLEN+1 bytes long - - may extend 'filename' by one character. -*/ + +/* Is module -- check for .pyc too. + Assumes 'filename' MAXPATHLEN+1 bytes long - + may extend 'filename' by one character. */ static int -ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc too */ +ismodule(wchar_t *filename, int update_filename) { size_t n; - if (exists(filename)) + if (exists(filename)) { return 1; + } /* Check for the compiled version of prefix. */ n = wcsnlen_s(filename, MAXPATHLEN+1); @@ -199,13 +227,15 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc filename[n] = L'c'; filename[n + 1] = L'\0'; exist = exists(filename); - if (!update_filename) + if (!update_filename) { filename[n] = L'\0'; + } return exist; } return 0; } + /* Add a path component, by appending stuff to buffer. buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a NUL-terminated string with no more than MAXPATHLEN characters (not counting @@ -217,7 +247,9 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc */ static int _PathCchCombineEx_Initialized = 0; -typedef HRESULT(__stdcall *PPathCchCombineEx)(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore, unsigned long dwFlags); +typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut, + PCWSTR pszPathIn, PCWSTR pszMore, + unsigned long dwFlags); static PPathCchCombineEx _PathCchCombineEx; static void @@ -225,28 +257,32 @@ join(wchar_t *buffer, const wchar_t *stuff) { if (_PathCchCombineEx_Initialized == 0) { HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll"); - if (pathapi) + if (pathapi) { _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx"); - else + } + else { _PathCchCombineEx = NULL; + } _PathCchCombineEx_Initialized = 1; } if (_PathCchCombineEx) { - if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) + if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) { Py_FatalError("buffer overflow in getpathp.c's join()"); + } } else { - if (!PathCombineW(buffer, buffer, stuff)) + if (!PathCombineW(buffer, buffer, stuff)) { Py_FatalError("buffer overflow in getpathp.c's join()"); + } } } + /* gotlandmark only called by search_for_prefix, which ensures 'prefix' is null terminated in bounds. join() ensures - 'landmark' can not overflow prefix if too long. -*/ + 'landmark' can not overflow prefix if too long. */ static int -gotlandmark(const wchar_t *landmark) +gotlandmark(wchar_t *prefix, const wchar_t *landmark) { int ok; Py_ssize_t n = wcsnlen_s(prefix, MAXPATHLEN); @@ -257,27 +293,29 @@ gotlandmark(const wchar_t *landmark) return ok; } + /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd. assumption provided by only caller, calculate_path() */ static int -search_for_prefix(wchar_t *argv0_path, const wchar_t *landmark) +search_for_prefix(wchar_t *prefix, wchar_t *argv0_path, const wchar_t *landmark) { /* Search from argv0_path, until landmark is found */ wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path); do { - if (gotlandmark(landmark)) + if (gotlandmark(prefix, landmark)) { return 1; + } reduce(prefix); } while (prefix[0]); return 0; } + #ifdef Py_ENABLE_SHARED /* a string loaded from the DLL at startup.*/ extern const char *PyWin_DLLVersionString; - /* Load a PYTHONPATH value from the registry. Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER. @@ -290,7 +328,6 @@ extern const char *PyWin_DLLVersionString; work on Win16, where the buffer sizes werent available in advance. It could be simplied now Win16/Win32s is dead! */ - static wchar_t * getpythonregpath(HKEY keyBase, int skipcore) { @@ -315,7 +352,9 @@ getpythonregpath(HKEY keyBase, int skipcore) sizeof(WCHAR)*(versionLen-1) + sizeof(keySuffix); keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen); - if (keyBuf==NULL) goto done; + if (keyBuf==NULL) { + goto done; + } memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR)); keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1; @@ -329,17 +368,25 @@ getpythonregpath(HKEY keyBase, int skipcore) 0, /* reserved */ KEY_READ, &newKey); - if (rc!=ERROR_SUCCESS) goto done; + if (rc!=ERROR_SUCCESS) { + goto done; + } /* Find out how big our core buffer is, and how many subkeys we have */ rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL, NULL, NULL, &dataSize, NULL, NULL); - if (rc!=ERROR_SUCCESS) goto done; - if (skipcore) dataSize = 0; /* Only count core ones if we want them! */ + if (rc!=ERROR_SUCCESS) { + goto done; + } + if (skipcore) { + dataSize = 0; /* Only count core ones if we want them! */ + } /* Allocate a temp array of char buffers, so we only need to loop reading the registry once */ ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys ); - if (ppPaths==NULL) goto done; + if (ppPaths==NULL) { + goto done; + } memset(ppPaths, 0, sizeof(WCHAR *) * numKeys); /* Loop over all subkeys, allocating a temp sub-buffer. */ for(index=0;index<numKeys;index++) { @@ -349,14 +396,18 @@ getpythonregpath(HKEY keyBase, int skipcore) /* Get the sub-key name */ DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize, NULL, NULL, NULL, NULL ); - if (rc!=ERROR_SUCCESS) goto done; + if (rc!=ERROR_SUCCESS) { + goto done; + } /* Open the sub-key */ rc=RegOpenKeyExW(newKey, keyBuf, /* subkey */ 0, /* reserved */ KEY_READ, &subKey); - if (rc!=ERROR_SUCCESS) goto done; + if (rc!=ERROR_SUCCESS) { + goto done; + } /* Find the value of the buffer size, malloc, then read it */ RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize); if (reqdSize) { @@ -372,7 +423,9 @@ getpythonregpath(HKEY keyBase, int skipcore) } /* return null if no path to return */ - if (dataSize == 0) goto done; + if (dataSize == 0) { + goto done; + } /* original datasize from RegQueryInfo doesn't include the \0 */ dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR)); @@ -392,8 +445,9 @@ getpythonregpath(HKEY keyBase, int skipcore) dataSize -= (DWORD)len; } } - if (skipcore) + if (skipcore) { *szCur = '\0'; + } else { /* If we have no values, we don't need a ';' */ if (numKeys) { @@ -420,33 +474,34 @@ done: PyMem_RawFree(ppPaths[index]); PyMem_RawFree(ppPaths); } - if (newKey) + if (newKey) { RegCloseKey(newKey); + } PyMem_RawFree(keyBuf); return retval; } #endif /* Py_ENABLE_SHARED */ + static void -get_progpath(void) +get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath) { - extern wchar_t *Py_GetProgramName(void); - wchar_t *path = _wgetenv(L"PATH"); - wchar_t *prog = Py_GetProgramName(); + wchar_t *path = calculate->path_env; #ifdef Py_ENABLE_SHARED extern HANDLE PyWin_DLLhModule; /* static init of progpath ensures final char remains \0 */ - if (PyWin_DLLhModule) - if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) + if (PyWin_DLLhModule) { + if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) { dllpath[0] = 0; + } + } #else dllpath[0] = 0; #endif - if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) + if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) { return; - if (prog == NULL || *prog == '\0') - prog = L"python"; + } /* If there is no slash in the argv0 path, then we have to * assume python is on the user's $PATH, since there's no @@ -454,11 +509,13 @@ get_progpath(void) * $PATH isn't exported, you lose. */ #ifdef ALTSEP - if (wcschr(prog, SEP) || wcschr(prog, ALTSEP)) + if (wcschr(calculate->prog, SEP) || wcschr(calculate->prog, ALTSEP)) #else - if (wcschr(prog, SEP)) + if (wcschr(calculate->prog, SEP)) #endif - wcsncpy(progpath, prog, MAXPATHLEN); + { + wcsncpy(progpath, calculate->prog, MAXPATHLEN); + } else if (path) { while (1) { wchar_t *delim = wcschr(path, DELIM); @@ -470,13 +527,15 @@ get_progpath(void) wcsncpy(progpath, path, len); *(progpath + len) = '\0'; } - else + else { wcsncpy(progpath, path, MAXPATHLEN); + } /* join() is safe for MAXPATHLEN+1 size buffer */ - join(progpath, prog); - if (exists(progpath)) + join(progpath, calculate->prog); + if (exists(progpath)) { break; + } if (!delim) { progpath[0] = '\0'; @@ -485,10 +544,12 @@ get_progpath(void) path = delim + 1; } } - else + else { progpath[0] = '\0'; + } } + static int find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) { @@ -502,15 +563,18 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) PyObject * decoded; size_t n; - if (p == NULL) + if (p == NULL) { break; + } n = strlen(p); if (p[n - 1] != '\n') { /* line has overflowed - bail */ break; } - if (p[0] == '#') /* Comment - skip */ + if (p[0] == '#') { + /* Comment - skip */ continue; + } decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape"); if (decoded != NULL) { Py_ssize_t k; @@ -537,12 +601,14 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) return result; } -static int + +static wchar_t* read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) { FILE *sp_file = _Py_wfopen(path, L"r"); - if (sp_file == NULL) - return -1; + if (sp_file == NULL) { + return NULL; + } wcscpy_s(prefix, MAXPATHLEN+1, path); reduce(prefix); @@ -558,10 +624,12 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) while (!feof(sp_file)) { char line[MAXPATHLEN + 1]; char *p = fgets(line, MAXPATHLEN + 1, sp_file); - if (!p) + if (!p) { break; - if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') + } + if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') { continue; + } while (*++p) { if (*p == '\r' || *p == '\n') { *p = '\0'; @@ -611,126 +679,176 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) PyMem_RawFree(wline); } - module_search_path = buf; - fclose(sp_file); - return 0; + return buf; error: PyMem_RawFree(buf); fclose(sp_file); - return -1; + return NULL; } -static void -calculate_path(const _PyMainInterpreterConfig *config) +static _PyInitError +calculate_init(PyCalculatePath *calculate, + const _PyMainInterpreterConfig *main_config) { - wchar_t argv0_path[MAXPATHLEN+1]; - wchar_t *buf; - size_t bufsz; - wchar_t *pythonhome = _Py_GetPythonHomeWithConfig(config); - wchar_t *envpath = NULL; - - int skiphome, skipdefault; - wchar_t *machinepath = NULL; - wchar_t *userpath = NULL; - wchar_t zip_path[MAXPATHLEN+1]; + _PyInitError err; - if (config) { - envpath = config->module_search_path_env; + err = _Py_GetPythonHomeWithConfig(main_config, &calculate->home); + if (_Py_INIT_FAILED(err)) { + return err; + } + + if (main_config) { + calculate->module_search_path_env = main_config->module_search_path_env; } else if (!Py_IgnoreEnvironmentFlag) { - envpath = _wgetenv(L"PYTHONPATH"); - if (envpath && *envpath == '\0') - envpath = NULL; + wchar_t *path = _wgetenv(L"PYTHONPATH"); + if (path && *path != '\0') { + calculate->module_search_path_env = path; + } } - get_progpath(); - /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ - wcscpy_s(argv0_path, MAXPATHLEN+1, progpath); - reduce(argv0_path); + calculate->path_env = _wgetenv(L"PATH"); - /* Search for a sys.path file */ - { - wchar_t spbuffer[MAXPATHLEN+1]; + wchar_t *prog = Py_GetProgramName(); + if (prog == NULL || *prog == '\0') { + prog = L"python"; + } + calculate->prog = prog; - if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) || - (progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) { + return _Py_INIT_OK(); +} - if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) { - return; - } + +static int +get_pth_filename(wchar_t *spbuffer, PyPathConfig *config) +{ + if (config->dllpath[0]) { + if (!change_ext(spbuffer, config->dllpath, L"._pth") && exists(spbuffer)) { + return 1; + } + } + if (config->progpath[0]) { + if (!change_ext(spbuffer, config->progpath, L"._pth") && exists(spbuffer)) { + return 1; } } + return 0; +} - /* Search for an environment configuration file, first in the - executable's directory and then in the parent directory. - If found, open it for use when searching for prefixes. - */ - { - wchar_t envbuffer[MAXPATHLEN+1]; - wchar_t tmpbuffer[MAXPATHLEN+1]; - const wchar_t *env_cfg = L"pyvenv.cfg"; - FILE * env_file = NULL; +static int +calculate_pth_file(PyPathConfig *config) +{ + wchar_t spbuffer[MAXPATHLEN+1]; + + if (!get_pth_filename(spbuffer, config)) { + return 0; + } + + config->module_search_path = read_pth_file(spbuffer, config->prefix, + &Py_IsolatedFlag, + &Py_NoSiteFlag); + if (!config->module_search_path) { + return 0; + } + return 1; +} + + +/* Search for an environment configuration file, first in the + executable's directory and then in the parent directory. + If found, open it for use when searching for prefixes. +*/ +static void +calculate_pyvenv_file(PyCalculatePath *calculate) +{ + wchar_t envbuffer[MAXPATHLEN+1]; + const wchar_t *env_cfg = L"pyvenv.cfg"; + + wcscpy_s(envbuffer, MAXPATHLEN+1, calculate->argv0_path); + join(envbuffer, env_cfg); - wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path); + FILE *env_file = _Py_wfopen(envbuffer, L"r"); + if (env_file == NULL) { + errno = 0; + reduce(envbuffer); + reduce(envbuffer); join(envbuffer, env_cfg); env_file = _Py_wfopen(envbuffer, L"r"); if (env_file == NULL) { errno = 0; - reduce(envbuffer); - reduce(envbuffer); - join(envbuffer, env_cfg); - env_file = _Py_wfopen(envbuffer, L"r"); - if (env_file == NULL) { - errno = 0; - } - } - if (env_file != NULL) { - /* Look for a 'home' variable and set argv0_path to it, if found */ - if (find_env_config_value(env_file, L"home", tmpbuffer)) { - wcscpy_s(argv0_path, MAXPATHLEN+1, tmpbuffer); - } - fclose(env_file); - env_file = NULL; } } - /* Calculate zip archive path from DLL or exe path */ - change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip"); + if (env_file == NULL) { + return; + } - if (pythonhome == NULL || *pythonhome == '\0') { - if (zip_path[0] && exists(zip_path)) { - wcscpy_s(prefix, MAXPATHLEN+1, zip_path); - reduce(prefix); - pythonhome = prefix; - } else if (search_for_prefix(argv0_path, LANDMARK)) - pythonhome = prefix; - else - pythonhome = NULL; + /* Look for a 'home' variable and set argv0_path to it, if found */ + wchar_t tmpbuffer[MAXPATHLEN+1]; + if (find_env_config_value(env_file, L"home", tmpbuffer)) { + wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, tmpbuffer); } - else - wcscpy_s(prefix, MAXPATHLEN+1, pythonhome); + fclose(env_file); +} - skiphome = pythonhome==NULL ? 0 : 1; +static void +calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config, + const _PyMainInterpreterConfig *main_config) +{ + get_progpath(calculate, config->progpath, config->dllpath); + /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ + wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->progpath); + reduce(calculate->argv0_path); + + /* Search for a sys.path file */ + if (calculate_pth_file(config)) { + return; + } + + calculate_pyvenv_file(calculate); + + /* Calculate zip archive path from DLL or exe path */ + change_ext(calculate->zip_path, + config->dllpath[0] ? config->dllpath : config->progpath, + L".zip"); + + if (calculate->home == NULL || *calculate->home == '\0') { + if (calculate->zip_path[0] && exists(calculate->zip_path)) { + wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->zip_path); + reduce(config->prefix); + calculate->home = config->prefix; + } else if (search_for_prefix(config->prefix, calculate->argv0_path, LANDMARK)) { + calculate->home = config->prefix; + } + else { + calculate->home = NULL; + } + } + else { + wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->home); + } + + int skiphome = calculate->home==NULL ? 0 : 1; #ifdef Py_ENABLE_SHARED - machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); - userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome); + calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); + calculate->user_path = getpythonregpath(HKEY_CURRENT_USER, skiphome); #endif /* We only use the default relative PYTHONPATH if we haven't anything better to use! */ - skipdefault = envpath!=NULL || pythonhome!=NULL || \ - machinepath!=NULL || userpath!=NULL; + int skipdefault = (calculate->module_search_path_env!=NULL || calculate->home!=NULL || \ + calculate->machine_path!=NULL || calculate->user_path!=NULL); /* We need to construct a path from the following parts. (1) the PYTHONPATH environment variable, if set; (2) for Win32, the zip archive file path; - (3) for Win32, the machinepath and userpath, if set; + (3) for Win32, the machine_path and user_path, if set; (4) the PYTHONPATH config macro, with the leading "." - of each component replaced with pythonhome, if set; + of each component replaced with home, if set; (5) the directory containing the executable (argv0_path). The length calculation calculates #4 first. Extra rules: @@ -739,74 +857,80 @@ calculate_path(const _PyMainInterpreterConfig *config) */ /* Calculate size of return buffer */ - if (pythonhome != NULL) { + size_t bufsz = 0; + if (calculate->home != NULL) { wchar_t *p; bufsz = 1; for (p = PYTHONPATH; *p; p++) { - if (*p == DELIM) + if (*p == DELIM) { bufsz++; /* number of DELIM plus one */ + } } - bufsz *= wcslen(pythonhome); + bufsz *= wcslen(calculate->home); } - else - bufsz = 0; bufsz += wcslen(PYTHONPATH) + 1; - bufsz += wcslen(argv0_path) + 1; - if (userpath) - bufsz += wcslen(userpath) + 1; - if (machinepath) - bufsz += wcslen(machinepath) + 1; - bufsz += wcslen(zip_path) + 1; - if (envpath != NULL) - bufsz += wcslen(envpath) + 1; - - module_search_path = buf = PyMem_RawMalloc(bufsz*sizeof(wchar_t)); + bufsz += wcslen(calculate->argv0_path) + 1; + if (calculate->user_path) { + bufsz += wcslen(calculate->user_path) + 1; + } + if (calculate->machine_path) { + bufsz += wcslen(calculate->machine_path) + 1; + } + bufsz += wcslen(calculate->zip_path) + 1; + if (calculate->module_search_path_env != NULL) { + bufsz += wcslen(calculate->module_search_path_env) + 1; + } + + wchar_t *buf, *start_buf; + buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t)); if (buf == NULL) { /* We can't exit, so print a warning and limp along */ fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n"); - if (envpath) { + if (calculate->module_search_path_env) { fprintf(stderr, "Using environment $PYTHONPATH.\n"); - module_search_path = envpath; + config->module_search_path = calculate->module_search_path_env; } else { fprintf(stderr, "Using default static path.\n"); - module_search_path = PYTHONPATH; + config->module_search_path = PYTHONPATH; } - PyMem_RawFree(machinepath); - PyMem_RawFree(userpath); return; } + start_buf = buf; - if (envpath) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), envpath)) + if (calculate->module_search_path_env) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->module_search_path_env)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; } - if (zip_path[0]) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), zip_path)) + if (calculate->zip_path[0]) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; } - if (userpath) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), userpath)) + if (calculate->user_path) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; - PyMem_RawFree(userpath); } - if (machinepath) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), machinepath)) + if (calculate->machine_path) { + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; - PyMem_RawFree(machinepath); } - if (pythonhome == NULL) { + if (calculate->home == NULL) { if (!skipdefault) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), PYTHONPATH)) + if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); *buf++ = DELIM; } @@ -816,13 +940,16 @@ calculate_path(const _PyMainInterpreterConfig *config) size_t n; for (;;) { q = wcschr(p, DELIM); - if (q == NULL) + if (q == NULL) { n = wcslen(p); - else + } + else { n = q-p; + } if (p[0] == '.' && is_sep(p[1])) { - if (wcscpy_s(buf, bufsz - (buf - module_search_path), pythonhome)) + if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) { Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); + } buf = wcschr(buf, L'\0'); p++; n--; @@ -830,17 +957,19 @@ calculate_path(const _PyMainInterpreterConfig *config) wcsncpy(buf, p, n); buf += n; *buf++ = DELIM; - if (q == NULL) + if (q == NULL) { break; + } p = q+1; } } - if (argv0_path) { - wcscpy(buf, argv0_path); + if (calculate->argv0_path) { + wcscpy(buf, calculate->argv0_path); buf = wcschr(buf, L'\0'); *buf++ = DELIM; } *(buf - 1) = L'\0'; + /* Now to pull one last hack/trick. If sys.prefix is empty, then try and find it somewhere on the paths we calculated. We scan backwards, as our general policy @@ -849,7 +978,7 @@ calculate_path(const _PyMainInterpreterConfig *config) on the path, and that our 'prefix' directory is the parent of that. */ - if (*prefix==L'\0') { + if (config->prefix[0] == L'\0') { wchar_t lookBuf[MAXPATHLEN+1]; wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */ while (1) { @@ -859,84 +988,129 @@ calculate_path(const _PyMainInterpreterConfig *config) start of the path in question - even if this is one character before the start of the buffer */ - while (look >= module_search_path && *look != DELIM) + while (look >= start_buf && *look != DELIM) look--; nchars = lookEnd-look; wcsncpy(lookBuf, look+1, nchars); lookBuf[nchars] = L'\0'; /* Up one level to the parent */ reduce(lookBuf); - if (search_for_prefix(lookBuf, LANDMARK)) { + if (search_for_prefix(config->prefix, lookBuf, LANDMARK)) { break; } /* If we are out of paths to search - give up */ - if (look < module_search_path) + if (look < start_buf) { break; + } look--; } } + + config->module_search_path = start_buf; +} + + +static void +calculate_free(PyCalculatePath *calculate) +{ + PyMem_RawFree(calculate->machine_path); + PyMem_RawFree(calculate->user_path); } +static void +calculate_path(const _PyMainInterpreterConfig *main_config) +{ + PyCalculatePath calculate; + memset(&calculate, 0, sizeof(calculate)); + + _PyInitError err = calculate_init(&calculate, main_config); + if (_Py_INIT_FAILED(err)) { + calculate_free(&calculate); + _Py_FatalInitError(err); + } + + PyPathConfig new_path_config; + memset(&new_path_config, 0, sizeof(new_path_config)); + + calculate_path_impl(&calculate, &new_path_config, main_config); + path_config = new_path_config; + + calculate_free(&calculate); +} + + /* External interface */ void Py_SetPath(const wchar_t *path) { - if (module_search_path != NULL) { - PyMem_RawFree(module_search_path); - module_search_path = NULL; - } - if (path != NULL) { - extern wchar_t *Py_GetProgramName(void); - wchar_t *prog = Py_GetProgramName(); - wcsncpy(progpath, prog, MAXPATHLEN); - prefix[0] = L'\0'; - module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); - if (module_search_path != NULL) - wcscpy(module_search_path, path); + if (path_config.module_search_path != NULL) { + PyMem_RawFree(path_config.module_search_path); + path_config.module_search_path = NULL; + } + + if (path == NULL) { + return; + } + + wchar_t *prog = Py_GetProgramName(); + wcsncpy(path_config.progpath, prog, MAXPATHLEN); + path_config.prefix[0] = L'\0'; + path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); + if (path_config.module_search_path != NULL) { + wcscpy(path_config.module_search_path, path); } } + wchar_t * -_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) +_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config) { - if (!module_search_path) { - calculate_path(config); + if (!path_config.module_search_path) { + calculate_path(main_config); } - return module_search_path; + return path_config.module_search_path; } + wchar_t * Py_GetPath(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return module_search_path; + } + return path_config.module_search_path; } + wchar_t * Py_GetPrefix(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return prefix; + } + return path_config.prefix; } + wchar_t * Py_GetExecPrefix(void) { return Py_GetPrefix(); } + wchar_t * Py_GetProgramFullPath(void) { - if (!module_search_path) + if (!path_config.module_search_path) { calculate_path(NULL); - return progpath; + } + return path_config.progpath; } + /* Load python3.dll before loading any extension module that might refer to it. That way, we can be sure that always the python3.dll corresponding to this python DLL is loaded, not a python3.dll that might be on the path @@ -950,20 +1124,23 @@ _Py_CheckPython3() { wchar_t py3path[MAXPATHLEN+1]; wchar_t *s; - if (python3_checked) + if (python3_checked) { return hPython3 != NULL; + } python3_checked = 1; /* If there is a python3.dll next to the python3y.dll, assume this is a build tree; use that DLL */ - wcscpy(py3path, dllpath); + wcscpy(py3path, path_config.dllpath); s = wcsrchr(py3path, L'\\'); - if (!s) + if (!s) { s = py3path; + } wcscpy(s, L"\\python3.dll"); hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (hPython3 != NULL) + if (hPython3 != NULL) { return 1; + } /* Check sys.prefix\DLLs\python3.dll */ wcscpy(py3path, Py_GetPrefix()); |