diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h index 15447f54490fb42..64ca38b65a31f1a 100644 --- a/Include/internal/pycore_pathconfig.h +++ b/Include/internal/pycore_pathconfig.h @@ -8,6 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include + typedef struct _PyPathConfig { /* Full path to the Python program */ wchar_t *program_full_path; @@ -67,6 +69,11 @@ extern PyStatus _PyConfig_WritePathConfig(const PyConfig *config); extern void _Py_DumpPathConfig(PyThreadState *tstate); extern PyObject* _PyPathConfig_AsDict(void); + +/* locating the stdlib */ + +extern bool _Py_IsStdlibDir(const wchar_t *stdlibdir, bool checkpyc); + #ifdef __cplusplus } #endif diff --git a/Modules/getpath.c b/Modules/getpath.c index de1c6e3fbb657b0..ba671abda84ae67 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -109,10 +109,6 @@ extern "C" { #error "PREFIX, EXEC_PREFIX, VERSION and VPATH macros must be defined" #endif -#ifndef LANDMARK -#define LANDMARK L"os.py" -#endif - #define BUILD_LANDMARK L"Modules/Setup.local" #define PATHLEN_ERR() _PyStatus_ERR("path configuration: path too long") @@ -325,33 +321,7 @@ absolutize(wchar_t **path_p) static PyStatus ismodule(const wchar_t *path, int *result) { - wchar_t *filename = joinpath2(path, LANDMARK); - if (filename == NULL) { - return _PyStatus_NO_MEMORY(); - } - - if (isfile(filename)) { - PyMem_RawFree(filename); - *result = 1; - return _PyStatus_OK(); - } - - /* Check for the compiled version of prefix. */ - size_t len = wcslen(filename); - wchar_t *pyc = PyMem_RawMalloc((len + 2) * sizeof(wchar_t)); - if (pyc == NULL) { - PyMem_RawFree(filename); - return _PyStatus_NO_MEMORY(); - } - - memcpy(pyc, filename, len * sizeof(wchar_t)); - pyc[len] = L'c'; - pyc[len + 1] = L'\0'; - *result = isfile(pyc); - - PyMem_RawFree(filename); - PyMem_RawFree(pyc); - + *result = _Py_IsStdlibDir(path, true) ? 1 : 0; return _PyStatus_OK(); } diff --git a/PC/getpathp.c b/PC/getpathp.c index 38009465ae649cb..061dbfeeebc22da 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -85,6 +85,7 @@ #include "pycore_fileutils.h" // _Py_add_relfile() #include "osdefs.h" // SEP, ALTSEP #include +#include #ifndef MS_WINDOWS #error getpathp.c should only be built on Windows @@ -209,33 +210,6 @@ exists(const wchar_t *filename) } -/* Is module -- check for .pyc too. - Assumes 'filename' MAXPATHLEN+1 bytes long - - may extend 'filename' by one character. */ -static int -ismodule(wchar_t *filename) -{ - size_t n; - - if (exists(filename)) { - return 1; - } - - /* Check for the compiled version of prefix. */ - n = wcsnlen_s(filename, MAXPATHLEN+1); - if (n < MAXPATHLEN) { - int exist = 0; - filename[n] = L'c'; - filename[n + 1] = L'\0'; - exist = exists(filename); - // Drop the 'c' we just added. - 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 @@ -269,18 +243,6 @@ canonicalize(wchar_t *buffer, const wchar_t *path) return _PyStatus_OK(); } -static int -is_stdlibdir(wchar_t *stdlibdir) -{ - wchar_t *filename = stdlibdir; -#ifndef LANDMARK -# define LANDMARK L"os.py" -#endif - /* join() ensures 'landmark' can not overflow prefix if too long. */ - join(filename, LANDMARK); - return ismodule(filename); -} - /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd. assumption provided by only caller, calculate_path() */ static int @@ -299,7 +261,7 @@ search_for_prefix(wchar_t *prefix, const wchar_t *argv0_path) /* Due to reduce() and our initial value, this result is guaranteed to fit. */ wcscpy(&stdlibdir[wcslen(prefix) + 1], L"lib"); - if (is_stdlibdir(stdlibdir)) { + if (_Py_IsStdlibDir(stdlibdir, true)) { return 1; } reduce(prefix); diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 470aba75bea9690..5c52ad070991263 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -6,6 +6,7 @@ #include "pycore_fileutils.h" #include "pycore_pathconfig.h" #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() +#include #include #ifdef MS_WINDOWS # include // GetFullPathNameW(), MAX_PATH @@ -813,6 +814,55 @@ _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key, return _PyStatus_OK(); } + +/* locating the stdlib */ + +static int +file_exists(const wchar_t *filename) +{ +#ifdef MS_WINDOWS + return GetFileAttributesW(filename) != 0xFFFFFFFF; +#else + struct stat buf; + return _Py_wstat(filename, &buf) == 0 && S_ISREG(buf.st_mode); +#endif +} + +/* Decide if the given directory hold the stdlib. */ +bool +_Py_IsStdlibDir(const wchar_t *stdlibdir, bool checkpyc) +{ + // Build the filename to look for. + wchar_t filename[MAXPATHLEN + 1]; + assert(stdlibdir != NULL); +#ifdef MS_WINDOWS + wcscpy_s(filename, MAXPATHLEN + 1, stdlibdir); +#else + wcscpy(filename, stdlibdir); +#endif +#ifndef LANDMARK +#define LANDMARK L"os.py" +#endif + _Py_add_relfile(filename, LANDMARK, MAXPATHLEN + 1); + + // Check if the file exists. + if (file_exists(filename)) { + return true; + } + + // Check for the compiled version. */ + size_t len = wcslen(filename); + if (checkpyc && len < MAXPATHLEN) { + filename[len] = 'c'; + filename[len + 1] = '\0'; + if (file_exists(filename)) { + return true; + } + } + + return false; +} + #ifdef __cplusplus } #endif