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