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