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