Commit 0327bde9 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-32030: Rewrite calculate_path() (#4521)

* calculate_path() rewritten in Modules/getpath.c and PC/getpathp.c
* Move global variables into a new PyPathConfig structure.
* calculate_path():

  * Split the huge calculate_path() function into subfunctions.
  * Add PyCalculatePath structure to pass data between subfunctions.
  * Document PyCalculatePath fields.
  * Move cleanup code into a new calculate_free() subfunction
  * calculate_init() now handles Py_DecodeLocale() failures properly
  * calculate_path() is now atomic: only replace PyPathConfig
    (path_config) at once on success.

* _Py_GetPythonHomeWithConfig() now returns an error on failure
* Add _Py_INIT_NO_MEMORY() helper: report a memory allocation failure
* Coding style fixes (PEP 7)
parent bdb8315c
...@@ -7,23 +7,7 @@ ...@@ -7,23 +7,7 @@
extern "C" { extern "C" {
#endif #endif
PyAPI_FUNC(void) Py_SetProgramName(wchar_t *);
PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *);
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
#ifdef Py_BUILD_CORE
PyAPI_FUNC(wchar_t *) _Py_GetPythonHomeWithConfig(
const _PyMainInterpreterConfig *config);
#endif
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
/* Only used by applications that embed the interpreter and need to
* override the standard encoding determination mechanism
*/
PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding,
const char *errors);
typedef struct { typedef struct {
const char *prefix; const char *prefix;
const char *msg; const char *msg;
...@@ -46,9 +30,31 @@ typedef struct { ...@@ -46,9 +30,31 @@ typedef struct {
Don't abort() the process on such error. */ Don't abort() the process on such error. */
#define _Py_INIT_USER_ERR(MSG) \ #define _Py_INIT_USER_ERR(MSG) \
(_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1} (_PyInitError){.prefix = _Py_INIT_GET_FUNC(), .msg = (MSG), .user_err = 1}
#define _Py_INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
#define _Py_INIT_FAILED(err) \ #define _Py_INIT_FAILED(err) \
(err.msg != NULL) (err.msg != NULL)
#endif
PyAPI_FUNC(void) Py_SetProgramName(wchar_t *);
PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *);
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
#ifdef Py_BUILD_CORE
PyAPI_FUNC(_PyInitError) _Py_GetPythonHomeWithConfig(
const _PyMainInterpreterConfig *config,
wchar_t **home);
#endif
#ifndef Py_LIMITED_API
/* Only used by applications that embed the interpreter and need to
* override the standard encoding determination mechanism
*/
PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding,
const char *errors);
/* PEP 432 Multi-phase initialization API (Private while provisional!) */ /* PEP 432 Multi-phase initialization API (Private while provisional!) */
PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *); PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *);
PyAPI_FUNC(int) _Py_IsCoreInitialized(void); PyAPI_FUNC(int) _Py_IsCoreInitialized(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include <string.h> #include <string.h>
#ifdef __APPLE__ #ifdef __APPLE__
#include <mach-o/dyld.h> # include <mach-o/dyld.h>
#endif #endif
/* Search in some common locations for the associated Python libraries. /* Search in some common locations for the associated Python libraries.
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
*/ */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
...@@ -109,13 +109,38 @@ ...@@ -109,13 +109,38 @@
#define LANDMARK L"os.py" #define LANDMARK L"os.py"
#endif #endif
static wchar_t prefix[MAXPATHLEN+1]; typedef struct {
static wchar_t exec_prefix[MAXPATHLEN+1]; wchar_t prefix[MAXPATHLEN+1];
static wchar_t progpath[MAXPATHLEN+1]; wchar_t exec_prefix[MAXPATHLEN+1];
static wchar_t *module_search_path = NULL; wchar_t progpath[MAXPATHLEN+1];
wchar_t *module_search_path;
} PyPathConfig;
typedef struct {
wchar_t *path_env; /* PATH environment variable */
wchar_t *home; /* PYTHONHOME environment variable */
wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
wchar_t *module_search_path_buffer;
wchar_t *prog; /* Program name */
wchar_t *pythonpath; /* PYTHONPATH define */
wchar_t *prefix; /* PREFIX define */
wchar_t *exec_prefix; /* EXEC_PREFIX define */
wchar_t *lib_python; /* "lib/pythonX.Y" */
wchar_t argv0_path[MAXPATHLEN+1];
wchar_t zip_path[MAXPATHLEN+1]; /* ".../lib/pythonXY.zip" */
int prefix_found; /* found platform independent libraries? */
int exec_prefix_found; /* found the platform dependent libraries? */
} PyCalculatePath;
static const wchar_t delimiter[2] = {DELIM, '\0'};
static const wchar_t separator[2] = {SEP, '\0'};
static PyPathConfig path_config = {.module_search_path = NULL};
/* Get file status. Encode the path to the locale encoding. */
/* Get file status. Encode the path to the locale encoding. */
static int static int
_Py_wstat(const wchar_t* path, struct stat *buf) _Py_wstat(const wchar_t* path, struct stat *buf)
{ {
...@@ -131,6 +156,7 @@ _Py_wstat(const wchar_t* path, struct stat *buf) ...@@ -131,6 +156,7 @@ _Py_wstat(const wchar_t* path, struct stat *buf)
return err; return err;
} }
static void static void
reduce(wchar_t *dir) reduce(wchar_t *dir)
{ {
...@@ -140,14 +166,17 @@ reduce(wchar_t *dir) ...@@ -140,14 +166,17 @@ reduce(wchar_t *dir)
dir[i] = '\0'; dir[i] = '\0';
} }
static int static int
isfile(wchar_t *filename) /* Is file, not directory */ isfile(wchar_t *filename) /* Is file, not directory */
{ {
struct stat buf; struct stat buf;
if (_Py_wstat(filename, &buf) != 0) if (_Py_wstat(filename, &buf) != 0) {
return 0; return 0;
if (!S_ISREG(buf.st_mode)) }
if (!S_ISREG(buf.st_mode)) {
return 0; return 0;
}
return 1; return 1;
} }
...@@ -155,41 +184,50 @@ isfile(wchar_t *filename) /* Is file, not directory */ ...@@ -155,41 +184,50 @@ isfile(wchar_t *filename) /* Is file, not directory */
static int static int
ismodule(wchar_t *filename) /* Is module -- check for .pyc too */ ismodule(wchar_t *filename) /* Is module -- check for .pyc too */
{ {
if (isfile(filename)) if (isfile(filename)) {
return 1; return 1;
}
/* Check for the compiled version of prefix. */ /* Check for the compiled version of prefix. */
if (wcslen(filename) < MAXPATHLEN) { if (wcslen(filename) < MAXPATHLEN) {
wcscat(filename, L"c"); wcscat(filename, L"c");
if (isfile(filename)) if (isfile(filename)) {
return 1; return 1;
}
} }
return 0; return 0;
} }
/* Is executable file */
static int static int
isxfile(wchar_t *filename) /* Is executable file */ isxfile(wchar_t *filename)
{ {
struct stat buf; struct stat buf;
if (_Py_wstat(filename, &buf) != 0) if (_Py_wstat(filename, &buf) != 0) {
return 0; return 0;
if (!S_ISREG(buf.st_mode)) }
if (!S_ISREG(buf.st_mode)) {
return 0; return 0;
if ((buf.st_mode & 0111) == 0) }
if ((buf.st_mode & 0111) == 0) {
return 0; return 0;
}
return 1; return 1;
} }
/* Is directory */
static int static int
isdir(wchar_t *filename) /* Is directory */ isdir(wchar_t *filename)
{ {
struct stat buf; struct stat buf;
if (_Py_wstat(filename, &buf) != 0) if (_Py_wstat(filename, &buf) != 0) {
return 0; return 0;
if (!S_ISDIR(buf.st_mode)) }
if (!S_ISDIR(buf.st_mode)) {
return 0; return 0;
}
return 1; return 1;
} }
...@@ -207,58 +245,67 @@ static void ...@@ -207,58 +245,67 @@ static void
joinpath(wchar_t *buffer, wchar_t *stuff) joinpath(wchar_t *buffer, wchar_t *stuff)
{ {
size_t n, k; size_t n, k;
if (stuff[0] == SEP) if (stuff[0] == SEP) {
n = 0; n = 0;
}
else { else {
n = wcslen(buffer); n = wcslen(buffer);
if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) {
buffer[n++] = SEP; buffer[n++] = SEP;
}
} }
if (n > MAXPATHLEN) if (n > MAXPATHLEN) {
Py_FatalError("buffer overflow in getpath.c's joinpath()"); Py_FatalError("buffer overflow in getpath.c's joinpath()");
}
k = wcslen(stuff); k = wcslen(stuff);
if (n + k > MAXPATHLEN) if (n + k > MAXPATHLEN) {
k = MAXPATHLEN - n; k = MAXPATHLEN - n;
}
wcsncpy(buffer+n, stuff, k); wcsncpy(buffer+n, stuff, k);
buffer[n+k] = '\0'; buffer[n+k] = '\0';
} }
/* copy_absolute requires that path be allocated at least /* copy_absolute requires that path be allocated at least
MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */ MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */
static void static void
copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen) copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen)
{ {
if (p[0] == SEP) if (p[0] == SEP) {
wcscpy(path, p); wcscpy(path, p);
}
else { else {
if (!_Py_wgetcwd(path, pathlen)) { if (!_Py_wgetcwd(path, pathlen)) {
/* unable to get the current directory */ /* unable to get the current directory */
wcscpy(path, p); wcscpy(path, p);
return; return;
} }
if (p[0] == '.' && p[1] == SEP) if (p[0] == '.' && p[1] == SEP) {
p += 2; p += 2;
}
joinpath(path, p); joinpath(path, p);
} }
} }
/* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */ /* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */
static void static void
absolutize(wchar_t *path) absolutize(wchar_t *path)
{ {
wchar_t buffer[MAXPATHLEN+1]; wchar_t buffer[MAXPATHLEN+1];
if (path[0] == SEP) if (path[0] == SEP) {
return; return;
}
copy_absolute(buffer, path, MAXPATHLEN+1); copy_absolute(buffer, path, MAXPATHLEN+1);
wcscpy(path, buffer); wcscpy(path, buffer);
} }
/* search for a prefix value in an environment file. If found, copy it /* search for a prefix value in an environment file. If found, copy it
to the provided buffer, which is expected to be no more than MAXPATHLEN to the provided buffer, which is expected to be no more than MAXPATHLEN
bytes long. bytes long.
*/ */
static int static int
find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
{ {
...@@ -272,15 +319,18 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) ...@@ -272,15 +319,18 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
PyObject * decoded; PyObject * decoded;
int n; int n;
if (p == NULL) if (p == NULL) {
break; break;
}
n = strlen(p); n = strlen(p);
if (p[n - 1] != '\n') { if (p[n - 1] != '\n') {
/* line has overflowed - bail */ /* line has overflowed - bail */
break; break;
} }
if (p[0] == '#') /* Comment - skip */ if (p[0] == '#') {
/* Comment - skip */
continue; continue;
}
decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape"); decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape");
if (decoded != NULL) { if (decoded != NULL) {
Py_ssize_t k; Py_ssize_t k;
...@@ -307,106 +357,151 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) ...@@ -307,106 +357,151 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
return result; return result;
} }
/* search_for_prefix requires that argv0_path be no more than MAXPATHLEN /* search_for_prefix requires that argv0_path be no more than MAXPATHLEN
bytes long. bytes long.
*/ */
static int static int
search_for_prefix(wchar_t *argv0_path, wchar_t *home, wchar_t *_prefix, search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config)
wchar_t *lib_python)
{ {
size_t n; size_t n;
wchar_t *vpath; wchar_t *vpath;
/* If PYTHONHOME is set, we believe it unconditionally */ /* If PYTHONHOME is set, we believe it unconditionally */
if (home) { if (calculate->home) {
wchar_t *delim; wcsncpy(config->prefix, calculate->home, MAXPATHLEN);
wcsncpy(prefix, home, MAXPATHLEN); config->prefix[MAXPATHLEN] = L'\0';
prefix[MAXPATHLEN] = L'\0'; wchar_t *delim = wcschr(config->prefix, DELIM);
delim = wcschr(prefix, DELIM); if (delim) {
if (delim)
*delim = L'\0'; *delim = L'\0';
joinpath(prefix, lib_python); }
joinpath(prefix, LANDMARK); joinpath(config->prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK);
return 1; return 1;
} }
/* Check to see if argv[0] is in the build directory */ /* Check to see if argv[0] is in the build directory */
wcsncpy(prefix, argv0_path, MAXPATHLEN); wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0'; config->prefix[MAXPATHLEN] = L'\0';
joinpath(prefix, L"Modules/Setup"); joinpath(config->prefix, L"Modules/Setup");
if (isfile(prefix)) { if (isfile(config->prefix)) {
/* Check VPATH to see if argv0_path is in the build directory. */ /* Check VPATH to see if argv0_path is in the build directory. */
vpath = Py_DecodeLocale(VPATH, NULL); vpath = Py_DecodeLocale(VPATH, NULL);
if (vpath != NULL) { if (vpath != NULL) {
wcsncpy(prefix, argv0_path, MAXPATHLEN); wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0'; config->prefix[MAXPATHLEN] = L'\0';
joinpath(prefix, vpath); joinpath(config->prefix, vpath);
PyMem_RawFree(vpath); PyMem_RawFree(vpath);
joinpath(prefix, L"Lib"); joinpath(config->prefix, L"Lib");
joinpath(prefix, LANDMARK); joinpath(config->prefix, LANDMARK);
if (ismodule(prefix)) if (ismodule(config->prefix)) {
return -1; return -1;
}
} }
} }
/* Search from argv0_path, until root is found */ /* Search from argv0_path, until root is found */
copy_absolute(prefix, argv0_path, MAXPATHLEN+1); copy_absolute(config->prefix, calculate->argv0_path, MAXPATHLEN+1);
do { do {
n = wcslen(prefix); n = wcslen(config->prefix);
joinpath(prefix, lib_python); joinpath(config->prefix, calculate->lib_python);
joinpath(prefix, LANDMARK); joinpath(config->prefix, LANDMARK);
if (ismodule(prefix)) if (ismodule(config->prefix)) {
return 1; return 1;
prefix[n] = L'\0'; }
reduce(prefix); config->prefix[n] = L'\0';
} while (prefix[0]); reduce(config->prefix);
} while (config->prefix[0]);
/* Look at configure's PREFIX */ /* Look at configure's PREFIX */
wcsncpy(prefix, _prefix, MAXPATHLEN); wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0'; config->prefix[MAXPATHLEN] = L'\0';
joinpath(prefix, lib_python); joinpath(config->prefix, calculate->lib_python);
joinpath(prefix, LANDMARK); joinpath(config->prefix, LANDMARK);
if (ismodule(prefix)) if (ismodule(config->prefix)) {
return 1; return 1;
}
/* Fail */ /* Fail */
return 0; return 0;
} }
static void
calculate_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{
calculate->prefix_found = search_for_prefix(calculate, config);
if (!calculate->prefix_found) {
if (!Py_FrozenFlag) {
fprintf(stderr,
"Could not find platform independent libraries <prefix>\n");
}
wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
joinpath(config->prefix, calculate->lib_python);
}
else {
reduce(config->prefix);
}
}
static void
calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{
/* Reduce prefix and exec_prefix to their essence,
* e.g. /usr/local/lib/python1.5 is reduced to /usr/local.
* If we're loading relative to the build directory,
* return the compiled-in defaults instead.
*/
if (calculate->prefix_found > 0) {
reduce(config->prefix);
reduce(config->prefix);
/* The prefix is the root directory, but reduce() chopped
* off the "/". */
if (!config->prefix[0]) {
wcscpy(config->prefix, separator);
}
}
else {
wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
}
}
/* search_for_exec_prefix requires that argv0_path be no more than /* search_for_exec_prefix requires that argv0_path be no more than
MAXPATHLEN bytes long. MAXPATHLEN bytes long.
*/ */
static int static int
search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
wchar_t *_exec_prefix, wchar_t *lib_python)
{ {
size_t n; size_t n;
/* If PYTHONHOME is set, we believe it unconditionally */ /* If PYTHONHOME is set, we believe it unconditionally */
if (home) { if (calculate->home) {
wchar_t *delim; wchar_t *delim = wcschr(calculate->home, DELIM);
delim = wcschr(home, DELIM); if (delim) {
if (delim) wcsncpy(config->exec_prefix, delim+1, MAXPATHLEN);
wcsncpy(exec_prefix, delim+1, MAXPATHLEN); }
else else {
wcsncpy(exec_prefix, home, MAXPATHLEN); wcsncpy(config->exec_prefix, calculate->home, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0'; }
joinpath(exec_prefix, lib_python); config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, L"lib-dynload"); joinpath(config->exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload");
return 1; return 1;
} }
/* Check to see if argv[0] is in the build directory. "pybuilddir.txt" /* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
is written by setup.py and contains the relative path to the location is written by setup.py and contains the relative path to the location
of shared library modules. */ of shared library modules. */
wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0'; config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, L"pybuilddir.txt"); joinpath(config->exec_prefix, L"pybuilddir.txt");
if (isfile(exec_prefix)) { if (isfile(config->exec_prefix)) {
FILE *f = _Py_wfopen(exec_prefix, L"rb"); FILE *f = _Py_wfopen(config->exec_prefix, L"rb");
if (f == NULL) if (f == NULL) {
errno = 0; errno = 0;
}
else { else {
char buf[MAXPATHLEN+1]; char buf[MAXPATHLEN+1];
PyObject *decoded; PyObject *decoded;
...@@ -422,9 +517,9 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, ...@@ -422,9 +517,9 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
Py_DECREF(decoded); Py_DECREF(decoded);
if (k >= 0) { if (k >= 0) {
rel_builddir_path[k] = L'\0'; rel_builddir_path[k] = L'\0';
wcsncpy(exec_prefix, argv0_path, MAXPATHLEN); wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0'; config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, rel_builddir_path); joinpath(config->exec_prefix, rel_builddir_path);
return -1; return -1;
} }
} }
...@@ -432,87 +527,85 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, ...@@ -432,87 +527,85 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
} }
/* Search from argv0_path, until root is found */ /* Search from argv0_path, until root is found */
copy_absolute(exec_prefix, argv0_path, MAXPATHLEN+1); copy_absolute(config->exec_prefix, calculate->argv0_path, MAXPATHLEN+1);
do { do {
n = wcslen(exec_prefix); n = wcslen(config->exec_prefix);
joinpath(exec_prefix, lib_python); joinpath(config->exec_prefix, calculate->lib_python);
joinpath(exec_prefix, L"lib-dynload"); joinpath(config->exec_prefix, L"lib-dynload");
if (isdir(exec_prefix)) if (isdir(config->exec_prefix)) {
return 1; return 1;
exec_prefix[n] = L'\0'; }
reduce(exec_prefix); config->exec_prefix[n] = L'\0';
} while (exec_prefix[0]); reduce(config->exec_prefix);
} while (config->exec_prefix[0]);
/* Look at configure's EXEC_PREFIX */ /* Look at configure's EXEC_PREFIX */
wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0'; config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, lib_python); joinpath(config->exec_prefix, calculate->lib_python);
joinpath(exec_prefix, L"lib-dynload"); joinpath(config->exec_prefix, L"lib-dynload");
if (isdir(exec_prefix)) if (isdir(config->exec_prefix)) {
return 1; return 1;
}
/* Fail */ /* Fail */
return 0; return 0;
} }
static void static void
calculate_path(const _PyMainInterpreterConfig *config) calculate_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{ {
extern wchar_t *Py_GetProgramName(void); calculate->exec_prefix_found = search_for_exec_prefix(calculate, config);
if (!calculate->exec_prefix_found) {
static const wchar_t delimiter[2] = {DELIM, '\0'}; if (!Py_FrozenFlag) {
static const wchar_t separator[2] = {SEP, '\0'}; fprintf(stderr,
wchar_t *home = _Py_GetPythonHomeWithConfig(config); "Could not find platform dependent libraries <exec_prefix>\n");
char *_path = getenv("PATH"); }
wchar_t *path_buffer = NULL; wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
wchar_t *path = NULL; joinpath(config->exec_prefix, L"lib/lib-dynload");
wchar_t *prog = Py_GetProgramName(); }
wchar_t argv0_path[MAXPATHLEN+1]; /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
wchar_t zip_path[MAXPATHLEN+1]; }
int pfound, efound; /* 1 if found; -1 if found build directory */
wchar_t *buf;
size_t bufsz;
size_t prefixsz;
wchar_t *defpath;
#ifdef WITH_NEXT_FRAMEWORK
NSModule pythonModule;
const char* modPath;
#endif
#ifdef __APPLE__
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
uint32_t nsexeclength = MAXPATHLEN;
#else
unsigned long nsexeclength = MAXPATHLEN;
#endif
char execpath[MAXPATHLEN+1];
#endif
wchar_t *_pythonpath, *_prefix, *_exec_prefix;
wchar_t *lib_python;
_pythonpath = Py_DecodeLocale(PYTHONPATH, NULL);
_prefix = Py_DecodeLocale(PREFIX, NULL);
_exec_prefix = Py_DecodeLocale(EXEC_PREFIX, NULL);
lib_python = Py_DecodeLocale("lib/python" VERSION, NULL);
if (!_pythonpath || !_prefix || !_exec_prefix || !lib_python) { static void
Py_FatalError( calculate_reduce_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
"Unable to decode path variables in getpath.c: " {
"memory error"); if (calculate->exec_prefix_found > 0) {
reduce(config->exec_prefix);
reduce(config->exec_prefix);
reduce(config->exec_prefix);
if (!config->exec_prefix[0]) {
wcscpy(config->exec_prefix, separator);
}
} }
else {
if (_path) { wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
path_buffer = Py_DecodeLocale(_path, NULL);
path = path_buffer;
} }
}
static void
calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
{
/* If there is no slash in the argv0 path, then we have to /* 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 * assume python is on the user's $PATH, since there's no
* other way to find a directory to start the search from. If * other way to find a directory to start the search from. If
* $PATH isn't exported, you lose. * $PATH isn't exported, you lose.
*/ */
if (wcschr(prog, SEP)) if (wcschr(calculate->prog, SEP)) {
wcsncpy(progpath, prog, MAXPATHLEN); wcsncpy(config->progpath, calculate->prog, MAXPATHLEN);
}
#ifdef __APPLE__ #ifdef __APPLE__
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
uint32_t nsexeclength = MAXPATHLEN;
#else
unsigned long nsexeclength = MAXPATHLEN;
#endif
char execpath[MAXPATHLEN+1];
/* On Mac OS X, if a script uses an interpreter of the form /* On Mac OS X, if a script uses an interpreter of the form
* "#!/opt/python2.3/bin/python", the kernel only passes "python" * "#!/opt/python2.3/bin/python", the kernel only passes "python"
* as argv[0], which falls through to the $PATH search below. * as argv[0], which falls through to the $PATH search below.
...@@ -524,47 +617,60 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -524,47 +617,60 @@ calculate_path(const _PyMainInterpreterConfig *config)
* absolutize() should help us out below * absolutize() should help us out below
*/ */
else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && execpath[0] == SEP) { else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && execpath[0] == SEP) {
size_t r = mbstowcs(progpath, execpath, MAXPATHLEN+1); size_t r = mbstowcs(config->progpath, execpath, MAXPATHLEN+1);
if (r == (size_t)-1 || r > MAXPATHLEN) { if (r == (size_t)-1 || r > MAXPATHLEN) {
/* Could not convert execpath, or it's too long. */ /* Could not convert execpath, or it's too long. */
progpath[0] = '\0'; config->progpath[0] = '\0';
} }
} }
#endif /* __APPLE__ */ #endif /* __APPLE__ */
else if (path) { else if (calculate->path_env) {
wchar_t *path = calculate->path_env;
while (1) { while (1) {
wchar_t *delim = wcschr(path, DELIM); wchar_t *delim = wcschr(path, DELIM);
if (delim) { if (delim) {
size_t len = delim - path; size_t len = delim - path;
if (len > MAXPATHLEN) if (len > MAXPATHLEN) {
len = MAXPATHLEN; len = MAXPATHLEN;
wcsncpy(progpath, path, len); }
*(progpath + len) = '\0'; wcsncpy(config->progpath, path, len);
*(config->progpath + len) = '\0';
}
else {
wcsncpy(config->progpath, path, MAXPATHLEN);
} }
else
wcsncpy(progpath, path, MAXPATHLEN);
joinpath(progpath, prog); joinpath(config->progpath, calculate->prog);
if (isxfile(progpath)) if (isxfile(config->progpath)) {
break; break;
}
if (!delim) { if (!delim) {
progpath[0] = L'\0'; config->progpath[0] = L'\0';
break; break;
} }
path = delim + 1; path = delim + 1;
} }
} }
else else {
progpath[0] = '\0'; config->progpath[0] = '\0';
PyMem_RawFree(path_buffer); }
if (progpath[0] != SEP && progpath[0] != '\0') if (config->progpath[0] != SEP && config->progpath[0] != '\0') {
absolutize(progpath); absolutize(config->progpath);
wcsncpy(argv0_path, progpath, MAXPATHLEN); }
argv0_path[MAXPATHLEN] = '\0'; }
static void
calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
{
wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN);
calculate->argv0_path[MAXPATHLEN] = '\0';
#ifdef WITH_NEXT_FRAMEWORK #ifdef WITH_NEXT_FRAMEWORK
NSModule pythonModule;
/* On Mac OS X we have a special case if we're running from a framework. /* On Mac OS X we have a special case if we're running from a framework.
** This is because the python home should be set relative to the library, ** This is because the python home should be set relative to the library,
** which is in the framework, not relative to the executable, which may ** which is in the framework, not relative to the executable, which may
...@@ -572,7 +678,7 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -572,7 +678,7 @@ calculate_path(const _PyMainInterpreterConfig *config)
*/ */
pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize")); pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
/* Use dylib functions to find out where the framework was loaded from */ /* Use dylib functions to find out where the framework was loaded from */
modPath = NSLibraryNameForModule(pythonModule); const char* modPath = NSLibraryNameForModule(pythonModule);
if (modPath != NULL) { if (modPath != NULL) {
/* We're in a framework. */ /* We're in a framework. */
/* See if we might be in the build directory. The framework in the /* See if we might be in the build directory. The framework in the
...@@ -587,153 +693,132 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -587,153 +693,132 @@ calculate_path(const _PyMainInterpreterConfig *config)
Py_FatalError("Cannot decode framework location"); Py_FatalError("Cannot decode framework location");
} }
wcsncpy(argv0_path, wbuf, MAXPATHLEN); wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
reduce(argv0_path); reduce(calculate->argv0_path);
joinpath(argv0_path, lib_python); joinpath(calculate->argv0_path, calculate->lib_python);
joinpath(argv0_path, LANDMARK); joinpath(calculate->argv0_path, LANDMARK);
if (!ismodule(argv0_path)) { if (!ismodule(calculate->argv0_path)) {
/* We are in the build directory so use the name of the /* We are in the build directory so use the name of the
executable - we know that the absolute path is passed */ executable - we know that the absolute path is passed */
wcsncpy(argv0_path, progpath, MAXPATHLEN); wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN);
} }
else { else {
/* Use the location of the library as the progpath */ /* Use the location of the library as the progpath */
wcsncpy(argv0_path, wbuf, MAXPATHLEN); wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
} }
PyMem_RawFree(wbuf); PyMem_RawFree(wbuf);
} }
#endif #endif
#if HAVE_READLINK #if HAVE_READLINK
{ wchar_t tmpbuffer[MAXPATHLEN+1];
wchar_t tmpbuffer[MAXPATHLEN+1]; int linklen = _Py_wreadlink(config->progpath, tmpbuffer, MAXPATHLEN);
int linklen = _Py_wreadlink(progpath, tmpbuffer, MAXPATHLEN); while (linklen != -1) {
while (linklen != -1) { if (tmpbuffer[0] == SEP) {
if (tmpbuffer[0] == SEP) /* tmpbuffer should never be longer than MAXPATHLEN,
/* tmpbuffer should never be longer than MAXPATHLEN, but extra check does not hurt */
but extra check does not hurt */ wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
wcsncpy(argv0_path, tmpbuffer, MAXPATHLEN); }
else { else {
/* Interpret relative to progpath */ /* Interpret relative to progpath */
reduce(argv0_path); reduce(calculate->argv0_path);
joinpath(argv0_path, tmpbuffer); joinpath(calculate->argv0_path, tmpbuffer);
}
linklen = _Py_wreadlink(argv0_path, tmpbuffer, MAXPATHLEN);
} }
linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
} }
#endif /* HAVE_READLINK */ #endif /* HAVE_READLINK */
reduce(argv0_path); reduce(calculate->argv0_path);
/* At this point, argv0_path is guaranteed to be less than /* At this point, argv0_path is guaranteed to be less than
MAXPATHLEN bytes long. MAXPATHLEN bytes long. */
*/ }
/* 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.
*/
{ /* Search for an "pyvenv.cfg" environment configuration file, first in the
wchar_t tmpbuffer[MAXPATHLEN+1]; executable's directory and then in the parent directory.
wchar_t *env_cfg = L"pyvenv.cfg"; If found, open it for use when searching for prefixes.
FILE * env_file = NULL; */
static void
calculate_read_pyenv(PyCalculatePath *calculate)
{
wchar_t tmpbuffer[MAXPATHLEN+1];
wchar_t *env_cfg = L"pyvenv.cfg";
FILE *env_file;
wcscpy(tmpbuffer, calculate->argv0_path);
wcscpy(tmpbuffer, argv0_path); joinpath(tmpbuffer, env_cfg);
env_file = _Py_wfopen(tmpbuffer, L"r");
if (env_file == NULL) {
errno = 0;
reduce(tmpbuffer);
reduce(tmpbuffer);
joinpath(tmpbuffer, env_cfg); joinpath(tmpbuffer, env_cfg);
env_file = _Py_wfopen(tmpbuffer, L"r"); env_file = _Py_wfopen(tmpbuffer, L"r");
if (env_file == NULL) { if (env_file == NULL) {
errno = 0; errno = 0;
reduce(tmpbuffer);
reduce(tmpbuffer);
joinpath(tmpbuffer, env_cfg);
env_file = _Py_wfopen(tmpbuffer, 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(argv0_path, tmpbuffer);
}
fclose(env_file);
env_file = NULL;
} }
} }
pfound = search_for_prefix(argv0_path, home, _prefix, lib_python); if (env_file == NULL) {
if (!pfound) { return;
if (!Py_FrozenFlag)
fprintf(stderr,
"Could not find platform independent libraries <prefix>\n");
wcsncpy(prefix, _prefix, MAXPATHLEN);
joinpath(prefix, lib_python);
}
else
reduce(prefix);
wcsncpy(zip_path, prefix, MAXPATHLEN);
zip_path[MAXPATHLEN] = L'\0';
if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */
reduce(zip_path);
reduce(zip_path);
}
else
wcsncpy(zip_path, _prefix, MAXPATHLEN);
joinpath(zip_path, L"lib/python00.zip");
bufsz = wcslen(zip_path); /* Replace "00" with version */
zip_path[bufsz - 6] = VERSION[0];
zip_path[bufsz - 5] = VERSION[2];
efound = search_for_exec_prefix(argv0_path, home,
_exec_prefix, lib_python);
if (!efound) {
if (!Py_FrozenFlag)
fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n");
wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
joinpath(exec_prefix, L"lib/lib-dynload");
} }
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
if ((!pfound || !efound) && !Py_FrozenFlag) /* Look for a 'home' variable and set argv0_path to it, if found */
fprintf(stderr, if (find_env_config_value(env_file, L"home", tmpbuffer)) {
"Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n"); wcscpy(calculate->argv0_path, tmpbuffer);
}
fclose(env_file);
}
/* Calculate size of return buffer.
*/
bufsz = 0;
wchar_t *env_path = NULL; static void
if (config) { calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config)
if (config->module_search_path_env) { {
bufsz += wcslen(config->module_search_path_env) + 1; wcsncpy(calculate->zip_path, config->prefix, MAXPATHLEN);
} calculate->zip_path[MAXPATHLEN] = L'\0';
if (calculate->prefix_found > 0) {
/* Use the reduced prefix returned by Py_GetPrefix() */
reduce(calculate->zip_path);
reduce(calculate->zip_path);
} }
else { else {
char *env_pathb = Py_GETENV("PYTHONPATH"); wcsncpy(calculate->zip_path, calculate->prefix, MAXPATHLEN);
if (env_pathb && env_pathb[0] != '\0') {
size_t env_path_len;
env_path = Py_DecodeLocale(env_pathb, &env_path_len);
/* FIXME: handle decoding and memory error */
if (env_path != NULL) {
bufsz += env_path_len + 1;
}
}
} }
joinpath(calculate->zip_path, L"lib/python00.zip");
/* Replace "00" with version */
size_t bufsz = wcslen(calculate->zip_path);
calculate->zip_path[bufsz - 6] = VERSION[0];
calculate->zip_path[bufsz - 5] = VERSION[2];
}
defpath = _pythonpath;
prefixsz = wcslen(prefix) + 1; static wchar_t *
calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
{
/* Calculate size of return buffer */
size_t bufsz = 0;
if (calculate->module_search_path_env != NULL) {
bufsz += wcslen(calculate->module_search_path_env) + 1;
}
wchar_t *defpath = calculate->pythonpath;
size_t prefixsz = wcslen(config->prefix) + 1;
while (1) { while (1) {
wchar_t *delim = wcschr(defpath, DELIM); wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP) if (defpath[0] != SEP) {
/* Paths are relative to prefix */ /* Paths are relative to prefix */
bufsz += prefixsz; bufsz += prefixsz;
}
if (delim) if (delim) {
bufsz += delim - defpath + 1; bufsz += delim - defpath + 1;
}
else { else {
bufsz += wcslen(defpath) + 1; bufsz += wcslen(defpath) + 1;
break; break;
...@@ -741,46 +826,40 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -741,46 +826,40 @@ calculate_path(const _PyMainInterpreterConfig *config)
defpath = delim + 1; defpath = delim + 1;
} }
bufsz += wcslen(zip_path) + 1; bufsz += wcslen(calculate->zip_path) + 1;
bufsz += wcslen(exec_prefix) + 1; bufsz += wcslen(config->exec_prefix) + 1;
buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t)); /* Allocate the buffer */
wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
if (buf == NULL) { if (buf == NULL) {
Py_FatalError( Py_FatalError(
"Not enough memory for dynamic PYTHONPATH"); "Not enough memory for dynamic PYTHONPATH");
} }
buf[0] = '\0';
/* Run-time value of $PYTHONPATH goes first */ /* Run-time value of $PYTHONPATH goes first */
buf[0] = '\0'; if (calculate->module_search_path_env) {
if (config) { wcscpy(buf, calculate->module_search_path_env);
if (config->module_search_path_env) { wcscat(buf, delimiter);
wcscpy(buf, config->module_search_path_env);
wcscat(buf, delimiter);
}
}
else {
if (env_path) {
wcscpy(buf, env_path);
wcscat(buf, delimiter);
}
} }
PyMem_RawFree(env_path);
/* Next is the default zip path */ /* Next is the default zip path */
wcscat(buf, zip_path); wcscat(buf, calculate->zip_path);
wcscat(buf, delimiter); wcscat(buf, delimiter);
/* Next goes merge of compile-time $PYTHONPATH with /* Next goes merge of compile-time $PYTHONPATH with
* dynamically located prefix. * dynamically located prefix.
*/ */
defpath = _pythonpath; defpath = calculate->pythonpath;
while (1) { while (1) {
wchar_t *delim = wcschr(defpath, DELIM); wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP) { if (defpath[0] != SEP) {
wcscat(buf, prefix); wcscat(buf, config->prefix);
if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP && if (prefixsz >= 2 && config->prefix[prefixsz - 2] != SEP &&
defpath[0] != (delim ? DELIM : L'\0')) { /* not empty */ defpath[0] != (delim ? DELIM : L'\0'))
{
/* not empty */
wcscat(buf, separator); wcscat(buf, separator);
} }
} }
...@@ -800,41 +879,130 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -800,41 +879,130 @@ calculate_path(const _PyMainInterpreterConfig *config)
wcscat(buf, delimiter); wcscat(buf, delimiter);
/* Finally, on goes the directory for dynamic-load modules */ /* Finally, on goes the directory for dynamic-load modules */
wcscat(buf, exec_prefix); wcscat(buf, config->exec_prefix);
/* And publish the results */ return buf;
module_search_path = buf; }
/* Reduce prefix and exec_prefix to their essence,
* e.g. /usr/local/lib/python1.5 is reduced to /usr/local. #define DECODE_FAILED(NAME, LEN) \
* If we're loading relative to the build directory, ((LEN) == (size_t)-2) \
* return the compiled-in defaults instead. ? _Py_INIT_ERR("failed to decode " #NAME) \
*/ : _Py_INIT_NO_MEMORY()
if (pfound > 0) {
reduce(prefix);
reduce(prefix); static _PyInitError
/* The prefix is the root directory, but reduce() chopped calculate_init(PyCalculatePath *calculate,
* off the "/". */ const _PyMainInterpreterConfig *main_config)
if (!prefix[0]) {
wcscpy(prefix, separator); _PyInitError err;
err = _Py_GetPythonHomeWithConfig(main_config, &calculate->home);
if (_Py_INIT_FAILED(err)) {
return err;
}
size_t len;
char *path = getenv("PATH");
if (path) {
calculate->path_env = Py_DecodeLocale(path, &len);
if (!calculate->path_env) {
return DECODE_FAILED("PATH environment variable", len);
}
}
calculate->prog = Py_GetProgramName();
calculate->pythonpath = Py_DecodeLocale(PYTHONPATH, &len);
if (!calculate->pythonpath) {
return DECODE_FAILED("PYTHONPATH define", len);
}
calculate->prefix = Py_DecodeLocale(PREFIX, &len);
if (!calculate->prefix) {
return DECODE_FAILED("PREFIX define", len);
}
calculate->exec_prefix = Py_DecodeLocale(EXEC_PREFIX, &len);
if (!calculate->prefix) {
return DECODE_FAILED("EXEC_PREFIX define", len);
}
calculate->lib_python = Py_DecodeLocale("lib/python" VERSION, &len);
if (!calculate->lib_python) {
return DECODE_FAILED("EXEC_PREFIX define", len);
} }
else
wcsncpy(prefix, _prefix, MAXPATHLEN);
if (efound > 0) { calculate->module_search_path_env = NULL;
reduce(exec_prefix); if (main_config) {
reduce(exec_prefix); if (main_config->module_search_path_env) {
reduce(exec_prefix); calculate->module_search_path_env = main_config->module_search_path_env;
if (!exec_prefix[0]) }
wcscpy(exec_prefix, separator);
}
else {
char *pythonpath = Py_GETENV("PYTHONPATH");
if (pythonpath && pythonpath[0] != '\0') {
calculate->module_search_path_buffer = Py_DecodeLocale(pythonpath, &len);
if (!calculate->module_search_path_buffer) {
return DECODE_FAILED("PYTHONPATH environment variable", len);
}
calculate->module_search_path_env = calculate->module_search_path_buffer;
}
} }
else return _Py_INIT_OK();
wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN); }
PyMem_RawFree(_pythonpath); static void
PyMem_RawFree(_prefix); calculate_free(PyCalculatePath *calculate)
PyMem_RawFree(_exec_prefix); {
PyMem_RawFree(lib_python); PyMem_RawFree(calculate->pythonpath);
PyMem_RawFree(calculate->prefix);
PyMem_RawFree(calculate->exec_prefix);
PyMem_RawFree(calculate->lib_python);
PyMem_RawFree(calculate->path_env);
PyMem_RawFree(calculate->module_search_path_buffer);
}
static void
calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config)
{
calculate_progpath(calculate, config);
calculate_argv0_path(calculate, config);
calculate_read_pyenv(calculate);
calculate_prefix(calculate, config);
calculate_zip_path(calculate, config);
calculate_exec_prefix(calculate, config);
if ((!calculate->prefix_found || !calculate->exec_prefix_found) && !Py_FrozenFlag) {
fprintf(stderr,
"Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
}
config->module_search_path = calculate_module_search_path(calculate, config);
calculate_reduce_prefix(calculate, config);
calculate_reduce_exec_prefix(calculate, config);
}
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);
path_config = new_path_config;
calculate_free(&calculate);
} }
...@@ -842,63 +1010,74 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -842,63 +1010,74 @@ calculate_path(const _PyMainInterpreterConfig *config)
void void
Py_SetPath(const wchar_t *path) Py_SetPath(const wchar_t *path)
{ {
if (module_search_path != NULL) { if (path_config.module_search_path != NULL) {
PyMem_RawFree(module_search_path); PyMem_RawFree(path_config.module_search_path);
module_search_path = NULL; path_config.module_search_path = NULL;
} }
if (path != NULL) {
extern wchar_t *Py_GetProgramName(void); if (path == NULL) {
wchar_t *prog = Py_GetProgramName(); return;
wcsncpy(progpath, prog, MAXPATHLEN); }
exec_prefix[0] = prefix[0] = L'\0';
module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); wchar_t *prog = Py_GetProgramName();
if (module_search_path != NULL) wcsncpy(path_config.progpath, prog, MAXPATHLEN);
wcscpy(module_search_path, path); path_config.exec_prefix[0] = 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 * wchar_t *
_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) _Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config)
{ {
if (!module_search_path) { if (!path_config.module_search_path) {
calculate_path(config); calculate_path(main_config);
} }
return module_search_path; return path_config.module_search_path;
} }
wchar_t * wchar_t *
Py_GetPath(void) Py_GetPath(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return module_search_path; }
return path_config.module_search_path;
} }
wchar_t * wchar_t *
Py_GetPrefix(void) Py_GetPrefix(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return prefix; }
return path_config.prefix;
} }
wchar_t * wchar_t *
Py_GetExecPrefix(void) Py_GetExecPrefix(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return exec_prefix; }
return path_config.exec_prefix;
} }
wchar_t * wchar_t *
Py_GetProgramFullPath(void) Py_GetProgramFullPath(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return progpath; }
return path_config.progpath;
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
...@@ -36,6 +36,16 @@ ...@@ -36,6 +36,16 @@
extern "C" { extern "C" {
#endif #endif
#define SET_DECODE_ERROR(NAME, LEN) \
do { \
if ((LEN) == (size_t)-2) { \
pymain->err = _Py_INIT_ERR("failed to decode " #NAME); \
} \
else { \
pymain->err = _Py_INIT_NO_MEMORY(); \
} \
} while (0)
/* For Py_GetArgcArgv(); set by main() */ /* For Py_GetArgcArgv(); set by main() */
static wchar_t **orig_argv; static wchar_t **orig_argv;
static int orig_argc; static int orig_argc;
...@@ -417,9 +427,6 @@ typedef struct { ...@@ -417,9 +427,6 @@ typedef struct {
.env_warning_options = {0, NULL}} .env_warning_options = {0, NULL}}
#define INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
static void static void
pymain_optlist_clear(_Py_OptList *list) pymain_optlist_clear(_Py_OptList *list)
{ {
...@@ -510,14 +517,14 @@ pymain_wstrdup(_PyMain *pymain, wchar_t *str) ...@@ -510,14 +517,14 @@ pymain_wstrdup(_PyMain *pymain, wchar_t *str)
{ {
size_t len = wcslen(str) + 1; /* +1 for NUL character */ size_t len = wcslen(str) + 1; /* +1 for NUL character */
if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) { if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return NULL; return NULL;
} }
size_t size = len * sizeof(wchar_t); size_t size = len * sizeof(wchar_t);
wchar_t *str2 = PyMem_RawMalloc(size); wchar_t *str2 = PyMem_RawMalloc(size);
if (str2 == NULL) { if (str2 == NULL) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return NULL; return NULL;
} }
...@@ -538,7 +545,7 @@ pymain_optlist_append(_PyMain *pymain, _Py_OptList *list, wchar_t *str) ...@@ -538,7 +545,7 @@ pymain_optlist_append(_PyMain *pymain, _Py_OptList *list, wchar_t *str)
wchar_t **options2 = (wchar_t **)PyMem_RawRealloc(list->options, size); wchar_t **options2 = (wchar_t **)PyMem_RawRealloc(list->options, size);
if (options2 == NULL) { if (options2 == NULL) {
PyMem_RawFree(str2); PyMem_RawFree(str2);
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
options2[list->len] = str2; options2[list->len] = str2;
...@@ -571,7 +578,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain) ...@@ -571,7 +578,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain)
size_t len = wcslen(_PyOS_optarg) + 1 + 1; size_t len = wcslen(_PyOS_optarg) + 1 + 1;
wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len); wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
if (command == NULL) { if (command == NULL) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
memcpy(command, _PyOS_optarg, len * sizeof(wchar_t)); memcpy(command, _PyOS_optarg, len * sizeof(wchar_t));
...@@ -717,7 +724,7 @@ pymain_add_xoptions(_PyMain *pymain) ...@@ -717,7 +724,7 @@ pymain_add_xoptions(_PyMain *pymain)
for (size_t i=0; i < options->len; i++) { for (size_t i=0; i < options->len; i++) {
wchar_t *option = options->options[i]; wchar_t *option = options->options[i];
if (_PySys_AddXOptionWithError(option) < 0) { if (_PySys_AddXOptionWithError(option) < 0) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
} }
...@@ -748,11 +755,11 @@ pymain_add_warnings_options(_PyMain *pymain) ...@@ -748,11 +755,11 @@ pymain_add_warnings_options(_PyMain *pymain)
PySys_ResetWarnOptions(); PySys_ResetWarnOptions();
if (pymain_add_warnings_optlist(&pymain->env_warning_options) < 0) { if (pymain_add_warnings_optlist(&pymain->env_warning_options) < 0) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
if (pymain_add_warnings_optlist(&pymain->cmdline.warning_options) < 0) { if (pymain_add_warnings_optlist(&pymain->cmdline.warning_options) < 0) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
return 0; return 0;
...@@ -801,7 +808,7 @@ pymain_warnings_envvar(_PyMain *pymain) ...@@ -801,7 +808,7 @@ pymain_warnings_envvar(_PyMain *pymain)
C89 wcstok */ C89 wcstok */
buf = (char *)PyMem_RawMalloc(strlen(p) + 1); buf = (char *)PyMem_RawMalloc(strlen(p) + 1);
if (buf == NULL) { if (buf == NULL) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
strcpy(buf, p); strcpy(buf, p);
...@@ -811,13 +818,7 @@ pymain_warnings_envvar(_PyMain *pymain) ...@@ -811,13 +818,7 @@ pymain_warnings_envvar(_PyMain *pymain)
size_t len; size_t len;
wchar_t *warning = Py_DecodeLocale(p, &len); wchar_t *warning = Py_DecodeLocale(p, &len);
if (warning == NULL) { if (warning == NULL) {
if (len == (size_t)-2) { SET_DECODE_ERROR("PYTHONWARNINGS environment variable", len);
pymain->err = _Py_INIT_ERR("failed to decode "
"PYTHONWARNINGS");
}
else {
pymain->err = INIT_NO_MEMORY();
}
return -1; return -1;
} }
if (pymain_optlist_append(pymain, &pymain->env_warning_options, if (pymain_optlist_append(pymain, &pymain->env_warning_options,
...@@ -902,7 +903,7 @@ pymain_get_program_name(_PyMain *pymain) ...@@ -902,7 +903,7 @@ pymain_get_program_name(_PyMain *pymain)
buffer = PyMem_RawMalloc(len * sizeof(wchar_t)); buffer = PyMem_RawMalloc(len * sizeof(wchar_t));
if (buffer == NULL) { if (buffer == NULL) {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
...@@ -919,15 +920,8 @@ pymain_get_program_name(_PyMain *pymain) ...@@ -919,15 +920,8 @@ pymain_get_program_name(_PyMain *pymain)
size_t len; size_t len;
wchar_t* wbuf = Py_DecodeLocale(pyvenv_launcher, &len); wchar_t* wbuf = Py_DecodeLocale(pyvenv_launcher, &len);
if (wbuf == NULL) { if (wbuf == NULL) {
if (len == (size_t)-2) { SET_DECODE_ERROR("__PYVENV_LAUNCHER__", len);
pymain->err = _Py_INIT_ERR("failed to decode " return -1;
"__PYVENV_LAUNCHER__");
return -1;
}
else {
pymain->err = INIT_NO_MEMORY();
return -1;
}
} }
pymain->program_name = wbuf; pymain->program_name = wbuf;
} }
...@@ -1403,7 +1397,7 @@ pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest, ...@@ -1403,7 +1397,7 @@ pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest,
return -2; return -2;
} }
else { else {
pymain->err = INIT_NO_MEMORY(); pymain->err = _Py_INIT_NO_MEMORY();
return -1; return -1;
} }
} }
...@@ -1421,7 +1415,7 @@ pymain_init_pythonpath(_PyMain *pymain) ...@@ -1421,7 +1415,7 @@ pymain_init_pythonpath(_PyMain *pymain)
L"PYTHONPATH", "PYTHONPATH"); L"PYTHONPATH", "PYTHONPATH");
if (res < 0) { if (res < 0) {
if (res == -2) { if (res == -2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONPATH"); SET_DECODE_ERROR("PYTHONPATH", (size_t)-2);
} }
return -1; return -1;
} }
...@@ -1450,7 +1444,7 @@ pymain_init_pythonhome(_PyMain *pymain) ...@@ -1450,7 +1444,7 @@ pymain_init_pythonhome(_PyMain *pymain)
L"PYTHONHOME", "PYTHONHOME"); L"PYTHONHOME", "PYTHONHOME");
if (res < 0) { if (res < 0) {
if (res == -2) { if (res == -2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME"); SET_DECODE_ERROR("PYTHONHOME", (size_t)-2);
} }
return -1; return -1;
} }
......
...@@ -116,14 +116,34 @@ ...@@ -116,14 +116,34 @@
#define LANDMARK L"lib\\os.py" #define LANDMARK L"lib\\os.py"
#endif #endif
static wchar_t prefix[MAXPATHLEN+1]; typedef struct {
static wchar_t progpath[MAXPATHLEN+1]; wchar_t prefix[MAXPATHLEN+1];
static wchar_t dllpath[MAXPATHLEN+1]; wchar_t progpath[MAXPATHLEN+1];
static wchar_t *module_search_path = NULL; 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 static int
is_sep(wchar_t ch) /* determine if "ch" is a separator character */ is_sep(wchar_t ch)
{ {
#ifdef ALTSEP #ifdef ALTSEP
return ch == SEP || ch == ALTSEP; return ch == SEP || ch == ALTSEP;
...@@ -132,28 +152,31 @@ is_sep(wchar_t ch) /* determine if "ch" is a separator character */ ...@@ -132,28 +152,31 @@ is_sep(wchar_t ch) /* determine if "ch" is a separator character */
#endif #endif
} }
/* assumes 'dir' null terminated in bounds. Never writes /* assumes 'dir' null terminated in bounds. Never writes
beyond existing terminator. beyond existing terminator. */
*/
static void static void
reduce(wchar_t *dir) reduce(wchar_t *dir)
{ {
size_t i = wcsnlen_s(dir, MAXPATHLEN+1); 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()"); Py_FatalError("buffer overflow in getpathp.c's reduce()");
}
while (i > 0 && !is_sep(dir[i])) while (i > 0 && !is_sep(dir[i]))
--i; --i;
dir[i] = '\0'; dir[i] = '\0';
} }
static int static int
change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
{ {
size_t src_len = wcsnlen_s(src, MAXPATHLEN+1); size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
size_t i = src_len; size_t i = src_len;
if (i >= MAXPATHLEN+1) if (i >= MAXPATHLEN+1) {
Py_FatalError("buffer overflow in getpathp.c's reduce()"); Py_FatalError("buffer overflow in getpathp.c's reduce()");
}
while (i > 0 && src[i] != '.' && !is_sep(src[i])) while (i > 0 && src[i] != '.' && !is_sep(src[i]))
--i; --i;
...@@ -163,11 +186,13 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) ...@@ -163,11 +186,13 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
return -1; return -1;
} }
if (is_sep(src[i])) if (is_sep(src[i])) {
i = src_len; i = src_len;
}
if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) || if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) ||
wcscat_s(dest, MAXPATHLEN+1, ext)) { wcscat_s(dest, MAXPATHLEN+1, ext))
{
dest[0] = '\0'; dest[0] = '\0';
return -1; return -1;
} }
...@@ -175,22 +200,25 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) ...@@ -175,22 +200,25 @@ change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
return 0; return 0;
} }
static int static int
exists(wchar_t *filename) exists(wchar_t *filename)
{ {
return GetFileAttributesW(filename) != 0xFFFFFFFF; 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 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; size_t n;
if (exists(filename)) if (exists(filename)) {
return 1; return 1;
}
/* Check for the compiled version of prefix. */ /* Check for the compiled version of prefix. */
n = wcsnlen_s(filename, MAXPATHLEN+1); n = wcsnlen_s(filename, MAXPATHLEN+1);
...@@ -199,13 +227,15 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc ...@@ -199,13 +227,15 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc
filename[n] = L'c'; filename[n] = L'c';
filename[n + 1] = L'\0'; filename[n + 1] = L'\0';
exist = exists(filename); exist = exists(filename);
if (!update_filename) if (!update_filename) {
filename[n] = L'\0'; filename[n] = L'\0';
}
return exist; return exist;
} }
return 0; return 0;
} }
/* Add a path component, by appending stuff to buffer. /* Add a path component, by appending stuff to buffer.
buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
NUL-terminated string with no more than MAXPATHLEN characters (not counting 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 ...@@ -217,7 +247,9 @@ ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc
*/ */
static int _PathCchCombineEx_Initialized = 0; 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 PPathCchCombineEx _PathCchCombineEx;
static void static void
...@@ -225,28 +257,32 @@ join(wchar_t *buffer, const wchar_t *stuff) ...@@ -225,28 +257,32 @@ join(wchar_t *buffer, const wchar_t *stuff)
{ {
if (_PathCchCombineEx_Initialized == 0) { if (_PathCchCombineEx_Initialized == 0) {
HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll"); HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
if (pathapi) if (pathapi) {
_PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx"); _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx");
else }
else {
_PathCchCombineEx = NULL; _PathCchCombineEx = NULL;
}
_PathCchCombineEx_Initialized = 1; _PathCchCombineEx_Initialized = 1;
} }
if (_PathCchCombineEx) { 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()"); Py_FatalError("buffer overflow in getpathp.c's join()");
}
} else { } else {
if (!PathCombineW(buffer, buffer, stuff)) if (!PathCombineW(buffer, buffer, stuff)) {
Py_FatalError("buffer overflow in getpathp.c's join()"); Py_FatalError("buffer overflow in getpathp.c's join()");
}
} }
} }
/* gotlandmark only called by search_for_prefix, which ensures /* gotlandmark only called by search_for_prefix, which ensures
'prefix' is null terminated in bounds. join() 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 static int
gotlandmark(const wchar_t *landmark) gotlandmark(wchar_t *prefix, const wchar_t *landmark)
{ {
int ok; int ok;
Py_ssize_t n = wcsnlen_s(prefix, MAXPATHLEN); Py_ssize_t n = wcsnlen_s(prefix, MAXPATHLEN);
...@@ -257,27 +293,29 @@ gotlandmark(const wchar_t *landmark) ...@@ -257,27 +293,29 @@ gotlandmark(const wchar_t *landmark)
return ok; return ok;
} }
/* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd. /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
assumption provided by only caller, calculate_path() */ assumption provided by only caller, calculate_path() */
static int 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 */ /* Search from argv0_path, until landmark is found */
wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path); wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
do { do {
if (gotlandmark(landmark)) if (gotlandmark(prefix, landmark)) {
return 1; return 1;
}
reduce(prefix); reduce(prefix);
} while (prefix[0]); } while (prefix[0]);
return 0; return 0;
} }
#ifdef Py_ENABLE_SHARED #ifdef Py_ENABLE_SHARED
/* a string loaded from the DLL at startup.*/ /* a string loaded from the DLL at startup.*/
extern const char *PyWin_DLLVersionString; extern const char *PyWin_DLLVersionString;
/* Load a PYTHONPATH value from the registry. /* Load a PYTHONPATH value from the registry.
Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER. Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
...@@ -290,7 +328,6 @@ extern const char *PyWin_DLLVersionString; ...@@ -290,7 +328,6 @@ extern const char *PyWin_DLLVersionString;
work on Win16, where the buffer sizes werent available work on Win16, where the buffer sizes werent available
in advance. It could be simplied now Win16/Win32s is dead! in advance. It could be simplied now Win16/Win32s is dead!
*/ */
static wchar_t * static wchar_t *
getpythonregpath(HKEY keyBase, int skipcore) getpythonregpath(HKEY keyBase, int skipcore)
{ {
...@@ -315,7 +352,9 @@ getpythonregpath(HKEY keyBase, int skipcore) ...@@ -315,7 +352,9 @@ getpythonregpath(HKEY keyBase, int skipcore)
sizeof(WCHAR)*(versionLen-1) + sizeof(WCHAR)*(versionLen-1) +
sizeof(keySuffix); sizeof(keySuffix);
keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen); keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen);
if (keyBuf==NULL) goto done; if (keyBuf==NULL) {
goto done;
}
memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR)); memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1; keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1;
...@@ -329,17 +368,25 @@ getpythonregpath(HKEY keyBase, int skipcore) ...@@ -329,17 +368,25 @@ getpythonregpath(HKEY keyBase, int skipcore)
0, /* reserved */ 0, /* reserved */
KEY_READ, KEY_READ,
&newKey); &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 */ /* Find out how big our core buffer is, and how many subkeys we have */
rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL, rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
NULL, NULL, &dataSize, NULL, NULL); NULL, NULL, &dataSize, NULL, NULL);
if (rc!=ERROR_SUCCESS) goto done; if (rc!=ERROR_SUCCESS) {
if (skipcore) dataSize = 0; /* Only count core ones if we want them! */ 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 /* Allocate a temp array of char buffers, so we only need to loop
reading the registry once reading the registry once
*/ */
ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys ); ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys );
if (ppPaths==NULL) goto done; if (ppPaths==NULL) {
goto done;
}
memset(ppPaths, 0, sizeof(WCHAR *) * numKeys); memset(ppPaths, 0, sizeof(WCHAR *) * numKeys);
/* Loop over all subkeys, allocating a temp sub-buffer. */ /* Loop over all subkeys, allocating a temp sub-buffer. */
for(index=0;index<numKeys;index++) { for(index=0;index<numKeys;index++) {
...@@ -349,14 +396,18 @@ getpythonregpath(HKEY keyBase, int skipcore) ...@@ -349,14 +396,18 @@ getpythonregpath(HKEY keyBase, int skipcore)
/* Get the sub-key name */ /* Get the sub-key name */
DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize, DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
NULL, NULL, NULL, NULL ); NULL, NULL, NULL, NULL );
if (rc!=ERROR_SUCCESS) goto done; if (rc!=ERROR_SUCCESS) {
goto done;
}
/* Open the sub-key */ /* Open the sub-key */
rc=RegOpenKeyExW(newKey, rc=RegOpenKeyExW(newKey,
keyBuf, /* subkey */ keyBuf, /* subkey */
0, /* reserved */ 0, /* reserved */
KEY_READ, KEY_READ,
&subKey); &subKey);
if (rc!=ERROR_SUCCESS) goto done; if (rc!=ERROR_SUCCESS) {
goto done;
}
/* Find the value of the buffer size, malloc, then read it */ /* Find the value of the buffer size, malloc, then read it */
RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize); RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
if (reqdSize) { if (reqdSize) {
...@@ -372,7 +423,9 @@ getpythonregpath(HKEY keyBase, int skipcore) ...@@ -372,7 +423,9 @@ getpythonregpath(HKEY keyBase, int skipcore)
} }
/* return null if no path to return */ /* 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 */ /* original datasize from RegQueryInfo doesn't include the \0 */
dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR)); dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
...@@ -392,8 +445,9 @@ getpythonregpath(HKEY keyBase, int skipcore) ...@@ -392,8 +445,9 @@ getpythonregpath(HKEY keyBase, int skipcore)
dataSize -= (DWORD)len; dataSize -= (DWORD)len;
} }
} }
if (skipcore) if (skipcore) {
*szCur = '\0'; *szCur = '\0';
}
else { else {
/* If we have no values, we don't need a ';' */ /* If we have no values, we don't need a ';' */
if (numKeys) { if (numKeys) {
...@@ -420,33 +474,34 @@ done: ...@@ -420,33 +474,34 @@ done:
PyMem_RawFree(ppPaths[index]); PyMem_RawFree(ppPaths[index]);
PyMem_RawFree(ppPaths); PyMem_RawFree(ppPaths);
} }
if (newKey) if (newKey) {
RegCloseKey(newKey); RegCloseKey(newKey);
}
PyMem_RawFree(keyBuf); PyMem_RawFree(keyBuf);
return retval; return retval;
} }
#endif /* Py_ENABLE_SHARED */ #endif /* Py_ENABLE_SHARED */
static void static void
get_progpath(void) get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath)
{ {
extern wchar_t *Py_GetProgramName(void); wchar_t *path = calculate->path_env;
wchar_t *path = _wgetenv(L"PATH");
wchar_t *prog = Py_GetProgramName();
#ifdef Py_ENABLE_SHARED #ifdef Py_ENABLE_SHARED
extern HANDLE PyWin_DLLhModule; extern HANDLE PyWin_DLLhModule;
/* static init of progpath ensures final char remains \0 */ /* static init of progpath ensures final char remains \0 */
if (PyWin_DLLhModule) if (PyWin_DLLhModule) {
if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) {
dllpath[0] = 0; dllpath[0] = 0;
}
}
#else #else
dllpath[0] = 0; dllpath[0] = 0;
#endif #endif
if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) {
return; return;
if (prog == NULL || *prog == '\0') }
prog = L"python";
/* If there is no slash in the argv0 path, then we have to /* 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 * assume python is on the user's $PATH, since there's no
...@@ -454,11 +509,13 @@ get_progpath(void) ...@@ -454,11 +509,13 @@ get_progpath(void)
* $PATH isn't exported, you lose. * $PATH isn't exported, you lose.
*/ */
#ifdef ALTSEP #ifdef ALTSEP
if (wcschr(prog, SEP) || wcschr(prog, ALTSEP)) if (wcschr(calculate->prog, SEP) || wcschr(calculate->prog, ALTSEP))
#else #else
if (wcschr(prog, SEP)) if (wcschr(calculate->prog, SEP))
#endif #endif
wcsncpy(progpath, prog, MAXPATHLEN); {
wcsncpy(progpath, calculate->prog, MAXPATHLEN);
}
else if (path) { else if (path) {
while (1) { while (1) {
wchar_t *delim = wcschr(path, DELIM); wchar_t *delim = wcschr(path, DELIM);
...@@ -470,13 +527,15 @@ get_progpath(void) ...@@ -470,13 +527,15 @@ get_progpath(void)
wcsncpy(progpath, path, len); wcsncpy(progpath, path, len);
*(progpath + len) = '\0'; *(progpath + len) = '\0';
} }
else else {
wcsncpy(progpath, path, MAXPATHLEN); wcsncpy(progpath, path, MAXPATHLEN);
}
/* join() is safe for MAXPATHLEN+1 size buffer */ /* join() is safe for MAXPATHLEN+1 size buffer */
join(progpath, prog); join(progpath, calculate->prog);
if (exists(progpath)) if (exists(progpath)) {
break; break;
}
if (!delim) { if (!delim) {
progpath[0] = '\0'; progpath[0] = '\0';
...@@ -485,10 +544,12 @@ get_progpath(void) ...@@ -485,10 +544,12 @@ get_progpath(void)
path = delim + 1; path = delim + 1;
} }
} }
else else {
progpath[0] = '\0'; progpath[0] = '\0';
}
} }
static int static int
find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) 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) ...@@ -502,15 +563,18 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
PyObject * decoded; PyObject * decoded;
size_t n; size_t n;
if (p == NULL) if (p == NULL) {
break; break;
}
n = strlen(p); n = strlen(p);
if (p[n - 1] != '\n') { if (p[n - 1] != '\n') {
/* line has overflowed - bail */ /* line has overflowed - bail */
break; break;
} }
if (p[0] == '#') /* Comment - skip */ if (p[0] == '#') {
/* Comment - skip */
continue; continue;
}
decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape"); decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape");
if (decoded != NULL) { if (decoded != NULL) {
Py_ssize_t k; Py_ssize_t k;
...@@ -537,12 +601,14 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value) ...@@ -537,12 +601,14 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
return result; return result;
} }
static int
static wchar_t*
read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
{ {
FILE *sp_file = _Py_wfopen(path, L"r"); FILE *sp_file = _Py_wfopen(path, L"r");
if (sp_file == NULL) if (sp_file == NULL) {
return -1; return NULL;
}
wcscpy_s(prefix, MAXPATHLEN+1, path); wcscpy_s(prefix, MAXPATHLEN+1, path);
reduce(prefix); reduce(prefix);
...@@ -558,10 +624,12 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) ...@@ -558,10 +624,12 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
while (!feof(sp_file)) { while (!feof(sp_file)) {
char line[MAXPATHLEN + 1]; char line[MAXPATHLEN + 1];
char *p = fgets(line, MAXPATHLEN + 1, sp_file); char *p = fgets(line, MAXPATHLEN + 1, sp_file);
if (!p) if (!p) {
break; break;
if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') }
if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') {
continue; continue;
}
while (*++p) { while (*++p) {
if (*p == '\r' || *p == '\n') { if (*p == '\r' || *p == '\n') {
*p = '\0'; *p = '\0';
...@@ -611,126 +679,176 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) ...@@ -611,126 +679,176 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
PyMem_RawFree(wline); PyMem_RawFree(wline);
} }
module_search_path = buf;
fclose(sp_file); fclose(sp_file);
return 0; return buf;
error: error:
PyMem_RawFree(buf); PyMem_RawFree(buf);
fclose(sp_file); fclose(sp_file);
return -1; return NULL;
} }
static void static _PyInitError
calculate_path(const _PyMainInterpreterConfig *config) calculate_init(PyCalculatePath *calculate,
const _PyMainInterpreterConfig *main_config)
{ {
wchar_t argv0_path[MAXPATHLEN+1]; _PyInitError err;
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];
if (config) { err = _Py_GetPythonHomeWithConfig(main_config, &calculate->home);
envpath = config->module_search_path_env; 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) { else if (!Py_IgnoreEnvironmentFlag) {
envpath = _wgetenv(L"PYTHONPATH"); wchar_t *path = _wgetenv(L"PYTHONPATH");
if (envpath && *envpath == '\0') if (path && *path != '\0') {
envpath = NULL; calculate->module_search_path_env = path;
}
} }
get_progpath(); calculate->path_env = _wgetenv(L"PATH");
/* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
wcscpy_s(argv0_path, MAXPATHLEN+1, progpath);
reduce(argv0_path);
/* Search for a sys.path file */ wchar_t *prog = Py_GetProgramName();
{ if (prog == NULL || *prog == '\0') {
wchar_t spbuffer[MAXPATHLEN+1]; prog = L"python";
}
calculate->prog = prog;
if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) || return _Py_INIT_OK();
(progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) { }
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.
*/
{ static int
wchar_t envbuffer[MAXPATHLEN+1]; calculate_pth_file(PyPathConfig *config)
wchar_t tmpbuffer[MAXPATHLEN+1]; {
const wchar_t *env_cfg = L"pyvenv.cfg"; wchar_t spbuffer[MAXPATHLEN+1];
FILE * env_file = NULL;
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); join(envbuffer, env_cfg);
env_file = _Py_wfopen(envbuffer, L"r"); env_file = _Py_wfopen(envbuffer, L"r");
if (env_file == NULL) { if (env_file == NULL) {
errno = 0; 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 */ if (env_file == NULL) {
change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip"); return;
}
if (pythonhome == NULL || *pythonhome == '\0') { /* Look for a 'home' variable and set argv0_path to it, if found */
if (zip_path[0] && exists(zip_path)) { wchar_t tmpbuffer[MAXPATHLEN+1];
wcscpy_s(prefix, MAXPATHLEN+1, zip_path); if (find_env_config_value(env_file, L"home", tmpbuffer)) {
reduce(prefix); wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, tmpbuffer);
pythonhome = prefix;
} else if (search_for_prefix(argv0_path, LANDMARK))
pythonhome = prefix;
else
pythonhome = NULL;
} }
else fclose(env_file);
wcscpy_s(prefix, MAXPATHLEN+1, pythonhome); }
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 #ifdef Py_ENABLE_SHARED
machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);
userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome); calculate->user_path = getpythonregpath(HKEY_CURRENT_USER, skiphome);
#endif #endif
/* We only use the default relative PYTHONPATH if we haven't /* We only use the default relative PYTHONPATH if we haven't
anything better to use! */ anything better to use! */
skipdefault = envpath!=NULL || pythonhome!=NULL || \ int skipdefault = (calculate->module_search_path_env!=NULL || calculate->home!=NULL || \
machinepath!=NULL || userpath!=NULL; calculate->machine_path!=NULL || calculate->user_path!=NULL);
/* We need to construct a path from the following parts. /* We need to construct a path from the following parts.
(1) the PYTHONPATH environment variable, if set; (1) the PYTHONPATH environment variable, if set;
(2) for Win32, the zip archive file path; (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 "." (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). (5) the directory containing the executable (argv0_path).
The length calculation calculates #4 first. The length calculation calculates #4 first.
Extra rules: Extra rules:
...@@ -739,74 +857,80 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -739,74 +857,80 @@ calculate_path(const _PyMainInterpreterConfig *config)
*/ */
/* Calculate size of return buffer */ /* Calculate size of return buffer */
if (pythonhome != NULL) { size_t bufsz = 0;
if (calculate->home != NULL) {
wchar_t *p; wchar_t *p;
bufsz = 1; bufsz = 1;
for (p = PYTHONPATH; *p; p++) { for (p = PYTHONPATH; *p; p++) {
if (*p == DELIM) if (*p == DELIM) {
bufsz++; /* number of DELIM plus one */ bufsz++; /* number of DELIM plus one */
}
} }
bufsz *= wcslen(pythonhome); bufsz *= wcslen(calculate->home);
} }
else
bufsz = 0;
bufsz += wcslen(PYTHONPATH) + 1; bufsz += wcslen(PYTHONPATH) + 1;
bufsz += wcslen(argv0_path) + 1; bufsz += wcslen(calculate->argv0_path) + 1;
if (userpath) if (calculate->user_path) {
bufsz += wcslen(userpath) + 1; bufsz += wcslen(calculate->user_path) + 1;
if (machinepath) }
bufsz += wcslen(machinepath) + 1; if (calculate->machine_path) {
bufsz += wcslen(zip_path) + 1; bufsz += wcslen(calculate->machine_path) + 1;
if (envpath != NULL) }
bufsz += wcslen(envpath) + 1; bufsz += wcslen(calculate->zip_path) + 1;
if (calculate->module_search_path_env != NULL) {
module_search_path = buf = PyMem_RawMalloc(bufsz*sizeof(wchar_t)); bufsz += wcslen(calculate->module_search_path_env) + 1;
}
wchar_t *buf, *start_buf;
buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
if (buf == NULL) { if (buf == NULL) {
/* We can't exit, so print a warning and limp along */ /* We can't exit, so print a warning and limp along */
fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n"); fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
if (envpath) { if (calculate->module_search_path_env) {
fprintf(stderr, "Using environment $PYTHONPATH.\n"); fprintf(stderr, "Using environment $PYTHONPATH.\n");
module_search_path = envpath; config->module_search_path = calculate->module_search_path_env;
} }
else { else {
fprintf(stderr, "Using default static path.\n"); fprintf(stderr, "Using default static path.\n");
module_search_path = PYTHONPATH; config->module_search_path = PYTHONPATH;
} }
PyMem_RawFree(machinepath);
PyMem_RawFree(userpath);
return; return;
} }
start_buf = buf;
if (envpath) { if (calculate->module_search_path_env) {
if (wcscpy_s(buf, bufsz - (buf - module_search_path), envpath)) if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->module_search_path_env)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
}
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
if (zip_path[0]) { if (calculate->zip_path[0]) {
if (wcscpy_s(buf, bufsz - (buf - module_search_path), zip_path)) if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
}
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
if (userpath) { if (calculate->user_path) {
if (wcscpy_s(buf, bufsz - (buf - module_search_path), userpath)) if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
}
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
PyMem_RawFree(userpath);
} }
if (machinepath) { if (calculate->machine_path) {
if (wcscpy_s(buf, bufsz - (buf - module_search_path), machinepath)) if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
}
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
PyMem_RawFree(machinepath);
} }
if (pythonhome == NULL) { if (calculate->home == NULL) {
if (!skipdefault) { 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()"); Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
}
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
...@@ -816,13 +940,16 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -816,13 +940,16 @@ calculate_path(const _PyMainInterpreterConfig *config)
size_t n; size_t n;
for (;;) { for (;;) {
q = wcschr(p, DELIM); q = wcschr(p, DELIM);
if (q == NULL) if (q == NULL) {
n = wcslen(p); n = wcslen(p);
else }
else {
n = q-p; n = q-p;
}
if (p[0] == '.' && is_sep(p[1])) { 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()"); Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
}
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
p++; p++;
n--; n--;
...@@ -830,17 +957,19 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -830,17 +957,19 @@ calculate_path(const _PyMainInterpreterConfig *config)
wcsncpy(buf, p, n); wcsncpy(buf, p, n);
buf += n; buf += n;
*buf++ = DELIM; *buf++ = DELIM;
if (q == NULL) if (q == NULL) {
break; break;
}
p = q+1; p = q+1;
} }
} }
if (argv0_path) { if (calculate->argv0_path) {
wcscpy(buf, argv0_path); wcscpy(buf, calculate->argv0_path);
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
*(buf - 1) = L'\0'; *(buf - 1) = L'\0';
/* Now to pull one last hack/trick. If sys.prefix is /* Now to pull one last hack/trick. If sys.prefix is
empty, then try and find it somewhere on the paths empty, then try and find it somewhere on the paths
we calculated. We scan backwards, as our general policy we calculated. We scan backwards, as our general policy
...@@ -849,7 +978,7 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -849,7 +978,7 @@ calculate_path(const _PyMainInterpreterConfig *config)
on the path, and that our 'prefix' directory is on the path, and that our 'prefix' directory is
the parent of that. the parent of that.
*/ */
if (*prefix==L'\0') { if (config->prefix[0] == L'\0') {
wchar_t lookBuf[MAXPATHLEN+1]; wchar_t lookBuf[MAXPATHLEN+1];
wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */ wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
while (1) { while (1) {
...@@ -859,84 +988,129 @@ calculate_path(const _PyMainInterpreterConfig *config) ...@@ -859,84 +988,129 @@ calculate_path(const _PyMainInterpreterConfig *config)
start of the path in question - even if this start of the path in question - even if this
is one character before the start of the buffer is one character before the start of the buffer
*/ */
while (look >= module_search_path && *look != DELIM) while (look >= start_buf && *look != DELIM)
look--; look--;
nchars = lookEnd-look; nchars = lookEnd-look;
wcsncpy(lookBuf, look+1, nchars); wcsncpy(lookBuf, look+1, nchars);
lookBuf[nchars] = L'\0'; lookBuf[nchars] = L'\0';
/* Up one level to the parent */ /* Up one level to the parent */
reduce(lookBuf); reduce(lookBuf);
if (search_for_prefix(lookBuf, LANDMARK)) { if (search_for_prefix(config->prefix, lookBuf, LANDMARK)) {
break; break;
} }
/* If we are out of paths to search - give up */ /* If we are out of paths to search - give up */
if (look < module_search_path) if (look < start_buf) {
break; break;
}
look--; 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 */ /* External interface */
void void
Py_SetPath(const wchar_t *path) Py_SetPath(const wchar_t *path)
{ {
if (module_search_path != NULL) { if (path_config.module_search_path != NULL) {
PyMem_RawFree(module_search_path); PyMem_RawFree(path_config.module_search_path);
module_search_path = NULL; path_config.module_search_path = NULL;
} }
if (path != NULL) {
extern wchar_t *Py_GetProgramName(void); if (path == NULL) {
wchar_t *prog = Py_GetProgramName(); return;
wcsncpy(progpath, prog, MAXPATHLEN); }
prefix[0] = L'\0';
module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); wchar_t *prog = Py_GetProgramName();
if (module_search_path != NULL) wcsncpy(path_config.progpath, prog, MAXPATHLEN);
wcscpy(module_search_path, path); 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 * wchar_t *
_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config) _Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config)
{ {
if (!module_search_path) { if (!path_config.module_search_path) {
calculate_path(config); calculate_path(main_config);
} }
return module_search_path; return path_config.module_search_path;
} }
wchar_t * wchar_t *
Py_GetPath(void) Py_GetPath(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return module_search_path; }
return path_config.module_search_path;
} }
wchar_t * wchar_t *
Py_GetPrefix(void) Py_GetPrefix(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return prefix; }
return path_config.prefix;
} }
wchar_t * wchar_t *
Py_GetExecPrefix(void) Py_GetExecPrefix(void)
{ {
return Py_GetPrefix(); return Py_GetPrefix();
} }
wchar_t * wchar_t *
Py_GetProgramFullPath(void) Py_GetProgramFullPath(void)
{ {
if (!module_search_path) if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path(NULL);
return progpath; }
return path_config.progpath;
} }
/* Load python3.dll before loading any extension module that might refer /* 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 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 to this python DLL is loaded, not a python3.dll that might be on the path
...@@ -950,20 +1124,23 @@ _Py_CheckPython3() ...@@ -950,20 +1124,23 @@ _Py_CheckPython3()
{ {
wchar_t py3path[MAXPATHLEN+1]; wchar_t py3path[MAXPATHLEN+1];
wchar_t *s; wchar_t *s;
if (python3_checked) if (python3_checked) {
return hPython3 != NULL; return hPython3 != NULL;
}
python3_checked = 1; python3_checked = 1;
/* If there is a python3.dll next to the python3y.dll, /* If there is a python3.dll next to the python3y.dll,
assume this is a build tree; use that DLL */ assume this is a build tree; use that DLL */
wcscpy(py3path, dllpath); wcscpy(py3path, path_config.dllpath);
s = wcsrchr(py3path, L'\\'); s = wcsrchr(py3path, L'\\');
if (!s) if (!s) {
s = py3path; s = py3path;
}
wcscpy(s, L"\\python3.dll"); wcscpy(s, L"\\python3.dll");
hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (hPython3 != NULL) if (hPython3 != NULL) {
return 1; return 1;
}
/* Check sys.prefix\DLLs\python3.dll */ /* Check sys.prefix\DLLs\python3.dll */
wcscpy(py3path, Py_GetPrefix()); wcscpy(py3path, Py_GetPrefix());
......
...@@ -1477,8 +1477,9 @@ Py_SetPythonHome(wchar_t *home) ...@@ -1477,8 +1477,9 @@ Py_SetPythonHome(wchar_t *home)
default_home = home; default_home = home;
} }
wchar_t *
_Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config) _PyInitError
_Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config, wchar_t **homep)
{ {
/* Use a static buffer to avoid heap memory allocation failure. /* Use a static buffer to avoid heap memory allocation failure.
Py_GetPythonHome() doesn't allow to report error, and the caller Py_GetPythonHome() doesn't allow to report error, and the caller
...@@ -1486,32 +1487,40 @@ _Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config) ...@@ -1486,32 +1487,40 @@ _Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config)
static wchar_t buffer[MAXPATHLEN+1]; static wchar_t buffer[MAXPATHLEN+1];
if (default_home) { if (default_home) {
return default_home; *homep = default_home;
return _Py_INIT_OK();
} }
if (config) { if (config) {
return config->pythonhome; *homep = config->pythonhome;
return _Py_INIT_OK();
} }
char *home = Py_GETENV("PYTHONHOME"); char *home = Py_GETENV("PYTHONHOME");
if (!home) { if (!home) {
return NULL; *homep = NULL;
return _Py_INIT_OK();
} }
size_t size = Py_ARRAY_LENGTH(buffer); size_t size = Py_ARRAY_LENGTH(buffer);
size_t r = mbstowcs(buffer, home, size); size_t r = mbstowcs(buffer, home, size);
if (r == (size_t)-1 || r >= size) { if (r == (size_t)-1 || r >= size) {
/* conversion failed or the static buffer is too small */ /* conversion failed or the static buffer is too small */
return NULL; *homep = NULL;
return _Py_INIT_ERR("failed to decode PYTHONHOME environment variable");
} }
return buffer; *homep = buffer;
return _Py_INIT_OK();
} }
wchar_t * wchar_t *
Py_GetPythonHome(void) Py_GetPythonHome(void)
{ {
return _Py_GetPythonHomeWithConfig(NULL); wchar_t *home;
/* Ignore error */
(void)_Py_GetPythonHomeWithConfig(NULL, &home);
return home;
} }
/* Add the __main__ module */ /* Add the __main__ module */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment