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