bpo-38234: read_pth_file() now returns PyStatus (GH-16338)
Refactor path configuration code: * read_pth_file() now returns PyStatus to report errors, rather than calling Py_FatalError(). * Move argv0_path and zip_path buffers out of PyCalculatePath structures. * On Windows, _PyPathConfig.home is now preferred over PyConfig.home.
This commit is contained in:
parent
9c42f8cda5
commit
85ce0a7178
|
@ -123,13 +123,11 @@ extern "C" {
|
|||
typedef struct {
|
||||
wchar_t *path_env; /* PATH environment variable */
|
||||
|
||||
wchar_t *pythonpath; /* PYTHONPATH define */
|
||||
wchar_t *prefix; /* PREFIX define */
|
||||
wchar_t *exec_prefix; /* EXEC_PREFIX define */
|
||||
wchar_t *pythonpath; /* PYTHONPATH macro */
|
||||
wchar_t *prefix; /* PREFIX macro */
|
||||
wchar_t *exec_prefix; /* EXEC_PREFIX macro */
|
||||
|
||||
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? */
|
||||
|
@ -369,6 +367,7 @@ add_exe_suffix(wchar_t *progpath, size_t progpathlen)
|
|||
*/
|
||||
static PyStatus
|
||||
search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
const wchar_t *argv0_path,
|
||||
wchar_t *prefix, size_t prefix_len, int *found)
|
||||
{
|
||||
PyStatus status;
|
||||
|
@ -397,7 +396,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
}
|
||||
|
||||
/* Check to see if argv[0] is in the build directory */
|
||||
if (safe_wcscpy(prefix, calculate->argv0_path, prefix_len) < 0) {
|
||||
if (safe_wcscpy(prefix, argv0_path, prefix_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
status = joinpath(prefix, L"Modules/Setup.local", prefix_len);
|
||||
|
@ -409,7 +408,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
/* Check VPATH to see if argv0_path is in the build directory. */
|
||||
vpath = Py_DecodeLocale(VPATH, NULL);
|
||||
if (vpath != NULL) {
|
||||
if (safe_wcscpy(prefix, calculate->argv0_path, prefix_len) < 0) {
|
||||
if (safe_wcscpy(prefix, argv0_path, prefix_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
status = joinpath(prefix, vpath, prefix_len);
|
||||
|
@ -435,7 +434,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
}
|
||||
|
||||
/* Search from argv0_path, until root is found */
|
||||
status = copy_absolute(prefix, calculate->argv0_path, prefix_len);
|
||||
status = copy_absolute(prefix, argv0_path, prefix_len);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
@ -485,11 +484,13 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
|
||||
static PyStatus
|
||||
calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
const wchar_t *argv0_path,
|
||||
wchar_t *prefix, size_t prefix_len)
|
||||
{
|
||||
PyStatus status;
|
||||
|
||||
status = search_for_prefix(calculate, pathconfig, prefix, prefix_len,
|
||||
status = search_for_prefix(calculate, pathconfig, argv0_path,
|
||||
prefix, prefix_len,
|
||||
&calculate->prefix_found);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
|
@ -516,8 +517,8 @@ calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
|
||||
|
||||
static PyStatus
|
||||
calculate_reduce_prefix(PyCalculatePath *calculate,
|
||||
wchar_t *prefix, size_t prefix_len)
|
||||
calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
wchar_t *prefix)
|
||||
{
|
||||
/* Reduce prefix and exec_prefix to their essence,
|
||||
* e.g. /usr/local/lib/python1.5 is reduced to /usr/local.
|
||||
|
@ -532,11 +533,14 @@ calculate_reduce_prefix(PyCalculatePath *calculate,
|
|||
if (!prefix[0]) {
|
||||
wcscpy(prefix, separator);
|
||||
}
|
||||
pathconfig->prefix = _PyMem_RawWcsdup(prefix);
|
||||
}
|
||||
else {
|
||||
if (safe_wcscpy(prefix, calculate->prefix, prefix_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
pathconfig->prefix = _PyMem_RawWcsdup(calculate->prefix);
|
||||
}
|
||||
|
||||
if (pathconfig->prefix == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
@ -547,6 +551,7 @@ calculate_reduce_prefix(PyCalculatePath *calculate,
|
|||
*/
|
||||
static PyStatus
|
||||
search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
const wchar_t *argv0_path,
|
||||
wchar_t *exec_prefix, size_t exec_prefix_len,
|
||||
int *found)
|
||||
{
|
||||
|
@ -581,7 +586,7 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
/* 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. */
|
||||
if (safe_wcscpy(exec_prefix, calculate->argv0_path, exec_prefix_len) < 0) {
|
||||
if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
status = joinpath(exec_prefix, L"pybuilddir.txt", exec_prefix_len);
|
||||
|
@ -607,7 +612,7 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
return DECODE_LOCALE_ERR("pybuilddir.txt", dec_len);
|
||||
}
|
||||
|
||||
if (safe_wcscpy(exec_prefix, calculate->argv0_path, exec_prefix_len) < 0) {
|
||||
if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
status = joinpath(exec_prefix, pybuilddir, exec_prefix_len);
|
||||
|
@ -622,7 +627,7 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
}
|
||||
|
||||
/* Search from argv0_path, until root is found */
|
||||
status = copy_absolute(exec_prefix, calculate->argv0_path, exec_prefix_len);
|
||||
status = copy_absolute(exec_prefix, argv0_path, exec_prefix_len);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
@ -670,11 +675,12 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
|
||||
static PyStatus
|
||||
calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
const wchar_t *argv0_path,
|
||||
wchar_t *exec_prefix, size_t exec_prefix_len)
|
||||
{
|
||||
PyStatus status;
|
||||
|
||||
status = search_for_exec_prefix(calculate, pathconfig,
|
||||
status = search_for_exec_prefix(calculate, pathconfig, argv0_path,
|
||||
exec_prefix, exec_prefix_len,
|
||||
&calculate->exec_prefix_found);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
|
@ -700,8 +706,9 @@ calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
|
||||
|
||||
static PyStatus
|
||||
calculate_reduce_exec_prefix(PyCalculatePath *calculate,
|
||||
wchar_t *exec_prefix, size_t exec_prefix_len)
|
||||
calculate_set_exec_prefix(PyCalculatePath *calculate,
|
||||
_PyPathConfig *pathconfig,
|
||||
wchar_t *exec_prefix)
|
||||
{
|
||||
if (calculate->exec_prefix_found > 0) {
|
||||
reduce(exec_prefix);
|
||||
|
@ -710,12 +717,17 @@ calculate_reduce_exec_prefix(PyCalculatePath *calculate,
|
|||
if (!exec_prefix[0]) {
|
||||
wcscpy(exec_prefix, separator);
|
||||
}
|
||||
|
||||
pathconfig->exec_prefix = _PyMem_RawWcsdup(exec_prefix);
|
||||
}
|
||||
else {
|
||||
if (safe_wcscpy(exec_prefix, calculate->exec_prefix, exec_prefix_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
pathconfig->exec_prefix = _PyMem_RawWcsdup(calculate->exec_prefix);
|
||||
}
|
||||
|
||||
if (pathconfig->exec_prefix == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
|
@ -843,10 +855,10 @@ calculate_program_full_path(PyCalculatePath *calculate, _PyPathConfig *pathconfi
|
|||
|
||||
|
||||
static PyStatus
|
||||
calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_path)
|
||||
calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_path,
|
||||
wchar_t *argv0_path, size_t argv0_path_len)
|
||||
{
|
||||
const size_t argv0_path_len = Py_ARRAY_LENGTH(calculate->argv0_path);
|
||||
if (safe_wcscpy(calculate->argv0_path, program_full_path, argv0_path_len) < 0) {
|
||||
if (safe_wcscpy(argv0_path, program_full_path, argv0_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
|
||||
|
@ -877,32 +889,31 @@ calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_pat
|
|||
return DECODE_LOCALE_ERR("framework location", len);
|
||||
}
|
||||
|
||||
if (safe_wcscpy(calculate->argv0_path, wbuf, argv0_path_len) < 0) {
|
||||
if (safe_wcscpy(argv0_path, wbuf, argv0_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
reduce(calculate->argv0_path);
|
||||
status = joinpath(calculate->argv0_path, calculate->lib_python, argv0_path_len);
|
||||
reduce(argv0_path);
|
||||
status = joinpath(argv0_path, calculate->lib_python, argv0_path_len);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
PyMem_RawFree(wbuf);
|
||||
return status;
|
||||
}
|
||||
status = joinpath(calculate->argv0_path, LANDMARK, argv0_path_len);
|
||||
status = joinpath(argv0_path, LANDMARK, argv0_path_len);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
PyMem_RawFree(wbuf);
|
||||
return status;
|
||||
}
|
||||
if (!ismodule(calculate->argv0_path,
|
||||
Py_ARRAY_LENGTH(calculate->argv0_path))) {
|
||||
if (!ismodule(argv0_path, Py_ARRAY_LENGTH(argv0_path))) {
|
||||
/* We are in the build directory so use the name of the
|
||||
executable - we know that the absolute path is passed */
|
||||
if (safe_wcscpy(calculate->argv0_path, program_full_path,
|
||||
if (safe_wcscpy(argv0_path, program_full_path,
|
||||
argv0_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Use the location of the library as the program_full_path */
|
||||
if (safe_wcscpy(calculate->argv0_path, wbuf, argv0_path_len) < 0) {
|
||||
if (safe_wcscpy(argv0_path, wbuf, argv0_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
}
|
||||
|
@ -918,24 +929,24 @@ calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_pat
|
|||
if (_Py_isabs(tmpbuffer)) {
|
||||
/* tmpbuffer should never be longer than MAXPATHLEN,
|
||||
but extra check does not hurt */
|
||||
if (safe_wcscpy(calculate->argv0_path, tmpbuffer, argv0_path_len) < 0) {
|
||||
if (safe_wcscpy(argv0_path, tmpbuffer, argv0_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Interpret relative to program_full_path */
|
||||
PyStatus status;
|
||||
reduce(calculate->argv0_path);
|
||||
status = joinpath(calculate->argv0_path, tmpbuffer, argv0_path_len);
|
||||
reduce(argv0_path);
|
||||
status = joinpath(argv0_path, tmpbuffer, argv0_path_len);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, buflen);
|
||||
linklen = _Py_wreadlink(argv0_path, tmpbuffer, buflen);
|
||||
}
|
||||
#endif /* HAVE_READLINK */
|
||||
|
||||
reduce(calculate->argv0_path);
|
||||
reduce(argv0_path);
|
||||
/* At this point, argv0_path is guaranteed to be less than
|
||||
MAXPATHLEN bytes long. */
|
||||
return _PyStatus_OK();
|
||||
|
@ -947,7 +958,8 @@ calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_pat
|
|||
If found, open it for use when searching for prefixes.
|
||||
*/
|
||||
static PyStatus
|
||||
calculate_read_pyenv(PyCalculatePath *calculate)
|
||||
calculate_read_pyenv(PyCalculatePath *calculate,
|
||||
wchar_t *argv0_path, size_t argv0_path_len)
|
||||
{
|
||||
PyStatus status;
|
||||
wchar_t tmpbuffer[MAXPATHLEN+1];
|
||||
|
@ -955,7 +967,7 @@ calculate_read_pyenv(PyCalculatePath *calculate)
|
|||
wchar_t *env_cfg = L"pyvenv.cfg";
|
||||
FILE *env_file;
|
||||
|
||||
if (safe_wcscpy(tmpbuffer, calculate->argv0_path, buflen) < 0) {
|
||||
if (safe_wcscpy(tmpbuffer, argv0_path, buflen) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
|
||||
|
@ -986,8 +998,7 @@ calculate_read_pyenv(PyCalculatePath *calculate)
|
|||
|
||||
/* Look for a 'home' variable and set argv0_path to it, if found */
|
||||
if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, buflen)) {
|
||||
if (safe_wcscpy(calculate->argv0_path, tmpbuffer,
|
||||
Py_ARRAY_LENGTH(calculate->argv0_path)) < 0) {
|
||||
if (safe_wcscpy(argv0_path, tmpbuffer, argv0_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
}
|
||||
|
@ -997,33 +1008,33 @@ calculate_read_pyenv(PyCalculatePath *calculate)
|
|||
|
||||
|
||||
static PyStatus
|
||||
calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix)
|
||||
calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix,
|
||||
wchar_t *zip_path, size_t zip_path_len)
|
||||
{
|
||||
PyStatus status;
|
||||
const size_t zip_path_len = Py_ARRAY_LENGTH(calculate->zip_path);
|
||||
if (safe_wcscpy(calculate->zip_path, prefix, zip_path_len) < 0) {
|
||||
if (safe_wcscpy(zip_path, prefix, zip_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
|
||||
if (calculate->prefix_found > 0) {
|
||||
/* Use the reduced prefix returned by Py_GetPrefix() */
|
||||
reduce(calculate->zip_path);
|
||||
reduce(calculate->zip_path);
|
||||
reduce(zip_path);
|
||||
reduce(zip_path);
|
||||
}
|
||||
else {
|
||||
if (safe_wcscpy(calculate->zip_path, calculate->prefix, zip_path_len) < 0) {
|
||||
if (safe_wcscpy(zip_path, calculate->prefix, zip_path_len) < 0) {
|
||||
return PATHLEN_ERR();
|
||||
}
|
||||
}
|
||||
status = joinpath(calculate->zip_path, L"lib/python00.zip", zip_path_len);
|
||||
status = joinpath(zip_path, L"lib/python00.zip", zip_path_len);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* 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];
|
||||
size_t bufsz = wcslen(zip_path);
|
||||
zip_path[bufsz - 6] = VERSION[0];
|
||||
zip_path[bufsz - 5] = VERSION[2];
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
|
@ -1031,7 +1042,9 @@ calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix)
|
|||
static PyStatus
|
||||
calculate_module_search_path(PyCalculatePath *calculate,
|
||||
_PyPathConfig *pathconfig,
|
||||
const wchar_t *prefix, const wchar_t *exec_prefix)
|
||||
const wchar_t *prefix,
|
||||
const wchar_t *exec_prefix,
|
||||
const wchar_t *zip_path)
|
||||
{
|
||||
/* Calculate size of return buffer */
|
||||
size_t bufsz = 0;
|
||||
|
@ -1059,7 +1072,7 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
defpath = delim + 1;
|
||||
}
|
||||
|
||||
bufsz += wcslen(calculate->zip_path) + 1;
|
||||
bufsz += wcslen(zip_path) + 1;
|
||||
bufsz += wcslen(exec_prefix) + 1;
|
||||
|
||||
/* Allocate the buffer */
|
||||
|
@ -1076,7 +1089,7 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
}
|
||||
|
||||
/* Next is the default zip path */
|
||||
wcscat(buf, calculate->zip_path);
|
||||
wcscat(buf, zip_path);
|
||||
wcscat(buf, delimiter);
|
||||
|
||||
/* Next goes merge of compile-time $PYTHONPATH with
|
||||
|
@ -1119,8 +1132,7 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
|
||||
|
||||
static PyStatus
|
||||
calculate_init(PyCalculatePath *calculate,
|
||||
const PyConfig *config)
|
||||
calculate_init(PyCalculatePath *calculate, const PyConfig *config)
|
||||
{
|
||||
size_t len;
|
||||
const char *path = getenv("PATH");
|
||||
|
@ -1135,6 +1147,7 @@ calculate_init(PyCalculatePath *calculate,
|
|||
if (!calculate->pythonpath) {
|
||||
return DECODE_LOCALE_ERR("PYTHONPATH define", len);
|
||||
}
|
||||
|
||||
calculate->prefix = Py_DecodeLocale(PREFIX, &len);
|
||||
if (!calculate->prefix) {
|
||||
return DECODE_LOCALE_ERR("PREFIX define", len);
|
||||
|
@ -1178,12 +1191,17 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
|
|||
}
|
||||
}
|
||||
|
||||
status = calculate_argv0_path(calculate, pathconfig->program_full_path);
|
||||
wchar_t argv0_path[MAXPATHLEN+1];
|
||||
memset(argv0_path, 0, sizeof(argv0_path));
|
||||
|
||||
status = calculate_argv0_path(calculate, pathconfig->program_full_path,
|
||||
argv0_path, Py_ARRAY_LENGTH(argv0_path));
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = calculate_read_pyenv(calculate);
|
||||
status = calculate_read_pyenv(calculate,
|
||||
argv0_path, Py_ARRAY_LENGTH(argv0_path));
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
@ -1191,19 +1209,24 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
|
|||
wchar_t prefix[MAXPATHLEN+1];
|
||||
memset(prefix, 0, sizeof(prefix));
|
||||
status = calculate_prefix(calculate, pathconfig,
|
||||
argv0_path,
|
||||
prefix, Py_ARRAY_LENGTH(prefix));
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = calculate_zip_path(calculate, prefix);
|
||||
wchar_t zip_path[MAXPATHLEN+1]; /* ".../lib/pythonXY.zip" */
|
||||
memset(zip_path, 0, sizeof(zip_path));
|
||||
|
||||
status = calculate_zip_path(calculate, prefix,
|
||||
zip_path, Py_ARRAY_LENGTH(zip_path));
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
wchar_t exec_prefix[MAXPATHLEN+1];
|
||||
memset(exec_prefix, 0, sizeof(exec_prefix));
|
||||
status = calculate_exec_prefix(calculate, pathconfig,
|
||||
status = calculate_exec_prefix(calculate, pathconfig, argv0_path,
|
||||
exec_prefix, Py_ARRAY_LENGTH(exec_prefix));
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
|
@ -1218,50 +1241,60 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
|
|||
|
||||
if (pathconfig->module_search_path == NULL) {
|
||||
status = calculate_module_search_path(calculate, pathconfig,
|
||||
prefix, exec_prefix);
|
||||
prefix, exec_prefix, zip_path);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (pathconfig->prefix == NULL) {
|
||||
status = calculate_reduce_prefix(calculate, prefix, Py_ARRAY_LENGTH(prefix));
|
||||
status = calculate_set_prefix(calculate, pathconfig, prefix);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pathconfig->prefix = _PyMem_RawWcsdup(prefix);
|
||||
if (pathconfig->prefix == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
}
|
||||
|
||||
if (pathconfig->exec_prefix == NULL) {
|
||||
status = calculate_reduce_exec_prefix(calculate,
|
||||
exec_prefix,
|
||||
Py_ARRAY_LENGTH(exec_prefix));
|
||||
status = calculate_set_exec_prefix(calculate, pathconfig, exec_prefix);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
pathconfig->exec_prefix = _PyMem_RawWcsdup(exec_prefix);
|
||||
if (pathconfig->exec_prefix == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
}
|
||||
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
|
||||
/* Calculate 'pathconfig' attributes:
|
||||
/* Calculate the Python path configuration.
|
||||
|
||||
Inputs:
|
||||
|
||||
- PATH environment variable
|
||||
- Macros: PYTHONPATH, PREFIX, EXEC_PREFIX, VERSION (ex: "3.9").
|
||||
PREFIX and EXEC_PREFIX are generated by the configure script.
|
||||
PYTHONPATH macro is the default search path.
|
||||
- pybuilddir.txt file
|
||||
- pyvenv.cfg configuration file
|
||||
- PyConfig fields ('config' function argument):
|
||||
|
||||
- pathconfig_warnings
|
||||
- pythonpath_env (PYTHONPATH environment variable)
|
||||
|
||||
- _PyPathConfig fields ('pathconfig' function argument):
|
||||
|
||||
- program_name: see config_init_program_name()
|
||||
- home: Py_SetPythonHome() or PYTHONHOME environment variable
|
||||
|
||||
- current working directory: see copy_absolute()
|
||||
|
||||
Outputs, 'pathconfig' fields:
|
||||
|
||||
- program_full_path
|
||||
- module_search_path
|
||||
- prefix
|
||||
- exec_prefix
|
||||
|
||||
If an attribute is already set (non NULL), it is left unchanged. */
|
||||
If a field is already set (non NULL), it is left unchanged. */
|
||||
PyStatus
|
||||
_PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
|
||||
{
|
||||
|
|
207
PC/getpathp.c
207
PC/getpathp.c
|
@ -115,20 +115,21 @@
|
|||
*/
|
||||
|
||||
#ifndef LANDMARK
|
||||
#define LANDMARK L"lib\\os.py"
|
||||
# define LANDMARK L"lib\\os.py"
|
||||
#endif
|
||||
|
||||
#define INIT_ERR_BUFFER_OVERFLOW() _PyStatus_ERR("buffer overflow")
|
||||
|
||||
|
||||
typedef struct {
|
||||
const wchar_t *path_env; /* PATH environment variable */
|
||||
const wchar_t *home; /* PYTHONHOME environment variable */
|
||||
|
||||
/* Registry key "Software\Python\PythonCore\PythonPath" */
|
||||
/* Registry key "Software\Python\PythonCore\X.Y\PythonPath"
|
||||
where X.Y is the Python version (major.minor) */
|
||||
wchar_t *machine_path; /* from HKEY_LOCAL_MACHINE */
|
||||
wchar_t *user_path; /* from HKEY_CURRENT_USER */
|
||||
|
||||
wchar_t argv0_path[MAXPATHLEN+1];
|
||||
wchar_t zip_path[MAXPATHLEN+1];
|
||||
|
||||
wchar_t *dll_path;
|
||||
|
||||
const wchar_t *pythonpath_env;
|
||||
|
@ -276,7 +277,10 @@ typedef HRESULT(__stdcall *PPathCchCanonicalizeEx) (PWSTR pszPathOut, size_t cch
|
|||
PCWSTR pszPathIn, unsigned long dwFlags);
|
||||
static PPathCchCanonicalizeEx _PathCchCanonicalizeEx;
|
||||
|
||||
static PyStatus canonicalize(wchar_t *buffer, const wchar_t *path)
|
||||
/* Call PathCchCanonicalizeEx(path): remove navigation elements such as "."
|
||||
and ".." to produce a direct, well-formed path. */
|
||||
static PyStatus
|
||||
canonicalize(wchar_t *buffer, const wchar_t *path)
|
||||
{
|
||||
if (buffer == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
|
@ -295,12 +299,12 @@ static PyStatus canonicalize(wchar_t *buffer, const wchar_t *path)
|
|||
|
||||
if (_PathCchCanonicalizeEx) {
|
||||
if (FAILED(_PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) {
|
||||
return _PyStatus_ERR("buffer overflow in getpathp.c's canonicalize()");
|
||||
return INIT_ERR_BUFFER_OVERFLOW();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!PathCanonicalizeW(buffer, path)) {
|
||||
return _PyStatus_ERR("buffer overflow in getpathp.c's canonicalize()");
|
||||
return INIT_ERR_BUFFER_OVERFLOW();
|
||||
}
|
||||
}
|
||||
return _PyStatus_OK();
|
||||
|
@ -588,12 +592,18 @@ get_program_full_path(_PyPathConfig *pathconfig)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path)
|
||||
static PyStatus
|
||||
read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path,
|
||||
int *found)
|
||||
{
|
||||
FILE *sp_file = _Py_wfopen(path, L"r");
|
||||
PyStatus status;
|
||||
wchar_t *buf = NULL;
|
||||
wchar_t *wline = NULL;
|
||||
FILE *sp_file;
|
||||
|
||||
sp_file = _Py_wfopen(path, L"r");
|
||||
if (sp_file == NULL) {
|
||||
return 0;
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
wcscpy_s(prefix, MAXPATHLEN+1, path);
|
||||
|
@ -604,15 +614,16 @@ read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path)
|
|||
size_t bufsiz = MAXPATHLEN;
|
||||
size_t prefixlen = wcslen(prefix);
|
||||
|
||||
wchar_t *buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
|
||||
buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
|
||||
if (buf == NULL) {
|
||||
goto error;
|
||||
status = _PyStatus_NO_MEMORY();
|
||||
goto done;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
|
||||
while (!feof(sp_file)) {
|
||||
char line[MAXPATHLEN + 1];
|
||||
char *p = fgets(line, MAXPATHLEN + 1, sp_file);
|
||||
char *p = fgets(line, Py_ARRAY_LENGTH(line), sp_file);
|
||||
if (!p) {
|
||||
break;
|
||||
}
|
||||
|
@ -631,13 +642,16 @@ read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path)
|
|||
continue;
|
||||
}
|
||||
else if (strncmp(line, "import ", 7) == 0) {
|
||||
Py_FatalError("only 'import site' is supported in ._pth file");
|
||||
status = _PyStatus_ERR("only 'import site' is supported "
|
||||
"in ._pth file");
|
||||
goto done;
|
||||
}
|
||||
|
||||
DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
|
||||
wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
|
||||
if (wline == NULL) {
|
||||
goto error;
|
||||
status = _PyStatus_NO_MEMORY();
|
||||
goto done;
|
||||
}
|
||||
wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
|
||||
wline[wn] = '\0';
|
||||
|
@ -648,8 +662,8 @@ read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path)
|
|||
wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
|
||||
sizeof(wchar_t));
|
||||
if (tmp == NULL) {
|
||||
PyMem_RawFree(wline);
|
||||
goto error;
|
||||
status = _PyStatus_NO_MEMORY();
|
||||
goto done;
|
||||
}
|
||||
buf = tmp;
|
||||
}
|
||||
|
@ -663,48 +677,39 @@ read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path)
|
|||
_Py_BEGIN_SUPPRESS_IPH
|
||||
result = wcscat_s(buf, bufsiz, prefix);
|
||||
_Py_END_SUPPRESS_IPH
|
||||
|
||||
if (result == EINVAL) {
|
||||
Py_FatalError("invalid argument during ._pth processing");
|
||||
status = _PyStatus_ERR("invalid argument during ._pth processing");
|
||||
goto done;
|
||||
} else if (result == ERANGE) {
|
||||
Py_FatalError("buffer overflow during ._pth processing");
|
||||
status = _PyStatus_ERR("buffer overflow during ._pth processing");
|
||||
goto done;
|
||||
}
|
||||
|
||||
wchar_t *b = &buf[usedsiz];
|
||||
join(b, wline);
|
||||
|
||||
PyMem_RawFree(wline);
|
||||
wline = NULL;
|
||||
}
|
||||
|
||||
fclose(sp_file);
|
||||
if (pathconfig->module_search_path == NULL) {
|
||||
pathconfig->module_search_path = _PyMem_RawWcsdup(buf);
|
||||
if (pathconfig->module_search_path == NULL) {
|
||||
Py_FatalError("out of memory");
|
||||
status = _PyStatus_NO_MEMORY();
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
PyMem_RawFree(buf);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
*found = 1;
|
||||
status = _PyStatus_OK();
|
||||
goto done;
|
||||
|
||||
done:
|
||||
PyMem_RawFree(buf);
|
||||
PyMem_RawFree(wline);
|
||||
fclose(sp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyStatus
|
||||
calculate_init(PyCalculatePath *calculate, const PyConfig *config)
|
||||
{
|
||||
calculate->home = config->home;
|
||||
calculate->path_env = _wgetenv(L"PATH");
|
||||
|
||||
calculate->dll_path = _Py_GetDLLPath();
|
||||
if (calculate->dll_path == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
|
||||
calculate->pythonpath_env = config->pythonpath_env;
|
||||
|
||||
return _PyStatus_OK();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
@ -730,17 +735,17 @@ get_pth_filename(PyCalculatePath *calculate, wchar_t *filename,
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
static PyStatus
|
||||
calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
wchar_t *prefix)
|
||||
wchar_t *prefix, int *found)
|
||||
{
|
||||
wchar_t filename[MAXPATHLEN+1];
|
||||
|
||||
if (!get_pth_filename(calculate, filename, pathconfig)) {
|
||||
return 0;
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
return read_pth_file(pathconfig, prefix, filename);
|
||||
return read_pth_file(pathconfig, prefix, filename, found);
|
||||
}
|
||||
|
||||
|
||||
|
@ -749,12 +754,13 @@ calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
|||
If found, open it for use when searching for prefixes.
|
||||
*/
|
||||
static void
|
||||
calculate_pyvenv_file(PyCalculatePath *calculate)
|
||||
calculate_pyvenv_file(PyCalculatePath *calculate,
|
||||
wchar_t *argv0_path, size_t argv0_path_len)
|
||||
{
|
||||
wchar_t envbuffer[MAXPATHLEN+1];
|
||||
const wchar_t *env_cfg = L"pyvenv.cfg";
|
||||
|
||||
wcscpy_s(envbuffer, MAXPATHLEN+1, calculate->argv0_path);
|
||||
wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path);
|
||||
join(envbuffer, env_cfg);
|
||||
|
||||
FILE *env_file = _Py_wfopen(envbuffer, L"r");
|
||||
|
@ -778,25 +784,25 @@ calculate_pyvenv_file(PyCalculatePath *calculate)
|
|||
/* Look for a 'home' variable and set argv0_path to it, if found */
|
||||
wchar_t tmpbuffer[MAXPATHLEN+1];
|
||||
if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, MAXPATHLEN)) {
|
||||
wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, tmpbuffer);
|
||||
wcscpy_s(argv0_path, argv0_path_len, tmpbuffer);
|
||||
}
|
||||
fclose(env_file);
|
||||
}
|
||||
|
||||
|
||||
#define INIT_ERR_BUFFER_OVERFLOW() _PyStatus_ERR("buffer overflow")
|
||||
|
||||
|
||||
static void
|
||||
calculate_home_prefix(PyCalculatePath *calculate, wchar_t *prefix)
|
||||
calculate_home_prefix(PyCalculatePath *calculate,
|
||||
const wchar_t *argv0_path,
|
||||
const wchar_t *zip_path,
|
||||
wchar_t *prefix)
|
||||
{
|
||||
if (calculate->home == NULL || *calculate->home == '\0') {
|
||||
if (calculate->zip_path[0] && exists(calculate->zip_path)) {
|
||||
wcscpy_s(prefix, MAXPATHLEN+1, calculate->zip_path);
|
||||
if (zip_path[0] && exists(zip_path)) {
|
||||
wcscpy_s(prefix, MAXPATHLEN+1, zip_path);
|
||||
reduce(prefix);
|
||||
calculate->home = prefix;
|
||||
}
|
||||
else if (search_for_prefix(prefix, calculate->argv0_path, LANDMARK)) {
|
||||
else if (search_for_prefix(prefix, argv0_path, LANDMARK)) {
|
||||
calculate->home = prefix;
|
||||
}
|
||||
else {
|
||||
|
@ -812,7 +818,9 @@ calculate_home_prefix(PyCalculatePath *calculate, wchar_t *prefix)
|
|||
static PyStatus
|
||||
calculate_module_search_path(PyCalculatePath *calculate,
|
||||
_PyPathConfig *pathconfig,
|
||||
wchar_t *prefix)
|
||||
const wchar_t *argv0_path,
|
||||
wchar_t *prefix,
|
||||
const wchar_t *zip_path)
|
||||
{
|
||||
int skiphome = calculate->home==NULL ? 0 : 1;
|
||||
#ifdef Py_ENABLE_SHARED
|
||||
|
@ -852,14 +860,14 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
bufsz *= wcslen(calculate->home);
|
||||
}
|
||||
bufsz += wcslen(PYTHONPATH) + 1;
|
||||
bufsz += wcslen(calculate->argv0_path) + 1;
|
||||
bufsz += wcslen(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;
|
||||
bufsz += wcslen(zip_path) + 1;
|
||||
if (calculate->pythonpath_env != NULL) {
|
||||
bufsz += wcslen(calculate->pythonpath_env) + 1;
|
||||
}
|
||||
|
@ -867,7 +875,7 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
wchar_t *buf, *start_buf;
|
||||
buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
|
||||
if (buf == NULL) {
|
||||
Py_FatalError("Can't malloc dynamic PYTHONPATH");
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
start_buf = buf;
|
||||
|
||||
|
@ -879,8 +887,8 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
buf = wcschr(buf, L'\0');
|
||||
*buf++ = DELIM;
|
||||
}
|
||||
if (calculate->zip_path[0]) {
|
||||
if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) {
|
||||
if (zip_path[0]) {
|
||||
if (wcscpy_s(buf, bufsz - (buf - start_buf), zip_path)) {
|
||||
return INIT_ERR_BUFFER_OVERFLOW();
|
||||
}
|
||||
buf = wcschr(buf, L'\0');
|
||||
|
@ -937,8 +945,8 @@ calculate_module_search_path(PyCalculatePath *calculate,
|
|||
p = q+1;
|
||||
}
|
||||
}
|
||||
if (calculate->argv0_path) {
|
||||
wcscpy(buf, calculate->argv0_path);
|
||||
if (argv0_path) {
|
||||
wcscpy(buf, argv0_path);
|
||||
buf = wcschr(buf, L'\0');
|
||||
*buf++ = DELIM;
|
||||
}
|
||||
|
@ -996,28 +1004,40 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
|
|||
}
|
||||
|
||||
/* program_full_path guaranteed \0 terminated in MAXPATH+1 bytes. */
|
||||
wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, pathconfig->program_full_path);
|
||||
reduce(calculate->argv0_path);
|
||||
wchar_t argv0_path[MAXPATHLEN+1];
|
||||
memset(argv0_path, 0, sizeof(argv0_path));
|
||||
|
||||
wcscpy_s(argv0_path, MAXPATHLEN+1, pathconfig->program_full_path);
|
||||
reduce(argv0_path);
|
||||
|
||||
wchar_t prefix[MAXPATHLEN+1];
|
||||
memset(prefix, 0, sizeof(prefix));
|
||||
|
||||
/* Search for a sys.path file */
|
||||
if (calculate_pth_file(calculate, pathconfig, prefix)) {
|
||||
int pth_found = 0;
|
||||
status = calculate_pth_file(calculate, pathconfig, prefix, &pth_found);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
if (pth_found) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
calculate_pyvenv_file(calculate);
|
||||
calculate_pyvenv_file(calculate, argv0_path, Py_ARRAY_LENGTH(argv0_path));
|
||||
|
||||
/* Calculate zip archive path from DLL or exe path */
|
||||
change_ext(calculate->zip_path,
|
||||
wchar_t zip_path[MAXPATHLEN+1];
|
||||
memset(zip_path, 0, sizeof(zip_path));
|
||||
|
||||
change_ext(zip_path,
|
||||
calculate->dll_path[0] ? calculate->dll_path : pathconfig->program_full_path,
|
||||
L".zip");
|
||||
|
||||
calculate_home_prefix(calculate, prefix);
|
||||
calculate_home_prefix(calculate, argv0_path, zip_path, prefix);
|
||||
|
||||
if (pathconfig->module_search_path == NULL) {
|
||||
status = calculate_module_search_path(calculate, pathconfig, prefix);
|
||||
status = calculate_module_search_path(calculate, pathconfig,
|
||||
argv0_path, prefix, zip_path);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
@ -1041,6 +1061,24 @@ done:
|
|||
}
|
||||
|
||||
|
||||
static PyStatus
|
||||
calculate_init(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
|
||||
const PyConfig *config)
|
||||
{
|
||||
calculate->home = pathconfig->home;
|
||||
calculate->path_env = _wgetenv(L"PATH");
|
||||
|
||||
calculate->dll_path = _Py_GetDLLPath();
|
||||
if (calculate->dll_path == NULL) {
|
||||
return _PyStatus_NO_MEMORY();
|
||||
}
|
||||
|
||||
calculate->pythonpath_env = config->pythonpath_env;
|
||||
|
||||
return _PyStatus_OK();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calculate_free(PyCalculatePath *calculate)
|
||||
{
|
||||
|
@ -1050,7 +1088,24 @@ calculate_free(PyCalculatePath *calculate)
|
|||
}
|
||||
|
||||
|
||||
/* Calculate 'pathconfig' attributes:
|
||||
/* Calculate the Python path configuration.
|
||||
|
||||
Inputs:
|
||||
|
||||
- PyConfig.pythonpath_env: PYTHONPATH environment variable
|
||||
- _PyPathConfig.home: Py_SetPythonHome() or PYTHONHOME environment variable
|
||||
- DLL path: _Py_GetDLLPath()
|
||||
- PATH environment variable
|
||||
- __PYVENV_LAUNCHER__ environment variable
|
||||
- GetModuleFileNameW(NULL): fully qualified path of the executable file of
|
||||
the current process
|
||||
- .pth configuration file
|
||||
- pyvenv.cfg configuration file
|
||||
- Registry key "Software\Python\PythonCore\X.Y\PythonPath"
|
||||
of HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER where X.Y is the Python
|
||||
version (major.minor).
|
||||
|
||||
Outputs, 'pathconfig' fields:
|
||||
|
||||
- base_executable
|
||||
- program_full_path
|
||||
|
@ -1060,7 +1115,7 @@ calculate_free(PyCalculatePath *calculate)
|
|||
- isolated
|
||||
- site_import
|
||||
|
||||
If an attribute is already set (non NULL), it is left unchanged. */
|
||||
If a field is already set (non NULL), it is left unchanged. */
|
||||
PyStatus
|
||||
_PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
|
||||
{
|
||||
|
@ -1068,7 +1123,7 @@ _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
|
|||
PyCalculatePath calculate;
|
||||
memset(&calculate, 0, sizeof(calculate));
|
||||
|
||||
status = calculate_init(&calculate, config);
|
||||
status = calculate_init(&calculate, pathconfig, config);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
goto done;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue