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