1 /* Return the initial module search path. */
2
3 #include "Python.h"
4 #include "marshal.h" // PyMarshal_ReadObjectFromString
5 #include "osdefs.h" // DELIM
6 #include "pycore_initconfig.h"
7 #include "pycore_fileutils.h"
8 #include "pycore_pathconfig.h"
9 #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
10 #include <wchar.h>
11
12 #ifdef MS_WINDOWS
13 # include <windows.h> // GetFullPathNameW(), MAX_PATH
14 # include <pathcch.h>
15 #endif
16
17 #ifdef __APPLE__
18 # include <mach-o/dyld.h>
19 #endif
20
21 /* Reference the precompiled getpath.py */
22 #include "../Python/frozen_modules/getpath.h"
23
24 #if (!defined(PREFIX) || !defined(EXEC_PREFIX) \
25 || !defined(VERSION) || !defined(VPATH) \
26 || !defined(PLATLIBDIR))
27 #error "PREFIX, EXEC_PREFIX, VERSION, VPATH and PLATLIBDIR macros must be defined"
28 #endif
29
30 #if !defined(PYTHONPATH)
31 #define PYTHONPATH NULL
32 #endif
33
34 #if !defined(PYDEBUGEXT)
35 #define PYDEBUGEXT NULL
36 #endif
37
38 #if !defined(PYWINVER)
39 #ifdef MS_DLL_ID
40 #define PYWINVER MS_DLL_ID
41 #else
42 #define PYWINVER NULL
43 #endif
44 #endif
45
46 #if !defined(EXE_SUFFIX)
47 #if defined(MS_WINDOWS) || defined(__CYGWIN__) || defined(__MINGW32__)
48 #define EXE_SUFFIX L".exe"
49 #else
50 #define EXE_SUFFIX NULL
51 #endif
52 #endif
53
54
55 /* HELPER FUNCTIONS for getpath.py */
56
57 static PyObject *
58 getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args)
59 {
60 PyObject *r = NULL;
61 PyObject *pathobj;
62 wchar_t *path;
63 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
64 return NULL;
65 }
66 Py_ssize_t len;
67 path = PyUnicode_AsWideCharString(pathobj, &len);
68 if (path) {
69 wchar_t *abs;
70 if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) {
71 r = PyUnicode_FromWideChar(abs, -1);
72 PyMem_RawFree((void *)abs);
73 } else {
74 PyErr_SetString(PyExc_OSError, "failed to make path absolute");
75 }
76 PyMem_Free((void *)path);
77 }
78 return r;
79 }
80
81
82 static PyObject *
83 getpath_basename(PyObject *Py_UNUSED(self), PyObject *args)
84 {
85 PyObject *path;
86 if (!PyArg_ParseTuple(args, "U", &path)) {
87 return NULL;
88 }
89 Py_ssize_t end = PyUnicode_GET_LENGTH(path);
90 Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1);
91 if (pos < 0) {
92 return Py_NewRef(path);
93 }
94 return PyUnicode_Substring(path, pos + 1, end);
95 }
96
97
98 static PyObject *
99 getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args)
100 {
101 PyObject *path;
102 if (!PyArg_ParseTuple(args, "U", &path)) {
103 return NULL;
104 }
105 Py_ssize_t end = PyUnicode_GET_LENGTH(path);
106 Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1);
107 if (pos < 0) {
108 return PyUnicode_FromStringAndSize(NULL, 0);
109 }
110 return PyUnicode_Substring(path, 0, pos);
111 }
112
113
114 static PyObject *
115 getpath_isabs(PyObject *Py_UNUSED(self), PyObject *args)
116 {
117 PyObject *r = NULL;
118 PyObject *pathobj;
119 const wchar_t *path;
120 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
121 return NULL;
122 }
123 path = PyUnicode_AsWideCharString(pathobj, NULL);
124 if (path) {
125 r = _Py_isabs(path) ? Py_True : Py_False;
126 PyMem_Free((void *)path);
127 }
128 Py_XINCREF(r);
129 return r;
130 }
131
132
133 static PyObject *
134 getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args)
135 {
136 PyObject *r = NULL;
137 PyObject *pathobj;
138 PyObject *suffixobj;
139 const wchar_t *path;
140 const wchar_t *suffix;
141 if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) {
142 return NULL;
143 }
144 Py_ssize_t len, suffixLen;
145 path = PyUnicode_AsWideCharString(pathobj, &len);
146 if (path) {
147 suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen);
148 if (suffix) {
149 if (suffixLen > len ||
150 #ifdef MS_WINDOWS
151 wcsicmp(&path[len - suffixLen], suffix) != 0
152 #else
153 wcscmp(&path[len - suffixLen], suffix) != 0
154 #endif
155 ) {
156 r = Py_False;
157 } else {
158 r = Py_True;
159 }
160 Py_INCREF(r);
161 PyMem_Free((void *)suffix);
162 }
163 PyMem_Free((void *)path);
164 }
165 return r;
166 }
167
168
169 static PyObject *
170 getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args)
171 {
172 PyObject *r = NULL;
173 PyObject *pathobj;
174 const wchar_t *path;
175 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
176 return NULL;
177 }
178 path = PyUnicode_AsWideCharString(pathobj, NULL);
179 if (path) {
180 #ifdef MS_WINDOWS
181 DWORD attr = GetFileAttributesW(path);
182 r = (attr != INVALID_FILE_ATTRIBUTES) &&
183 (attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
184 #else
185 struct stat st;
186 r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False;
187 #endif
188 PyMem_Free((void *)path);
189 }
190 Py_XINCREF(r);
191 return r;
192 }
193
194
195 static PyObject *
196 getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args)
197 {
198 PyObject *r = NULL;
199 PyObject *pathobj;
200 const wchar_t *path;
201 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
202 return NULL;
203 }
204 path = PyUnicode_AsWideCharString(pathobj, NULL);
205 if (path) {
206 #ifdef MS_WINDOWS
207 DWORD attr = GetFileAttributesW(path);
208 r = (attr != INVALID_FILE_ATTRIBUTES) &&
209 !(attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
210 #else
211 struct stat st;
212 r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False;
213 #endif
214 PyMem_Free((void *)path);
215 }
216 Py_XINCREF(r);
217 return r;
218 }
219
220
221 static PyObject *
222 getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args)
223 {
224 PyObject *r = NULL;
225 PyObject *pathobj;
226 const wchar_t *path;
227 Py_ssize_t cchPath;
228 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
229 return NULL;
230 }
231 path = PyUnicode_AsWideCharString(pathobj, &cchPath);
232 if (path) {
233 #ifdef MS_WINDOWS
234 const wchar_t *ext;
235 DWORD attr = GetFileAttributesW(path);
236 r = (attr != INVALID_FILE_ATTRIBUTES) &&
237 !(attr & FILE_ATTRIBUTE_DIRECTORY) &&
238 SUCCEEDED(PathCchFindExtension(path, cchPath + 1, &ext)) &&
239 (CompareStringOrdinal(ext, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL)
240 ? Py_True : Py_False;
241 #else
242 struct stat st;
243 r = (_Py_wstat(path, &st) == 0) &&
244 S_ISREG(st.st_mode) &&
245 (st.st_mode & 0111)
246 ? Py_True : Py_False;
247 #endif
248 PyMem_Free((void *)path);
249 }
250 Py_XINCREF(r);
251 return r;
252 }
253
254
255 static PyObject *
256 getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args)
257 {
258 if (!PyTuple_Check(args)) {
259 PyErr_SetString(PyExc_TypeError, "requires tuple of arguments");
260 return NULL;
261 }
262 Py_ssize_t n = PyTuple_GET_SIZE(args);
263 if (n == 0) {
264 return PyUnicode_FromStringAndSize(NULL, 0);
265 }
266 /* Convert all parts to wchar and accumulate max final length */
267 wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *));
268 memset(parts, 0, n * sizeof(wchar_t *));
269 Py_ssize_t cchFinal = 0;
270 Py_ssize_t first = 0;
271
272 for (Py_ssize_t i = 0; i < n; ++i) {
273 PyObject *s = PyTuple_GET_ITEM(args, i);
274 Py_ssize_t cch;
275 if (s == Py_None) {
276 cch = 0;
277 } else if (PyUnicode_Check(s)) {
278 parts[i] = PyUnicode_AsWideCharString(s, &cch);
279 if (!parts[i]) {
280 cchFinal = -1;
281 break;
282 }
283 if (_Py_isabs(parts[i])) {
284 first = i;
285 }
286 } else {
287 PyErr_SetString(PyExc_TypeError, "all arguments to joinpath() must be str or None");
288 cchFinal = -1;
289 break;
290 }
291 cchFinal += cch + 1;
292 }
293
294 wchar_t *final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL;
295 if (!final) {
296 for (Py_ssize_t i = 0; i < n; ++i) {
297 PyMem_Free(parts[i]);
298 }
299 PyMem_Free(parts);
300 if (cchFinal) {
301 PyErr_NoMemory();
302 return NULL;
303 }
304 return PyUnicode_FromStringAndSize(NULL, 0);
305 }
306
307 final[0] = '\0';
308 /* Now join all the paths. The final result should be shorter than the buffer */
309 for (Py_ssize_t i = 0; i < n; ++i) {
310 if (!parts[i]) {
311 continue;
312 }
313 if (i >= first && final) {
314 if (!final[0]) {
315 /* final is definitely long enough to fit any individual part */
316 wcscpy(final, parts[i]);
317 } else if (_Py_add_relfile(final, parts[i], cchFinal) < 0) {
318 /* if we fail, keep iterating to free memory, but stop adding parts */
319 PyMem_Free(final);
320 final = NULL;
321 }
322 }
323 PyMem_Free(parts[i]);
324 }
325 PyMem_Free(parts);
326 if (!final) {
327 PyErr_SetString(PyExc_SystemError, "failed to join paths");
328 return NULL;
329 }
330 PyObject *r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1);
331 PyMem_Free(final);
332 return r;
333 }
334
335
336 static PyObject *
337 getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args)
338 {
339 PyObject *r = NULL;
340 PyObject *pathobj;
341 const wchar_t *path;
342 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
343 return NULL;
344 }
345 path = PyUnicode_AsWideCharString(pathobj, NULL);
346 if (!path) {
347 return NULL;
348 }
349 FILE *fp = _Py_wfopen(path, L"rb");
350 if (!fp) {
351 PyErr_SetFromErrno(PyExc_OSError);
352 PyMem_Free((void *)path);
353 return NULL;
354 }
355 PyMem_Free((void *)path);
356
357 r = PyList_New(0);
358 if (!r) {
359 fclose(fp);
360 return NULL;
361 }
362 const size_t MAX_FILE = 32 * 1024;
363 char *buffer = (char *)PyMem_Malloc(MAX_FILE);
364 if (!buffer) {
365 Py_DECREF(r);
366 fclose(fp);
367 return NULL;
368 }
369
370 size_t cb = fread(buffer, 1, MAX_FILE, fp);
371 fclose(fp);
372 if (!cb) {
373 return r;
374 }
375 if (cb >= MAX_FILE) {
376 Py_DECREF(r);
377 PyErr_SetString(PyExc_MemoryError,
378 "cannot read file larger than 32KB during initialization");
379 return NULL;
380 }
381 buffer[cb] = '\0';
382
383 size_t len;
384 wchar_t *wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len);
385 PyMem_Free((void *)buffer);
386 if (!wbuffer) {
387 Py_DECREF(r);
388 PyErr_NoMemory();
389 return NULL;
390 }
391
392 wchar_t *p1 = wbuffer;
393 wchar_t *p2 = p1;
394 while ((p2 = wcschr(p1, L'\n')) != NULL) {
395 Py_ssize_t cb = p2 - p1;
396 while (cb >= 0 && (p1[cb] == L'\n' || p1[cb] == L'\r')) {
397 --cb;
398 }
399 PyObject *u = PyUnicode_FromWideChar(p1, cb >= 0 ? cb + 1 : 0);
400 if (!u || PyList_Append(r, u) < 0) {
401 Py_XDECREF(u);
402 Py_CLEAR(r);
403 break;
404 }
405 Py_DECREF(u);
406 p1 = p2 + 1;
407 }
408 if (r && p1 && *p1) {
409 PyObject *u = PyUnicode_FromWideChar(p1, -1);
410 if (!u || PyList_Append(r, u) < 0) {
411 Py_CLEAR(r);
412 }
413 Py_XDECREF(u);
414 }
415 PyMem_RawFree(wbuffer);
416 return r;
417 }
418
419
420 static PyObject *
421 getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args)
422 {
423 PyObject *pathobj;
424 if (!PyArg_ParseTuple(args, "U", &pathobj)) {
425 return NULL;
426 }
427 #if defined(HAVE_READLINK)
428 /* This readlink calculation only resolves a symlinked file, and
429 does not resolve any path segments. This is consistent with
430 prior releases, however, the realpath implementation below is
431 potentially correct in more cases. */
432 PyObject *r = NULL;
433 int nlink = 0;
434 wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
435 if (!path) {
436 goto done;
437 }
438 wchar_t *path2 = _PyMem_RawWcsdup(path);
439 PyMem_Free((void *)path);
440 path = path2;
441 while (path) {
442 wchar_t resolved[MAXPATHLEN + 1];
443 int linklen = _Py_wreadlink(path, resolved, Py_ARRAY_LENGTH(resolved));
444 if (linklen == -1) {
445 r = PyUnicode_FromWideChar(path, -1);
446 break;
447 }
448 if (_Py_isabs(resolved)) {
449 PyMem_RawFree((void *)path);
450 path = _PyMem_RawWcsdup(resolved);
451 } else {
452 wchar_t *s = wcsrchr(path, SEP);
453 if (s) {
454 *s = L'\0';
455 }
456 path2 = _Py_join_relfile(path, resolved);
457 if (path2) {
458 path2 = _Py_normpath(path2, -1);
459 }
460 PyMem_RawFree((void *)path);
461 path = path2;
462 }
463 nlink++;
464 /* 40 is the Linux kernel 4.2 limit */
465 if (nlink >= 40) {
466 PyErr_SetString(PyExc_OSError, "maximum number of symbolic links reached");
467 break;
468 }
469 }
470 if (!path) {
471 PyErr_NoMemory();
472 }
473 done:
474 PyMem_RawFree((void *)path);
475 return r;
476
477 #elif defined(HAVE_REALPATH)
478 PyObject *r = NULL;
479 struct stat st;
480 const char *narrow = NULL;
481 wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
482 if (!path) {
483 goto done;
484 }
485 narrow = Py_EncodeLocale(path, NULL);
486 if (!narrow) {
487 PyErr_NoMemory();
488 goto done;
489 }
490 if (lstat(narrow, &st)) {
491 PyErr_SetFromErrno(PyExc_OSError);
492 goto done;
493 }
494 if (!S_ISLNK(st.st_mode)) {
495 Py_INCREF(pathobj);
496 r = pathobj;
497 goto done;
498 }
499 wchar_t resolved[MAXPATHLEN+1];
500 if (_Py_wrealpath(path, resolved, MAXPATHLEN) == NULL) {
501 PyErr_SetFromErrno(PyExc_OSError);
502 } else {
503 r = PyUnicode_FromWideChar(resolved, -1);
504 }
505 done:
506 PyMem_Free((void *)path);
507 PyMem_Free((void *)narrow);
508 return r;
509 #endif
510
511 Py_INCREF(pathobj);
512 return pathobj;
513 }
514
515
516 static PyMethodDef getpath_methods[] = {
517 {"abspath", getpath_abspath, METH_VARARGS, NULL},
518 {"basename", getpath_basename, METH_VARARGS, NULL},
519 {"dirname", getpath_dirname, METH_VARARGS, NULL},
520 {"hassuffix", getpath_hassuffix, METH_VARARGS, NULL},
521 {"isabs", getpath_isabs, METH_VARARGS, NULL},
522 {"isdir", getpath_isdir, METH_VARARGS, NULL},
523 {"isfile", getpath_isfile, METH_VARARGS, NULL},
524 {"isxfile", getpath_isxfile, METH_VARARGS, NULL},
525 {"joinpath", getpath_joinpath, METH_VARARGS, NULL},
526 {"readlines", getpath_readlines, METH_VARARGS, NULL},
527 {"realpath", getpath_realpath, METH_VARARGS, NULL},
528 {NULL, NULL, 0, NULL}
529 };
530
531
532 /* Two implementations of warn() to use depending on whether warnings
533 are enabled or not. */
534
535 static PyObject *
536 getpath_warn(PyObject *Py_UNUSED(self), PyObject *args)
537 {
538 PyObject *msgobj;
539 if (!PyArg_ParseTuple(args, "U", &msgobj)) {
540 return NULL;
541 }
542 fprintf(stderr, "%s\n", PyUnicode_AsUTF8(msgobj));
543 Py_RETURN_NONE;
544 }
545
546
547 static PyObject *
548 getpath_nowarn(PyObject *Py_UNUSED(self), PyObject *args)
549 {
550 Py_RETURN_NONE;
551 }
552
553
554 static PyMethodDef getpath_warn_method = {"warn", getpath_warn, METH_VARARGS, NULL};
555 static PyMethodDef getpath_nowarn_method = {"warn", getpath_nowarn, METH_VARARGS, NULL};
556
557 /* Add the helper functions to the dict */
558 static int
559 funcs_to_dict(PyObject *dict, int warnings)
560 {
561 for (PyMethodDef *m = getpath_methods; m->ml_name; ++m) {
562 PyObject *f = PyCFunction_NewEx(m, NULL, NULL);
563 if (!f) {
564 return 0;
565 }
566 if (PyDict_SetItemString(dict, m->ml_name, f) < 0) {
567 Py_DECREF(f);
568 return 0;
569 }
570 Py_DECREF(f);
571 }
572 PyMethodDef *m2 = warnings ? &getpath_warn_method : &getpath_nowarn_method;
573 PyObject *f = PyCFunction_NewEx(m2, NULL, NULL);
574 if (!f) {
575 return 0;
576 }
577 if (PyDict_SetItemString(dict, m2->ml_name, f) < 0) {
578 Py_DECREF(f);
579 return 0;
580 }
581 Py_DECREF(f);
582 return 1;
583 }
584
585
586 /* Add a wide-character string constant to the dict */
587 static int
588 wchar_to_dict(PyObject *dict, const char *key, const wchar_t *s)
589 {
590 PyObject *u;
591 int r;
592 if (s && s[0]) {
593 u = PyUnicode_FromWideChar(s, -1);
594 if (!u) {
595 return 0;
596 }
597 } else {
598 u = Py_None;
599 Py_INCREF(u);
600 }
601 r = PyDict_SetItemString(dict, key, u) == 0;
602 Py_DECREF(u);
603 return r;
604 }
605
606
607 /* Add a narrow string constant to the dict, using default locale decoding */
608 static int
609 decode_to_dict(PyObject *dict, const char *key, const char *s)
610 {
611 PyObject *u = NULL;
612 int r;
613 if (s && s[0]) {
614 size_t len;
615 const wchar_t *w = Py_DecodeLocale(s, &len);
616 if (w) {
617 u = PyUnicode_FromWideChar(w, len);
618 PyMem_RawFree((void *)w);
619 }
620 if (!u) {
621 return 0;
622 }
623 } else {
624 u = Py_None;
625 Py_INCREF(u);
626 }
627 r = PyDict_SetItemString(dict, key, u) == 0;
628 Py_DECREF(u);
629 return r;
630 }
631
632 /* Add an environment variable to the dict, optionally clearing it afterwards */
633 static int
634 env_to_dict(PyObject *dict, const char *key, int and_clear)
635 {
636 PyObject *u = NULL;
637 int r = 0;
638 assert(strncmp(key, "ENV_", 4) == 0);
639 assert(strlen(key) < 64);
640 #ifdef MS_WINDOWS
641 wchar_t wkey[64];
642 // Quick convert to wchar_t, since we know key is ASCII
643 wchar_t *wp = wkey;
644 for (const char *p = &key[4]; *p; ++p) {
645 assert(*p < 128);
646 *wp++ = *p;
647 }
648 *wp = L'\0';
649 const wchar_t *v = _wgetenv(wkey);
650 if (v) {
651 u = PyUnicode_FromWideChar(v, -1);
652 if (!u) {
653 PyErr_Clear();
654 }
655 }
656 #else
657 const char *v = getenv(&key[4]);
658 if (v) {
659 size_t len;
660 const wchar_t *w = Py_DecodeLocale(v, &len);
661 if (w) {
662 u = PyUnicode_FromWideChar(w, len);
663 if (!u) {
664 PyErr_Clear();
665 }
666 PyMem_RawFree((void *)w);
667 }
668 }
669 #endif
670 if (u) {
671 r = PyDict_SetItemString(dict, key, u) == 0;
672 Py_DECREF(u);
673 } else {
674 r = PyDict_SetItemString(dict, key, Py_None) == 0;
675 }
676 if (r && and_clear) {
677 #ifdef MS_WINDOWS
678 _wputenv_s(wkey, L"");
679 #else
680 unsetenv(&key[4]);
681 #endif
682 }
683 return r;
684 }
685
686
687 /* Add an integer constant to the dict */
688 static int
689 int_to_dict(PyObject *dict, const char *key, int v)
690 {
691 PyObject *o;
692 int r;
693 o = PyLong_FromLong(v);
694 if (!o) {
695 return 0;
696 }
697 r = PyDict_SetItemString(dict, key, o) == 0;
698 Py_DECREF(o);
699 return r;
700 }
701
702
703 #ifdef MS_WINDOWS
704 static int
705 winmodule_to_dict(PyObject *dict, const char *key, HMODULE mod)
706 {
707 wchar_t *buffer = NULL;
708 for (DWORD cch = 256; buffer == NULL && cch < (1024 * 1024); cch *= 2) {
709 buffer = (wchar_t*)PyMem_RawMalloc(cch * sizeof(wchar_t));
710 if (buffer) {
711 if (GetModuleFileNameW(mod, buffer, cch) == cch) {
712 PyMem_RawFree(buffer);
713 buffer = NULL;
714 }
715 }
716 }
717 int r = wchar_to_dict(dict, key, buffer);
718 PyMem_RawFree(buffer);
719 return r;
720 }
721 #endif
722
723
724 /* Add the current executable's path to the dict */
725 static int
726 progname_to_dict(PyObject *dict, const char *key)
727 {
728 #ifdef MS_WINDOWS
729 return winmodule_to_dict(dict, key, NULL);
730 #elif defined(__APPLE__)
731 char *path;
732 uint32_t pathLen = 256;
733 while (pathLen) {
734 path = PyMem_RawMalloc((pathLen + 1) * sizeof(char));
735 if (!path) {
736 return 0;
737 }
738 if (_NSGetExecutablePath(path, &pathLen) != 0) {
739 PyMem_RawFree(path);
740 continue;
741 }
742 // Only keep if the path is absolute
743 if (path[0] == SEP) {
744 int r = decode_to_dict(dict, key, path);
745 PyMem_RawFree(path);
746 return r;
747 }
748 // Fall back and store None
749 PyMem_RawFree(path);
750 break;
751 }
752 #endif
753 return PyDict_SetItemString(dict, key, Py_None) == 0;
754 }
755
756
757 /* Add the runtime library's path to the dict */
758 static int
759 library_to_dict(PyObject *dict, const char *key)
760 {
761 #ifdef MS_WINDOWS
762 extern HMODULE PyWin_DLLhModule;
763 if (PyWin_DLLhModule) {
764 return winmodule_to_dict(dict, key, PyWin_DLLhModule);
765 }
766 #elif defined(WITH_NEXT_FRAMEWORK)
767 static char modPath[MAXPATHLEN + 1];
768 static int modPathInitialized = -1;
769 if (modPathInitialized < 0) {
770 modPathInitialized = 0;
771
772 /* On Mac OS X we have a special case if we're running from a framework.
773 This is because the python home should be set relative to the library,
774 which is in the framework, not relative to the executable, which may
775 be outside of the framework. Except when we're in the build
776 directory... */
777 NSSymbol symbol = NSLookupAndBindSymbol("_Py_Initialize");
778 if (symbol != NULL) {
779 NSModule pythonModule = NSModuleForSymbol(symbol);
780 if (pythonModule != NULL) {
781 /* Use dylib functions to find out where the framework was loaded from */
782 const char *path = NSLibraryNameForModule(pythonModule);
783 if (path) {
784 strncpy(modPath, path, MAXPATHLEN);
785 modPathInitialized = 1;
786 }
787 }
788 }
789 }
790 if (modPathInitialized > 0) {
791 return decode_to_dict(dict, key, modPath);
792 }
793 #endif
794 return PyDict_SetItemString(dict, key, Py_None) == 0;
795 }
796
797
798 PyObject *
799 _Py_Get_Getpath_CodeObject(void)
800 {
801 return PyMarshal_ReadObjectFromString(
802 (const char*)_Py_M__getpath, sizeof(_Py_M__getpath));
803 }
804
805
806 /* Perform the actual path calculation.
807
808 When compute_path_config is 0, this only reads any initialised path
809 config values into the PyConfig struct. For example, Py_SetHome() or
810 Py_SetPath(). The only error should be due to failed memory allocation.
811
812 When compute_path_config is 1, full path calculation is performed.
813 The GIL must be held, and there may be filesystem access, side
814 effects, and potential unraisable errors that are reported directly
815 to stderr.
816
817 Calling this function multiple times on the same PyConfig is only
818 safe because already-configured values are not recalculated. To
819 actually recalculate paths, you need a clean PyConfig.
820 */
821 PyStatus
822 _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
823 {
824 PyStatus status = _PyPathConfig_ReadGlobal(config);
825
826 if (_PyStatus_EXCEPTION(status) || !compute_path_config) {
827 return status;
828 }
829
830 if (!_PyThreadState_UncheckedGet()) {
831 return PyStatus_Error("cannot calculate path configuration without GIL");
832 }
833
834 PyObject *configDict = _PyConfig_AsDict(config);
835 if (!configDict) {
836 PyErr_Clear();
837 return PyStatus_NoMemory();
838 }
839
840 PyObject *dict = PyDict_New();
841 if (!dict) {
842 PyErr_Clear();
843 Py_DECREF(configDict);
844 return PyStatus_NoMemory();
845 }
846
847 if (PyDict_SetItemString(dict, "config", configDict) < 0) {
848 PyErr_Clear();
849 Py_DECREF(configDict);
850 Py_DECREF(dict);
851 return PyStatus_NoMemory();
852 }
853 /* reference now held by dict */
854 Py_DECREF(configDict);
855
856 PyObject *co = _Py_Get_Getpath_CodeObject();
857 if (!co || !PyCode_Check(co)) {
858 PyErr_Clear();
859 Py_XDECREF(co);
860 Py_DECREF(dict);
861 return PyStatus_Error("error reading frozen getpath.py");
862 }
863
864 #ifdef MS_WINDOWS
865 PyObject *winreg = PyImport_ImportModule("winreg");
866 if (!winreg || PyDict_SetItemString(dict, "winreg", winreg) < 0) {
867 PyErr_Clear();
868 Py_XDECREF(winreg);
869 if (PyDict_SetItemString(dict, "winreg", Py_None) < 0) {
870 PyErr_Clear();
871 Py_DECREF(co);
872 Py_DECREF(dict);
873 return PyStatus_Error("error importing winreg module");
874 }
875 } else {
876 Py_DECREF(winreg);
877 }
878 #endif
879
880 if (
881 #ifdef MS_WINDOWS
882 !decode_to_dict(dict, "os_name", "nt") ||
883 #elif defined(__APPLE__)
884 !decode_to_dict(dict, "os_name", "darwin") ||
885 #else
886 !decode_to_dict(dict, "os_name", "posix") ||
887 #endif
888 #ifdef WITH_NEXT_FRAMEWORK
889 !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 1) ||
890 #else
891 !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 0) ||
892 #endif
893 !decode_to_dict(dict, "PREFIX", PREFIX) ||
894 !decode_to_dict(dict, "EXEC_PREFIX", EXEC_PREFIX) ||
895 !decode_to_dict(dict, "PYTHONPATH", PYTHONPATH) ||
896 !decode_to_dict(dict, "VPATH", VPATH) ||
897 !decode_to_dict(dict, "PLATLIBDIR", PLATLIBDIR) ||
898 !decode_to_dict(dict, "PYDEBUGEXT", PYDEBUGEXT) ||
899 !int_to_dict(dict, "VERSION_MAJOR", PY_MAJOR_VERSION) ||
900 !int_to_dict(dict, "VERSION_MINOR", PY_MINOR_VERSION) ||
901 !decode_to_dict(dict, "PYWINVER", PYWINVER) ||
902 !wchar_to_dict(dict, "EXE_SUFFIX", EXE_SUFFIX) ||
903 !env_to_dict(dict, "ENV_PATH", 0) ||
904 !env_to_dict(dict, "ENV_PYTHONHOME", 0) ||
905 !env_to_dict(dict, "ENV_PYTHONEXECUTABLE", 0) ||
906 !env_to_dict(dict, "ENV___PYVENV_LAUNCHER__", 1) ||
907 !progname_to_dict(dict, "real_executable") ||
908 !library_to_dict(dict, "library") ||
909 !wchar_to_dict(dict, "executable_dir", NULL) ||
910 !wchar_to_dict(dict, "py_setpath", _PyPathConfig_GetGlobalModuleSearchPath()) ||
911 !funcs_to_dict(dict, config->pathconfig_warnings) ||
912 #ifndef MS_WINDOWS
913 PyDict_SetItemString(dict, "winreg", Py_None) < 0 ||
914 #endif
915 PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0
916 ) {
917 Py_DECREF(co);
918 Py_DECREF(dict);
919 _PyErr_WriteUnraisableMsg("error evaluating initial values", NULL);
920 return PyStatus_Error("error evaluating initial values");
921 }
922
923 PyObject *r = PyEval_EvalCode(co, dict, dict);
924 Py_DECREF(co);
925
926 if (!r) {
927 Py_DECREF(dict);
928 _PyErr_WriteUnraisableMsg("error evaluating path", NULL);
929 return PyStatus_Error("error evaluating path");
930 }
931 Py_DECREF(r);
932
933 #if 0
934 PyObject *it = PyObject_GetIter(configDict);
935 for (PyObject *k = PyIter_Next(it); k; k = PyIter_Next(it)) {
936 if (!strcmp("__builtins__", PyUnicode_AsUTF8(k))) {
937 Py_DECREF(k);
938 continue;
939 }
940 fprintf(stderr, "%s = ", PyUnicode_AsUTF8(k));
941 PyObject *o = PyDict_GetItem(configDict, k);
942 o = PyObject_Repr(o);
943 fprintf(stderr, "%s\n", PyUnicode_AsUTF8(o));
944 Py_DECREF(o);
945 Py_DECREF(k);
946 }
947 Py_DECREF(it);
948 #endif
949
950 if (_PyConfig_FromDict(config, configDict) < 0) {
951 _PyErr_WriteUnraisableMsg("reading getpath results", NULL);
952 Py_DECREF(dict);
953 return PyStatus_Error("error getting getpath results");
954 }
955
956 Py_DECREF(dict);
957
958 return _PyStatus_OK();
959 }
960