Unverified Kaydet (Commit) 0327bde9 authored tarafından Victor Stinner's avatar Victor Stinner Kaydeden (comit) 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)
üst bdb8315c
......@@ -7,23 +7,7 @@
extern "C" {
#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
/* 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 {
const char *prefix;
const char *msg;
......@@ -46,9 +30,31 @@ typedef struct {
Don't abort() the process on such error. */
#define _Py_INIT_USER_ERR(MSG) \
(_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) \
(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!) */
PyAPI_FUNC(_PyInitError) _Py_InitializeCore(const _PyCoreConfig *);
PyAPI_FUNC(int) _Py_IsCoreInitialized(void);
......
......@@ -7,7 +7,7 @@
#include <string.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
# include <mach-o/dyld.h>
#endif
/* Search in some common locations for the associated Python libraries.
......@@ -97,7 +97,7 @@
*/
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
......@@ -109,13 +109,38 @@
#define LANDMARK L"os.py"
#endif
static wchar_t prefix[MAXPATHLEN+1];
static wchar_t exec_prefix[MAXPATHLEN+1];
static wchar_t progpath[MAXPATHLEN+1];
static wchar_t *module_search_path = NULL;
typedef struct {
wchar_t prefix[MAXPATHLEN+1];
wchar_t exec_prefix[MAXPATHLEN+1];
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
_Py_wstat(const wchar_t* path, struct stat *buf)
{
......@@ -131,6 +156,7 @@ _Py_wstat(const wchar_t* path, struct stat *buf)
return err;
}
static void
reduce(wchar_t *dir)
{
......@@ -140,14 +166,17 @@ reduce(wchar_t *dir)
dir[i] = '\0';
}
static int
isfile(wchar_t *filename) /* Is file, not directory */
{
struct stat buf;
if (_Py_wstat(filename, &buf) != 0)
if (_Py_wstat(filename, &buf) != 0) {
return 0;
if (!S_ISREG(buf.st_mode))
}
if (!S_ISREG(buf.st_mode)) {
return 0;
}
return 1;
}
......@@ -155,41 +184,50 @@ isfile(wchar_t *filename) /* Is file, not directory */
static int
ismodule(wchar_t *filename) /* Is module -- check for .pyc too */
{
if (isfile(filename))
if (isfile(filename)) {
return 1;
}
/* Check for the compiled version of prefix. */
if (wcslen(filename) < MAXPATHLEN) {
wcscat(filename, L"c");
if (isfile(filename))
if (isfile(filename)) {
return 1;
}
}
return 0;
}
/* Is executable file */
static int
isxfile(wchar_t *filename) /* Is executable file */
isxfile(wchar_t *filename)
{
struct stat buf;
if (_Py_wstat(filename, &buf) != 0)
if (_Py_wstat(filename, &buf) != 0) {
return 0;
if (!S_ISREG(buf.st_mode))
}
if (!S_ISREG(buf.st_mode)) {
return 0;
if ((buf.st_mode & 0111) == 0)
}
if ((buf.st_mode & 0111) == 0) {
return 0;
}
return 1;
}
/* Is directory */
static int
isdir(wchar_t *filename) /* Is directory */
isdir(wchar_t *filename)
{
struct stat buf;
if (_Py_wstat(filename, &buf) != 0)
if (_Py_wstat(filename, &buf) != 0) {
return 0;
if (!S_ISDIR(buf.st_mode))
}
if (!S_ISDIR(buf.st_mode)) {
return 0;
}
return 1;
}
......@@ -207,58 +245,67 @@ static void
joinpath(wchar_t *buffer, wchar_t *stuff)
{
size_t n, k;
if (stuff[0] == SEP)
if (stuff[0] == SEP) {
n = 0;
}
else {
n = wcslen(buffer);
if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN)
if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) {
buffer[n++] = SEP;
}
}
if (n > MAXPATHLEN)
if (n > MAXPATHLEN) {
Py_FatalError("buffer overflow in getpath.c's joinpath()");
}
k = wcslen(stuff);
if (n + k > MAXPATHLEN)
if (n + k > MAXPATHLEN) {
k = MAXPATHLEN - n;
}
wcsncpy(buffer+n, stuff, k);
buffer[n+k] = '\0';
}
/* copy_absolute requires that path be allocated at least
MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */
static void
copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen)
{
if (p[0] == SEP)
if (p[0] == SEP) {
wcscpy(path, p);
}
else {
if (!_Py_wgetcwd(path, pathlen)) {
/* unable to get the current directory */
wcscpy(path, p);
return;
}
if (p[0] == '.' && p[1] == SEP)
if (p[0] == '.' && p[1] == SEP) {
p += 2;
}
joinpath(path, p);
}
}
/* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */
static void
absolutize(wchar_t *path)
{
wchar_t buffer[MAXPATHLEN+1];
if (path[0] == SEP)
if (path[0] == SEP) {
return;
}
copy_absolute(buffer, path, MAXPATHLEN+1);
wcscpy(path, buffer);
}
/* 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
bytes long.
*/
static int
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;
int 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;
......@@ -307,106 +357,151 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
return result;
}
/* search_for_prefix requires that argv0_path be no more than MAXPATHLEN
bytes long.
*/
static int
search_for_prefix(wchar_t *argv0_path, wchar_t *home, wchar_t *_prefix,
wchar_t *lib_python)
search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{
size_t n;
wchar_t *vpath;
/* If PYTHONHOME is set, we believe it unconditionally */
if (home) {
wchar_t *delim;
wcsncpy(prefix, home, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0';
delim = wcschr(prefix, DELIM);
if (delim)
if (calculate->home) {
wcsncpy(config->prefix, calculate->home, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0';
wchar_t *delim = wcschr(config->prefix, DELIM);
if (delim) {
*delim = L'\0';
joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK);
}
joinpath(config->prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK);
return 1;
}
/* Check to see if argv[0] is in the build directory */
wcsncpy(prefix, argv0_path, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0';
joinpath(prefix, L"Modules/Setup");
if (isfile(prefix)) {
wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0';
joinpath(config->prefix, L"Modules/Setup");
if (isfile(config->prefix)) {
/* Check VPATH to see if argv0_path is in the build directory. */
vpath = Py_DecodeLocale(VPATH, NULL);
if (vpath != NULL) {
wcsncpy(prefix, argv0_path, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0';
joinpath(prefix, vpath);
wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0';
joinpath(config->prefix, vpath);
PyMem_RawFree(vpath);
joinpath(prefix, L"Lib");
joinpath(prefix, LANDMARK);
if (ismodule(prefix))
joinpath(config->prefix, L"Lib");
joinpath(config->prefix, LANDMARK);
if (ismodule(config->prefix)) {
return -1;
}
}
}
/* 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 {
n = wcslen(prefix);
joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK);
if (ismodule(prefix))
n = wcslen(config->prefix);
joinpath(config->prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK);
if (ismodule(config->prefix)) {
return 1;
prefix[n] = L'\0';
reduce(prefix);
} while (prefix[0]);
}
config->prefix[n] = L'\0';
reduce(config->prefix);
} while (config->prefix[0]);
/* Look at configure's PREFIX */
wcsncpy(prefix, _prefix, MAXPATHLEN);
prefix[MAXPATHLEN] = L'\0';
joinpath(prefix, lib_python);
joinpath(prefix, LANDMARK);
if (ismodule(prefix))
wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0';
joinpath(config->prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK);
if (ismodule(config->prefix)) {
return 1;
}
/* Fail */
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
MAXPATHLEN bytes long.
*/
static int
search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
wchar_t *_exec_prefix, wchar_t *lib_python)
search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{
size_t n;
/* If PYTHONHOME is set, we believe it unconditionally */
if (home) {
wchar_t *delim;
delim = wcschr(home, DELIM);
if (delim)
wcsncpy(exec_prefix, delim+1, MAXPATHLEN);
else
wcsncpy(exec_prefix, home, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, L"lib-dynload");
if (calculate->home) {
wchar_t *delim = wcschr(calculate->home, DELIM);
if (delim) {
wcsncpy(config->exec_prefix, delim+1, MAXPATHLEN);
}
else {
wcsncpy(config->exec_prefix, calculate->home, MAXPATHLEN);
}
config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload");
return 1;
}
/* 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
of shared library modules. */
wcsncpy(exec_prefix, argv0_path, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, L"pybuilddir.txt");
if (isfile(exec_prefix)) {
FILE *f = _Py_wfopen(exec_prefix, L"rb");
if (f == NULL)
wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN);
config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, L"pybuilddir.txt");
if (isfile(config->exec_prefix)) {
FILE *f = _Py_wfopen(config->exec_prefix, L"rb");
if (f == NULL) {
errno = 0;
}
else {
char buf[MAXPATHLEN+1];
PyObject *decoded;
......@@ -422,9 +517,9 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
Py_DECREF(decoded);
if (k >= 0) {
rel_builddir_path[k] = L'\0';
wcsncpy(exec_prefix, argv0_path, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, rel_builddir_path);
wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN);
config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, rel_builddir_path);
return -1;
}
}
......@@ -432,87 +527,85 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
}
/* 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 {
n = wcslen(exec_prefix);
joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, L"lib-dynload");
if (isdir(exec_prefix))
n = wcslen(config->exec_prefix);
joinpath(config->exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload");
if (isdir(config->exec_prefix)) {
return 1;
exec_prefix[n] = L'\0';
reduce(exec_prefix);
} while (exec_prefix[0]);
}
config->exec_prefix[n] = L'\0';
reduce(config->exec_prefix);
} while (config->exec_prefix[0]);
/* Look at configure's EXEC_PREFIX */
wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
exec_prefix[MAXPATHLEN] = L'\0';
joinpath(exec_prefix, lib_python);
joinpath(exec_prefix, L"lib-dynload");
if (isdir(exec_prefix))
wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
config->exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload");
if (isdir(config->exec_prefix)) {
return 1;
}
/* Fail */
return 0;
}
static void
calculate_path(const _PyMainInterpreterConfig *config)
calculate_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{
extern wchar_t *Py_GetProgramName(void);
static const wchar_t delimiter[2] = {DELIM, '\0'};
static const wchar_t separator[2] = {SEP, '\0'};
wchar_t *home = _Py_GetPythonHomeWithConfig(config);
char *_path = getenv("PATH");
wchar_t *path_buffer = NULL;
wchar_t *path = NULL;
wchar_t *prog = Py_GetProgramName();
wchar_t argv0_path[MAXPATHLEN+1];
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;
calculate->exec_prefix_found = search_for_exec_prefix(calculate, config);
if (!calculate->exec_prefix_found) {
if (!Py_FrozenFlag) {
fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n");
}
wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
joinpath(config->exec_prefix, L"lib/lib-dynload");
}
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
}
_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) {
Py_FatalError(
"Unable to decode path variables in getpath.c: "
"memory error");
static void
calculate_reduce_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
{
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);
}
}
if (_path) {
path_buffer = Py_DecodeLocale(_path, NULL);
path = path_buffer;
else {
wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN);
}
}
static void
calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
{
/* 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
* other way to find a directory to start the search from. If
* $PATH isn't exported, you lose.
*/
if (wcschr(prog, SEP))
wcsncpy(progpath, prog, MAXPATHLEN);
if (wcschr(calculate->prog, SEP)) {
wcsncpy(config->progpath, calculate->prog, MAXPATHLEN);
}
#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
* "#!/opt/python2.3/bin/python", the kernel only passes "python"
* as argv[0], which falls through to the $PATH search below.
......@@ -524,47 +617,60 @@ calculate_path(const _PyMainInterpreterConfig *config)
* absolutize() should help us out below
*/
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) {
/* Could not convert execpath, or it's too long. */
progpath[0] = '\0';
config->progpath[0] = '\0';
}
}
#endif /* __APPLE__ */
else if (path) {
else if (calculate->path_env) {
wchar_t *path = calculate->path_env;
while (1) {
wchar_t *delim = wcschr(path, DELIM);
if (delim) {
size_t len = delim - path;
if (len > MAXPATHLEN)
if (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);
if (isxfile(progpath))
joinpath(config->progpath, calculate->prog);
if (isxfile(config->progpath)) {
break;
}
if (!delim) {
progpath[0] = L'\0';
config->progpath[0] = L'\0';
break;
}
path = delim + 1;
}
}
else
progpath[0] = '\0';
PyMem_RawFree(path_buffer);
if (progpath[0] != SEP && progpath[0] != '\0')
absolutize(progpath);
wcsncpy(argv0_path, progpath, MAXPATHLEN);
argv0_path[MAXPATHLEN] = '\0';
else {
config->progpath[0] = '\0';
}
if (config->progpath[0] != SEP && config->progpath[0] != '\0') {
absolutize(config->progpath);
}
}
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
NSModule pythonModule;
/* 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,
** which is in the framework, not relative to the executable, which may
......@@ -572,7 +678,7 @@ calculate_path(const _PyMainInterpreterConfig *config)
*/
pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
/* Use dylib functions to find out where the framework was loaded from */
modPath = NSLibraryNameForModule(pythonModule);
const char* modPath = NSLibraryNameForModule(pythonModule);
if (modPath != NULL) {
/* We're in a framework. */
/* See if we might be in the build directory. The framework in the
......@@ -587,153 +693,132 @@ calculate_path(const _PyMainInterpreterConfig *config)
Py_FatalError("Cannot decode framework location");
}
wcsncpy(argv0_path, wbuf, MAXPATHLEN);
reduce(argv0_path);
joinpath(argv0_path, lib_python);
joinpath(argv0_path, LANDMARK);
if (!ismodule(argv0_path)) {
wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
reduce(calculate->argv0_path);
joinpath(calculate->argv0_path, calculate->lib_python);
joinpath(calculate->argv0_path, LANDMARK);
if (!ismodule(calculate->argv0_path)) {
/* We are in the build directory so use the name of the
executable - we know that the absolute path is passed */
wcsncpy(argv0_path, progpath, MAXPATHLEN);
wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN);
}
else {
/* Use the location of the library as the progpath */
wcsncpy(argv0_path, wbuf, MAXPATHLEN);
wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
}
PyMem_RawFree(wbuf);
}
#endif
#if HAVE_READLINK
{
wchar_t tmpbuffer[MAXPATHLEN+1];
int linklen = _Py_wreadlink(progpath, tmpbuffer, MAXPATHLEN);
while (linklen != -1) {
if (tmpbuffer[0] == SEP)
/* tmpbuffer should never be longer than MAXPATHLEN,
but extra check does not hurt */
wcsncpy(argv0_path, tmpbuffer, MAXPATHLEN);
else {
/* Interpret relative to progpath */
reduce(argv0_path);
joinpath(argv0_path, tmpbuffer);
}
linklen = _Py_wreadlink(argv0_path, tmpbuffer, MAXPATHLEN);
wchar_t tmpbuffer[MAXPATHLEN+1];
int linklen = _Py_wreadlink(config->progpath, tmpbuffer, MAXPATHLEN);
while (linklen != -1) {
if (tmpbuffer[0] == SEP) {
/* tmpbuffer should never be longer than MAXPATHLEN,
but extra check does not hurt */
wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
}
else {
/* Interpret relative to progpath */
reduce(calculate->argv0_path);
joinpath(calculate->argv0_path, tmpbuffer);
}
linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
}
#endif /* HAVE_READLINK */
reduce(argv0_path);
reduce(calculate->argv0_path);
/* 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.
*/
{
wchar_t tmpbuffer[MAXPATHLEN+1];
wchar_t *env_cfg = L"pyvenv.cfg";
FILE * env_file = NULL;
/* Search for an "pyvenv.cfg" 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_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);
env_file = _Py_wfopen(tmpbuffer, L"r");
if (env_file == NULL) {
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 (!pfound) {
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 (env_file == NULL) {
return;
}
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
if ((!pfound || !efound) && !Py_FrozenFlag)
fprintf(stderr,
"Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
/* Look for a 'home' variable and set argv0_path to it, if found */
if (find_env_config_value(env_file, L"home", tmpbuffer)) {
wcscpy(calculate->argv0_path, tmpbuffer);
}
fclose(env_file);
}
/* Calculate size of return buffer.
*/
bufsz = 0;
wchar_t *env_path = NULL;
if (config) {
if (config->module_search_path_env) {
bufsz += wcslen(config->module_search_path_env) + 1;
}
static void
calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config)
{
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 {
char *env_pathb = Py_GETENV("PYTHONPATH");
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;
}
}
wcsncpy(calculate->zip_path, calculate->prefix, MAXPATHLEN);
}
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) {
wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP)
if (defpath[0] != SEP) {
/* Paths are relative to prefix */
bufsz += prefixsz;
}
if (delim)
if (delim) {
bufsz += delim - defpath + 1;
}
else {
bufsz += wcslen(defpath) + 1;
break;
......@@ -741,46 +826,40 @@ calculate_path(const _PyMainInterpreterConfig *config)
defpath = delim + 1;
}
bufsz += wcslen(zip_path) + 1;
bufsz += wcslen(exec_prefix) + 1;
bufsz += wcslen(calculate->zip_path) + 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) {
Py_FatalError(
"Not enough memory for dynamic PYTHONPATH");
}
buf[0] = '\0';
/* Run-time value of $PYTHONPATH goes first */
buf[0] = '\0';
if (config) {
if (config->module_search_path_env) {
wcscpy(buf, config->module_search_path_env);
wcscat(buf, delimiter);
}
}
else {
if (env_path) {
wcscpy(buf, env_path);
wcscat(buf, delimiter);
}
if (calculate->module_search_path_env) {
wcscpy(buf, calculate->module_search_path_env);
wcscat(buf, delimiter);
}
PyMem_RawFree(env_path);
/* Next is the default zip path */
wcscat(buf, zip_path);
wcscat(buf, calculate->zip_path);
wcscat(buf, delimiter);
/* Next goes merge of compile-time $PYTHONPATH with
* dynamically located prefix.
*/
defpath = _pythonpath;
defpath = calculate->pythonpath;
while (1) {
wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP) {
wcscat(buf, prefix);
if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP &&
defpath[0] != (delim ? DELIM : L'\0')) { /* not empty */
wcscat(buf, config->prefix);
if (prefixsz >= 2 && config->prefix[prefixsz - 2] != SEP &&
defpath[0] != (delim ? DELIM : L'\0'))
{
/* not empty */
wcscat(buf, separator);
}
}
......@@ -800,41 +879,130 @@ calculate_path(const _PyMainInterpreterConfig *config)
wcscat(buf, delimiter);
/* Finally, on goes the directory for dynamic-load modules */
wcscat(buf, exec_prefix);
wcscat(buf, config->exec_prefix);
/* And publish the results */
module_search_path = buf;
return buf;
}
/* 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 (pfound > 0) {
reduce(prefix);
reduce(prefix);
/* The prefix is the root directory, but reduce() chopped
* off the "/". */
if (!prefix[0])
wcscpy(prefix, separator);
#define DECODE_FAILED(NAME, LEN) \
((LEN) == (size_t)-2) \
? _Py_INIT_ERR("failed to decode " #NAME) \
: _Py_INIT_NO_MEMORY()
static _PyInitError
calculate_init(PyCalculatePath *calculate,
const _PyMainInterpreterConfig *main_config)
{
_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) {
reduce(exec_prefix);
reduce(exec_prefix);
reduce(exec_prefix);
if (!exec_prefix[0])
wcscpy(exec_prefix, separator);
calculate->module_search_path_env = NULL;
if (main_config) {
if (main_config->module_search_path_env) {
calculate->module_search_path_env = main_config->module_search_path_env;
}
}
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
wcsncpy(exec_prefix, _exec_prefix, MAXPATHLEN);
return _Py_INIT_OK();
}
PyMem_RawFree(_pythonpath);
PyMem_RawFree(_prefix);
PyMem_RawFree(_exec_prefix);
PyMem_RawFree(lib_python);
static void
calculate_free(PyCalculatePath *calculate)
{
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)
void
Py_SetPath(const wchar_t *path)
{
if (module_search_path != NULL) {
PyMem_RawFree(module_search_path);
module_search_path = NULL;
if (path_config.module_search_path != NULL) {
PyMem_RawFree(path_config.module_search_path);
path_config.module_search_path = NULL;
}
if (path != NULL) {
extern wchar_t *Py_GetProgramName(void);
wchar_t *prog = Py_GetProgramName();
wcsncpy(progpath, prog, MAXPATHLEN);
exec_prefix[0] = 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 == NULL) {
return;
}
wchar_t *prog = Py_GetProgramName();
wcsncpy(path_config.progpath, prog, MAXPATHLEN);
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 *
_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)
{
if (!module_search_path)
if (!path_config.module_search_path) {
calculate_path(NULL);
return exec_prefix;
}
return path_config.exec_prefix;
}
wchar_t *
Py_GetProgramFullPath(void)
{
if (!module_search_path)
if (!path_config.module_search_path) {
calculate_path(NULL);
return progpath;
}
return path_config.progpath;
}
#ifdef __cplusplus
}
#endif
......@@ -36,6 +36,16 @@
extern "C" {
#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() */
static wchar_t **orig_argv;
static int orig_argc;
......@@ -417,9 +427,6 @@ typedef struct {
.env_warning_options = {0, NULL}}
#define INIT_NO_MEMORY() _Py_INIT_ERR("memory allocation failed")
static void
pymain_optlist_clear(_Py_OptList *list)
{
......@@ -510,14 +517,14 @@ pymain_wstrdup(_PyMain *pymain, wchar_t *str)
{
size_t len = wcslen(str) + 1; /* +1 for NUL character */
if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return NULL;
}
size_t size = len * sizeof(wchar_t);
wchar_t *str2 = PyMem_RawMalloc(size);
if (str2 == NULL) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return NULL;
}
......@@ -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);
if (options2 == NULL) {
PyMem_RawFree(str2);
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
options2[list->len] = str2;
......@@ -571,7 +578,7 @@ pymain_parse_cmdline_impl(_PyMain *pymain)
size_t len = wcslen(_PyOS_optarg) + 1 + 1;
wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
if (command == NULL) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
memcpy(command, _PyOS_optarg, len * sizeof(wchar_t));
......@@ -717,7 +724,7 @@ pymain_add_xoptions(_PyMain *pymain)
for (size_t i=0; i < options->len; i++) {
wchar_t *option = options->options[i];
if (_PySys_AddXOptionWithError(option) < 0) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
}
......@@ -748,11 +755,11 @@ pymain_add_warnings_options(_PyMain *pymain)
PySys_ResetWarnOptions();
if (pymain_add_warnings_optlist(&pymain->env_warning_options) < 0) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
if (pymain_add_warnings_optlist(&pymain->cmdline.warning_options) < 0) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
return 0;
......@@ -801,7 +808,7 @@ pymain_warnings_envvar(_PyMain *pymain)
C89 wcstok */
buf = (char *)PyMem_RawMalloc(strlen(p) + 1);
if (buf == NULL) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
strcpy(buf, p);
......@@ -811,13 +818,7 @@ pymain_warnings_envvar(_PyMain *pymain)
size_t len;
wchar_t *warning = Py_DecodeLocale(p, &len);
if (warning == NULL) {
if (len == (size_t)-2) {
pymain->err = _Py_INIT_ERR("failed to decode "
"PYTHONWARNINGS");
}
else {
pymain->err = INIT_NO_MEMORY();
}
SET_DECODE_ERROR("PYTHONWARNINGS environment variable", len);
return -1;
}
if (pymain_optlist_append(pymain, &pymain->env_warning_options,
......@@ -902,7 +903,7 @@ pymain_get_program_name(_PyMain *pymain)
buffer = PyMem_RawMalloc(len * sizeof(wchar_t));
if (buffer == NULL) {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
......@@ -919,15 +920,8 @@ pymain_get_program_name(_PyMain *pymain)
size_t len;
wchar_t* wbuf = Py_DecodeLocale(pyvenv_launcher, &len);
if (wbuf == NULL) {
if (len == (size_t)-2) {
pymain->err = _Py_INIT_ERR("failed to decode "
"__PYVENV_LAUNCHER__");
return -1;
}
else {
pymain->err = INIT_NO_MEMORY();
return -1;
}
SET_DECODE_ERROR("__PYVENV_LAUNCHER__", len);
return -1;
}
pymain->program_name = wbuf;
}
......@@ -1403,7 +1397,7 @@ pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest,
return -2;
}
else {
pymain->err = INIT_NO_MEMORY();
pymain->err = _Py_INIT_NO_MEMORY();
return -1;
}
}
......@@ -1421,7 +1415,7 @@ pymain_init_pythonpath(_PyMain *pymain)
L"PYTHONPATH", "PYTHONPATH");
if (res < 0) {
if (res == -2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONPATH");
SET_DECODE_ERROR("PYTHONPATH", (size_t)-2);
}
return -1;
}
......@@ -1450,7 +1444,7 @@ pymain_init_pythonhome(_PyMain *pymain)
L"PYTHONHOME", "PYTHONHOME");
if (res < 0) {
if (res == -2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME");
SET_DECODE_ERROR("PYTHONHOME", (size_t)-2);
}
return -1;
}
......
......@@ -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());
......
......@@ -1477,8 +1477,9 @@ Py_SetPythonHome(wchar_t *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.
Py_GetPythonHome() doesn't allow to report error, and the caller
......@@ -1486,32 +1487,40 @@ _Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config)
static wchar_t buffer[MAXPATHLEN+1];
if (default_home) {
return default_home;
*homep = default_home;
return _Py_INIT_OK();
}
if (config) {
return config->pythonhome;
*homep = config->pythonhome;
return _Py_INIT_OK();
}
char *home = Py_GETENV("PYTHONHOME");
if (!home) {
return NULL;
*homep = NULL;
return _Py_INIT_OK();
}
size_t size = Py_ARRAY_LENGTH(buffer);
size_t r = mbstowcs(buffer, home, size);
if (r == (size_t)-1 || r >= size) {
/* 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 *
Py_GetPythonHome(void)
{
return _Py_GetPythonHomeWithConfig(NULL);
wchar_t *home;
/* Ignore error */
(void)_Py_GetPythonHomeWithConfig(NULL, &home);
return home;
}
/* 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