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 : 25 : getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args)
59 : : {
60 : 25 : PyObject *r = NULL;
61 : : PyObject *pathobj;
62 : : wchar_t *path;
63 [ - + ]: 25 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
64 : 0 : return NULL;
65 : : }
66 : : Py_ssize_t len;
67 : 25 : path = PyUnicode_AsWideCharString(pathobj, &len);
68 [ + - ]: 25 : if (path) {
69 : : wchar_t *abs;
70 [ + - + - ]: 25 : if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) {
71 : 25 : r = PyUnicode_FromWideChar(abs, -1);
72 : 25 : PyMem_RawFree((void *)abs);
73 : : } else {
74 : 0 : PyErr_SetString(PyExc_OSError, "failed to make path absolute");
75 : : }
76 : 25 : PyMem_Free((void *)path);
77 : : }
78 : 25 : return r;
79 : : }
80 : :
81 : :
82 : : static PyObject *
83 : 0 : getpath_basename(PyObject *Py_UNUSED(self), PyObject *args)
84 : : {
85 : : PyObject *path;
86 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "U", &path)) {
87 : 0 : return NULL;
88 : : }
89 : 0 : Py_ssize_t end = PyUnicode_GET_LENGTH(path);
90 : 0 : Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1);
91 [ # # ]: 0 : if (pos < 0) {
92 : 0 : return Py_NewRef(path);
93 : : }
94 : 0 : return PyUnicode_Substring(path, pos + 1, end);
95 : : }
96 : :
97 : :
98 : : static PyObject *
99 : 75 : getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args)
100 : : {
101 : : PyObject *path;
102 [ - + ]: 75 : if (!PyArg_ParseTuple(args, "U", &path)) {
103 : 0 : return NULL;
104 : : }
105 : 75 : Py_ssize_t end = PyUnicode_GET_LENGTH(path);
106 : 75 : Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1);
107 [ - + ]: 75 : if (pos < 0) {
108 : 0 : return PyUnicode_FromStringAndSize(NULL, 0);
109 : : }
110 : 75 : return PyUnicode_Substring(path, 0, pos);
111 : : }
112 : :
113 : :
114 : : static PyObject *
115 : 0 : getpath_isabs(PyObject *Py_UNUSED(self), PyObject *args)
116 : : {
117 : 0 : PyObject *r = NULL;
118 : : PyObject *pathobj;
119 : : const wchar_t *path;
120 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
121 : 0 : return NULL;
122 : : }
123 : 0 : path = PyUnicode_AsWideCharString(pathobj, NULL);
124 [ # # ]: 0 : if (path) {
125 [ # # ]: 0 : r = _Py_isabs(path) ? Py_True : Py_False;
126 : 0 : PyMem_Free((void *)path);
127 : : }
128 : 0 : return Py_XNewRef(r);
129 : : }
130 : :
131 : :
132 : : static PyObject *
133 : 0 : getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args)
134 : : {
135 : 0 : PyObject *r = NULL;
136 : : PyObject *pathobj;
137 : : PyObject *suffixobj;
138 : : const wchar_t *path;
139 : : const wchar_t *suffix;
140 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) {
141 : 0 : return NULL;
142 : : }
143 : : Py_ssize_t len, suffixLen;
144 : 0 : path = PyUnicode_AsWideCharString(pathobj, &len);
145 [ # # ]: 0 : if (path) {
146 : 0 : suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen);
147 [ # # ]: 0 : if (suffix) {
148 [ # # ]: 0 : if (suffixLen > len ||
149 : : #ifdef MS_WINDOWS
150 : : wcsicmp(&path[len - suffixLen], suffix) != 0
151 : : #else
152 [ # # ]: 0 : wcscmp(&path[len - suffixLen], suffix) != 0
153 : : #endif
154 : : ) {
155 : 0 : r = Py_NewRef(Py_False);
156 : : } else {
157 : 0 : r = Py_NewRef(Py_True);
158 : : }
159 : 0 : PyMem_Free((void *)suffix);
160 : : }
161 : 0 : PyMem_Free((void *)path);
162 : : }
163 : 0 : return r;
164 : : }
165 : :
166 : :
167 : : static PyObject *
168 : 0 : getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args)
169 : : {
170 : 0 : PyObject *r = NULL;
171 : : PyObject *pathobj;
172 : : const wchar_t *path;
173 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
174 : 0 : return NULL;
175 : : }
176 : 0 : path = PyUnicode_AsWideCharString(pathobj, NULL);
177 [ # # ]: 0 : if (path) {
178 : : #ifdef MS_WINDOWS
179 : : DWORD attr = GetFileAttributesW(path);
180 : : r = (attr != INVALID_FILE_ATTRIBUTES) &&
181 : : (attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
182 : : #else
183 : : struct stat st;
184 [ # # # # ]: 0 : r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False;
185 : : #endif
186 : 0 : PyMem_Free((void *)path);
187 : : }
188 : 0 : return Py_XNewRef(r);
189 : : }
190 : :
191 : :
192 : : static PyObject *
193 : 46 : getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args)
194 : : {
195 : 46 : PyObject *r = NULL;
196 : : PyObject *pathobj;
197 : : const wchar_t *path;
198 [ - + ]: 46 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
199 : 0 : return NULL;
200 : : }
201 : 46 : path = PyUnicode_AsWideCharString(pathobj, NULL);
202 [ + - ]: 46 : if (path) {
203 : : #ifdef MS_WINDOWS
204 : : DWORD attr = GetFileAttributesW(path);
205 : : r = (attr != INVALID_FILE_ATTRIBUTES) &&
206 : : !(attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False;
207 : : #else
208 : : struct stat st;
209 [ + - + - ]: 46 : r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False;
210 : : #endif
211 : 46 : PyMem_Free((void *)path);
212 : : }
213 : 46 : return Py_XNewRef(r);
214 : : }
215 : :
216 : :
217 : : static PyObject *
218 : 0 : getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args)
219 : : {
220 : 0 : PyObject *r = NULL;
221 : : PyObject *pathobj;
222 : : const wchar_t *path;
223 : : Py_ssize_t cchPath;
224 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
225 : 0 : return NULL;
226 : : }
227 : 0 : path = PyUnicode_AsWideCharString(pathobj, &cchPath);
228 [ # # ]: 0 : if (path) {
229 : : #ifdef MS_WINDOWS
230 : : DWORD attr = GetFileAttributesW(path);
231 : : r = (attr != INVALID_FILE_ATTRIBUTES) &&
232 : : !(attr & FILE_ATTRIBUTE_DIRECTORY) &&
233 : : (cchPath >= 4) &&
234 : : (CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL)
235 : : ? Py_True : Py_False;
236 : : #else
237 : : struct stat st;
238 : 0 : r = (_Py_wstat(path, &st) == 0) &&
239 [ # # ]: 0 : S_ISREG(st.st_mode) &&
240 [ # # ]: 0 : (st.st_mode & 0111)
241 [ # # ]: 0 : ? Py_True : Py_False;
242 : : #endif
243 : 0 : PyMem_Free((void *)path);
244 : : }
245 : 0 : return Py_XNewRef(r);
246 : : }
247 : :
248 : :
249 : : static PyObject *
250 : 221 : getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args)
251 : : {
252 [ - + ]: 221 : if (!PyTuple_Check(args)) {
253 : 0 : PyErr_SetString(PyExc_TypeError, "requires tuple of arguments");
254 : 0 : return NULL;
255 : : }
256 : 221 : Py_ssize_t n = PyTuple_GET_SIZE(args);
257 [ - + ]: 221 : if (n == 0) {
258 : 0 : return PyUnicode_FromStringAndSize(NULL, 0);
259 : : }
260 : : /* Convert all parts to wchar and accumulate max final length */
261 : 221 : wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *));
262 : 221 : memset(parts, 0, n * sizeof(wchar_t *));
263 : 221 : Py_ssize_t cchFinal = 0;
264 : 221 : Py_ssize_t first = 0;
265 : :
266 [ + + ]: 663 : for (Py_ssize_t i = 0; i < n; ++i) {
267 : 442 : PyObject *s = PyTuple_GET_ITEM(args, i);
268 : : Py_ssize_t cch;
269 [ + + ]: 442 : if (s == Py_None) {
270 : 25 : cch = 0;
271 [ + - ]: 417 : } else if (PyUnicode_Check(s)) {
272 : 417 : parts[i] = PyUnicode_AsWideCharString(s, &cch);
273 [ - + ]: 417 : if (!parts[i]) {
274 : 0 : cchFinal = -1;
275 : 0 : break;
276 : : }
277 [ + + ]: 417 : if (_Py_isabs(parts[i])) {
278 : 221 : first = i;
279 : : }
280 : : } else {
281 : 0 : PyErr_SetString(PyExc_TypeError, "all arguments to joinpath() must be str or None");
282 : 0 : cchFinal = -1;
283 : 0 : break;
284 : : }
285 : 442 : cchFinal += cch + 1;
286 : : }
287 : :
288 [ + - ]: 221 : wchar_t *final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL;
289 [ - + ]: 221 : if (!final) {
290 [ # # ]: 0 : for (Py_ssize_t i = 0; i < n; ++i) {
291 : 0 : PyMem_Free(parts[i]);
292 : : }
293 : 0 : PyMem_Free(parts);
294 [ # # ]: 0 : if (cchFinal) {
295 : 0 : PyErr_NoMemory();
296 : 0 : return NULL;
297 : : }
298 : 0 : return PyUnicode_FromStringAndSize(NULL, 0);
299 : : }
300 : :
301 : 221 : final[0] = '\0';
302 : : /* Now join all the paths. The final result should be shorter than the buffer */
303 [ + + ]: 663 : for (Py_ssize_t i = 0; i < n; ++i) {
304 [ + + ]: 442 : if (!parts[i]) {
305 : 25 : continue;
306 : : }
307 [ + - + - ]: 417 : if (i >= first && final) {
308 [ + + ]: 417 : if (!final[0]) {
309 : : /* final is definitely long enough to fit any individual part */
310 : 221 : wcscpy(final, parts[i]);
311 [ - + ]: 196 : } else if (_Py_add_relfile(final, parts[i], cchFinal) < 0) {
312 : : /* if we fail, keep iterating to free memory, but stop adding parts */
313 : 0 : PyMem_Free(final);
314 : 0 : final = NULL;
315 : : }
316 : : }
317 : 417 : PyMem_Free(parts[i]);
318 : : }
319 : 221 : PyMem_Free(parts);
320 [ - + ]: 221 : if (!final) {
321 : 0 : PyErr_SetString(PyExc_SystemError, "failed to join paths");
322 : 0 : return NULL;
323 : : }
324 : 221 : PyObject *r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1);
325 : 221 : PyMem_Free(final);
326 : 221 : return r;
327 : : }
328 : :
329 : :
330 : : static PyObject *
331 : 125 : getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args)
332 : : {
333 : 125 : PyObject *r = NULL;
334 : : PyObject *pathobj;
335 : : const wchar_t *path;
336 [ - + ]: 125 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
337 : 0 : return NULL;
338 : : }
339 : 125 : path = PyUnicode_AsWideCharString(pathobj, NULL);
340 [ - + ]: 125 : if (!path) {
341 : 0 : return NULL;
342 : : }
343 : 125 : FILE *fp = _Py_wfopen(path, L"rb");
344 : 125 : PyMem_Free((void *)path);
345 [ + + ]: 125 : if (!fp) {
346 : 121 : PyErr_SetFromErrno(PyExc_OSError);
347 : 121 : return NULL;
348 : : }
349 : :
350 : 4 : r = PyList_New(0);
351 [ - + ]: 4 : if (!r) {
352 : 0 : fclose(fp);
353 : 0 : return NULL;
354 : : }
355 : 4 : const size_t MAX_FILE = 32 * 1024;
356 : 4 : char *buffer = (char *)PyMem_Malloc(MAX_FILE);
357 [ - + ]: 4 : if (!buffer) {
358 : 0 : Py_DECREF(r);
359 : 0 : fclose(fp);
360 : 0 : return NULL;
361 : : }
362 : :
363 : 4 : size_t cb = fread(buffer, 1, MAX_FILE, fp);
364 : 4 : fclose(fp);
365 [ - + ]: 4 : if (!cb) {
366 : 0 : return r;
367 : : }
368 [ - + ]: 4 : if (cb >= MAX_FILE) {
369 : 0 : Py_DECREF(r);
370 : 0 : PyErr_SetString(PyExc_MemoryError,
371 : : "cannot read file larger than 32KB during initialization");
372 : 0 : return NULL;
373 : : }
374 : 4 : buffer[cb] = '\0';
375 : :
376 : : size_t len;
377 : 4 : wchar_t *wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len);
378 : 4 : PyMem_Free((void *)buffer);
379 [ - + ]: 4 : if (!wbuffer) {
380 : 0 : Py_DECREF(r);
381 : 0 : PyErr_NoMemory();
382 : 0 : return NULL;
383 : : }
384 : :
385 : 4 : wchar_t *p1 = wbuffer;
386 : 4 : wchar_t *p2 = p1;
387 [ + + ]: 5 : while ((p2 = wcschr(p1, L'\n')) != NULL) {
388 : 1 : Py_ssize_t cb = p2 - p1;
389 [ + - + + : 2 : while (cb >= 0 && (p1[cb] == L'\n' || p1[cb] == L'\r')) {
- + ]
390 : 1 : --cb;
391 : : }
392 : 1 : PyObject *u = PyUnicode_FromWideChar(p1, cb >= 0 ? cb + 1 : 0);
393 [ + - - + ]: 1 : if (!u || PyList_Append(r, u) < 0) {
394 : 0 : Py_XDECREF(u);
395 [ # # ]: 0 : Py_CLEAR(r);
396 : 0 : break;
397 : : }
398 : 1 : Py_DECREF(u);
399 : 1 : p1 = p2 + 1;
400 : : }
401 [ + - + - : 4 : if (r && p1 && *p1) {
+ + ]
402 : 3 : PyObject *u = PyUnicode_FromWideChar(p1, -1);
403 [ + - - + ]: 3 : if (!u || PyList_Append(r, u) < 0) {
404 [ # # ]: 0 : Py_CLEAR(r);
405 : : }
406 : 3 : Py_XDECREF(u);
407 : : }
408 : 4 : PyMem_RawFree(wbuffer);
409 : 4 : return r;
410 : : }
411 : :
412 : :
413 : : static PyObject *
414 : 25 : getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args)
415 : : {
416 : : PyObject *pathobj;
417 [ - + ]: 25 : if (!PyArg_ParseTuple(args, "U", &pathobj)) {
418 : 0 : return NULL;
419 : : }
420 : : #if defined(HAVE_READLINK)
421 : : /* This readlink calculation only resolves a symlinked file, and
422 : : does not resolve any path segments. This is consistent with
423 : : prior releases, however, the realpath implementation below is
424 : : potentially correct in more cases. */
425 : 25 : PyObject *r = NULL;
426 : 25 : int nlink = 0;
427 : 25 : wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
428 [ - + ]: 25 : if (!path) {
429 : 0 : goto done;
430 : : }
431 : 25 : wchar_t *path2 = _PyMem_RawWcsdup(path);
432 : 25 : PyMem_Free((void *)path);
433 : 25 : path = path2;
434 [ + - ]: 25 : while (path) {
435 : : wchar_t resolved[MAXPATHLEN + 1];
436 : 25 : int linklen = _Py_wreadlink(path, resolved, Py_ARRAY_LENGTH(resolved));
437 [ + - ]: 25 : if (linklen == -1) {
438 : 25 : r = PyUnicode_FromWideChar(path, -1);
439 : 25 : break;
440 : : }
441 [ # # ]: 0 : if (_Py_isabs(resolved)) {
442 : 0 : PyMem_RawFree((void *)path);
443 : 0 : path = _PyMem_RawWcsdup(resolved);
444 : : } else {
445 : 0 : wchar_t *s = wcsrchr(path, SEP);
446 [ # # ]: 0 : if (s) {
447 : 0 : *s = L'\0';
448 : : }
449 : 0 : path2 = _Py_join_relfile(path, resolved);
450 [ # # ]: 0 : if (path2) {
451 : 0 : path2 = _Py_normpath(path2, -1);
452 : : }
453 : 0 : PyMem_RawFree((void *)path);
454 : 0 : path = path2;
455 : : }
456 : 0 : nlink++;
457 : : /* 40 is the Linux kernel 4.2 limit */
458 [ # # ]: 0 : if (nlink >= 40) {
459 : 0 : PyErr_SetString(PyExc_OSError, "maximum number of symbolic links reached");
460 : 0 : break;
461 : : }
462 : : }
463 [ + - ]: 25 : if (!path) {
464 : 0 : PyErr_NoMemory();
465 : : }
466 : 25 : done:
467 : 25 : PyMem_RawFree((void *)path);
468 : 25 : return r;
469 : :
470 : : #elif defined(HAVE_REALPATH)
471 : : PyObject *r = NULL;
472 : : struct stat st;
473 : : const char *narrow = NULL;
474 : : wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
475 : : if (!path) {
476 : : goto done;
477 : : }
478 : : narrow = Py_EncodeLocale(path, NULL);
479 : : if (!narrow) {
480 : : PyErr_NoMemory();
481 : : goto done;
482 : : }
483 : : if (lstat(narrow, &st)) {
484 : : PyErr_SetFromErrno(PyExc_OSError);
485 : : goto done;
486 : : }
487 : : if (!S_ISLNK(st.st_mode)) {
488 : : r = Py_NewRef(pathobj);
489 : : goto done;
490 : : }
491 : : wchar_t resolved[MAXPATHLEN+1];
492 : : if (_Py_wrealpath(path, resolved, MAXPATHLEN) == NULL) {
493 : : PyErr_SetFromErrno(PyExc_OSError);
494 : : } else {
495 : : r = PyUnicode_FromWideChar(resolved, -1);
496 : : }
497 : : done:
498 : : PyMem_Free((void *)path);
499 : : PyMem_Free((void *)narrow);
500 : : return r;
501 : : #endif
502 : :
503 : : return Py_NewRef(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 : 0 : getpath_warn(PyObject *Py_UNUSED(self), PyObject *args)
528 : : {
529 : : PyObject *msgobj;
530 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "U", &msgobj)) {
531 : 0 : return NULL;
532 : : }
533 : 0 : fprintf(stderr, "%s\n", PyUnicode_AsUTF8(msgobj));
534 : 0 : 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 : 25 : funcs_to_dict(PyObject *dict, int warnings)
551 : : {
552 [ + + ]: 300 : for (PyMethodDef *m = getpath_methods; m->ml_name; ++m) {
553 : 275 : PyObject *f = PyCFunction_NewEx(m, NULL, NULL);
554 [ - + ]: 275 : if (!f) {
555 : 0 : return 0;
556 : : }
557 [ - + ]: 275 : if (PyDict_SetItemString(dict, m->ml_name, f) < 0) {
558 : 0 : Py_DECREF(f);
559 : 0 : return 0;
560 : : }
561 : 275 : Py_DECREF(f);
562 : : }
563 [ + + ]: 25 : PyMethodDef *m2 = warnings ? &getpath_warn_method : &getpath_nowarn_method;
564 : 25 : PyObject *f = PyCFunction_NewEx(m2, NULL, NULL);
565 [ - + ]: 25 : if (!f) {
566 : 0 : return 0;
567 : : }
568 [ - + ]: 25 : if (PyDict_SetItemString(dict, m2->ml_name, f) < 0) {
569 : 0 : Py_DECREF(f);
570 : 0 : return 0;
571 : : }
572 : 25 : Py_DECREF(f);
573 : 25 : return 1;
574 : : }
575 : :
576 : :
577 : : /* Add a wide-character string constant to the dict */
578 : : static int
579 : 75 : wchar_to_dict(PyObject *dict, const char *key, const wchar_t *s)
580 : : {
581 : : PyObject *u;
582 : : int r;
583 [ - + - - ]: 75 : if (s && s[0]) {
584 : 0 : u = PyUnicode_FromWideChar(s, -1);
585 [ # # ]: 0 : if (!u) {
586 : 0 : return 0;
587 : : }
588 : : } else {
589 : 75 : u = Py_NewRef(Py_None);
590 : : }
591 : 75 : r = PyDict_SetItemString(dict, key, u) == 0;
592 : 75 : Py_DECREF(u);
593 : 75 : return r;
594 : : }
595 : :
596 : :
597 : : /* Add a narrow string constant to the dict, using default locale decoding */
598 : : static int
599 : 200 : decode_to_dict(PyObject *dict, const char *key, const char *s)
600 : : {
601 : 200 : PyObject *u = NULL;
602 : : int r;
603 [ + + + + ]: 300 : if (s && s[0]) {
604 : : size_t len;
605 : 100 : const wchar_t *w = Py_DecodeLocale(s, &len);
606 [ + - ]: 100 : if (w) {
607 : 100 : u = PyUnicode_FromWideChar(w, len);
608 : 100 : PyMem_RawFree((void *)w);
609 : : }
610 [ - + ]: 100 : if (!u) {
611 : 0 : return 0;
612 : : }
613 : : } else {
614 : 100 : u = Py_NewRef(Py_None);
615 : : }
616 : 200 : r = PyDict_SetItemString(dict, key, u) == 0;
617 : 200 : Py_DECREF(u);
618 : 200 : return r;
619 : : }
620 : :
621 : : /* Add an environment variable to the dict, optionally clearing it afterwards */
622 : : static int
623 : 100 : env_to_dict(PyObject *dict, const char *key, int and_clear)
624 : : {
625 : 100 : PyObject *u = NULL;
626 : 100 : int r = 0;
627 : : assert(strncmp(key, "ENV_", 4) == 0);
628 : : assert(strlen(key) < 64);
629 : : #ifdef MS_WINDOWS
630 : : wchar_t wkey[64];
631 : : // Quick convert to wchar_t, since we know key is ASCII
632 : : wchar_t *wp = wkey;
633 : : for (const char *p = &key[4]; *p; ++p) {
634 : : assert(*p < 128);
635 : : *wp++ = *p;
636 : : }
637 : : *wp = L'\0';
638 : : const wchar_t *v = _wgetenv(wkey);
639 : : if (v) {
640 : : u = PyUnicode_FromWideChar(v, -1);
641 : : if (!u) {
642 : : PyErr_Clear();
643 : : }
644 : : }
645 : : #else
646 : 100 : const char *v = getenv(&key[4]);
647 [ + + ]: 100 : if (v) {
648 : : size_t len;
649 : 25 : const wchar_t *w = Py_DecodeLocale(v, &len);
650 [ + - ]: 25 : if (w) {
651 : 25 : u = PyUnicode_FromWideChar(w, len);
652 [ - + ]: 25 : if (!u) {
653 : 0 : PyErr_Clear();
654 : : }
655 : 25 : PyMem_RawFree((void *)w);
656 : : }
657 : : }
658 : : #endif
659 [ + + ]: 100 : if (u) {
660 : 25 : r = PyDict_SetItemString(dict, key, u) == 0;
661 : 25 : Py_DECREF(u);
662 : : } else {
663 : 75 : r = PyDict_SetItemString(dict, key, Py_None) == 0;
664 : : }
665 [ + - + + ]: 100 : if (r && and_clear) {
666 : : #ifdef MS_WINDOWS
667 : : _wputenv_s(wkey, L"");
668 : : #else
669 : 25 : unsetenv(&key[4]);
670 : : #endif
671 : : }
672 : 100 : return r;
673 : : }
674 : :
675 : :
676 : : /* Add an integer constant to the dict */
677 : : static int
678 : 75 : int_to_dict(PyObject *dict, const char *key, int v)
679 : : {
680 : : PyObject *o;
681 : : int r;
682 : 75 : o = PyLong_FromLong(v);
683 [ - + ]: 75 : if (!o) {
684 : 0 : return 0;
685 : : }
686 : 75 : r = PyDict_SetItemString(dict, key, o) == 0;
687 : 75 : Py_DECREF(o);
688 : 75 : return r;
689 : : }
690 : :
691 : :
692 : : #ifdef MS_WINDOWS
693 : : static int
694 : : winmodule_to_dict(PyObject *dict, const char *key, HMODULE mod)
695 : : {
696 : : wchar_t *buffer = NULL;
697 : : for (DWORD cch = 256; buffer == NULL && cch < (1024 * 1024); cch *= 2) {
698 : : buffer = (wchar_t*)PyMem_RawMalloc(cch * sizeof(wchar_t));
699 : : if (buffer) {
700 : : if (GetModuleFileNameW(mod, buffer, cch) == cch) {
701 : : PyMem_RawFree(buffer);
702 : : buffer = NULL;
703 : : }
704 : : }
705 : : }
706 : : int r = wchar_to_dict(dict, key, buffer);
707 : : PyMem_RawFree(buffer);
708 : : return r;
709 : : }
710 : : #endif
711 : :
712 : :
713 : : /* Add the current executable's path to the dict */
714 : : static int
715 : 25 : progname_to_dict(PyObject *dict, const char *key)
716 : : {
717 : : #ifdef MS_WINDOWS
718 : : return winmodule_to_dict(dict, key, NULL);
719 : : #elif defined(__APPLE__)
720 : : char *path;
721 : : uint32_t pathLen = 256;
722 : : while (pathLen) {
723 : : path = PyMem_RawMalloc((pathLen + 1) * sizeof(char));
724 : : if (!path) {
725 : : return 0;
726 : : }
727 : : if (_NSGetExecutablePath(path, &pathLen) != 0) {
728 : : PyMem_RawFree(path);
729 : : continue;
730 : : }
731 : : // Only keep if the path is absolute
732 : : if (path[0] == SEP) {
733 : : int r = decode_to_dict(dict, key, path);
734 : : PyMem_RawFree(path);
735 : : return r;
736 : : }
737 : : // Fall back and store None
738 : : PyMem_RawFree(path);
739 : : break;
740 : : }
741 : : #endif
742 : 25 : return PyDict_SetItemString(dict, key, Py_None) == 0;
743 : : }
744 : :
745 : :
746 : : /* Add the runtime library's path to the dict */
747 : : static int
748 : 25 : library_to_dict(PyObject *dict, const char *key)
749 : : {
750 : : #ifdef MS_WINDOWS
751 : : #ifdef Py_ENABLE_SHARED
752 : : extern HMODULE PyWin_DLLhModule;
753 : : if (PyWin_DLLhModule) {
754 : : return winmodule_to_dict(dict, key, PyWin_DLLhModule);
755 : : }
756 : : #endif
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 : 25 : return PyDict_SetItemString(dict, key, Py_None) == 0;
786 : : }
787 : :
788 : :
789 : : PyObject *
790 : 25 : _Py_Get_Getpath_CodeObject(void)
791 : : {
792 : 25 : 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 : 71 : _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
814 : : {
815 : 71 : PyStatus status = _PyPathConfig_ReadGlobal(config);
816 : :
817 [ + - + + ]: 71 : if (_PyStatus_EXCEPTION(status) || !compute_path_config) {
818 : 46 : return status;
819 : : }
820 : :
821 [ - + ]: 25 : if (!_PyThreadState_UncheckedGet()) {
822 : 0 : return PyStatus_Error("cannot calculate path configuration without GIL");
823 : : }
824 : :
825 : 25 : PyObject *configDict = _PyConfig_AsDict(config);
826 [ - + ]: 25 : if (!configDict) {
827 : 0 : PyErr_Clear();
828 : 0 : return PyStatus_NoMemory();
829 : : }
830 : :
831 : 25 : PyObject *dict = PyDict_New();
832 [ - + ]: 25 : if (!dict) {
833 : 0 : PyErr_Clear();
834 : 0 : Py_DECREF(configDict);
835 : 0 : return PyStatus_NoMemory();
836 : : }
837 : :
838 [ - + ]: 25 : 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 : 25 : Py_DECREF(configDict);
846 : :
847 : 25 : PyObject *co = _Py_Get_Getpath_CodeObject();
848 [ + - - + ]: 25 : 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 [ + - ]: 25 : 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 [ + - ]: 50 : !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 [ + - ]: 50 : !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 0) ||
883 : : #endif
884 [ + - ]: 50 : !decode_to_dict(dict, "PREFIX", PREFIX) ||
885 [ + - ]: 50 : !decode_to_dict(dict, "EXEC_PREFIX", EXEC_PREFIX) ||
886 [ + - ]: 50 : !decode_to_dict(dict, "PYTHONPATH", PYTHONPATH) ||
887 [ + - ]: 50 : !decode_to_dict(dict, "VPATH", VPATH) ||
888 [ + - ]: 50 : !decode_to_dict(dict, "PLATLIBDIR", PLATLIBDIR) ||
889 [ + - ]: 50 : !decode_to_dict(dict, "PYDEBUGEXT", PYDEBUGEXT) ||
890 [ + - ]: 50 : !int_to_dict(dict, "VERSION_MAJOR", PY_MAJOR_VERSION) ||
891 [ + - ]: 50 : !int_to_dict(dict, "VERSION_MINOR", PY_MINOR_VERSION) ||
892 [ + - ]: 50 : !decode_to_dict(dict, "PYWINVER", PYWINVER) ||
893 [ + - ]: 50 : !wchar_to_dict(dict, "EXE_SUFFIX", EXE_SUFFIX) ||
894 [ + - ]: 50 : !env_to_dict(dict, "ENV_PATH", 0) ||
895 [ + - ]: 50 : !env_to_dict(dict, "ENV_PYTHONHOME", 0) ||
896 [ + - ]: 50 : !env_to_dict(dict, "ENV_PYTHONEXECUTABLE", 0) ||
897 [ + - ]: 50 : !env_to_dict(dict, "ENV___PYVENV_LAUNCHER__", 1) ||
898 [ + - ]: 50 : !progname_to_dict(dict, "real_executable") ||
899 [ + - ]: 50 : !library_to_dict(dict, "library") ||
900 [ + - ]: 50 : !wchar_to_dict(dict, "executable_dir", NULL) ||
901 [ + - ]: 50 : !wchar_to_dict(dict, "py_setpath", _PyPathConfig_GetGlobalModuleSearchPath()) ||
902 [ + - ]: 50 : !funcs_to_dict(dict, config->pathconfig_warnings) ||
903 : : #ifndef MS_WINDOWS
904 [ - + ]: 50 : PyDict_SetItemString(dict, "winreg", Py_None) < 0 ||
905 : : #endif
906 : 25 : 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 : 25 : PyObject *r = PyEval_EvalCode(co, dict, dict);
915 : 25 : Py_DECREF(co);
916 : :
917 [ - + ]: 25 : 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 : 25 : 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 [ - + ]: 25 : 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 : 25 : Py_DECREF(dict);
948 : :
949 : 25 : return _PyStatus_OK();
950 : : }
951 : :
|