1 
2 /* Return the initial module search path. */
3 /* Used by DOS, Windows 3.1, Windows 95/98, Windows NT. */
4 
5 /* ----------------------------------------------------------------
6    PATH RULES FOR WINDOWS:
7    This describes how sys.path is formed on Windows.  It describes the
8    functionality, not the implementation (ie, the order in which these
9    are actually fetched is different). The presence of a python._pth or
10    pythonXY._pth file alongside the program overrides these rules - see
11    below.
12 
13    * Python always adds an empty entry at the start, which corresponds
14      to the current directory.
15 
16    * If the PYTHONPATH env. var. exists, its entries are added next.
17 
18    * We look in the registry for "application paths" - that is, sub-keys
19      under the main PythonPath registry key.  These are added next (the
20      order of sub-key processing is undefined).
21      HKEY_CURRENT_USER is searched and added first.
22      HKEY_LOCAL_MACHINE is searched and added next.
23      (Note that all known installers only use HKLM, so HKCU is typically
24      empty)
25 
26    * We attempt to locate the "Python Home" - if the PYTHONHOME env var
27      is set, we believe it.  Otherwise, we use the path of our host .EXE's
28      to try and locate one of our "landmarks" and deduce our home.
29      - If we DO have a Python Home: The relevant sub-directories (Lib,
30        DLLs, etc) are based on the Python Home
31      - If we DO NOT have a Python Home, the core Python Path is
32        loaded from the registry.  This is the main PythonPath key,
33        and both HKLM and HKCU are combined to form the path)
34 
35    * Iff - we can not locate the Python Home, have not had a PYTHONPATH
36      specified, and can't locate any Registry entries (ie, we have _nothing_
37      we can assume is a good path), a default path with relative entries is
38      used (eg. .\Lib;.\DLLs, etc)
39 
40 
41    If a '._pth' file exists adjacent to the executable with the same base name
42    (e.g. python._pth adjacent to python.exe) or adjacent to the shared library
43    (e.g. python36._pth adjacent to python36.dll), it is used in preference to
44    the above process. The shared library file takes precedence over the
45    executable. The path file must contain a list of paths to add to sys.path,
46    one per line. Each path is relative to the directory containing the file.
47    Blank lines and comments beginning with '#' are permitted.
48 
49    In the presence of this ._pth file, no other paths are added to the search
50    path, the registry finder is not enabled, site.py is not imported and
51    isolated mode is enabled. The site package can be enabled by including a
52    line reading "import site"; no other imports are recognized. Any invalid
53    entry (other than directories that do not exist) will result in immediate
54    termination of the program.
55 
56 
57   The end result of all this is:
58   * When running python.exe, or any other .exe in the main Python directory
59     (either an installed version, or directly from the PCbuild directory),
60     the core path is deduced, and the core paths in the registry are
61     ignored.  Other "application paths" in the registry are always read.
62 
63   * When Python is hosted in another exe (different directory, embedded via
64     COM, etc), the Python Home will not be deduced, so the core path from
65     the registry is used.  Other "application paths" in the registry are
66     always read.
67 
68   * If Python can't find its home and there is no registry (eg, frozen
69     exe, some very strange installation setup) you get a path with
70     some default, but relative, paths.
71 
72   * An embedding application can use Py_SetPath() to override all of
73     these automatic path computations.
74 
75   * An install of Python can fully specify the contents of sys.path using
76     either a 'EXENAME._pth' or 'DLLNAME._pth' file, optionally including
77     "import site" to enable the site module.
78 
79    ---------------------------------------------------------------- */
80 
81 
82 #include "Python.h"
83 #include "osdefs.h"
84 #include <wchar.h>
85 
86 #ifndef MS_WINDOWS
87 #error getpathp.c should only be built on Windows
88 #endif
89 
90 #include <windows.h>
91 #include <Shlwapi.h>
92 
93 #ifdef HAVE_SYS_TYPES_H
94 #include <sys/types.h>
95 #endif /* HAVE_SYS_TYPES_H */
96 
97 #ifdef HAVE_SYS_STAT_H
98 #include <sys/stat.h>
99 #endif /* HAVE_SYS_STAT_H */
100 
101 #include <string.h>
102 
103 /* Search in some common locations for the associated Python libraries.
104  *
105  * Py_GetPath() tries to return a sensible Python module search path.
106  *
107  * The approach is an adaptation for Windows of the strategy used in
108  * ../Modules/getpath.c; it uses the Windows Registry as one of its
109  * information sources.
110  *
111  * Py_SetPath() can be used to override this mechanism.  Call Py_SetPath
112  * with a semicolon separated path prior to calling Py_Initialize.
113  */
114 
115 #ifndef LANDMARK
116 #define LANDMARK L"lib\\os.py"
117 #endif
118 
119 static wchar_t prefix[MAXPATHLEN+1];
120 static wchar_t progpath[MAXPATHLEN+1];
121 static wchar_t dllpath[MAXPATHLEN+1];
122 static wchar_t *module_search_path = NULL;
123 
124 
125 static int
is_sep(wchar_t ch)126 is_sep(wchar_t ch)      /* determine if "ch" is a separator character */
127 {
128 #ifdef ALTSEP
129     return ch == SEP || ch == ALTSEP;
130 #else
131     return ch == SEP;
132 #endif
133 }
134 
135 /* assumes 'dir' null terminated in bounds.  Never writes
136    beyond existing terminator.
137 */
138 static void
reduce(wchar_t * dir)139 reduce(wchar_t *dir)
140 {
141     size_t i = wcsnlen_s(dir, MAXPATHLEN+1);
142     if (i >= MAXPATHLEN+1)
143         Py_FatalError("buffer overflow in getpathp.c's reduce()");
144 
145     while (i > 0 && !is_sep(dir[i]))
146         --i;
147     dir[i] = '\0';
148 }
149 
150 static int
change_ext(wchar_t * dest,const wchar_t * src,const wchar_t * ext)151 change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
152 {
153     size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
154     size_t i = src_len;
155     if (i >= MAXPATHLEN+1)
156         Py_FatalError("buffer overflow in getpathp.c's reduce()");
157 
158     while (i > 0 && src[i] != '.' && !is_sep(src[i]))
159         --i;
160 
161     if (i == 0) {
162         dest[0] = '\0';
163         return -1;
164     }
165 
166     if (is_sep(src[i]))
167         i = src_len;
168 
169     if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) ||
170         wcscat_s(dest, MAXPATHLEN+1, ext)) {
171         dest[0] = '\0';
172         return -1;
173     }
174 
175     return 0;
176 }
177 
178 static int
exists(wchar_t * filename)179 exists(wchar_t *filename)
180 {
181     return GetFileAttributesW(filename) != 0xFFFFFFFF;
182 }
183 
184 /* Assumes 'filename' MAXPATHLEN+1 bytes long -
185    may extend 'filename' by one character.
186 */
187 static int
ismodule(wchar_t * filename,int update_filename)188 ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc/.pyo too */
189 {
190     size_t n;
191 
192     if (exists(filename))
193         return 1;
194 
195     /* Check for the compiled version of prefix. */
196     n = wcsnlen_s(filename, MAXPATHLEN+1);
197     if (n < MAXPATHLEN) {
198         int exist = 0;
199         filename[n] = Py_OptimizeFlag ? L'o' : L'c';
200         filename[n + 1] = L'\0';
201         exist = exists(filename);
202         if (!update_filename)
203             filename[n] = L'\0';
204         return exist;
205     }
206     return 0;
207 }
208 
209 /* Add a path component, by appending stuff to buffer.
210    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
211    NUL-terminated string with no more than MAXPATHLEN characters (not counting
212    the trailing NUL).  It's a fatal error if it contains a string longer than
213    that (callers must be careful!).  If these requirements are met, it's
214    guaranteed that buffer will still be a NUL-terminated string with no more
215    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
216    stuff as fits will be appended.
217 */
218 
219 static int _PathCchCombineEx_Initialized = 0;
220 typedef HRESULT(__stdcall *PPathCchCombineEx)(PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore, unsigned long dwFlags);
221 static PPathCchCombineEx _PathCchCombineEx;
222 
223 static void
join(wchar_t * buffer,const wchar_t * stuff)224 join(wchar_t *buffer, const wchar_t *stuff)
225 {
226     if (_PathCchCombineEx_Initialized == 0) {
227         HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
228         if (pathapi)
229             _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx");
230         else
231             _PathCchCombineEx = NULL;
232         _PathCchCombineEx_Initialized = 1;
233     }
234 
235     if (_PathCchCombineEx) {
236         if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0)))
237             Py_FatalError("buffer overflow in getpathp.c's join()");
238     } else {
239         if (!PathCombineW(buffer, buffer, stuff))
240             Py_FatalError("buffer overflow in getpathp.c's join()");
241     }
242 }
243 
244 /* gotlandmark only called by search_for_prefix, which ensures
245    'prefix' is null terminated in bounds.  join() ensures
246    'landmark' can not overflow prefix if too long.
247 */
248 static int
gotlandmark(const wchar_t * landmark)249 gotlandmark(const wchar_t *landmark)
250 {
251     int ok;
252     Py_ssize_t n = wcsnlen_s(prefix, MAXPATHLEN);
253 
254     join(prefix, landmark);
255     ok = ismodule(prefix, FALSE);
256     prefix[n] = '\0';
257     return ok;
258 }
259 
260 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
261    assumption provided by only caller, calculate_path() */
262 static int
search_for_prefix(wchar_t * argv0_path,const wchar_t * landmark)263 search_for_prefix(wchar_t *argv0_path, const wchar_t *landmark)
264 {
265     /* Search from argv0_path, until landmark is found */
266     wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
267     do {
268         if (gotlandmark(landmark))
269             return 1;
270         reduce(prefix);
271     } while (prefix[0]);
272     return 0;
273 }
274 
275 #ifdef Py_ENABLE_SHARED
276 
277 /* a string loaded from the DLL at startup.*/
278 extern const char *PyWin_DLLVersionString;
279 
280 
281 /* Load a PYTHONPATH value from the registry.
282    Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
283 
284    Works in both Unicode and 8bit environments.  Only uses the
285    Ex family of functions so it also works with Windows CE.
286 
287    Returns NULL, or a pointer that should be freed.
288 
289    XXX - this code is pretty strange, as it used to also
290    work on Win16, where the buffer sizes werent available
291    in advance.  It could be simplied now Win16/Win32s is dead!
292 */
293 
294 static wchar_t *
getpythonregpath(HKEY keyBase,int skipcore)295 getpythonregpath(HKEY keyBase, int skipcore)
296 {
297     HKEY newKey = 0;
298     DWORD dataSize = 0;
299     DWORD numKeys = 0;
300     LONG rc;
301     wchar_t *retval = NULL;
302     WCHAR *dataBuf = NULL;
303     static const WCHAR keyPrefix[] = L"Software\\Python\\PythonCore\\";
304     static const WCHAR keySuffix[] = L"\\PythonPath";
305     size_t versionLen, keyBufLen;
306     DWORD index;
307     WCHAR *keyBuf = NULL;
308     WCHAR *keyBufPtr;
309     WCHAR **ppPaths = NULL;
310 
311     /* Tried to use sysget("winver") but here is too early :-( */
312     versionLen = strlen(PyWin_DLLVersionString);
313     /* Space for all the chars, plus one \0 */
314     keyBufLen = sizeof(keyPrefix) +
315                 sizeof(WCHAR)*(versionLen-1) +
316                 sizeof(keySuffix);
317     keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen);
318     if (keyBuf==NULL) goto done;
319 
320     memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
321     keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1;
322     mbstowcs(keyBufPtr, PyWin_DLLVersionString, versionLen);
323     keyBufPtr += versionLen;
324     /* NULL comes with this one! */
325     memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
326     /* Open the root Python key */
327     rc=RegOpenKeyExW(keyBase,
328                     keyBuf, /* subkey */
329             0, /* reserved */
330             KEY_READ,
331             &newKey);
332     if (rc!=ERROR_SUCCESS) goto done;
333     /* Find out how big our core buffer is, and how many subkeys we have */
334     rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
335                     NULL, NULL, &dataSize, NULL, NULL);
336     if (rc!=ERROR_SUCCESS) goto done;
337     if (skipcore) dataSize = 0; /* Only count core ones if we want them! */
338     /* Allocate a temp array of char buffers, so we only need to loop
339        reading the registry once
340     */
341     ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys );
342     if (ppPaths==NULL) goto done;
343     memset(ppPaths, 0, sizeof(WCHAR *) * numKeys);
344     /* Loop over all subkeys, allocating a temp sub-buffer. */
345     for(index=0;index<numKeys;index++) {
346         WCHAR keyBuf[MAX_PATH+1];
347         HKEY subKey = 0;
348         DWORD reqdSize = MAX_PATH+1;
349         /* Get the sub-key name */
350         DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
351                                  NULL, NULL, NULL, NULL );
352         if (rc!=ERROR_SUCCESS) goto done;
353         /* Open the sub-key */
354         rc=RegOpenKeyExW(newKey,
355                                         keyBuf, /* subkey */
356                         0, /* reserved */
357                         KEY_READ,
358                         &subKey);
359         if (rc!=ERROR_SUCCESS) goto done;
360         /* Find the value of the buffer size, malloc, then read it */
361         RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
362         if (reqdSize) {
363             ppPaths[index] = PyMem_RawMalloc(reqdSize);
364             if (ppPaths[index]) {
365                 RegQueryValueExW(subKey, NULL, 0, NULL,
366                                 (LPBYTE)ppPaths[index],
367                                 &reqdSize);
368                 dataSize += reqdSize + 1; /* 1 for the ";" */
369             }
370         }
371         RegCloseKey(subKey);
372     }
373 
374     /* return null if no path to return */
375     if (dataSize == 0) goto done;
376 
377     /* original datasize from RegQueryInfo doesn't include the \0 */
378     dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
379     if (dataBuf) {
380         WCHAR *szCur = dataBuf;
381         /* Copy our collected strings */
382         for (index=0;index<numKeys;index++) {
383             if (index > 0) {
384                 *(szCur++) = L';';
385                 dataSize--;
386             }
387             if (ppPaths[index]) {
388                 Py_ssize_t len = wcslen(ppPaths[index]);
389                 wcsncpy(szCur, ppPaths[index], len);
390                 szCur += len;
391                 assert(dataSize > (DWORD)len);
392                 dataSize -= (DWORD)len;
393             }
394         }
395         if (skipcore)
396             *szCur = '\0';
397         else {
398             /* If we have no values, we dont need a ';' */
399             if (numKeys) {
400                 *(szCur++) = L';';
401                 dataSize--;
402             }
403             /* Now append the core path entries -
404                this will include the NULL
405             */
406             rc = RegQueryValueExW(newKey, NULL, 0, NULL,
407                                   (LPBYTE)szCur, &dataSize);
408             if (rc != ERROR_SUCCESS) {
409                 PyMem_RawFree(dataBuf);
410                 goto done;
411             }
412         }
413         /* And set the result - caller must free */
414         retval = dataBuf;
415     }
416 done:
417     /* Loop freeing my temp buffers */
418     if (ppPaths) {
419         for(index=0; index<numKeys; index++)
420             PyMem_RawFree(ppPaths[index]);
421         PyMem_RawFree(ppPaths);
422     }
423     if (newKey)
424         RegCloseKey(newKey);
425     PyMem_RawFree(keyBuf);
426     return retval;
427 }
428 #endif /* Py_ENABLE_SHARED */
429 
430 static void
get_progpath(void)431 get_progpath(void)
432 {
433     extern wchar_t *Py_GetProgramName(void);
434     wchar_t *path = _wgetenv(L"PATH");
435     wchar_t *prog = Py_GetProgramName();
436 
437 #ifdef Py_ENABLE_SHARED
438     extern HANDLE PyWin_DLLhModule;
439     /* static init of progpath ensures final char remains \0 */
440     if (PyWin_DLLhModule)
441         if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN))
442             dllpath[0] = 0;
443 #else
444     dllpath[0] = 0;
445 #endif
446     if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN))
447         return;
448     if (prog == NULL || *prog == '\0')
449         prog = L"python";
450 
451     /* If there is no slash in the argv0 path, then we have to
452      * assume python is on the user's $PATH, since there's no
453      * other way to find a directory to start the search from.  If
454      * $PATH isn't exported, you lose.
455      */
456 #ifdef ALTSEP
457     if (wcschr(prog, SEP) || wcschr(prog, ALTSEP))
458 #else
459     if (wcschr(prog, SEP))
460 #endif
461         wcsncpy(progpath, prog, MAXPATHLEN);
462     else if (path) {
463         while (1) {
464             wchar_t *delim = wcschr(path, DELIM);
465 
466             if (delim) {
467                 size_t len = delim - path;
468                 /* ensure we can't overwrite buffer */
469                 len = min(MAXPATHLEN,len);
470                 wcsncpy(progpath, path, len);
471                 *(progpath + len) = '\0';
472             }
473             else
474                 wcsncpy(progpath, path, MAXPATHLEN);
475 
476             /* join() is safe for MAXPATHLEN+1 size buffer */
477             join(progpath, prog);
478             if (exists(progpath))
479                 break;
480 
481             if (!delim) {
482                 progpath[0] = '\0';
483                 break;
484             }
485             path = delim + 1;
486         }
487     }
488     else
489         progpath[0] = '\0';
490 }
491 
492 static int
find_env_config_value(FILE * env_file,const wchar_t * key,wchar_t * value)493 find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
494 {
495     int result = 0; /* meaning not found */
496     char buffer[MAXPATHLEN*2+1];  /* allow extra for key, '=', etc. */
497 
498     fseek(env_file, 0, SEEK_SET);
499     while (!feof(env_file)) {
500         char * p = fgets(buffer, MAXPATHLEN*2, env_file);
501         wchar_t tmpbuffer[MAXPATHLEN*2+1];
502         PyObject * decoded;
503         size_t n;
504 
505         if (p == NULL)
506             break;
507         n = strlen(p);
508         if (p[n - 1] != '\n') {
509             /* line has overflowed - bail */
510             break;
511         }
512         if (p[0] == '#')    /* Comment - skip */
513             continue;
514         decoded = PyUnicode_DecodeUTF8(buffer, n, "surrogateescape");
515         if (decoded != NULL) {
516             Py_ssize_t k;
517             k = PyUnicode_AsWideChar(decoded,
518                                      tmpbuffer, MAXPATHLEN * 2);
519             Py_DECREF(decoded);
520             if (k >= 0) {
521                 wchar_t * context = NULL;
522                 wchar_t * tok = wcstok_s(tmpbuffer, L" \t\r\n", &context);
523                 if ((tok != NULL) && !wcscmp(tok, key)) {
524                     tok = wcstok_s(NULL, L" \t", &context);
525                     if ((tok != NULL) && !wcscmp(tok, L"=")) {
526                         tok = wcstok_s(NULL, L"\r\n", &context);
527                         if (tok != NULL) {
528                             wcsncpy(value, tok, MAXPATHLEN);
529                             result = 1;
530                             break;
531                         }
532                     }
533                 }
534             }
535         }
536     }
537     return result;
538 }
539 
540 static int
read_pth_file(const wchar_t * path,wchar_t * prefix,int * isolated,int * nosite)541 read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
542 {
543     FILE *sp_file = _Py_wfopen(path, L"r");
544     if (sp_file == NULL)
545         return -1;
546 
547     wcscpy_s(prefix, MAXPATHLEN+1, path);
548     reduce(prefix);
549     *isolated = 1;
550     *nosite = 1;
551 
552     size_t bufsiz = MAXPATHLEN;
553     size_t prefixlen = wcslen(prefix);
554 
555     wchar_t *buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
556     buf[0] = '\0';
557 
558     while (!feof(sp_file)) {
559         char line[MAXPATHLEN + 1];
560         char *p = fgets(line, MAXPATHLEN + 1, sp_file);
561         if (!p)
562             break;
563         if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#')
564             continue;
565         while (*++p) {
566             if (*p == '\r' || *p == '\n') {
567                 *p = '\0';
568                 break;
569             }
570         }
571 
572         if (strcmp(line, "import site") == 0) {
573             *nosite = 0;
574             continue;
575         } else if (strncmp(line, "import ", 7) == 0) {
576             Py_FatalError("only 'import site' is supported in ._pth file");
577         }
578 
579         DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
580         wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
581         wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
582         wline[wn] = '\0';
583 
584         size_t usedsiz = wcslen(buf);
585         while (usedsiz + wn + prefixlen + 4 > bufsiz) {
586             bufsiz += MAXPATHLEN;
587             buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t));
588             if (!buf) {
589                 PyMem_RawFree(wline);
590                 goto error;
591             }
592         }
593 
594         if (usedsiz) {
595             wcscat_s(buf, bufsiz, L";");
596             usedsiz += 1;
597         }
598 
599         errno_t result;
600         _Py_BEGIN_SUPPRESS_IPH
601         result = wcscat_s(buf, bufsiz, prefix);
602         _Py_END_SUPPRESS_IPH
603         if (result == EINVAL) {
604             Py_FatalError("invalid argument during ._pth processing");
605         } else if (result == ERANGE) {
606             Py_FatalError("buffer overflow during ._pth processing");
607         }
608         wchar_t *b = &buf[usedsiz];
609         join(b, wline);
610 
611         PyMem_RawFree(wline);
612     }
613 
614     module_search_path = buf;
615 
616     fclose(sp_file);
617     return 0;
618 
619 error:
620     PyMem_RawFree(buf);
621     fclose(sp_file);
622     return -1;
623 }
624 
625 
626 static void
calculate_path(void)627 calculate_path(void)
628 {
629     wchar_t argv0_path[MAXPATHLEN+1];
630     wchar_t *buf;
631     size_t bufsz;
632     wchar_t *pythonhome = Py_GetPythonHome();
633     wchar_t *envpath = NULL;
634 
635     int skiphome, skipdefault;
636     wchar_t *machinepath = NULL;
637     wchar_t *userpath = NULL;
638     wchar_t zip_path[MAXPATHLEN+1];
639 
640     if (!Py_IgnoreEnvironmentFlag) {
641         envpath = _wgetenv(L"PYTHONPATH");
642     }
643 
644     get_progpath();
645     /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
646     wcscpy_s(argv0_path, MAXPATHLEN+1, progpath);
647     reduce(argv0_path);
648 
649     /* Search for a sys.path file */
650     {
651         wchar_t spbuffer[MAXPATHLEN+1];
652 
653         if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) ||
654             (progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) {
655 
656             if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) {
657                 return;
658             }
659         }
660     }
661 
662     /* Search for an environment configuration file, first in the
663        executable's directory and then in the parent directory.
664        If found, open it for use when searching for prefixes.
665     */
666 
667     {
668         wchar_t envbuffer[MAXPATHLEN+1];
669         wchar_t tmpbuffer[MAXPATHLEN+1];
670         const wchar_t *env_cfg = L"pyvenv.cfg";
671         FILE * env_file = NULL;
672 
673         wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path);
674         join(envbuffer, env_cfg);
675         env_file = _Py_wfopen(envbuffer, L"r");
676         if (env_file == NULL) {
677             errno = 0;
678             reduce(envbuffer);
679             reduce(envbuffer);
680             join(envbuffer, env_cfg);
681             env_file = _Py_wfopen(envbuffer, L"r");
682             if (env_file == NULL) {
683                 errno = 0;
684             }
685         }
686         if (env_file != NULL) {
687             /* Look for a 'home' variable and set argv0_path to it, if found */
688             if (find_env_config_value(env_file, L"home", tmpbuffer)) {
689                 wcscpy_s(argv0_path, MAXPATHLEN+1, tmpbuffer);
690             }
691             fclose(env_file);
692             env_file = NULL;
693         }
694     }
695 
696     /* Calculate zip archive path from DLL or exe path */
697     change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip");
698 
699     if (pythonhome == NULL || *pythonhome == '\0') {
700         if (zip_path[0] && exists(zip_path)) {
701             wcscpy_s(prefix, MAXPATHLEN+1, zip_path);
702             reduce(prefix);
703             pythonhome = prefix;
704         } else if (search_for_prefix(argv0_path, LANDMARK))
705             pythonhome = prefix;
706         else
707             pythonhome = NULL;
708     }
709     else
710         wcscpy_s(prefix, MAXPATHLEN+1, pythonhome);
711 
712     if (envpath && *envpath == '\0')
713         envpath = NULL;
714 
715 
716     skiphome = pythonhome==NULL ? 0 : 1;
717 #ifdef Py_ENABLE_SHARED
718     machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);
719     userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome);
720 #endif
721     /* We only use the default relative PYTHONPATH if we havent
722        anything better to use! */
723     skipdefault = envpath!=NULL || pythonhome!=NULL || \
724                   machinepath!=NULL || userpath!=NULL;
725 
726     /* We need to construct a path from the following parts.
727        (1) the PYTHONPATH environment variable, if set;
728        (2) for Win32, the zip archive file path;
729        (3) for Win32, the machinepath and userpath, if set;
730        (4) the PYTHONPATH config macro, with the leading "."
731            of each component replaced with pythonhome, if set;
732        (5) the directory containing the executable (argv0_path).
733        The length calculation calculates #4 first.
734        Extra rules:
735        - If PYTHONHOME is set (in any way) item (3) is ignored.
736        - If registry values are used, (4) and (5) are ignored.
737     */
738 
739     /* Calculate size of return buffer */
740     if (pythonhome != NULL) {
741         wchar_t *p;
742         bufsz = 1;
743         for (p = PYTHONPATH; *p; p++) {
744             if (*p == DELIM)
745                 bufsz++; /* number of DELIM plus one */
746         }
747         bufsz *= wcslen(pythonhome);
748     }
749     else
750         bufsz = 0;
751     bufsz += wcslen(PYTHONPATH) + 1;
752     bufsz += wcslen(argv0_path) + 1;
753     if (userpath)
754         bufsz += wcslen(userpath) + 1;
755     if (machinepath)
756         bufsz += wcslen(machinepath) + 1;
757     bufsz += wcslen(zip_path) + 1;
758     if (envpath != NULL)
759         bufsz += wcslen(envpath) + 1;
760 
761     module_search_path = buf = PyMem_RawMalloc(bufsz*sizeof(wchar_t));
762     if (buf == NULL) {
763         /* We can't exit, so print a warning and limp along */
764         fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
765         if (envpath) {
766             fprintf(stderr, "Using environment $PYTHONPATH.\n");
767             module_search_path = envpath;
768         }
769         else {
770             fprintf(stderr, "Using default static path.\n");
771             module_search_path = PYTHONPATH;
772         }
773         PyMem_RawFree(machinepath);
774         PyMem_RawFree(userpath);
775         return;
776     }
777 
778     if (envpath) {
779         if (wcscpy_s(buf, bufsz - (buf - module_search_path), envpath))
780             Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
781         buf = wcschr(buf, L'\0');
782         *buf++ = DELIM;
783     }
784     if (zip_path[0]) {
785         if (wcscpy_s(buf, bufsz - (buf - module_search_path), zip_path))
786             Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
787         buf = wcschr(buf, L'\0');
788         *buf++ = DELIM;
789     }
790     if (userpath) {
791         if (wcscpy_s(buf, bufsz - (buf - module_search_path), userpath))
792             Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
793         buf = wcschr(buf, L'\0');
794         *buf++ = DELIM;
795         PyMem_RawFree(userpath);
796     }
797     if (machinepath) {
798         if (wcscpy_s(buf, bufsz - (buf - module_search_path), machinepath))
799             Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
800         buf = wcschr(buf, L'\0');
801         *buf++ = DELIM;
802         PyMem_RawFree(machinepath);
803     }
804     if (pythonhome == NULL) {
805         if (!skipdefault) {
806             if (wcscpy_s(buf, bufsz - (buf - module_search_path), PYTHONPATH))
807                 Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
808             buf = wcschr(buf, L'\0');
809             *buf++ = DELIM;
810         }
811     } else {
812         wchar_t *p = PYTHONPATH;
813         wchar_t *q;
814         size_t n;
815         for (;;) {
816             q = wcschr(p, DELIM);
817             if (q == NULL)
818                 n = wcslen(p);
819             else
820                 n = q-p;
821             if (p[0] == '.' && is_sep(p[1])) {
822                 if (wcscpy_s(buf, bufsz - (buf - module_search_path), pythonhome))
823                     Py_FatalError("buffer overflow in getpathp.c's calculate_path()");
824                 buf = wcschr(buf, L'\0');
825                 p++;
826                 n--;
827             }
828             wcsncpy(buf, p, n);
829             buf += n;
830             *buf++ = DELIM;
831             if (q == NULL)
832                 break;
833             p = q+1;
834         }
835     }
836     if (argv0_path) {
837         wcscpy(buf, argv0_path);
838         buf = wcschr(buf, L'\0');
839         *buf++ = DELIM;
840     }
841     *(buf - 1) = L'\0';
842     /* Now to pull one last hack/trick.  If sys.prefix is
843        empty, then try and find it somewhere on the paths
844        we calculated.  We scan backwards, as our general policy
845        is that Python core directories are at the *end* of
846        sys.path.  We assume that our "lib" directory is
847        on the path, and that our 'prefix' directory is
848        the parent of that.
849     */
850     if (*prefix==L'\0') {
851         wchar_t lookBuf[MAXPATHLEN+1];
852         wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
853         while (1) {
854             Py_ssize_t nchars;
855             wchar_t *lookEnd = look;
856             /* 'look' will end up one character before the
857                start of the path in question - even if this
858                is one character before the start of the buffer
859             */
860             while (look >= module_search_path && *look != DELIM)
861                 look--;
862             nchars = lookEnd-look;
863             wcsncpy(lookBuf, look+1, nchars);
864             lookBuf[nchars] = L'\0';
865             /* Up one level to the parent */
866             reduce(lookBuf);
867             if (search_for_prefix(lookBuf, LANDMARK)) {
868                 break;
869             }
870             /* If we are out of paths to search - give up */
871             if (look < module_search_path)
872                 break;
873             look--;
874         }
875     }
876 }
877 
878 
879 /* External interface */
880 
881 void
Py_SetPath(const wchar_t * path)882 Py_SetPath(const wchar_t *path)
883 {
884     if (module_search_path != NULL) {
885         PyMem_RawFree(module_search_path);
886         module_search_path = NULL;
887     }
888     if (path != NULL) {
889         extern wchar_t *Py_GetProgramName(void);
890         wchar_t *prog = Py_GetProgramName();
891         wcsncpy(progpath, prog, MAXPATHLEN);
892         prefix[0] = L'\0';
893         module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t));
894         if (module_search_path != NULL)
895             wcscpy(module_search_path, path);
896     }
897 }
898 
899 wchar_t *
Py_GetPath(void)900 Py_GetPath(void)
901 {
902     if (!module_search_path)
903         calculate_path();
904     return module_search_path;
905 }
906 
907 wchar_t *
Py_GetPrefix(void)908 Py_GetPrefix(void)
909 {
910     if (!module_search_path)
911         calculate_path();
912     return prefix;
913 }
914 
915 wchar_t *
Py_GetExecPrefix(void)916 Py_GetExecPrefix(void)
917 {
918     return Py_GetPrefix();
919 }
920 
921 wchar_t *
Py_GetProgramFullPath(void)922 Py_GetProgramFullPath(void)
923 {
924     if (!module_search_path)
925         calculate_path();
926     return progpath;
927 }
928 
929 /* Load python3.dll before loading any extension module that might refer
930    to it. That way, we can be sure that always the python3.dll corresponding
931    to this python DLL is loaded, not a python3.dll that might be on the path
932    by chance.
933    Return whether the DLL was found.
934 */
935 static int python3_checked = 0;
936 static HANDLE hPython3;
937 int
_Py_CheckPython3()938 _Py_CheckPython3()
939 {
940     wchar_t py3path[MAXPATHLEN+1];
941     wchar_t *s;
942     if (python3_checked)
943         return hPython3 != NULL;
944     python3_checked = 1;
945 
946     /* If there is a python3.dll next to the python3y.dll,
947        assume this is a build tree; use that DLL */
948     wcscpy(py3path, dllpath);
949     s = wcsrchr(py3path, L'\\');
950     if (!s)
951         s = py3path;
952     wcscpy(s, L"\\python3.dll");
953     hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
954     if (hPython3 != NULL)
955         return 1;
956 
957     /* Check sys.prefix\DLLs\python3.dll */
958     wcscpy(py3path, Py_GetPrefix());
959     wcscat(py3path, L"\\DLLs\\python3.dll");
960     hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
961     return hPython3 != NULL;
962 }
963