From 41b152c5f6ec3a5a6e51b4f8f0f90291a5895edc Mon Sep 17 00:00:00 2001 From: darylm503 Date: Mon, 3 Oct 2011 18:54:12 +0000 Subject: StdLib: Improve robustness of stat() and make basename() a public function. AppPkg: Refinements to pyconfig.h and port of getpath.c to EDK II. Signed-off-by: darylm503 Reviewed-by: geekboy15a Reviewed-by: jljusten git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12508 6f19259b-4bc3-4df7-8a09-765794883524 --- AppPkg/Applications/Python/Efi/config.c | 59 ++- AppPkg/Applications/Python/Efi/getpath.c | 788 ++++++++++++++++++++++++++++++ AppPkg/Applications/Python/Efi/getpathp.c | 714 --------------------------- 3 files changed, 827 insertions(+), 734 deletions(-) create mode 100644 AppPkg/Applications/Python/Efi/getpath.c delete mode 100644 AppPkg/Applications/Python/Efi/getpathp.c (limited to 'AppPkg/Applications/Python/Efi') diff --git a/AppPkg/Applications/Python/Efi/config.c b/AppPkg/Applications/Python/Efi/config.c index 52c7795446..98e7e2a31e 100644 --- a/AppPkg/Applications/Python/Efi/config.c +++ b/AppPkg/Applications/Python/Efi/config.c @@ -1,4 +1,15 @@ -/* Module configuration */ +/** @file + Python Module configuration. + + Copyright (c) 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ /* This file contains the table of built-in modules. See init_builtin() in import.c. */ @@ -6,9 +17,9 @@ #include "Python.h" extern void initarray(void); -//#ifndef MS_WINI64 -//extern void initaudioop(void); -//#endif +#ifndef MS_WINI64 +extern void initaudioop(void); +#endif extern void initbinascii(void); extern void initcmath(void); extern void initerrno(void); @@ -27,7 +38,7 @@ extern void init_sha256(void); extern void init_sha512(void); extern void initstrop(void); extern void inittime(void); -//extern void initthread(void); +extern void initthread(void); extern void initcStringIO(void); extern void initcPickle(void); #ifdef WIN32 @@ -38,23 +49,23 @@ extern void init_codecs(void); extern void init_weakref(void); extern void init_hotshot(void); extern void initxxsubtype(void); -//extern void initzipimport(void); +extern void initzipimport(void); extern void init_random(void); extern void inititertools(void); extern void init_collections(void); extern void init_heapq(void); extern void init_bisect(void); extern void init_symtable(void); -//extern void initmmap(void); +extern void initmmap(void); extern void init_csv(void); extern void init_sre(void); extern void initparser(void); -//extern void init_winreg(void); +extern void init_winreg(void); extern void init_struct(void); extern void initdatetime(void); extern void init_functools(void); extern void init_json(void); -//extern void initzlib(void); +extern void initzlib(void); extern void init_multibytecodec(void); extern void init_codecs_cn(void); @@ -63,8 +74,8 @@ extern void init_codecs_iso2022(void); extern void init_codecs_jp(void); extern void init_codecs_kr(void); extern void init_codecs_tw(void); -//extern void init_subprocess(void); -//extern void init_lsprof(void); +extern void init_subprocess(void); +extern void init_lsprof(void); extern void init_ast(void); extern void init_io(void); extern void _PyWarnings_Init(void); @@ -79,16 +90,20 @@ struct _inittab _PyImport_Inittab[] = { {"array", initarray}, {"_ast", init_ast}, -//#ifdef MS_WINDOWS -//#ifndef MS_WINI64 -// {"audioop", initaudioop}, -//#endif -//#endif +#ifdef MS_WINDOWS +#ifndef MS_WINI64 + {"audioop", initaudioop}, +#endif +#endif {"binascii", initbinascii}, //{"cmath", initcmath}, {"errno", initerrno}, - {"future_builtins", initfuture_builtins}, + {"gc", initgc}, + {"signal", initsignal}, + +#if 0 + {"future_builtins", initfuture_builtins}, #ifndef MS_WINI64 {"imageop", initimageop}, #endif @@ -96,7 +111,6 @@ struct _inittab _PyImport_Inittab[] = { {"_md5", init_md5}, //{"nt", initnt}, /* Use the NT os functions, not posix */ {"operator", initoperator}, - {"signal", initsignal}, {"_sha", init_sha}, {"_sha256", init_sha256}, {"_sha512", init_sha512}, @@ -127,10 +141,14 @@ struct _inittab _PyImport_Inittab[] = { //{"mmap", initmmap}, {"_csv", init_csv}, {"_sre", init_sre}, +#endif + {"parser", initparser}, + +#if 0 //{"_winreg", init_winreg}, {"_struct", init_struct}, - //{"datetime", initdatetime}, + {"datetime", initdatetime}, {"_functools", init_functools}, {"_json", init_json}, @@ -146,6 +164,7 @@ struct _inittab _PyImport_Inittab[] = { {"_codecs_jp", init_codecs_jp}, {"_codecs_kr", init_codecs_kr}, {"_codecs_tw", init_codecs_tw}, +#endif /* tools/freeze/makeconfig.py marker for additional "_inittab" entries */ /* -- ADDMODULE MARKER 2 -- */ @@ -153,7 +172,7 @@ struct _inittab _PyImport_Inittab[] = { /* This module "lives in" with marshal.c */ {"marshal", PyMarshal_Init}, - /* This lives it with import.c */ + /* This lives in with import.c */ {"imp", initimp}, /* These entries are here for sys.builtin_module_names */ diff --git a/AppPkg/Applications/Python/Efi/getpath.c b/AppPkg/Applications/Python/Efi/getpath.c new file mode 100644 index 0000000000..ba837bf522 --- /dev/null +++ b/AppPkg/Applications/Python/Efi/getpath.c @@ -0,0 +1,788 @@ +/** @file + Return the initial module search path. + + Search in specified locations for the associated Python libraries. + + Py_GetPath returns module_search_path. + Py_GetPrefix returns PREFIX + Py_GetExec_Prefix returns PREFIX + Py_GetProgramFullPath returns the full path to the python executable. + + These are built dynamically so that the proper volume name can be prefixed + to the paths. + + For the EDK II, UEFI, implementation of Python, PREFIX and EXEC_PREFIX + are set as follows: + PREFIX = /Efi/StdLib + EXEC_PREFIX = PREFIX + + The following final paths are assumed: + /Efi/Tools/Python.efi The Python executable. + /Efi/StdLib/lib/python.VERSION The platform independent Python modules. + /Efi/StdLib/lib/python.VERSION/dynalib Dynamically loadable Python extension modules. + + Copyright (c) 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* VERSION must be at least two characters long. */ +#ifndef VERSION + #define VERSION "27" +#endif + +#ifndef VPATH + #define VPATH "." +#endif + +/* Search path entry delimiter */ +#ifdef DELIM + #define sDELIM ";" +#endif + +#ifndef PREFIX + #define PREFIX "/Efi/StdLib" +#endif + +#ifndef EXEC_PREFIX + #define EXEC_PREFIX PREFIX +#endif + +#ifndef LIBPYTHON + #define LIBPYTHON "lib/python." VERSION +#endif + +#ifndef PYTHONPATH +//#define PYTHONPATH PREFIX LIBPYTHON sDELIM \ +// EXEC_PREFIX LIBPYTHON "/lib-dynload" + #define PYTHONPATH LIBPYTHON // sDELIM +// LIBPYTHON "/lib-dynload" +#endif + +#ifndef LANDMARK +#define LANDMARK "os.py" +#endif + +static char prefix[MAXPATHLEN+1]; +static char exec_prefix[MAXPATHLEN+1]; +static char progpath[MAXPATHLEN+1]; +static char *module_search_path = NULL; +static char lib_python[] = LIBPYTHON; +static char volume_name[32] = { 0 }; + +/** Determine if "ch" is a separator character. + + @param[in] ch The character to test. + + @retval TRUE ch is a separator character. + @retval FALSE ch is NOT a separator character. +**/ +static int +is_sep(char ch) +{ +#ifdef ALTSEP + return ch == SEP || ch == ALTSEP; +#else + return ch == SEP; +#endif +} + +/** Reduce a path by its last element. + + The last element (everything to the right of the last separator character) + in the path, dir, is removed from the path. Parameter dir is modified in place. + + @param[in,out] dir Pointer to the path to modify. +**/ +static void +reduce(char *dir) +{ + size_t i = strlen(dir); + while (i > 0 && !is_sep(dir[i])) + --i; + dir[i] = '\0'; +} + +/** Does filename point to a file and not directory? + + @param[in] filename The fully qualified path to the object to test. + + @retval 0 Filename was not found, or is a directory. + @retval 1 Filename refers to a regular file. +**/ +static int +isfile(char *filename) +{ + struct stat buf; + if (stat(filename, &buf) != 0) { + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] Not Found: file = \"%s\"\n", __func__, __LINE__, filename); + return 0; + } + //if (!S_ISREG(buf.st_mode)) + if (S_ISDIR(buf.st_mode)) { + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] Is DIR: file = \"%s\"\n", __func__, __LINE__, filename); + return 0; + } + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] SUCCESS: file = \"%s\"\n", __func__, __LINE__, filename); + return 1; +} + +/** Determine if filename refers to a Python module. + + A Python module is indicated if the file exists, or if the file with + 'o' or 'c' appended exists. + + @param[in] filename The fully qualified path to the object to test. + + @retval 0 +**/ +static int +ismodule(char *filename) +{ + if (isfile(filename)) { + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: file = \"%s\"\n", __func__, __LINE__, filename); + return 1; + } + + /* Check for the compiled version of prefix. */ + if (strlen(filename) < MAXPATHLEN) { + strcat(filename, Py_OptimizeFlag ? "o" : "c"); + if (isfile(filename)) { + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: file = \"%s\"\n", __func__, __LINE__, filename); + return 1; + } + } + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] FAIL: file = \"%s\"\n", __func__, __LINE__, filename); + return 0; +} + +/** Does filename point to a directory? + + @param[in] filename The fully qualified path to the object to test. + + @retval 0 Filename was not found, or is not a regular file. + @retval 1 Filename refers to a directory. +**/ +static int +isdir(char *filename) +{ + struct stat buf; + + if (stat(filename, &buf) != 0) + return 0; + + if (!S_ISDIR(buf.st_mode)) + return 0; + + return 1; +} + +/** Determine if a path is absolute, or not. + An absolute path consists of a volume name, "VOL:", followed by a rooted path, + "/path/elements". If both of these components are present, the path is absolute. + + Let P be a pointer to the path to test. + Let A be a pointer to the first ':' in P. + Let B be a pointer to the first '/' or '\\' in P. + + If A and B are not NULL + If (A-P+1) == (B-P) then the path is absolute. + Otherwise, the path is NOT absolute. + + @param[in] path The path to test. + + @retval -1 Path is absolute but lacking volume name. + @retval 0 Path is NOT absolute. + @retval 1 Path is absolute. +*/ +static int +is_absolute(char *path) +{ + char *A; + char *B; + + A = strchr(path, ':'); + B = strpbrk(path, "/\\"); + + if(B != NULL) { + if(A == NULL) { + if(B == path) { + return -1; + } + } + else { + if(((A - path) + 1) == (B - path)) { + return 1; + } + } + } + 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 + the trailing NUL). It's a fatal error if it contains a string longer than + that (callers must be careful!). If these requirements are met, it's + guaranteed that buffer will still be a NUL-terminated string with no more + than MAXPATHLEN characters at exit. If stuff is too long, only as much of + stuff as fits will be appended. + + @param[in,out] buffer The path to be extended. + @param[in] stuff The stuff to join onto the path. +*/ +static void +joinpath(char *buffer, char *stuff) +{ + size_t n, k; + + k = 0; + if (is_absolute(stuff) == 1) { + n = 0; + } + else { + n = strlen(buffer); + if(n == 0) { + strncpy(buffer, volume_name, MAXPATHLEN); + n = strlen(buffer); + } + /* We must not use an else clause here because we want to test n again. + volume_name may have been empty. + */ + if (n > 0 && n < MAXPATHLEN) { + if(!is_sep(buffer[n-1])) { + buffer[n++] = SEP; + } + if(is_sep(stuff[0])) ++stuff; + } + } + if (n > MAXPATHLEN) + Py_FatalError("buffer overflow in getpath.c's joinpath()"); + k = strlen(stuff); + if (n + k > MAXPATHLEN) + k = MAXPATHLEN - n; + strncpy(buffer+n, stuff, k); + buffer[n+k] = '\0'; +} + +/** Is filename an executable file? + + An executable file: + 1) exists + 2) is a file, not a directory + 3) has a name ending with ".efi" + 4) Only has a single '.' in the name. + + If basename(filename) does not contain a '.', append ".efi" to filename + If filename ends in ".efi", it is executable, else it isn't. + + This routine is used to when searching for the file named by argv[0]. + As such, there is no need to search for extensions other than ".efi". + + @param[in] filename The name of the file to test. It may, or may not, have an extension. + + @retval 0 filename already has a path other than ".efi", or it doesn't exist, or is a directory. + @retval 1 filename refers to an executable file. +**/ +static int +isxfile(char *filename) +{ + struct stat buf; + char *bn; + char *newbn; + int bnlen; + + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] ENTER: file = \"%s\"\n", __func__, __LINE__, filename); + bn = basename(filename); // Separate off the file name component + reduce(filename); // and isolate the path component + bnlen = strlen(bn); + newbn = strrchr(bn, '.'); // Does basename contain a period? + if(newbn == NULL) { // Does NOT contain a period. + newbn = &bn[bnlen]; + strncpyX(newbn, ".efi", MAXPATHLEN - bnlen); // append ".efi" to basename + bnlen += 4; + } + else if(strcmp(newbn, ".efi") != 0) { + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: Bad extension\n", __func__, __LINE__); + return 0; // File can not be executable. + } + joinpath(filename, bn); // Stitch path and file name back together + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: file = \"%s\"\n", __func__, __LINE__, filename); + + if (stat(filename, &buf) != 0) { // Now, verify that file exists + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: Does not exist\n", __func__, __LINE__); + return 0; + } + if(S_ISDIR(buf.st_mode)) { // And it is not a directory. + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: Is a directory\n", __func__, __LINE__); + return 0; + } + + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] EXIT: file = \"%s\"\n", __func__, __LINE__, filename); + return 1; +} + +/** Copy p into path, ensuring that the result is an absolute path. + + copy_absolute requires that path be allocated at least + MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. + + @param[out] path Destination to receive the absolute path. + @param[in] p Path to be tested and possibly converted. +**/ +static void +copy_absolute(char *path, char *p) +{ + if (is_absolute(p) == 1) + strcpy(path, p); + else { + if (!getcwd(path, MAXPATHLEN)) { + /* unable to get the current directory */ + if(volume_name[0] != 0) { + strcpy(path, volume_name); + joinpath(path, p); + } + else + strcpy(path, p); + return; + } + if (p[0] == '.' && is_sep(p[1])) + p += 2; + joinpath(path, p); + } +} + +/** Modify path so that the result is an absolute path. + absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. + + @param[in,out] path The path to be made absolute. +*/ +static void +absolutize(char *path) +{ + char buffer[MAXPATHLEN + 1]; + + if (is_absolute(path) == 1) + return; + copy_absolute(buffer, path); + strcpy(path, buffer); +} + +/** Extract the volume name from a path. + + @param[out] Dest Pointer to location in which to store the extracted volume name. + @param[in] path Pointer to the path to extract the volume name from. +**/ +static void +set_volume(char *Dest, char *path) +{ + size_t VolLen; + + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] ENTER: path = \"%s\"\n", __func__, __LINE__, path); + if(is_absolute(path)) { + VolLen = strcspn(path, "/\\:"); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: VolLen = %d\n", __func__, __LINE__, VolLen); + if((VolLen != 0) && (path[VolLen] == ':')) { + (void) strncpyX(Dest, path, VolLen + 1); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: VolLen = %d, Dest = \"%s\" path = \"%s\"\n", + // __func__, __LINE__, VolLen, Dest, path); + } + } + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d] EXIT: Dest = \"%s\"\n", __func__, __LINE__, Dest); +} + + +/** Determine paths. + + Two directories must be found, the platform independent directory + (prefix), containing the common .py and .pyc files, and the platform + dependent directory (exec_prefix), containing the shared library + modules. Note that prefix and exec_prefix are the same directory + for UEFI installations. + + Separate searches are carried out for prefix and exec_prefix. + Each search tries a number of different locations until a ``landmark'' + file or directory is found. If no prefix or exec_prefix is found, a + warning message is issued and the preprocessor defined PREFIX and + EXEC_PREFIX are used (even though they may not work); python carries on + as best as is possible, but some imports may fail. + + Before any searches are done, the location of the executable is + determined. If argv[0] has one or more slashes in it, it is used + unchanged. Otherwise, it must have been invoked from the shell's path, + so we search %PATH% for the named executable and use that. If the + executable was not found on %PATH% (or there was no %PATH% environment + variable), the original argv[0] string is used. + + Finally, argv0_path is set to the directory containing the executable + (i.e. the last component is stripped). + + With argv0_path in hand, we perform a number of steps. The same steps + are performed for prefix and for exec_prefix, but with a different + landmark. + + The prefix landmark will always be lib/python.VERSION/os.py and the + exec_prefix will always be lib/python.VERSION/dynaload, where VERSION + is Python's version number as defined at the beginning of this file. + + First. See if the %PYTHONHOME% environment variable points to the + installed location of the Python libraries. If %PYTHONHOME% is set, then + it points to prefix and exec_prefix. %PYTHONHOME% can be a single + directory, which is used for both, or the prefix and exec_prefix + directories separated by the DELIM character. + + Next. Search the directories pointed to by the preprocessor variables + PREFIX and EXEC_PREFIX. These paths are prefixed with the volume name + extracted from argv0_path. The volume names correspond to the UEFI + shell "map" names. + + That's it! + + Well, almost. Once we have determined prefix and exec_prefix, the + preprocessor variable PYTHONPATH is used to construct a path. Each + relative path on PYTHONPATH is prefixed with prefix. Then the directory + containing the shared library modules is appended. The environment + variable $PYTHONPATH is inserted in front of it all. Finally, the + prefix and exec_prefix globals are tweaked so they reflect the values + expected by other code, by stripping the "lib/python$VERSION/..." stuff + off. This seems to make more sense given that currently the only + known use of sys.prefix and sys.exec_prefix is for the ILU installation + process to find the installed Python tree. + + The final, fully resolved, paths should look something like: + fs0:/Efi/Tools/python.efi + fs0:/Efi/StdLib/lib/python27 + fs0:/Efi/StdLib/lib/python27/dynaload + +**/ +static void +calculate_path(void) +{ + extern char *Py_GetProgramName(void); + + static char delimiter[2] = {DELIM, '\0'}; + static char separator[2] = {SEP, '\0'}; + char *pythonpath = PYTHONPATH; + char *rtpypath = Py_GETENV("PYTHONPATH"); + //char *home = Py_GetPythonHome(); + char *path = getenv("PATH"); + char *prog = Py_GetProgramName(); + char argv0_path[MAXPATHLEN+1]; + char zip_path[MAXPATHLEN+1]; + //int pfound, efound; /* 1 if found; -1 if found build directory */ + char *buf; + size_t bufsz; + size_t prefixsz; + char *defpath; + //uint32_t nsexeclength = MAXPATHLEN; + + //unixify(path); + //unixify(rtpypath); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]:\nENTER prog=\"%s\"\n path=\"%s\"\n", __func__, __LINE__, prog, path); + + +/* ########################################################################### + Determine path to the Python.efi binary. + Produces progpath, argv0_path, and volume_name. +########################################################################### */ + + /* 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 (strchr(prog, SEP)) + strncpy(progpath, prog, MAXPATHLEN); + else if (path) { + while (1) { + char *delim = strchr(path, DELIM); + + if (delim) { + size_t len = delim - path; + if (len > MAXPATHLEN) + len = MAXPATHLEN; + strncpy(progpath, path, len); + *(progpath + len) = '\0'; + } + else + strncpy(progpath, path, MAXPATHLEN); + + joinpath(progpath, prog); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: progpath = \"%s\"\n", __func__, __LINE__, progpath); + if (isxfile(progpath)) + break; + + if (!delim) { + progpath[0] = '\0'; + break; + } + path = delim + 1; + } + } + else + progpath[0] = '\0'; + if ( (!is_absolute(progpath)) && (progpath[0] != '\0') ) + absolutize(progpath); + strncpy(argv0_path, progpath, MAXPATHLEN); + argv0_path[MAXPATHLEN] = '\0'; + set_volume(volume_name, argv0_path); + + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: volume_name = \"%s\"\n", __func__, __LINE__, volume_name); + reduce(argv0_path); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: progpath = \"%s\"\n", __func__, __LINE__, progpath); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: argv0_path = \"%s\"\n", __func__, __LINE__, argv0_path); + /* At this point, argv0_path is guaranteed to be less than + MAXPATHLEN bytes long. + */ + +/* ########################################################################### + Build the FULL prefix string, including volume name. + This is the full path to the platform independent libraries. +########################################################################### */ + + //if (!(pfound = search_for_prefix(argv0_path, home))) { + // if (!Py_FrozenFlag) + // fprintf(stderr, + // "Could not find platform independent libraries \n"); + strncpy(prefix, volume_name, MAXPATHLEN); + joinpath(prefix, PREFIX); + joinpath(prefix, lib_python); + //} + //else + // reduce(prefix); + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: V = \"%s\", Prefix = \"%s\"\n", __func__, __LINE__, volume_name, prefix); + +/* ########################################################################### + Build the FULL path to the zipped-up Python library. +########################################################################### */ + + strncpy(zip_path, prefix, MAXPATHLEN); + zip_path[MAXPATHLEN] = '\0'; + //if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */ + reduce(zip_path); + //reduce(zip_path); + //} + //else + // strncpy(zip_path, PREFIX, MAXPATHLEN); + joinpath(zip_path, "python00.zip"); + bufsz = strlen(zip_path); /* Replace "00" with version */ + zip_path[bufsz - 6] = VERSION[0]; + zip_path[bufsz - 5] = VERSION[1]; + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: Zip_path = \"%s\"\n", __func__, __LINE__, zip_path); + +/* ########################################################################### + Build the FULL path to dynamically loadable libraries. +########################################################################### */ + + //if (!(efound = search_for_exec_prefix(argv0_path, home))) { + // if (!Py_FrozenFlag) + // fprintf(stderr, + // "Could not find platform dependent libraries \n"); + strncpy(exec_prefix, volume_name, MAXPATHLEN); + joinpath(exec_prefix, EXEC_PREFIX); + joinpath(exec_prefix, lib_python); + joinpath(exec_prefix, "dynaload"); + //} + /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: Exec_prefix = \"%s\"\n", __func__, __LINE__, exec_prefix); + + //if ((!pfound || !efound) && !Py_FrozenFlag) + // fprintf(stderr, + // "Consider setting $PYTHONHOME to [%c]\n", DELIM); + +/* ########################################################################### + Build the module search path. +########################################################################### */ + + /* 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]) { + strcpy(prefix, volume_name); + } + bufsz = strlen(prefix); + if(prefix[bufsz-1] == ':') { + prefix[bufsz] = SEP; + prefix[bufsz+1] = 0; + } + //} + //else + // strncpy(prefix, PREFIX, MAXPATHLEN); + +//if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: prefix = \"%s\"\n", __func__, __LINE__, prefix); + + /* Calculate size of return buffer. + */ + defpath = pythonpath; + bufsz = 0; + + if (rtpypath) + bufsz += strlen(rtpypath) + 1; + + prefixsz = strlen(prefix) + 1; + + while (1) { + char *delim = strchr(defpath, DELIM); + + if (is_absolute(defpath) == 0) + /* Paths are relative to prefix */ + bufsz += prefixsz; + + if (delim) + bufsz += delim - defpath + 1; + else { + bufsz += strlen(defpath) + 1; + break; + } + defpath = delim + 1; + } +//if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: defpath = \"%s\"\n", __func__, __LINE__, defpath); + + bufsz += strlen(zip_path) + 1; + bufsz += strlen(exec_prefix) + 1; + + /* This is the only malloc call in this file */ + buf = (char *)PyMem_Malloc(bufsz); + + if (buf == NULL) { + /* We can't exit, so print a warning and limp along */ + fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n"); + fprintf(stderr, "Using default static PYTHONPATH.\n"); + module_search_path = PYTHONPATH; + } + else { + //if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]:\n", __func__, __LINE__); + /* Run-time value of $PYTHONPATH goes first */ + if (rtpypath) { + strcpy(buf, rtpypath); + strcat(buf, delimiter); + } + else + buf[0] = '\0'; +//if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: RTpath = \"%s\"\n", __func__, __LINE__, buf); + + /* Next is the default zip path */ + strcat(buf, zip_path); + strcat(buf, delimiter); +//if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: +Zip = \"%s\"\n", __func__, __LINE__, buf); + + /* Next goes merge of compile-time $PYTHONPATH with + * dynamically located prefix. + */ + defpath = pythonpath; + while (1) { + char *delim = strchr(defpath, DELIM); + + if (is_absolute(defpath) != 1) { + strcat(buf, prefix); + strcat(buf, separator); + } + + if (delim) { + size_t len = delim - defpath + 1; + size_t end = strlen(buf) + len; + strncat(buf, defpath, len); + *(buf + end) = '\0'; + } + else { + strcat(buf, defpath); + break; + } + defpath = delim + 1; + } + strcat(buf, delimiter); +//if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: +Merge = \"%s\"\n", __func__, __LINE__, buf); + + /* Finally, on goes the directory for dynamic-load modules */ + strcat(buf, exec_prefix); + + /* And publish the results */ + module_search_path = buf; +//if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: module_search_path = \"%s\"\n", __func__, __LINE__, module_search_path); + } + + //if (efound > 0) { + /* At this point, exec_prefix is set to VOL:/Efi/StdLib/lib/python.27/dynalib. + We want to get back to the root value, so we have to remove the final three + segments to get VOL:/Efi/StdLib. Because we don't know what VOL is, and + EXEC_PREFIX is also indeterminate, we just remove the three final segments. + */ + reduce(exec_prefix); + reduce(exec_prefix); + reduce(exec_prefix); + if (!exec_prefix[0]) { + strcpy(exec_prefix, volume_name); + } + bufsz = strlen(exec_prefix); + if(exec_prefix[bufsz-1] == ':') { + exec_prefix[bufsz] = SEP; + exec_prefix[bufsz+1] = 0; + } + //} + //else + // strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); + if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: module_search_path = \"%s\"\n", __func__, __LINE__, module_search_path); + if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: prefix = \"%s\"\n", __func__, __LINE__, prefix); + if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: exec_prefix = \"%s\"\n", __func__, __LINE__, exec_prefix); + if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: progpath = \"%s\"\n", __func__, __LINE__, progpath); +} + + +/* External interface */ + +char * +Py_GetPath(void) +{ + if (!module_search_path) + calculate_path(); + return module_search_path; +} + +char * +Py_GetPrefix(void) +{ + if (!module_search_path) + calculate_path(); + return prefix; +} + +char * +Py_GetExecPrefix(void) +{ + if (!module_search_path) + calculate_path(); + return exec_prefix; +} + +char * +Py_GetProgramFullPath(void) +{ + if (!module_search_path) + calculate_path(); + return progpath; +} + + +#ifdef __cplusplus +} +#endif + diff --git a/AppPkg/Applications/Python/Efi/getpathp.c b/AppPkg/Applications/Python/Efi/getpathp.c deleted file mode 100644 index 9f78806611..0000000000 --- a/AppPkg/Applications/Python/Efi/getpathp.c +++ /dev/null @@ -1,714 +0,0 @@ - -/* Return the initial module search path. */ -/* Used by DOS, OS/2, Windows 3.1, Windows 95/98, Windows NT. */ - -/* ---------------------------------------------------------------- - PATH RULES FOR WINDOWS: - This describes how sys.path is formed on Windows. It describes the - functionality, not the implementation (ie, the order in which these - are actually fetched is different) - - * Python always adds an empty entry at the start, which corresponds - to the current directory. - - * If the PYTHONPATH env. var. exists, its entries are added next. - - * We look in the registry for "application paths" - that is, sub-keys - under the main PythonPath registry key. These are added next (the - order of sub-key processing is undefined). - HKEY_CURRENT_USER is searched and added first. - HKEY_LOCAL_MACHINE is searched and added next. - (Note that all known installers only use HKLM, so HKCU is typically - empty) - - * We attempt to locate the "Python Home" - if the PYTHONHOME env var - is set, we believe it. Otherwise, we use the path of our host .EXE's - to try and locate our "landmark" (lib\\os.py) and deduce our home. - - If we DO have a Python Home: The relevant sub-directories (Lib, - plat-win, lib-tk, etc) are based on the Python Home - - If we DO NOT have a Python Home, the core Python Path is - loaded from the registry. This is the main PythonPath key, - and both HKLM and HKCU are combined to form the path) - - * Iff - we can not locate the Python Home, have not had a PYTHONPATH - specified, and can't locate any Registry entries (ie, we have _nothing_ - we can assume is a good path), a default path with relative entries is - used (eg. .\Lib;.\plat-win, etc) - - - The end result of all this is: - * When running python.exe, or any other .exe in the main Python directory - (either an installed version, or directly from the PCbuild directory), - the core path is deduced, and the core paths in the registry are - ignored. Other "application paths" in the registry are always read. - - * When Python is hosted in another exe (different directory, embedded via - COM, etc), the Python Home will not be deduced, so the core path from - the registry is used. Other "application paths" in the registry are - always read. - - * If Python can't find its home and there is no registry (eg, frozen - exe, some very strange installation setup) you get a path with - some default, but relative, paths. - - ---------------------------------------------------------------- */ - - -#include "Python.h" -#include "osdefs.h" - -#ifdef MS_WINDOWS -#include -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif /* HAVE_SYS_TYPES_H */ - -#ifdef HAVE_SYS_STAT_H -#include -#endif /* HAVE_SYS_STAT_H */ - -#include - -/* Search in some common locations for the associated Python libraries. - * - * Py_GetPath() tries to return a sensible Python module search path. - * - * The approach is an adaptation for Windows of the strategy used in - * ../Modules/getpath.c; it uses the Windows Registry as one of its - * information sources. - */ - -#ifndef LANDMARK -#define LANDMARK "lib\\os.py" -#endif - -static char prefix[MAXPATHLEN+1]; -static char progpath[MAXPATHLEN+1]; -static char dllpath[MAXPATHLEN+1]; -static char *module_search_path = NULL; - - -static int -is_sep(char ch) /* determine if "ch" is a separator character */ -{ -#ifdef ALTSEP - return ch == SEP || ch == ALTSEP; -#else - return ch == SEP; -#endif -} - -/* assumes 'dir' null terminated in bounds. Never writes - beyond existing terminator. -*/ -static void -reduce(char *dir) -{ - size_t i = strlen(dir); - while (i > 0 && !is_sep(dir[i])) - --i; - dir[i] = '\0'; -} - - -static int -exists(char *filename) -{ - struct stat buf; - return stat(filename, &buf) == 0; -} - -/* Assumes 'filename' MAXPATHLEN+1 bytes long - - may extend 'filename' by one character. -*/ -static int -ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */ -{ - if (exists(filename)) - return 1; - - /* Check for the compiled version of prefix. */ - if (strlen(filename) < MAXPATHLEN) { - strcat(filename, Py_OptimizeFlag ? "o" : "c"); - if (exists(filename)) - return 1; - } - 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 - the trailing NUL). It's a fatal error if it contains a string longer than - that (callers must be careful!). If these requirements are met, it's - guaranteed that buffer will still be a NUL-terminated string with no more - than MAXPATHLEN characters at exit. If stuff is too long, only as much of - stuff as fits will be appended. -*/ -static void -join(char *buffer, char *stuff) -{ - size_t n, k; - if (is_sep(stuff[0])) - n = 0; - else { - n = strlen(buffer); - if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN) - buffer[n++] = SEP; - } - if (n > MAXPATHLEN) - Py_FatalError("buffer overflow in getpathp.c's joinpath()"); - k = strlen(stuff); - if (n + k > MAXPATHLEN) - k = MAXPATHLEN - n; - strncpy(buffer+n, stuff, k); - buffer[n+k] = '\0'; -} - -/* 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. -*/ -static int -gotlandmark(char *landmark) -{ - int ok; - Py_ssize_t n; - - n = strlen(prefix); - join(prefix, landmark); - ok = ismodule(prefix); - prefix[n] = '\0'; - 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(char *argv0_path, char *landmark) -{ - /* Search from argv0_path, until landmark is found */ - strcpy(prefix, argv0_path); - do { - if (gotlandmark(landmark)) - return 1; - reduce(prefix); - } while (prefix[0]); - return 0; -} - -#ifdef MS_WINDOWS -#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. - - Works in both Unicode and 8bit environments. Only uses the - Ex family of functions so it also works with Windows CE. - - Returns NULL, or a pointer that should be freed. - - XXX - this code is pretty strange, as it used to also - work on Win16, where the buffer sizes werent available - in advance. It could be simplied now Win16/Win32s is dead! -*/ - -static char * -getpythonregpath(HKEY keyBase, int skipcore) -{ - HKEY newKey = 0; - DWORD dataSize = 0; - DWORD numKeys = 0; - LONG rc; - char *retval = NULL; - TCHAR *dataBuf = NULL; - static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\"); - static const TCHAR keySuffix[] = _T("\\PythonPath"); - size_t versionLen; - DWORD index; - TCHAR *keyBuf = NULL; - TCHAR *keyBufPtr; - TCHAR **ppPaths = NULL; - - /* Tried to use sysget("winver") but here is too early :-( */ - versionLen = _tcslen(PyWin_DLLVersionString); - /* Space for all the chars, plus one \0 */ - keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) + - sizeof(TCHAR)*(versionLen-1) + - sizeof(keySuffix)); - if (keyBuf==NULL) goto done; - - memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(TCHAR)); - keyBufPtr += sizeof(keyPrefix)/sizeof(TCHAR) - 1; - memcpy(keyBufPtr, PyWin_DLLVersionString, versionLen * sizeof(TCHAR)); - keyBufPtr += versionLen; - /* NULL comes with this one! */ - memcpy(keyBufPtr, keySuffix, sizeof(keySuffix)); - /* Open the root Python key */ - rc=RegOpenKeyEx(keyBase, - keyBuf, /* subkey */ - 0, /* reserved */ - KEY_READ, - &newKey); - 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! */ - /* Allocate a temp array of char buffers, so we only need to loop - reading the registry once - */ - ppPaths = malloc( sizeof(TCHAR *) * numKeys ); - if (ppPaths==NULL) goto done; - memset(ppPaths, 0, sizeof(TCHAR *) * numKeys); - /* Loop over all subkeys, allocating a temp sub-buffer. */ - for(index=0;index 0) { - *(szCur++) = _T(';'); - dataSize--; - } - if (ppPaths[index]) { - Py_ssize_t len = _tcslen(ppPaths[index]); - _tcsncpy(szCur, ppPaths[index], len); - szCur += len; - assert(dataSize > (DWORD)len); - dataSize -= (DWORD)len; - } - } - if (skipcore) - *szCur = '\0'; - else { - /* If we have no values, we dont need a ';' */ - if (numKeys) { - *(szCur++) = _T(';'); - dataSize--; - } - /* Now append the core path entries - - this will include the NULL - */ - rc = RegQueryValueEx(newKey, NULL, 0, NULL, - (LPBYTE)szCur, &dataSize); - } - /* And set the result - caller must free - If MBCS, it is fine as is. If Unicode, allocate new - buffer and convert. - */ -#ifdef UNICODE - retval = (char *)malloc(reqdSize+1); - if (retval) - WideCharToMultiByte(CP_ACP, 0, - dataBuf, -1, /* source */ - retval, reqdSize+1, /* dest */ - NULL, NULL); - free(dataBuf); -#else - retval = dataBuf; -#endif - } -done: - /* Loop freeing my temp buffers */ - if (ppPaths) { - for(index=0;index 4) { - zip_path[len-3] = 'z'; /* change ending to "zip" */ - zip_path[len-2] = 'i'; - zip_path[len-1] = 'p'; - } - else { - zip_path[0] = 0; - } - - skiphome = pythonhome==NULL ? 0 : 1; -#ifdef Py_ENABLE_SHARED - machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); - userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome); -#endif - /* We only use the default relative PYTHONPATH if we havent - anything better to use! */ - skipdefault = envpath!=NULL || pythonhome!=NULL || \ - machinepath!=NULL || userpath!=NULL; -#endif - - /* 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; - (4) the PYTHONPATH config macro, with the leading "." - of each component replaced with pythonhome, if set; - (5) the directory containing the executable (argv0_path). - The length calculation calculates #4 first. - Extra rules: - - If PYTHONHOME is set (in any way) item (3) is ignored. - - If registry values are used, (4) and (5) are ignored. - */ - - /* Calculate size of return buffer */ - if (pythonhome != NULL) { - char *p; - bufsz = 1; - for (p = PYTHONPATH; *p; p++) { - if (*p == DELIM) - bufsz++; /* number of DELIM plus one */ - } - bufsz *= strlen(pythonhome); - } - else - bufsz = 0; - bufsz += strlen(PYTHONPATH) + 1; - bufsz += strlen(argv0_path) + 1; -#ifdef MS_WINDOWS - if (userpath) - bufsz += strlen(userpath) + 1; - if (machinepath) - bufsz += strlen(machinepath) + 1; - bufsz += strlen(zip_path) + 1; -#endif - if (envpath != NULL) - bufsz += strlen(envpath) + 1; - - module_search_path = buf = malloc(bufsz); - if (buf == NULL) { - /* We can't exit, so print a warning and limp along */ - fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n"); - if (envpath) { - fprintf(stderr, "Using environment $PYTHONPATH.\n"); - module_search_path = envpath; - } - else { - fprintf(stderr, "Using default static path.\n"); - module_search_path = PYTHONPATH; - } -#ifdef MS_WINDOWS - if (machinepath) - free(machinepath); - if (userpath) - free(userpath); -#endif /* MS_WINDOWS */ - return; - } - - if (envpath) { - strcpy(buf, envpath); - buf = strchr(buf, '\0'); - *buf++ = DELIM; - } -#ifdef MS_WINDOWS - if (zip_path[0]) { - strcpy(buf, zip_path); - buf = strchr(buf, '\0'); - *buf++ = DELIM; - } - if (userpath) { - strcpy(buf, userpath); - buf = strchr(buf, '\0'); - *buf++ = DELIM; - free(userpath); - } - if (machinepath) { - strcpy(buf, machinepath); - buf = strchr(buf, '\0'); - *buf++ = DELIM; - free(machinepath); - } - if (pythonhome == NULL) { - if (!skipdefault) { - strcpy(buf, PYTHONPATH); - buf = strchr(buf, '\0'); - } - } -#else - if (pythonhome == NULL) { - strcpy(buf, PYTHONPATH); - buf = strchr(buf, '\0'); - } -#endif /* MS_WINDOWS */ - else { - char *p = PYTHONPATH; - char *q; - size_t n; - for (;;) { - q = strchr(p, DELIM); - if (q == NULL) - n = strlen(p); - else - n = q-p; - if (p[0] == '.' && is_sep(p[1])) { - strcpy(buf, pythonhome); - buf = strchr(buf, '\0'); - p++; - n--; - } - strncpy(buf, p, n); - buf += n; - if (q == NULL) - break; - *buf++ = DELIM; - p = q+1; - } - } - if (argv0_path) { - *buf++ = DELIM; - strcpy(buf, argv0_path); - buf = strchr(buf, '\0'); - } - *buf = '\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 - is that Python core directories are at the *end* of - sys.path. We assume that our "lib" directory is - on the path, and that our 'prefix' directory is - the parent of that. - */ - if (*prefix=='\0') { - char lookBuf[MAXPATHLEN+1]; - char *look = buf - 1; /* 'buf' is at the end of the buffer */ - while (1) { - Py_ssize_t nchars; - char *lookEnd = look; - /* 'look' will end up one character before the - 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) - look--; - nchars = lookEnd-look; - strncpy(lookBuf, look+1, nchars); - lookBuf[nchars] = '\0'; - /* Up one level to the parent */ - reduce(lookBuf); - if (search_for_prefix(lookBuf, LANDMARK)) { - break; - } - /* If we are out of paths to search - give up */ - if (look < module_search_path) - break; - look--; - } - } -} - - -/* External interface */ - -char * -Py_GetPath(void) -{ - if (!module_search_path) - calculate_path(); - return module_search_path; -} - -char * -Py_GetPrefix(void) -{ - if (!module_search_path) - calculate_path(); - return prefix; -} - -char * -Py_GetExecPrefix(void) -{ - return Py_GetPrefix(); -} - -char * -Py_GetProgramFullPath(void) -{ - if (!module_search_path) - calculate_path(); - return progpath; -} -- cgit v1.2.3