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 "pycore_initconfig.h"    // PyStatus
84 #include "pycore_pathconfig.h"    // _PyPathConfig
85 #include "osdefs.h"               // SEP, ALTSEP
86 #include <wchar.h>
87 
88 #ifndef MS_WINDOWS
89 #error getpathp.c should only be built on Windows
90 #endif
91 
92 #include <windows.h>
93 #include <pathcch.h>
94 
95 #ifdef HAVE_SYS_TYPES_H
96 #include <sys/types.h>
97 #endif /* HAVE_SYS_TYPES_H */
98 
99 #ifdef HAVE_SYS_STAT_H
100 #include <sys/stat.h>
101 #endif /* HAVE_SYS_STAT_H */
102 
103 #include <string.h>
104 
105 /* Search in some common locations for the associated Python libraries.
106  *
107  * Py_GetPath() tries to return a sensible Python module search path.
108  *
109  * The approach is an adaptation for Windows of the strategy used in
110  * ../Modules/getpath.c; it uses the Windows Registry as one of its
111  * information sources.
112  *
113  * Py_SetPath() can be used to override this mechanism.  Call Py_SetPath
114  * with a semicolon separated path prior to calling Py_Initialize.
115  */
116 
117 #ifndef LANDMARK
118 #  define LANDMARK L"lib\\os.py"
119 #endif
120 
121 #define INIT_ERR_BUFFER_OVERFLOW() _PyStatus_ERR("buffer overflow")
122 
123 
124 typedef struct {
125     const wchar_t *path_env;           /* PATH environment variable */
126     const wchar_t *home;               /* PYTHONHOME environment variable */
127 
128     /* Registry key "Software\Python\PythonCore\X.Y\PythonPath"
129        where X.Y is the Python version (major.minor) */
130     wchar_t *machine_path;   /* from HKEY_LOCAL_MACHINE */
131     wchar_t *user_path;      /* from HKEY_CURRENT_USER */
132 
133     const wchar_t *pythonpath_env;
134 } PyCalculatePath;
135 
136 
137 /* determine if "ch" is a separator character */
138 static int
is_sep(wchar_t ch)139 is_sep(wchar_t ch)
140 {
141 #ifdef ALTSEP
142     return ch == SEP || ch == ALTSEP;
143 #else
144     return ch == SEP;
145 #endif
146 }
147 
148 
149 /* assumes 'dir' null terminated in bounds.  Never writes
150    beyond existing terminator. */
151 static void
reduce(wchar_t * dir)152 reduce(wchar_t *dir)
153 {
154     size_t i = wcsnlen_s(dir, MAXPATHLEN+1);
155     if (i >= MAXPATHLEN+1) {
156         Py_FatalError("buffer overflow in getpathp.c's reduce()");
157     }
158 
159     while (i > 0 && !is_sep(dir[i]))
160         --i;
161     dir[i] = '\0';
162 }
163 
164 
165 static int
change_ext(wchar_t * dest,const wchar_t * src,const wchar_t * ext)166 change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
167 {
168     if (src && src != dest) {
169         size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
170         size_t i = src_len;
171         if (i >= MAXPATHLEN+1) {
172             Py_FatalError("buffer overflow in getpathp.c's reduce()");
173         }
174 
175         while (i > 0 && src[i] != '.' && !is_sep(src[i]))
176             --i;
177 
178         if (i == 0) {
179             dest[0] = '\0';
180             return -1;
181         }
182 
183         if (is_sep(src[i])) {
184             i = src_len;
185         }
186 
187         if (wcsncpy_s(dest, MAXPATHLEN+1, src, i)) {
188             dest[0] = '\0';
189             return -1;
190         }
191     } else {
192         wchar_t *s = wcsrchr(dest, L'.');
193         if (s) {
194             s[0] = '\0';
195         }
196     }
197 
198     if (wcscat_s(dest, MAXPATHLEN+1, ext)) {
199         dest[0] = '\0';
200         return -1;
201     }
202 
203     return 0;
204 }
205 
206 
207 static int
exists(const wchar_t * filename)208 exists(const wchar_t *filename)
209 {
210     return GetFileAttributesW(filename) != 0xFFFFFFFF;
211 }
212 
213 
214 /* Is module -- check for .pyc too.
215    Assumes 'filename' MAXPATHLEN+1 bytes long -
216    may extend 'filename' by one character. */
217 static int
ismodule(wchar_t * filename,int update_filename)218 ismodule(wchar_t *filename, int update_filename)
219 {
220     size_t n;
221 
222     if (exists(filename)) {
223         return 1;
224     }
225 
226     /* Check for the compiled version of prefix. */
227     n = wcsnlen_s(filename, MAXPATHLEN+1);
228     if (n < MAXPATHLEN) {
229         int exist = 0;
230         filename[n] = L'c';
231         filename[n + 1] = L'\0';
232         exist = exists(filename);
233         if (!update_filename) {
234             filename[n] = L'\0';
235         }
236         return exist;
237     }
238     return 0;
239 }
240 
241 
242 /* Add a path component, by appending stuff to buffer.
243    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
244    NUL-terminated string with no more than MAXPATHLEN characters (not counting
245    the trailing NUL).  It's a fatal error if it contains a string longer than
246    that (callers must be careful!).  If these requirements are met, it's
247    guaranteed that buffer will still be a NUL-terminated string with no more
248    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
249    stuff as fits will be appended.
250 */
251 
252 static void
join(wchar_t * buffer,const wchar_t * stuff)253 join(wchar_t *buffer, const wchar_t *stuff)
254 {
255     if (FAILED(PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) {
256         Py_FatalError("buffer overflow in getpathp.c's join()");
257     }
258 }
259 
260 /* Call PathCchCanonicalizeEx(path): remove navigation elements such as "."
261    and ".." to produce a direct, well-formed path. */
262 static PyStatus
canonicalize(wchar_t * buffer,const wchar_t * path)263 canonicalize(wchar_t *buffer, const wchar_t *path)
264 {
265     if (buffer == NULL) {
266         return _PyStatus_NO_MEMORY();
267     }
268 
269     if (FAILED(PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) {
270         return INIT_ERR_BUFFER_OVERFLOW();
271     }
272     return _PyStatus_OK();
273 }
274 
275 
276 /* gotlandmark only called by search_for_prefix, which ensures
277    'prefix' is null terminated in bounds.  join() ensures
278    'landmark' can not overflow prefix if too long. */
279 static int
gotlandmark(const wchar_t * prefix,const wchar_t * landmark)280 gotlandmark(const wchar_t *prefix, const wchar_t *landmark)
281 {
282     wchar_t filename[MAXPATHLEN+1];
283     memset(filename, 0, sizeof(filename));
284     wcscpy_s(filename, Py_ARRAY_LENGTH(filename), prefix);
285     join(filename, landmark);
286     return ismodule(filename, FALSE);
287 }
288 
289 
290 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
291    assumption provided by only caller, calculate_path() */
292 static int
search_for_prefix(wchar_t * prefix,const wchar_t * argv0_path,const wchar_t * landmark)293 search_for_prefix(wchar_t *prefix, const wchar_t *argv0_path, const wchar_t *landmark)
294 {
295     /* Search from argv0_path, until landmark is found */
296     wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
297     do {
298         if (gotlandmark(prefix, landmark)) {
299             return 1;
300         }
301         reduce(prefix);
302     } while (prefix[0]);
303     return 0;
304 }
305 
306 
307 static int
get_dllpath(wchar_t * dllpath)308 get_dllpath(wchar_t *dllpath)
309 {
310 #ifdef Py_ENABLE_SHARED
311     extern HANDLE PyWin_DLLhModule;
312     if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) {
313         return 0;
314     }
315 #endif
316     return -1;
317 }
318 
319 
320 #ifdef Py_ENABLE_SHARED
321 
322 /* a string loaded from the DLL at startup.*/
323 extern const char *PyWin_DLLVersionString;
324 
325 /* Load a PYTHONPATH value from the registry.
326    Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
327 
328    Works in both Unicode and 8bit environments.  Only uses the
329    Ex family of functions so it also works with Windows CE.
330 
331    Returns NULL, or a pointer that should be freed.
332 
333    XXX - this code is pretty strange, as it used to also
334    work on Win16, where the buffer sizes were not available
335    in advance.  It could be simplied now Win16/Win32s is dead!
336 */
337 static wchar_t *
getpythonregpath(HKEY keyBase,int skipcore)338 getpythonregpath(HKEY keyBase, int skipcore)
339 {
340     HKEY newKey = 0;
341     DWORD dataSize = 0;
342     DWORD numKeys = 0;
343     LONG rc;
344     wchar_t *retval = NULL;
345     WCHAR *dataBuf = NULL;
346     static const WCHAR keyPrefix[] = L"Software\\Python\\PythonCore\\";
347     static const WCHAR keySuffix[] = L"\\PythonPath";
348     size_t versionLen, keyBufLen;
349     DWORD index;
350     WCHAR *keyBuf = NULL;
351     WCHAR *keyBufPtr;
352     WCHAR **ppPaths = NULL;
353 
354     /* Tried to use sysget("winver") but here is too early :-( */
355     versionLen = strlen(PyWin_DLLVersionString);
356     /* Space for all the chars, plus one \0 */
357     keyBufLen = sizeof(keyPrefix) +
358                 sizeof(WCHAR)*(versionLen-1) +
359                 sizeof(keySuffix);
360     keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen);
361     if (keyBuf==NULL) {
362         goto done;
363     }
364 
365     memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
366     keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1;
367     mbstowcs(keyBufPtr, PyWin_DLLVersionString, versionLen);
368     keyBufPtr += versionLen;
369     /* NULL comes with this one! */
370     memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
371     /* Open the root Python key */
372     rc=RegOpenKeyExW(keyBase,
373                     keyBuf, /* subkey */
374             0, /* reserved */
375             KEY_READ,
376             &newKey);
377     if (rc!=ERROR_SUCCESS) {
378         goto done;
379     }
380     /* Find out how big our core buffer is, and how many subkeys we have */
381     rc = RegQueryInfoKeyW(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
382                     NULL, NULL, &dataSize, NULL, NULL);
383     if (rc!=ERROR_SUCCESS) {
384         goto done;
385     }
386     if (skipcore) {
387         dataSize = 0; /* Only count core ones if we want them! */
388     }
389     /* Allocate a temp array of char buffers, so we only need to loop
390        reading the registry once
391     */
392     ppPaths = PyMem_RawCalloc(numKeys, sizeof(WCHAR *));
393     if (ppPaths==NULL) {
394         goto done;
395     }
396     /* Loop over all subkeys, allocating a temp sub-buffer. */
397     for(index=0;index<numKeys;index++) {
398         WCHAR keyBuf[MAX_PATH+1];
399         HKEY subKey = 0;
400         DWORD reqdSize = MAX_PATH+1;
401         /* Get the sub-key name */
402         DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
403                                  NULL, NULL, NULL, NULL );
404         if (rc!=ERROR_SUCCESS) {
405             goto done;
406         }
407         /* Open the sub-key */
408         rc=RegOpenKeyExW(newKey,
409                                         keyBuf, /* subkey */
410                         0, /* reserved */
411                         KEY_READ,
412                         &subKey);
413         if (rc!=ERROR_SUCCESS) {
414             goto done;
415         }
416         /* Find the value of the buffer size, malloc, then read it */
417         RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
418         if (reqdSize) {
419             ppPaths[index] = PyMem_RawMalloc(reqdSize);
420             if (ppPaths[index]) {
421                 RegQueryValueExW(subKey, NULL, 0, NULL,
422                                 (LPBYTE)ppPaths[index],
423                                 &reqdSize);
424                 dataSize += reqdSize + 1; /* 1 for the ";" */
425             }
426         }
427         RegCloseKey(subKey);
428     }
429 
430     /* return null if no path to return */
431     if (dataSize == 0) {
432         goto done;
433     }
434 
435     /* original datasize from RegQueryInfo doesn't include the \0 */
436     dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
437     if (dataBuf) {
438         WCHAR *szCur = dataBuf;
439         /* Copy our collected strings */
440         for (index=0;index<numKeys;index++) {
441             if (index > 0) {
442                 *(szCur++) = L';';
443                 dataSize--;
444             }
445             if (ppPaths[index]) {
446                 Py_ssize_t len = wcslen(ppPaths[index]);
447                 wcsncpy(szCur, ppPaths[index], len);
448                 szCur += len;
449                 assert(dataSize > (DWORD)len);
450                 dataSize -= (DWORD)len;
451             }
452         }
453         if (skipcore) {
454             *szCur = '\0';
455         }
456         else {
457             /* If we have no values, we don't need a ';' */
458             if (numKeys) {
459                 *(szCur++) = L';';
460                 dataSize--;
461             }
462             /* Now append the core path entries -
463                this will include the NULL
464             */
465             rc = RegQueryValueExW(newKey, NULL, 0, NULL,
466                                   (LPBYTE)szCur, &dataSize);
467             if (rc != ERROR_SUCCESS) {
468                 PyMem_RawFree(dataBuf);
469                 goto done;
470             }
471         }
472         /* And set the result - caller must free */
473         retval = dataBuf;
474     }
475 done:
476     /* Loop freeing my temp buffers */
477     if (ppPaths) {
478         for(index=0; index<numKeys; index++)
479             PyMem_RawFree(ppPaths[index]);
480         PyMem_RawFree(ppPaths);
481     }
482     if (newKey) {
483         RegCloseKey(newKey);
484     }
485     PyMem_RawFree(keyBuf);
486     return retval;
487 }
488 #endif /* Py_ENABLE_SHARED */
489 
490 
491 static PyStatus
get_program_full_path(_PyPathConfig * pathconfig)492 get_program_full_path(_PyPathConfig *pathconfig)
493 {
494     PyStatus status;
495     const wchar_t *pyvenv_launcher;
496     wchar_t program_full_path[MAXPATHLEN+1];
497     memset(program_full_path, 0, sizeof(program_full_path));
498 
499     if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
500         /* GetModuleFileName should never fail when passed NULL */
501         return _PyStatus_ERR("Cannot determine program path");
502     }
503 
504     /* The launcher may need to force the executable path to a
505      * different environment, so override it here. */
506     pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
507     if (pyvenv_launcher && pyvenv_launcher[0]) {
508         /* If overridden, preserve the original full path */
509         if (pathconfig->base_executable == NULL) {
510             pathconfig->base_executable = PyMem_RawMalloc(
511                 sizeof(wchar_t) * (MAXPATHLEN + 1));
512             if (pathconfig->base_executable == NULL) {
513                 return _PyStatus_NO_MEMORY();
514             }
515 
516             status = canonicalize(pathconfig->base_executable,
517                                   program_full_path);
518             if (_PyStatus_EXCEPTION(status)) {
519                 return status;
520             }
521         }
522 
523         wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
524         /* bpo-35873: Clear the environment variable to avoid it being
525         * inherited by child processes. */
526         _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
527     }
528 
529     if (pathconfig->program_full_path == NULL) {
530         pathconfig->program_full_path = PyMem_RawMalloc(
531             sizeof(wchar_t) * (MAXPATHLEN + 1));
532         if (pathconfig->program_full_path == NULL) {
533             return _PyStatus_NO_MEMORY();
534         }
535 
536         status = canonicalize(pathconfig->program_full_path,
537                               program_full_path);
538         if (_PyStatus_EXCEPTION(status)) {
539             return status;
540         }
541     }
542     return _PyStatus_OK();
543 }
544 
545 
546 static PyStatus
read_pth_file(_PyPathConfig * pathconfig,wchar_t * prefix,const wchar_t * path,int * found)547 read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path,
548               int *found)
549 {
550     PyStatus status;
551     wchar_t *buf = NULL;
552     wchar_t *wline = NULL;
553     FILE *sp_file;
554 
555     sp_file = _Py_wfopen(path, L"r");
556     if (sp_file == NULL) {
557         return _PyStatus_OK();
558     }
559 
560     wcscpy_s(prefix, MAXPATHLEN+1, path);
561     reduce(prefix);
562     pathconfig->isolated = 1;
563     pathconfig->site_import = 0;
564 
565     size_t bufsiz = MAXPATHLEN;
566     size_t prefixlen = wcslen(prefix);
567 
568     buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
569     if (buf == NULL) {
570         status = _PyStatus_NO_MEMORY();
571         goto done;
572     }
573     buf[0] = '\0';
574 
575     while (!feof(sp_file)) {
576         char line[MAXPATHLEN + 1];
577         char *p = fgets(line, Py_ARRAY_LENGTH(line), sp_file);
578         if (!p) {
579             break;
580         }
581         if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') {
582             continue;
583         }
584         while (*++p) {
585             if (*p == '\r' || *p == '\n') {
586                 *p = '\0';
587                 break;
588             }
589         }
590 
591         if (strcmp(line, "import site") == 0) {
592             pathconfig->site_import = 1;
593             continue;
594         }
595         else if (strncmp(line, "import ", 7) == 0) {
596             status = _PyStatus_ERR("only 'import site' is supported "
597                                    "in ._pth file");
598             goto done;
599         }
600 
601         DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
602         wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
603         if (wline == NULL) {
604             status = _PyStatus_NO_MEMORY();
605             goto done;
606         }
607         wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
608         wline[wn] = '\0';
609 
610         size_t usedsiz = wcslen(buf);
611         while (usedsiz + wn + prefixlen + 4 > bufsiz) {
612             bufsiz += MAXPATHLEN;
613             wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
614                                                             sizeof(wchar_t));
615             if (tmp == NULL) {
616                 status = _PyStatus_NO_MEMORY();
617                 goto done;
618             }
619             buf = tmp;
620         }
621 
622         if (usedsiz) {
623             wcscat_s(buf, bufsiz, L";");
624             usedsiz += 1;
625         }
626 
627         errno_t result;
628         _Py_BEGIN_SUPPRESS_IPH
629         result = wcscat_s(buf, bufsiz, prefix);
630         _Py_END_SUPPRESS_IPH
631 
632         if (result == EINVAL) {
633             status = _PyStatus_ERR("invalid argument during ._pth processing");
634             goto done;
635         } else if (result == ERANGE) {
636             status = _PyStatus_ERR("buffer overflow during ._pth processing");
637             goto done;
638         }
639 
640         wchar_t *b = &buf[usedsiz];
641         join(b, wline);
642 
643         PyMem_RawFree(wline);
644         wline = NULL;
645     }
646 
647     if (pathconfig->module_search_path == NULL) {
648         pathconfig->module_search_path = _PyMem_RawWcsdup(buf);
649         if (pathconfig->module_search_path == NULL) {
650             status = _PyStatus_NO_MEMORY();
651             goto done;
652         }
653     }
654 
655     *found = 1;
656     status = _PyStatus_OK();
657     goto done;
658 
659 done:
660     PyMem_RawFree(buf);
661     PyMem_RawFree(wline);
662     fclose(sp_file);
663     return status;
664 }
665 
666 
667 static int
get_pth_filename(PyCalculatePath * calculate,wchar_t * filename,const _PyPathConfig * pathconfig)668 get_pth_filename(PyCalculatePath *calculate, wchar_t *filename,
669                  const _PyPathConfig *pathconfig)
670 {
671     if (!get_dllpath(filename) &&
672         !change_ext(filename, filename, L"._pth") &&
673         exists(filename))
674     {
675         return 1;
676     }
677     if (pathconfig->program_full_path[0] &&
678         !change_ext(filename, pathconfig->program_full_path, L"._pth") &&
679         exists(filename))
680     {
681         return 1;
682     }
683     return 0;
684 }
685 
686 
687 static PyStatus
calculate_pth_file(PyCalculatePath * calculate,_PyPathConfig * pathconfig,wchar_t * prefix,int * found)688 calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
689                    wchar_t *prefix, int *found)
690 {
691     wchar_t filename[MAXPATHLEN+1];
692 
693     if (!get_pth_filename(calculate, filename, pathconfig)) {
694         return _PyStatus_OK();
695     }
696 
697     return read_pth_file(pathconfig, prefix, filename, found);
698 }
699 
700 
701 /* Search for an environment configuration file, first in the
702    executable's directory and then in the parent directory.
703    If found, open it for use when searching for prefixes.
704 */
705 static PyStatus
calculate_pyvenv_file(PyCalculatePath * calculate,wchar_t * argv0_path,size_t argv0_path_len)706 calculate_pyvenv_file(PyCalculatePath *calculate,
707                       wchar_t *argv0_path, size_t argv0_path_len)
708 {
709     wchar_t filename[MAXPATHLEN+1];
710     const wchar_t *env_cfg = L"pyvenv.cfg";
711 
712     /* Filename: <argv0_path_len> / "pyvenv.cfg" */
713     wcscpy_s(filename, MAXPATHLEN+1, argv0_path);
714     join(filename, env_cfg);
715 
716     FILE *env_file = _Py_wfopen(filename, L"r");
717     if (env_file == NULL) {
718         errno = 0;
719 
720         /* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
721         reduce(filename);
722         reduce(filename);
723         join(filename, env_cfg);
724 
725         env_file = _Py_wfopen(filename, L"r");
726         if (env_file == NULL) {
727             errno = 0;
728             return _PyStatus_OK();
729         }
730     }
731 
732     /* Look for a 'home' variable and set argv0_path to it, if found */
733     wchar_t *home = NULL;
734     PyStatus status = _Py_FindEnvConfigValue(env_file, L"home", &home);
735     if (_PyStatus_EXCEPTION(status)) {
736         fclose(env_file);
737         return status;
738     }
739     if (home) {
740         wcscpy_s(argv0_path, argv0_path_len, home);
741         PyMem_RawFree(home);
742     }
743     fclose(env_file);
744     return _PyStatus_OK();
745 }
746 
747 
748 static void
calculate_home_prefix(PyCalculatePath * calculate,const wchar_t * argv0_path,const wchar_t * zip_path,wchar_t * prefix)749 calculate_home_prefix(PyCalculatePath *calculate,
750                       const wchar_t *argv0_path,
751                       const wchar_t *zip_path,
752                       wchar_t *prefix)
753 {
754     if (calculate->home == NULL || *calculate->home == '\0') {
755         if (zip_path[0] && exists(zip_path)) {
756             wcscpy_s(prefix, MAXPATHLEN+1, zip_path);
757             reduce(prefix);
758             calculate->home = prefix;
759         }
760         else if (search_for_prefix(prefix, argv0_path, LANDMARK)) {
761             calculate->home = prefix;
762         }
763         else {
764             calculate->home = NULL;
765         }
766     }
767     else {
768         wcscpy_s(prefix, MAXPATHLEN+1, calculate->home);
769     }
770 }
771 
772 
773 static PyStatus
calculate_module_search_path(PyCalculatePath * calculate,_PyPathConfig * pathconfig,const wchar_t * argv0_path,wchar_t * prefix,const wchar_t * zip_path)774 calculate_module_search_path(PyCalculatePath *calculate,
775                              _PyPathConfig *pathconfig,
776                              const wchar_t *argv0_path,
777                              wchar_t *prefix,
778                              const wchar_t *zip_path)
779 {
780     int skiphome = calculate->home==NULL ? 0 : 1;
781 #ifdef Py_ENABLE_SHARED
782     if (!Py_IgnoreEnvironmentFlag) {
783         calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE,
784                                                    skiphome);
785         calculate->user_path = getpythonregpath(HKEY_CURRENT_USER, skiphome);
786     }
787 #endif
788     /* We only use the default relative PYTHONPATH if we haven't
789        anything better to use! */
790     int skipdefault = (calculate->pythonpath_env != NULL ||
791                        calculate->home != NULL ||
792                        calculate->machine_path != NULL ||
793                        calculate->user_path != NULL);
794 
795     /* We need to construct a path from the following parts.
796        (1) the PYTHONPATH environment variable, if set;
797        (2) for Win32, the zip archive file path;
798        (3) for Win32, the machine_path and user_path, if set;
799        (4) the PYTHONPATH config macro, with the leading "."
800            of each component replaced with home, if set;
801        (5) the directory containing the executable (argv0_path).
802        The length calculation calculates #4 first.
803        Extra rules:
804        - If PYTHONHOME is set (in any way) item (3) is ignored.
805        - If registry values are used, (4) and (5) are ignored.
806     */
807 
808     /* Calculate size of return buffer */
809     size_t bufsz = 0;
810     if (calculate->home != NULL) {
811         const wchar_t *p;
812         bufsz = 1;
813         for (p = PYTHONPATH; *p; p++) {
814             if (*p == DELIM) {
815                 bufsz++; /* number of DELIM plus one */
816             }
817         }
818         bufsz *= wcslen(calculate->home);
819     }
820     bufsz += wcslen(PYTHONPATH) + 1;
821     bufsz += wcslen(argv0_path) + 1;
822     if (calculate->user_path) {
823         bufsz += wcslen(calculate->user_path) + 1;
824     }
825     if (calculate->machine_path) {
826         bufsz += wcslen(calculate->machine_path) + 1;
827     }
828     bufsz += wcslen(zip_path) + 1;
829     if (calculate->pythonpath_env != NULL) {
830         bufsz += wcslen(calculate->pythonpath_env) + 1;
831     }
832 
833     wchar_t *buf, *start_buf;
834     buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
835     if (buf == NULL) {
836         return _PyStatus_NO_MEMORY();
837     }
838     start_buf = buf;
839 
840     if (calculate->pythonpath_env) {
841         if (wcscpy_s(buf, bufsz - (buf - start_buf),
842                      calculate->pythonpath_env)) {
843             return INIT_ERR_BUFFER_OVERFLOW();
844         }
845         buf = wcschr(buf, L'\0');
846         *buf++ = DELIM;
847     }
848     if (zip_path[0]) {
849         if (wcscpy_s(buf, bufsz - (buf - start_buf), zip_path)) {
850             return INIT_ERR_BUFFER_OVERFLOW();
851         }
852         buf = wcschr(buf, L'\0');
853         *buf++ = DELIM;
854     }
855     if (calculate->user_path) {
856         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) {
857             return INIT_ERR_BUFFER_OVERFLOW();
858         }
859         buf = wcschr(buf, L'\0');
860         *buf++ = DELIM;
861     }
862     if (calculate->machine_path) {
863         if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) {
864             return INIT_ERR_BUFFER_OVERFLOW();
865         }
866         buf = wcschr(buf, L'\0');
867         *buf++ = DELIM;
868     }
869     if (calculate->home == NULL) {
870         if (!skipdefault) {
871             if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) {
872                 return INIT_ERR_BUFFER_OVERFLOW();
873             }
874             buf = wcschr(buf, L'\0');
875             *buf++ = DELIM;
876         }
877     } else {
878         const wchar_t *p = PYTHONPATH;
879         const wchar_t *q;
880         size_t n;
881         for (;;) {
882             q = wcschr(p, DELIM);
883             if (q == NULL) {
884                 n = wcslen(p);
885             }
886             else {
887                 n = q-p;
888             }
889             if (p[0] == '.' && is_sep(p[1])) {
890                 if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) {
891                     return INIT_ERR_BUFFER_OVERFLOW();
892                 }
893                 buf = wcschr(buf, L'\0');
894                 p++;
895                 n--;
896             }
897             wcsncpy(buf, p, n);
898             buf += n;
899             *buf++ = DELIM;
900             if (q == NULL) {
901                 break;
902             }
903             p = q+1;
904         }
905     }
906     if (argv0_path) {
907         wcscpy(buf, argv0_path);
908         buf = wcschr(buf, L'\0');
909         *buf++ = DELIM;
910     }
911     *(buf - 1) = L'\0';
912 
913     /* Now to pull one last hack/trick.  If sys.prefix is
914        empty, then try and find it somewhere on the paths
915        we calculated.  We scan backwards, as our general policy
916        is that Python core directories are at the *end* of
917        sys.path.  We assume that our "lib" directory is
918        on the path, and that our 'prefix' directory is
919        the parent of that.
920     */
921     if (prefix[0] == L'\0') {
922         wchar_t lookBuf[MAXPATHLEN+1];
923         const wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
924         while (1) {
925             Py_ssize_t nchars;
926             const wchar_t *lookEnd = look;
927             /* 'look' will end up one character before the
928                start of the path in question - even if this
929                is one character before the start of the buffer
930             */
931             while (look >= start_buf && *look != DELIM)
932                 look--;
933             nchars = lookEnd-look;
934             wcsncpy(lookBuf, look+1, nchars);
935             lookBuf[nchars] = L'\0';
936             /* Up one level to the parent */
937             reduce(lookBuf);
938             if (search_for_prefix(prefix, lookBuf, LANDMARK)) {
939                 break;
940             }
941             /* If we are out of paths to search - give up */
942             if (look < start_buf) {
943                 break;
944             }
945             look--;
946         }
947     }
948 
949     pathconfig->module_search_path = start_buf;
950     return _PyStatus_OK();
951 }
952 
953 
954 static PyStatus
calculate_path(PyCalculatePath * calculate,_PyPathConfig * pathconfig)955 calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
956 {
957     PyStatus status;
958 
959     status = get_program_full_path(pathconfig);
960     if (_PyStatus_EXCEPTION(status)) {
961         return status;
962     }
963 
964     /* program_full_path guaranteed \0 terminated in MAXPATH+1 bytes. */
965     wchar_t argv0_path[MAXPATHLEN+1];
966     memset(argv0_path, 0, sizeof(argv0_path));
967 
968     wcscpy_s(argv0_path, MAXPATHLEN+1, pathconfig->program_full_path);
969     reduce(argv0_path);
970 
971     wchar_t prefix[MAXPATHLEN+1];
972     memset(prefix, 0, sizeof(prefix));
973 
974     /* Search for a sys.path file */
975     int pth_found = 0;
976     status = calculate_pth_file(calculate, pathconfig, prefix, &pth_found);
977     if (_PyStatus_EXCEPTION(status)) {
978         return status;
979     }
980     if (pth_found) {
981         goto done;
982     }
983 
984     status = calculate_pyvenv_file(calculate,
985                                    argv0_path, Py_ARRAY_LENGTH(argv0_path));
986     if (_PyStatus_EXCEPTION(status)) {
987         return status;
988     }
989 
990     /* Calculate zip archive path from DLL or exe path */
991     wchar_t zip_path[MAXPATHLEN+1];
992     memset(zip_path, 0, sizeof(zip_path));
993 
994     if (get_dllpath(zip_path) || change_ext(zip_path, zip_path, L".zip"))
995     {
996         if (change_ext(zip_path, pathconfig->program_full_path, L".zip")) {
997             zip_path[0] = L'\0';
998         }
999     }
1000 
1001     calculate_home_prefix(calculate, argv0_path, zip_path, prefix);
1002 
1003     if (pathconfig->module_search_path == NULL) {
1004         status = calculate_module_search_path(calculate, pathconfig,
1005                                               argv0_path, prefix, zip_path);
1006         if (_PyStatus_EXCEPTION(status)) {
1007             return status;
1008         }
1009     }
1010 
1011 done:
1012     if (pathconfig->prefix == NULL) {
1013         pathconfig->prefix = _PyMem_RawWcsdup(prefix);
1014         if (pathconfig->prefix == NULL) {
1015             return _PyStatus_NO_MEMORY();
1016         }
1017     }
1018     if (pathconfig->exec_prefix == NULL) {
1019         pathconfig->exec_prefix = _PyMem_RawWcsdup(prefix);
1020         if (pathconfig->exec_prefix == NULL) {
1021             return _PyStatus_NO_MEMORY();
1022         }
1023     }
1024 
1025     return _PyStatus_OK();
1026 }
1027 
1028 
1029 static PyStatus
calculate_init(PyCalculatePath * calculate,_PyPathConfig * pathconfig,const PyConfig * config)1030 calculate_init(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
1031                const PyConfig *config)
1032 {
1033     calculate->home = pathconfig->home;
1034     calculate->path_env = _wgetenv(L"PATH");
1035 
1036     calculate->pythonpath_env = config->pythonpath_env;
1037 
1038     return _PyStatus_OK();
1039 }
1040 
1041 
1042 static void
calculate_free(PyCalculatePath * calculate)1043 calculate_free(PyCalculatePath *calculate)
1044 {
1045     PyMem_RawFree(calculate->machine_path);
1046     PyMem_RawFree(calculate->user_path);
1047 }
1048 
1049 
1050 /* Calculate the Python path configuration.
1051 
1052    Inputs:
1053 
1054    - PyConfig.pythonpath_env: PYTHONPATH environment variable
1055    - _PyPathConfig.home: Py_SetPythonHome() or PYTHONHOME environment variable
1056    - PATH environment variable
1057    - __PYVENV_LAUNCHER__ environment variable
1058    - GetModuleFileNameW(NULL): fully qualified path of the executable file of
1059      the current process
1060    - ._pth configuration file
1061    - pyvenv.cfg configuration file
1062    - Registry key "Software\Python\PythonCore\X.Y\PythonPath"
1063      of HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE where X.Y is the Python
1064      version.
1065 
1066    Outputs, 'pathconfig' fields:
1067 
1068    - base_executable
1069    - program_full_path
1070    - module_search_path
1071    - prefix
1072    - exec_prefix
1073    - isolated
1074    - site_import
1075 
1076    If a field is already set (non NULL), it is left unchanged. */
1077 PyStatus
_PyPathConfig_Calculate(_PyPathConfig * pathconfig,const PyConfig * config)1078 _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
1079 {
1080     PyStatus status;
1081     PyCalculatePath calculate;
1082     memset(&calculate, 0, sizeof(calculate));
1083 
1084     status = calculate_init(&calculate, pathconfig, config);
1085     if (_PyStatus_EXCEPTION(status)) {
1086         goto done;
1087     }
1088 
1089     status = calculate_path(&calculate, pathconfig);
1090 
1091 done:
1092     calculate_free(&calculate);
1093     return status;
1094 }
1095 
1096 
1097 /* Load python3.dll before loading any extension module that might refer
1098    to it. That way, we can be sure that always the python3.dll corresponding
1099    to this python DLL is loaded, not a python3.dll that might be on the path
1100    by chance.
1101    Return whether the DLL was found.
1102 */
1103 static int python3_checked = 0;
1104 static HANDLE hPython3;
1105 int
_Py_CheckPython3(void)1106 _Py_CheckPython3(void)
1107 {
1108     wchar_t py3path[MAXPATHLEN+1];
1109     if (python3_checked) {
1110         return hPython3 != NULL;
1111     }
1112     python3_checked = 1;
1113 
1114     /* If there is a python3.dll next to the python3y.dll,
1115        use that DLL */
1116     if (!get_dllpath(py3path)) {
1117         reduce(py3path);
1118         join(py3path, PY3_DLLNAME);
1119         hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
1120         if (hPython3 != NULL) {
1121             return 1;
1122         }
1123     }
1124 
1125     /* If we can locate python3.dll in our application dir,
1126        use that DLL */
1127     hPython3 = LoadLibraryExW(PY3_DLLNAME, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
1128     if (hPython3 != NULL) {
1129         return 1;
1130     }
1131 
1132     /* For back-compat, also search {sys.prefix}\DLLs, though
1133        that has not been a normal install layout for a while */
1134     wcscpy(py3path, Py_GetPrefix());
1135     if (py3path[0]) {
1136         join(py3path, L"DLLs\\" PY3_DLLNAME);
1137         hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
1138     }
1139     return hPython3 != NULL;
1140 }
1141