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