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