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 wchar_t *dll_path;
134
135 const wchar_t *pythonpath_env;
136 } PyCalculatePath;
137
138
139 /* determine if "ch" is a separator character */
140 static int
is_sep(wchar_t ch)141 is_sep(wchar_t ch)
142 {
143 #ifdef ALTSEP
144 return ch == SEP || ch == ALTSEP;
145 #else
146 return ch == SEP;
147 #endif
148 }
149
150
151 /* assumes 'dir' null terminated in bounds. Never writes
152 beyond existing terminator. */
153 static void
reduce(wchar_t * dir)154 reduce(wchar_t *dir)
155 {
156 size_t i = wcsnlen_s(dir, MAXPATHLEN+1);
157 if (i >= MAXPATHLEN+1) {
158 Py_FatalError("buffer overflow in getpathp.c's reduce()");
159 }
160
161 while (i > 0 && !is_sep(dir[i]))
162 --i;
163 dir[i] = '\0';
164 }
165
166
167 static int
change_ext(wchar_t * dest,const wchar_t * src,const wchar_t * ext)168 change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
169 {
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 wcscat_s(dest, MAXPATHLEN+1, ext))
190 {
191 dest[0] = '\0';
192 return -1;
193 }
194
195 return 0;
196 }
197
198
199 static int
exists(const wchar_t * filename)200 exists(const wchar_t *filename)
201 {
202 return GetFileAttributesW(filename) != 0xFFFFFFFF;
203 }
204
205
206 /* Is module -- check for .pyc too.
207 Assumes 'filename' MAXPATHLEN+1 bytes long -
208 may extend 'filename' by one character. */
209 static int
ismodule(wchar_t * filename,int update_filename)210 ismodule(wchar_t *filename, int update_filename)
211 {
212 size_t n;
213
214 if (exists(filename)) {
215 return 1;
216 }
217
218 /* Check for the compiled version of prefix. */
219 n = wcsnlen_s(filename, MAXPATHLEN+1);
220 if (n < MAXPATHLEN) {
221 int exist = 0;
222 filename[n] = L'c';
223 filename[n + 1] = L'\0';
224 exist = exists(filename);
225 if (!update_filename) {
226 filename[n] = L'\0';
227 }
228 return exist;
229 }
230 return 0;
231 }
232
233
234 /* Add a path component, by appending stuff to buffer.
235 buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
236 NUL-terminated string with no more than MAXPATHLEN characters (not counting
237 the trailing NUL). It's a fatal error if it contains a string longer than
238 that (callers must be careful!). If these requirements are met, it's
239 guaranteed that buffer will still be a NUL-terminated string with no more
240 than MAXPATHLEN characters at exit. If stuff is too long, only as much of
241 stuff as fits will be appended.
242 */
243
244 static int _PathCchCombineEx_Initialized = 0;
245 typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut,
246 PCWSTR pszPathIn, PCWSTR pszMore,
247 unsigned long dwFlags);
248 static PPathCchCombineEx _PathCchCombineEx;
249
250 static void
join(wchar_t * buffer,const wchar_t * stuff)251 join(wchar_t *buffer, const wchar_t *stuff)
252 {
253 if (_PathCchCombineEx_Initialized == 0) {
254 HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
255 if (pathapi) {
256 _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress(pathapi, "PathCchCombineEx");
257 }
258 else {
259 _PathCchCombineEx = NULL;
260 }
261 _PathCchCombineEx_Initialized = 1;
262 }
263
264 if (_PathCchCombineEx) {
265 if (FAILED(_PathCchCombineEx(buffer, MAXPATHLEN+1, buffer, stuff, 0))) {
266 Py_FatalError("buffer overflow in getpathp.c's join()");
267 }
268 } else {
269 if (!PathCombineW(buffer, buffer, stuff)) {
270 Py_FatalError("buffer overflow in getpathp.c's join()");
271 }
272 }
273 }
274
275 static int _PathCchCanonicalizeEx_Initialized = 0;
276 typedef HRESULT(__stdcall *PPathCchCanonicalizeEx) (PWSTR pszPathOut, size_t cchPathOut,
277 PCWSTR pszPathIn, unsigned long dwFlags);
278 static PPathCchCanonicalizeEx _PathCchCanonicalizeEx;
279
280 /* Call PathCchCanonicalizeEx(path): remove navigation elements such as "."
281 and ".." to produce a direct, well-formed path. */
282 static PyStatus
canonicalize(wchar_t * buffer,const wchar_t * path)283 canonicalize(wchar_t *buffer, const wchar_t *path)
284 {
285 if (buffer == NULL) {
286 return _PyStatus_NO_MEMORY();
287 }
288
289 if (_PathCchCanonicalizeEx_Initialized == 0) {
290 HMODULE pathapi = LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll");
291 if (pathapi) {
292 _PathCchCanonicalizeEx = (PPathCchCanonicalizeEx)GetProcAddress(pathapi, "PathCchCanonicalizeEx");
293 }
294 else {
295 _PathCchCanonicalizeEx = NULL;
296 }
297 _PathCchCanonicalizeEx_Initialized = 1;
298 }
299
300 if (_PathCchCanonicalizeEx) {
301 if (FAILED(_PathCchCanonicalizeEx(buffer, MAXPATHLEN + 1, path, 0))) {
302 return INIT_ERR_BUFFER_OVERFLOW();
303 }
304 }
305 else {
306 if (!PathCanonicalizeW(buffer, path)) {
307 return INIT_ERR_BUFFER_OVERFLOW();
308 }
309 }
310 return _PyStatus_OK();
311 }
312
313
314 /* gotlandmark only called by search_for_prefix, which ensures
315 'prefix' is null terminated in bounds. join() ensures
316 'landmark' can not overflow prefix if too long. */
317 static int
gotlandmark(const wchar_t * prefix,const wchar_t * landmark)318 gotlandmark(const wchar_t *prefix, const wchar_t *landmark)
319 {
320 wchar_t filename[MAXPATHLEN+1];
321 memset(filename, 0, sizeof(filename));
322 wcscpy_s(filename, Py_ARRAY_LENGTH(filename), prefix);
323 join(filename, landmark);
324 return ismodule(filename, FALSE);
325 }
326
327
328 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
329 assumption provided by only caller, calculate_path() */
330 static int
search_for_prefix(wchar_t * prefix,const wchar_t * argv0_path,const wchar_t * landmark)331 search_for_prefix(wchar_t *prefix, const wchar_t *argv0_path, const wchar_t *landmark)
332 {
333 /* Search from argv0_path, until landmark is found */
334 wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
335 do {
336 if (gotlandmark(prefix, landmark)) {
337 return 1;
338 }
339 reduce(prefix);
340 } while (prefix[0]);
341 return 0;
342 }
343
344
345 #ifdef Py_ENABLE_SHARED
346
347 /* a string loaded from the DLL at startup.*/
348 extern const char *PyWin_DLLVersionString;
349
350 /* Load a PYTHONPATH value from the registry.
351 Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.
352
353 Works in both Unicode and 8bit environments. Only uses the
354 Ex family of functions so it also works with Windows CE.
355
356 Returns NULL, or a pointer that should be freed.
357
358 XXX - this code is pretty strange, as it used to also
359 work on Win16, where the buffer sizes werent available
360 in advance. It could be simplied now Win16/Win32s is dead!
361 */
362 static wchar_t *
getpythonregpath(HKEY keyBase,int skipcore)363 getpythonregpath(HKEY keyBase, int skipcore)
364 {
365 HKEY newKey = 0;
366 DWORD dataSize = 0;
367 DWORD numKeys = 0;
368 LONG rc;
369 wchar_t *retval = NULL;
370 WCHAR *dataBuf = NULL;
371 static const WCHAR keyPrefix[] = L"Software\\Python\\PythonCore\\";
372 static const WCHAR keySuffix[] = L"\\PythonPath";
373 size_t versionLen, keyBufLen;
374 DWORD index;
375 WCHAR *keyBuf = NULL;
376 WCHAR *keyBufPtr;
377 WCHAR **ppPaths = NULL;
378
379 /* Tried to use sysget("winver") but here is too early :-( */
380 versionLen = strlen(PyWin_DLLVersionString);
381 /* Space for all the chars, plus one \0 */
382 keyBufLen = sizeof(keyPrefix) +
383 sizeof(WCHAR)*(versionLen-1) +
384 sizeof(keySuffix);
385 keyBuf = keyBufPtr = PyMem_RawMalloc(keyBufLen);
386 if (keyBuf==NULL) {
387 goto done;
388 }
389
390 memcpy_s(keyBufPtr, keyBufLen, keyPrefix, sizeof(keyPrefix)-sizeof(WCHAR));
391 keyBufPtr += Py_ARRAY_LENGTH(keyPrefix) - 1;
392 mbstowcs(keyBufPtr, PyWin_DLLVersionString, versionLen);
393 keyBufPtr += versionLen;
394 /* NULL comes with this one! */
395 memcpy(keyBufPtr, keySuffix, sizeof(keySuffix));
396 /* Open the root Python key */
397 rc=RegOpenKeyExW(keyBase,
398 keyBuf, /* subkey */
399 0, /* reserved */
400 KEY_READ,
401 &newKey);
402 if (rc!=ERROR_SUCCESS) {
403 goto done;
404 }
405 /* Find out how big our core buffer is, and how many subkeys we have */
406 rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL,
407 NULL, NULL, &dataSize, NULL, NULL);
408 if (rc!=ERROR_SUCCESS) {
409 goto done;
410 }
411 if (skipcore) {
412 dataSize = 0; /* Only count core ones if we want them! */
413 }
414 /* Allocate a temp array of char buffers, so we only need to loop
415 reading the registry once
416 */
417 ppPaths = PyMem_RawMalloc( sizeof(WCHAR *) * numKeys );
418 if (ppPaths==NULL) {
419 goto done;
420 }
421 memset(ppPaths, 0, sizeof(WCHAR *) * numKeys);
422 /* Loop over all subkeys, allocating a temp sub-buffer. */
423 for(index=0;index<numKeys;index++) {
424 WCHAR keyBuf[MAX_PATH+1];
425 HKEY subKey = 0;
426 DWORD reqdSize = MAX_PATH+1;
427 /* Get the sub-key name */
428 DWORD rc = RegEnumKeyExW(newKey, index, keyBuf, &reqdSize,
429 NULL, NULL, NULL, NULL );
430 if (rc!=ERROR_SUCCESS) {
431 goto done;
432 }
433 /* Open the sub-key */
434 rc=RegOpenKeyExW(newKey,
435 keyBuf, /* subkey */
436 0, /* reserved */
437 KEY_READ,
438 &subKey);
439 if (rc!=ERROR_SUCCESS) {
440 goto done;
441 }
442 /* Find the value of the buffer size, malloc, then read it */
443 RegQueryValueExW(subKey, NULL, 0, NULL, NULL, &reqdSize);
444 if (reqdSize) {
445 ppPaths[index] = PyMem_RawMalloc(reqdSize);
446 if (ppPaths[index]) {
447 RegQueryValueExW(subKey, NULL, 0, NULL,
448 (LPBYTE)ppPaths[index],
449 &reqdSize);
450 dataSize += reqdSize + 1; /* 1 for the ";" */
451 }
452 }
453 RegCloseKey(subKey);
454 }
455
456 /* return null if no path to return */
457 if (dataSize == 0) {
458 goto done;
459 }
460
461 /* original datasize from RegQueryInfo doesn't include the \0 */
462 dataBuf = PyMem_RawMalloc((dataSize+1) * sizeof(WCHAR));
463 if (dataBuf) {
464 WCHAR *szCur = dataBuf;
465 /* Copy our collected strings */
466 for (index=0;index<numKeys;index++) {
467 if (index > 0) {
468 *(szCur++) = L';';
469 dataSize--;
470 }
471 if (ppPaths[index]) {
472 Py_ssize_t len = wcslen(ppPaths[index]);
473 wcsncpy(szCur, ppPaths[index], len);
474 szCur += len;
475 assert(dataSize > (DWORD)len);
476 dataSize -= (DWORD)len;
477 }
478 }
479 if (skipcore) {
480 *szCur = '\0';
481 }
482 else {
483 /* If we have no values, we don't need a ';' */
484 if (numKeys) {
485 *(szCur++) = L';';
486 dataSize--;
487 }
488 /* Now append the core path entries -
489 this will include the NULL
490 */
491 rc = RegQueryValueExW(newKey, NULL, 0, NULL,
492 (LPBYTE)szCur, &dataSize);
493 if (rc != ERROR_SUCCESS) {
494 PyMem_RawFree(dataBuf);
495 goto done;
496 }
497 }
498 /* And set the result - caller must free */
499 retval = dataBuf;
500 }
501 done:
502 /* Loop freeing my temp buffers */
503 if (ppPaths) {
504 for(index=0; index<numKeys; index++)
505 PyMem_RawFree(ppPaths[index]);
506 PyMem_RawFree(ppPaths);
507 }
508 if (newKey) {
509 RegCloseKey(newKey);
510 }
511 PyMem_RawFree(keyBuf);
512 return retval;
513 }
514 #endif /* Py_ENABLE_SHARED */
515
516
517 wchar_t*
_Py_GetDLLPath(void)518 _Py_GetDLLPath(void)
519 {
520 wchar_t dll_path[MAXPATHLEN+1];
521 memset(dll_path, 0, sizeof(dll_path));
522
523 #ifdef Py_ENABLE_SHARED
524 extern HANDLE PyWin_DLLhModule;
525 if (PyWin_DLLhModule) {
526 if (!GetModuleFileNameW(PyWin_DLLhModule, dll_path, MAXPATHLEN)) {
527 dll_path[0] = 0;
528 }
529 }
530 #else
531 dll_path[0] = 0;
532 #endif
533
534 return _PyMem_RawWcsdup(dll_path);
535 }
536
537
538 static PyStatus
get_program_full_path(_PyPathConfig * pathconfig)539 get_program_full_path(_PyPathConfig *pathconfig)
540 {
541 PyStatus status;
542 const wchar_t *pyvenv_launcher;
543 wchar_t program_full_path[MAXPATHLEN+1];
544 memset(program_full_path, 0, sizeof(program_full_path));
545
546 if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
547 /* GetModuleFileName should never fail when passed NULL */
548 return _PyStatus_ERR("Cannot determine program path");
549 }
550
551 /* The launcher may need to force the executable path to a
552 * different environment, so override it here. */
553 pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
554 if (pyvenv_launcher && pyvenv_launcher[0]) {
555 /* If overridden, preserve the original full path */
556 if (pathconfig->base_executable == NULL) {
557 pathconfig->base_executable = PyMem_RawMalloc(
558 sizeof(wchar_t) * (MAXPATHLEN + 1));
559 if (pathconfig->base_executable == NULL) {
560 return _PyStatus_NO_MEMORY();
561 }
562
563 status = canonicalize(pathconfig->base_executable,
564 program_full_path);
565 if (_PyStatus_EXCEPTION(status)) {
566 return status;
567 }
568 }
569
570 wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
571 /* bpo-35873: Clear the environment variable to avoid it being
572 * inherited by child processes. */
573 _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
574 }
575
576 if (pathconfig->program_full_path == NULL) {
577 pathconfig->program_full_path = PyMem_RawMalloc(
578 sizeof(wchar_t) * (MAXPATHLEN + 1));
579 if (pathconfig->program_full_path == NULL) {
580 return _PyStatus_NO_MEMORY();
581 }
582
583 status = canonicalize(pathconfig->program_full_path,
584 program_full_path);
585 if (_PyStatus_EXCEPTION(status)) {
586 return status;
587 }
588 }
589 return _PyStatus_OK();
590 }
591
592
593 static PyStatus
read_pth_file(_PyPathConfig * pathconfig,wchar_t * prefix,const wchar_t * path,int * found)594 read_pth_file(_PyPathConfig *pathconfig, wchar_t *prefix, const wchar_t *path,
595 int *found)
596 {
597 PyStatus status;
598 wchar_t *buf = NULL;
599 wchar_t *wline = NULL;
600 FILE *sp_file;
601
602 sp_file = _Py_wfopen(path, L"r");
603 if (sp_file == NULL) {
604 return _PyStatus_OK();
605 }
606
607 wcscpy_s(prefix, MAXPATHLEN+1, path);
608 reduce(prefix);
609 pathconfig->isolated = 1;
610 pathconfig->site_import = 0;
611
612 size_t bufsiz = MAXPATHLEN;
613 size_t prefixlen = wcslen(prefix);
614
615 buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
616 if (buf == NULL) {
617 status = _PyStatus_NO_MEMORY();
618 goto done;
619 }
620 buf[0] = '\0';
621
622 while (!feof(sp_file)) {
623 char line[MAXPATHLEN + 1];
624 char *p = fgets(line, Py_ARRAY_LENGTH(line), sp_file);
625 if (!p) {
626 break;
627 }
628 if (*p == '\0' || *p == '\r' || *p == '\n' || *p == '#') {
629 continue;
630 }
631 while (*++p) {
632 if (*p == '\r' || *p == '\n') {
633 *p = '\0';
634 break;
635 }
636 }
637
638 if (strcmp(line, "import site") == 0) {
639 pathconfig->site_import = 1;
640 continue;
641 }
642 else if (strncmp(line, "import ", 7) == 0) {
643 status = _PyStatus_ERR("only 'import site' is supported "
644 "in ._pth file");
645 goto done;
646 }
647
648 DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
649 wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
650 if (wline == NULL) {
651 status = _PyStatus_NO_MEMORY();
652 goto done;
653 }
654 wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
655 wline[wn] = '\0';
656
657 size_t usedsiz = wcslen(buf);
658 while (usedsiz + wn + prefixlen + 4 > bufsiz) {
659 bufsiz += MAXPATHLEN;
660 wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
661 sizeof(wchar_t));
662 if (tmp == NULL) {
663 status = _PyStatus_NO_MEMORY();
664 goto done;
665 }
666 buf = tmp;
667 }
668
669 if (usedsiz) {
670 wcscat_s(buf, bufsiz, L";");
671 usedsiz += 1;
672 }
673
674 errno_t result;
675 _Py_BEGIN_SUPPRESS_IPH
676 result = wcscat_s(buf, bufsiz, prefix);
677 _Py_END_SUPPRESS_IPH
678
679 if (result == EINVAL) {
680 status = _PyStatus_ERR("invalid argument during ._pth processing");
681 goto done;
682 } else if (result == ERANGE) {
683 status = _PyStatus_ERR("buffer overflow during ._pth processing");
684 goto done;
685 }
686
687 wchar_t *b = &buf[usedsiz];
688 join(b, wline);
689
690 PyMem_RawFree(wline);
691 wline = NULL;
692 }
693
694 if (pathconfig->module_search_path == NULL) {
695 pathconfig->module_search_path = _PyMem_RawWcsdup(buf);
696 if (pathconfig->module_search_path == NULL) {
697 status = _PyStatus_NO_MEMORY();
698 goto done;
699 }
700 }
701
702 *found = 1;
703 status = _PyStatus_OK();
704 goto done;
705
706 done:
707 PyMem_RawFree(buf);
708 PyMem_RawFree(wline);
709 fclose(sp_file);
710 return status;
711 }
712
713
714 static int
get_pth_filename(PyCalculatePath * calculate,wchar_t * filename,const _PyPathConfig * pathconfig)715 get_pth_filename(PyCalculatePath *calculate, wchar_t *filename,
716 const _PyPathConfig *pathconfig)
717 {
718 if (calculate->dll_path[0]) {
719 if (!change_ext(filename, calculate->dll_path, L"._pth") &&
720 exists(filename))
721 {
722 return 1;
723 }
724 }
725 if (pathconfig->program_full_path[0]) {
726 if (!change_ext(filename, pathconfig->program_full_path, L"._pth") &&
727 exists(filename))
728 {
729 return 1;
730 }
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 change_ext(zip_path,
1031 calculate->dll_path[0] ? calculate->dll_path : pathconfig->program_full_path,
1032 L".zip");
1033
1034 calculate_home_prefix(calculate, argv0_path, zip_path, prefix);
1035
1036 if (pathconfig->module_search_path == NULL) {
1037 status = calculate_module_search_path(calculate, pathconfig,
1038 argv0_path, prefix, zip_path);
1039 if (_PyStatus_EXCEPTION(status)) {
1040 return status;
1041 }
1042 }
1043
1044 done:
1045 if (pathconfig->prefix == NULL) {
1046 pathconfig->prefix = _PyMem_RawWcsdup(prefix);
1047 if (pathconfig->prefix == NULL) {
1048 return _PyStatus_NO_MEMORY();
1049 }
1050 }
1051 if (pathconfig->exec_prefix == NULL) {
1052 pathconfig->exec_prefix = _PyMem_RawWcsdup(prefix);
1053 if (pathconfig->exec_prefix == NULL) {
1054 return _PyStatus_NO_MEMORY();
1055 }
1056 }
1057
1058 return _PyStatus_OK();
1059 }
1060
1061
1062 static PyStatus
calculate_init(PyCalculatePath * calculate,_PyPathConfig * pathconfig,const PyConfig * config)1063 calculate_init(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
1064 const PyConfig *config)
1065 {
1066 calculate->home = pathconfig->home;
1067 calculate->path_env = _wgetenv(L"PATH");
1068
1069 calculate->dll_path = _Py_GetDLLPath();
1070 if (calculate->dll_path == NULL) {
1071 return _PyStatus_NO_MEMORY();
1072 }
1073
1074 calculate->pythonpath_env = config->pythonpath_env;
1075
1076 return _PyStatus_OK();
1077 }
1078
1079
1080 static void
calculate_free(PyCalculatePath * calculate)1081 calculate_free(PyCalculatePath *calculate)
1082 {
1083 PyMem_RawFree(calculate->machine_path);
1084 PyMem_RawFree(calculate->user_path);
1085 PyMem_RawFree(calculate->dll_path);
1086 }
1087
1088
1089 /* Calculate the Python path configuration.
1090
1091 Inputs:
1092
1093 - PyConfig.pythonpath_env: PYTHONPATH environment variable
1094 - _PyPathConfig.home: Py_SetPythonHome() or PYTHONHOME environment variable
1095 - DLL path: _Py_GetDLLPath()
1096 - PATH environment variable
1097 - __PYVENV_LAUNCHER__ environment variable
1098 - GetModuleFileNameW(NULL): fully qualified path of the executable file of
1099 the current process
1100 - ._pth configuration file
1101 - pyvenv.cfg configuration file
1102 - Registry key "Software\Python\PythonCore\X.Y\PythonPath"
1103 of HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE where X.Y is the Python
1104 version.
1105
1106 Outputs, 'pathconfig' fields:
1107
1108 - base_executable
1109 - program_full_path
1110 - module_search_path
1111 - prefix
1112 - exec_prefix
1113 - isolated
1114 - site_import
1115
1116 If a field is already set (non NULL), it is left unchanged. */
1117 PyStatus
_PyPathConfig_Calculate(_PyPathConfig * pathconfig,const PyConfig * config)1118 _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
1119 {
1120 PyStatus status;
1121 PyCalculatePath calculate;
1122 memset(&calculate, 0, sizeof(calculate));
1123
1124 status = calculate_init(&calculate, pathconfig, config);
1125 if (_PyStatus_EXCEPTION(status)) {
1126 goto done;
1127 }
1128
1129 status = calculate_path(&calculate, pathconfig);
1130
1131 done:
1132 calculate_free(&calculate);
1133 return status;
1134 }
1135
1136
1137 /* Load python3.dll before loading any extension module that might refer
1138 to it. That way, we can be sure that always the python3.dll corresponding
1139 to this python DLL is loaded, not a python3.dll that might be on the path
1140 by chance.
1141 Return whether the DLL was found.
1142 */
1143 static int python3_checked = 0;
1144 static HANDLE hPython3;
1145 int
_Py_CheckPython3(void)1146 _Py_CheckPython3(void)
1147 {
1148 wchar_t py3path[MAXPATHLEN+1];
1149 wchar_t *s;
1150 if (python3_checked) {
1151 return hPython3 != NULL;
1152 }
1153 python3_checked = 1;
1154
1155 /* If there is a python3.dll next to the python3y.dll,
1156 assume this is a build tree; use that DLL */
1157 if (_Py_dll_path != NULL) {
1158 wcscpy(py3path, _Py_dll_path);
1159 }
1160 else {
1161 wcscpy(py3path, L"");
1162 }
1163 s = wcsrchr(py3path, L'\\');
1164 if (!s) {
1165 s = py3path;
1166 }
1167 wcscpy(s, L"\\python3.dll");
1168 hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1169 if (hPython3 != NULL) {
1170 return 1;
1171 }
1172
1173 /* Check sys.prefix\DLLs\python3.dll */
1174 wcscpy(py3path, Py_GetPrefix());
1175 wcscat(py3path, L"\\DLLs\\python3.dll");
1176 hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1177 return hPython3 != NULL;
1178 }
1179