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