/home/mdboom/Work/builds/cpython/Modules/getpath.c
Line | Count | Source (jump to first uncovered line) |
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)) { Branch (63:9): [True: 0, False: 104]
|
64 | return NULL; |
65 | } |
66 | Py_ssize_t len; |
67 | path = PyUnicode_AsWideCharString(pathobj, &len); |
68 | if (path) { Branch (68:9): [True: 104, False: 0]
|
69 | wchar_t *abs; |
70 | if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) { Branch (70:13): [True: 104, False: 0]
Branch (70:80): [True: 104, False: 0]
|
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 | const char *path; |
86 | if (!PyArg_ParseTuple(args, "s", &path)) { Branch (86:9): [True: 0, False: 0]
|
87 | return NULL; |
88 | } |
89 | const char *name = strrchr(path, SEP); |
90 | return PyUnicode_FromString(name ? name + 1 : path); Branch (90:33): [True: 0, False: 0]
|
91 | } |
92 | |
93 | |
94 | static PyObject * |
95 | getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args) |
96 | { |
97 | const char *path; |
98 | if (!PyArg_ParseTuple(args, "s", &path)) { Branch (98:9): [True: 0, False: 814]
|
99 | return NULL; |
100 | } |
101 | const char *name = strrchr(path, SEP); |
102 | if (!name) { Branch (102:9): [True: 2, False: 812]
|
103 | return PyUnicode_FromStringAndSize(NULL, 0); |
104 | } |
105 | return PyUnicode_FromStringAndSize(path, (name - path)); |
106 | } |
107 | |
108 | |
109 | static PyObject * |
110 | getpath_isabs(PyObject *Py_UNUSED(self), PyObject *args) |
111 | { |
112 | PyObject *r = NULL; |
113 | PyObject *pathobj; |
114 | const wchar_t *path; |
115 | if (!PyArg_ParseTuple(args, "U", &pathobj)) { Branch (115:9): [True: 0, False: 0]
|
116 | return NULL; |
117 | } |
118 | path = PyUnicode_AsWideCharString(pathobj, NULL); |
119 | if (path) { Branch (119:9): [True: 0, False: 0]
|
120 | r = _Py_isabs(path) ? Py_True : Py_False; Branch (120:13): [True: 0, False: 0]
|
121 | PyMem_Free((void *)path); |
122 | } |
123 | Py_XINCREF(r); |
124 | return r; |
125 | } |
126 | |
127 | |
128 | static PyObject * |
129 | getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args) |
130 | { |
131 | PyObject *r = NULL; |
132 | PyObject *pathobj; |
133 | PyObject *suffixobj; |
134 | const wchar_t *path; |
135 | const wchar_t *suffix; |
136 | if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) { Branch (136:9): [True: 0, False: 0]
|
137 | return NULL; |
138 | } |
139 | Py_ssize_t len, suffixLen; |
140 | path = PyUnicode_AsWideCharString(pathobj, &len); |
141 | if (path) { Branch (141:9): [True: 0, False: 0]
|
142 | suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen); |
143 | if (suffix) { Branch (143:13): [True: 0, False: 0]
|
144 | if (suffixLen > len || Branch (144:17): [True: 0, False: 0]
|
145 | #ifdef MS_WINDOWS |
146 | wcsicmp(&path[len - suffixLen], suffix) != 0 |
147 | #else |
148 | wcscmp(&path[len - suffixLen], suffix) != 0 Branch (148:17): [True: 0, False: 0]
|
149 | #endif |
150 | ) { |
151 | r = Py_False; |
152 | } else { |
153 | r = Py_True; |
154 | } |
155 | Py_INCREF(r); |
156 | PyMem_Free((void *)suffix); |
157 | } |
158 | PyMem_Free((void *)path); |
159 | } |
160 | return r; |
161 | } |
162 | |
163 | |
164 | static PyObject * |
165 | getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args) |
166 | { |
167 | PyObject *r = NULL; |
168 | PyObject *pathobj; |
169 | const wchar_t *path; |
170 | if (!PyArg_ParseTuple(args, "U", &pathobj)) { Branch (170:9): [True: 0, False: 0]
|
171 | return NULL; |
172 | } |
173 | path = PyUnicode_AsWideCharString(pathobj, NULL); |
174 | if (path) { Branch (174:9): [True: 0, False: 0]
|
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 | r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False; Branch (181:13): [True: 0, False: 0]
|
182 | #endif |
183 | PyMem_Free((void *)path); |
184 | } |
185 | Py_XINCREF(r); |
186 | return r; |
187 | } |
188 | |
189 | |
190 | static PyObject * |
191 | getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args) |
192 | { |
193 | PyObject *r = NULL; |
194 | PyObject *pathobj; |
195 | const wchar_t *path; |
196 | if (!PyArg_ParseTuple(args, "U", &pathobj)) { Branch (196:9): [True: 0, False: 274]
|
197 | return NULL; |
198 | } |
199 | path = PyUnicode_AsWideCharString(pathobj, NULL); |
200 | if (path) { Branch (200:9): [True: 274, False: 0]
|
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 | r = (_Py_wstat(path, &st) == 0) && S_ISREG(st.st_mode) ? Py_True : Py_False; Branch (207:13): [True: 274, False: 0]
|
208 | #endif |
209 | PyMem_Free((void *)path); |
210 | } |
211 | Py_XINCREF(r); |
212 | return r; |
213 | } |
214 | |
215 | |
216 | static PyObject * |
217 | getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args) |
218 | { |
219 | PyObject *r = NULL; |
220 | PyObject *pathobj; |
221 | const wchar_t *path; |
222 | Py_ssize_t cchPath; |
223 | if (!PyArg_ParseTuple(args, "U", &pathobj)) { Branch (223:9): [True: 0, False: 194]
|
224 | return NULL; |
225 | } |
226 | path = PyUnicode_AsWideCharString(pathobj, &cchPath); |
227 | if (path) { Branch (227:9): [True: 194, False: 0]
|
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 | r = (_Py_wstat(path, &st) == 0) && Branch (238:13): [True: 2, False: 192]
|
239 | S_ISREG(st.st_mode) && |
240 | (st.st_mode & 0111)2 Branch (240:13): [True: 2, False: 0]
|
241 | ? Py_True : Py_False; |
242 | #endif |
243 | PyMem_Free((void *)path); |
244 | } |
245 | Py_XINCREF(r); |
246 | return r; |
247 | } |
248 | |
249 | |
250 | static PyObject * |
251 | getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) |
252 | { |
253 | if (!PyTuple_Check(args)) { Branch (253:9): [True: 0, False: 2.22k]
|
254 | PyErr_SetString(PyExc_TypeError, "requires tuple of arguments"); |
255 | return NULL; |
256 | } |
257 | Py_ssize_t n = PyTuple_GET_SIZE(args); |
258 | if (n == 0) { Branch (258:9): [True: 0, False: 2.22k]
|
259 | return PyUnicode_FromString(NULL); |
260 | } |
261 | /* Convert all parts to wchar and accumulate max final length */ |
262 | wchar_t **parts = (wchar_t **)PyMem_Malloc(n * sizeof(wchar_t *)); |
263 | memset(parts, 0, n * sizeof(wchar_t *)); |
264 | Py_ssize_t cchFinal = 0; |
265 | Py_ssize_t first = 0; |
266 | |
267 | for (Py_ssize_t i = 0; i < n; ++i4.44k ) { Branch (267:28): [True: 4.44k, False: 2.22k]
|
268 | PyObject *s = PyTuple_GET_ITEM(args, i); |
269 | Py_ssize_t cch; |
270 | if (s == Py_None) { Branch (270:13): [True: 274, False: 4.16k]
|
271 | cch = 0; |
272 | } else if (PyUnicode_Check(s)) { |
273 | parts[i] = PyUnicode_AsWideCharString(s, &cch); |
274 | if (!parts[i]) { Branch (274:17): [True: 0, False: 4.16k]
|
275 | cchFinal = -1; |
276 | break; |
277 | } |
278 | if (_Py_isabs(parts[i])) { Branch (278:17): [True: 2.22k, False: 1.94k]
|
279 | first = i; |
280 | } |
281 | } else { |
282 | PyErr_SetString(PyExc_TypeError, "all arguments to joinpath() must be str or None"); |
283 | cchFinal = -1; |
284 | break; |
285 | } |
286 | cchFinal += cch + 1; |
287 | } |
288 | |
289 | wchar_t *final = cchFinal > 0 ? (wchar_t *)PyMem_Malloc(cchFinal * sizeof(wchar_t)) : NULL; Branch (289:22): [True: 2.22k, False: 0]
|
290 | if (!final) { Branch (290:9): [True: 0, False: 2.22k]
|
291 | for (Py_ssize_t i = 0; i < n; ++i) { Branch (291:32): [True: 0, False: 0]
|
292 | PyMem_Free(parts[i]); |
293 | } |
294 | PyMem_Free(parts); |
295 | if (cchFinal) { Branch (295:13): [True: 0, False: 0]
|
296 | PyErr_NoMemory(); |
297 | return NULL; |
298 | } |
299 | return PyUnicode_FromStringAndSize(NULL, 0); |
300 | } |
301 | |
302 | final[0] = '\0'; |
303 | /* Now join all the paths. The final result should be shorter than the buffer */ |
304 | for (Py_ssize_t i = 0; i < n; ++i4.44k ) { Branch (304:28): [True: 4.44k, False: 2.22k]
|
305 | if (!parts[i]) { Branch (305:13): [True: 274, False: 4.16k]
|
306 | continue; |
307 | } |
308 | if (i >= first && final) { Branch (308:13): [True: 4.16k, False: 0]
Branch (308:27): [True: 4.16k, False: 0]
|
309 | if (!final[0]) { Branch (309:17): [True: 2.22k, False: 1.94k]
|
310 | /* final is definitely long enough to fit any individual part */ |
311 | wcscpy(final, parts[i]); |
312 | } else if (1.94k _Py_add_relfile(final, parts[i], cchFinal) < 01.94k ) { Branch (312:24): [True: 0, False: 1.94k]
|
313 | /* if we fail, keep iterating to free memory, but stop adding parts */ |
314 | PyMem_Free(final); |
315 | final = NULL; |
316 | } |
317 | } |
318 | PyMem_Free(parts[i]); |
319 | } |
320 | PyMem_Free(parts); |
321 | if (!final) { Branch (321:9): [True: 0, False: 2.22k]
|
322 | PyErr_SetString(PyExc_SystemError, "failed to join paths"); |
323 | return NULL; |
324 | } |
325 | PyObject *r = PyUnicode_FromWideChar(_Py_normpath(final, -1), -1); |
326 | PyMem_Free(final); |
327 | return r; |
328 | } |
329 | |
330 | |
331 | static PyObject * |
332 | getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) |
333 | { |
334 | PyObject *r = NULL; |
335 | PyObject *pathobj; |
336 | const wchar_t *path; |
337 | if (!PyArg_ParseTuple(args, "U", &pathobj)) { Branch (337:9): [True: 0, False: 1.35k]
|
338 | return NULL; |
339 | } |
340 | path = PyUnicode_AsWideCharString(pathobj, NULL); |
341 | if (!path) { Branch (341:9): [True: 0, False: 1.35k]
|
342 | return NULL; |
343 | } |
344 | FILE *fp = _Py_wfopen(path, L"rb"); |
345 | PyMem_Free((void *)path); |
346 | if (!fp) { Branch (346:9): [True: 1.07k, False: 274]
|
347 | PyErr_SetFromErrno(PyExc_OSError); |
348 | return NULL; |
349 | } |
350 | |
351 | r = PyList_New(0); |
352 | if (!r) { Branch (352:9): [True: 0, False: 274]
|
353 | fclose(fp); |
354 | return NULL; |
355 | } |
356 | const size_t MAX_FILE = 32 * 1024; |
357 | char *buffer = (char *)PyMem_Malloc(MAX_FILE); |
358 | if (!buffer) { Branch (358:9): [True: 0, False: 274]
|
359 | Py_DECREF(r); |
360 | fclose(fp); |
361 | return NULL; |
362 | } |
363 | |
364 | size_t cb = fread(buffer, 1, MAX_FILE, fp); |
365 | fclose(fp); |
366 | if (!cb) { Branch (366:9): [True: 0, False: 274]
|
367 | return r; |
368 | } |
369 | if (cb >= MAX_FILE) { Branch (369:9): [True: 0, False: 274]
|
370 | Py_DECREF(r); |
371 | PyErr_SetString(PyExc_MemoryError, |
372 | "cannot read file larger than 32KB during initialization"); |
373 | return NULL; |
374 | } |
375 | buffer[cb] = '\0'; |
376 | |
377 | size_t len; |
378 | wchar_t *wbuffer = _Py_DecodeUTF8_surrogateescape(buffer, cb, &len); |
379 | PyMem_Free((void *)buffer); |
380 | if (!wbuffer) { Branch (380:9): [True: 0, False: 274]
|
381 | Py_DECREF(r); |
382 | PyErr_NoMemory(); |
383 | return NULL; |
384 | } |
385 | |
386 | wchar_t *p1 = wbuffer; |
387 | wchar_t *p2 = p1; |
388 | while ((p2 = wcschr(p1, L'\n')) != NULL) { Branch (388:12): [True: 0, False: 274]
|
389 | Py_ssize_t cb = p2 - p1; |
390 | while (cb >= 0 && (p1[cb] == L'\n' || p1[cb] == L'\r')) { Branch (390:16): [True: 0, False: 0]
Branch (390:28): [True: 0, False: 0]
Branch (390:47): [True: 0, False: 0]
|
391 | --cb; |
392 | } |
393 | PyObject *u = PyUnicode_FromWideChar(p1, cb >= 0 ? cb + 1 : 0); Branch (393:50): [True: 0, False: 0]
|
394 | if (!u || PyList_Append(r, u) < 0) { Branch (394:13): [True: 0, False: 0]
Branch (394:19): [True: 0, False: 0]
|
395 | Py_XDECREF(u); |
396 | Py_CLEAR(r); |
397 | break; |
398 | } |
399 | Py_DECREF(u); |
400 | p1 = p2 + 1; |
401 | } |
402 | if (r && p1 && *p1) { Branch (402:9): [True: 274, False: 0]
Branch (402:14): [True: 274, False: 0]
Branch (402:20): [True: 274, False: 0]
|
403 | PyObject *u = PyUnicode_FromWideChar(p1, -1); |
404 | if (!u || PyList_Append(r, u) < 0) { Branch (404:13): [True: 0, False: 274]
Branch (404:19): [True: 0, False: 274]
|
405 | Py_CLEAR(r); |
406 | } |
407 | Py_XDECREF(u); |
408 | } |
409 | PyMem_RawFree(wbuffer); |
410 | return r; |
411 | } |
412 | |
413 | |
414 | static PyObject * |
415 | getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) |
416 | { |
417 | PyObject *pathobj; |
418 | if (!PyArg_ParseTuple(args, "U", &pathobj)) { Branch (418:9): [True: 0, False: 279]
|
419 | 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 | PyObject *r = NULL; |
427 | int nlink = 0; |
428 | wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL); |
429 | if (!path) { Branch (429:9): [True: 0, False: 279]
|
430 | goto done; |
431 | } |
432 | wchar_t *path2 = _PyMem_RawWcsdup(path); |
433 | PyMem_Free((void *)path); |
434 | path = path2; |
435 | while (path) { Branch (435:12): [True: 279, False: 0]
|
436 | wchar_t resolved[MAXPATHLEN + 1]; |
437 | int linklen = _Py_wreadlink(path, resolved, Py_ARRAY_LENGTH(resolved)); |
438 | if (linklen == -1) { Branch (438:13): [True: 279, False: 0]
|
439 | r = PyUnicode_FromWideChar(path, -1); |
440 | break; |
441 | } |
442 | if (_Py_isabs(resolved)) { Branch (442:13): [True: 0, False: 0]
|
443 | PyMem_RawFree((void *)path); |
444 | path = _PyMem_RawWcsdup(resolved); |
445 | } else { |
446 | wchar_t *s = wcsrchr(path, SEP); |
447 | if (s) { Branch (447:17): [True: 0, False: 0]
|
448 | *s = L'\0'; |
449 | } |
450 | path2 = _Py_normpath(_Py_join_relfile(path, resolved), -1); |
451 | PyMem_RawFree((void *)path); |
452 | path = path2; |
453 | } |
454 | nlink++; |
455 | /* 40 is the Linux kernel 4.2 limit */ |
456 | if (nlink >= 40) { Branch (456:13): [True: 0, False: 0]
|
457 | PyErr_SetString(PyExc_OSError, "maximum number of symbolic links reached"); |
458 | break; |
459 | } |
460 | } |
461 | if (!path) { Branch (461:9): [True: 0, False: 279]
|
462 | PyErr_NoMemory(); |
463 | } |
464 | done: |
465 | PyMem_RawFree((void *)path); |
466 | 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 | getpath_warn(PyObject *Py_UNUSED(self), PyObject *args) |
528 | { |
529 | PyObject *msgobj; |
530 | if (!PyArg_ParseTuple(args, "U", &msgobj)) { Branch (530:9): [True: 0, False: 0]
|
531 | return NULL; |
532 | } |
533 | fprintf(stderr, "%s\n", PyUnicode_AsUTF8(msgobj)); |
534 | Py_RETURN_NONE; |
535 | } |
536 | |
537 | |
538 | static PyObject * |
539 | getpath_nowarn(PyObject *Py_UNUSED(self), PyObject *args) |
540 | { |
541 | 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 | funcs_to_dict(PyObject *dict, int warnings) |
551 | { |
552 | for (PyMethodDef *m = getpath_methods; m->ml_name; ++m3.06k ) { Branch (552:44): [True: 3.06k, False: 279]
|
553 | PyObject *f = PyCFunction_NewEx(m, NULL, NULL); |
554 | if (!f) { Branch (554:13): [True: 0, False: 3.06k]
|
555 | return 0; |
556 | } |
557 | if (PyDict_SetItemString(dict, m->ml_name, f) < 0) { Branch (557:13): [True: 0, False: 3.06k]
|
558 | Py_DECREF(f); |
559 | return 0; |
560 | } |
561 | Py_DECREF(f); |
562 | } |
563 | PyMethodDef *m2 = warnings ? &getpath_warn_method271 : &getpath_nowarn_method8 ; Branch (563:23): [True: 271, False: 8]
|
564 | PyObject *f = PyCFunction_NewEx(m2, NULL, NULL); |
565 | if (!f) { Branch (565:9): [True: 0, False: 279]
|
566 | return 0; |
567 | } |
568 | if (PyDict_SetItemString(dict, m2->ml_name, f) < 0) { Branch (568:9): [True: 0, False: 279]
|
569 | Py_DECREF(f); |
570 | return 0; |
571 | } |
572 | Py_DECREF(f); |
573 | return 1; |
574 | } |
575 | |
576 | |
577 | /* Add a wide-character string constant to the dict */ |
578 | static int |
579 | wchar_to_dict(PyObject *dict, const char *key, const wchar_t *s) |
580 | { |
581 | PyObject *u; |
582 | int r; |
583 | if (s && s[0]2 ) { Branch (583:9): [True: 2, False: 835]
Branch (583:14): [True: 2, False: 0]
|
584 | u = PyUnicode_FromWideChar(s, -1); |
585 | if (!u) { Branch (585:13): [True: 0, False: 2]
|
586 | return 0; |
587 | } |
588 | } else { |
589 | u = Py_None; |
590 | Py_INCREF(u); |
591 | } |
592 | r = PyDict_SetItemString(dict, key, u) == 0; |
593 | Py_DECREF(u); |
594 | return r; |
595 | } |
596 | |
597 | |
598 | /* Add a narrow string constant to the dict, using default locale decoding */ |
599 | static int |
600 | decode_to_dict(PyObject *dict, const char *key, const char *s) |
601 | { |
602 | PyObject *u = NULL; |
603 | int r; |
604 | if (s && s[0]1.67k ) { Branch (604:9): [True: 1.67k, False: 558]
Branch (604:14): [True: 1.11k, False: 558]
|
605 | size_t len; |
606 | const wchar_t *w = Py_DecodeLocale(s, &len); |
607 | if (w) { Branch (607:13): [True: 1.11k, False: 0]
|
608 | u = PyUnicode_FromWideChar(w, len); |
609 | PyMem_RawFree((void *)w); |
610 | } |
611 | if (!u) { Branch (611:13): [True: 0, False: 1.11k]
|
612 | return 0; |
613 | } |
614 | } else { |
615 | u = Py_None; |
616 | Py_INCREF(u); |
617 | } |
618 | r = PyDict_SetItemString(dict, key, u) == 0; |
619 | Py_DECREF(u); |
620 | return r; |
621 | } |
622 | |
623 | /* Add an environment variable to the dict, optionally clearing it afterwards */ |
624 | static int |
625 | env_to_dict(PyObject *dict, const char *key, int and_clear) |
626 | { |
627 | PyObject *u = NULL; |
628 | 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 | const char *v = getenv(&key[4]); |
649 | if (v) { Branch (649:9): [True: 279, False: 837]
|
650 | size_t len; |
651 | const wchar_t *w = Py_DecodeLocale(v, &len); |
652 | if (w) { Branch (652:13): [True: 279, False: 0]
|
653 | u = PyUnicode_FromWideChar(w, len); |
654 | if (!u) { Branch (654:17): [True: 0, False: 279]
|
655 | PyErr_Clear(); |
656 | } |
657 | PyMem_RawFree((void *)w); |
658 | } |
659 | } |
660 | #endif |
661 | if (u) { Branch (661:9): [True: 279, False: 837]
|
662 | r = PyDict_SetItemString(dict, key, u) == 0; |
663 | Py_DECREF(u); |
664 | } else { |
665 | r = PyDict_SetItemString(dict, key, Py_None) == 0; |
666 | } |
667 | if (r && and_clear) { Branch (667:9): [True: 1.11k, False: 0]
Branch (667:14): [True: 279, False: 837]
|
668 | #ifdef MS_WINDOWS |
669 | _wputenv_s(wkey, L""); |
670 | #else |
671 | unsetenv(&key[4]); |
672 | #endif |
673 | } |
674 | return r; |
675 | } |
676 | |
677 | |
678 | /* Add an integer constant to the dict */ |
679 | static int |
680 | int_to_dict(PyObject *dict, const char *key, int v) |
681 | { |
682 | PyObject *o; |
683 | int r; |
684 | o = PyLong_FromLong(v); |
685 | if (!o) { Branch (685:9): [True: 0, False: 837]
|
686 | return 0; |
687 | } |
688 | r = PyDict_SetItemString(dict, key, o) == 0; |
689 | Py_DECREF(o); |
690 | 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 | 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 | 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 | 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 | return PyDict_SetItemString(dict, key, Py_None) == 0; |
786 | } |
787 | |
788 | |
789 | PyObject * |
790 | _Py_Get_Getpath_CodeObject(void) |
791 | { |
792 | 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 | _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) |
814 | { |
815 | PyStatus status = _PyPathConfig_ReadGlobal(config); |
816 | |
817 | if (_PyStatus_EXCEPTION(status) || !compute_path_config) { Branch (817:40): [True: 110, False: 279]
|
818 | return status; |
819 | } |
820 | |
821 | if (!_PyThreadState_UncheckedGet()) { Branch (821:9): [True: 0, False: 279]
|
822 | return PyStatus_Error("cannot calculate path configuration without GIL"); |
823 | } |
824 | |
825 | PyObject *configDict = _PyConfig_AsDict(config); |
826 | if (!configDict) { Branch (826:9): [True: 0, False: 279]
|
827 | PyErr_Clear(); |
828 | return PyStatus_NoMemory(); |
829 | } |
830 | |
831 | PyObject *dict = PyDict_New(); |
832 | if (!dict) { Branch (832:9): [True: 0, False: 279]
|
833 | PyErr_Clear(); |
834 | Py_DECREF(configDict); |
835 | return PyStatus_NoMemory(); |
836 | } |
837 | |
838 | if (PyDict_SetItemString(dict, "config", configDict) < 0) { Branch (838:9): [True: 0, False: 279]
|
839 | PyErr_Clear(); |
840 | Py_DECREF(configDict); |
841 | Py_DECREF(dict); |
842 | return PyStatus_NoMemory(); |
843 | } |
844 | /* reference now held by dict */ |
845 | Py_DECREF(configDict); |
846 | |
847 | PyObject *co = _Py_Get_Getpath_CodeObject(); |
848 | if (!co || !PyCode_Check(co)) { Branch (848:9): [True: 0, False: 279]
Branch (848:16): [True: 0, False: 279]
|
849 | PyErr_Clear(); |
850 | Py_XDECREF(co); |
851 | Py_DECREF(dict); |
852 | 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 | 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 | !decode_to_dict(dict, "os_name", "posix") || Branch (877:9): [True: 0, False: 279]
|
878 | #endif |
879 | #ifdef WITH_NEXT_FRAMEWORK |
880 | !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 1) || |
881 | #else |
882 | !int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 0) || Branch (882:9): [True: 0, False: 279]
|
883 | #endif |
884 | !decode_to_dict(dict, "PREFIX", PREFIX) || Branch (884:9): [True: 0, False: 279]
|
885 | !decode_to_dict(dict, "EXEC_PREFIX", EXEC_PREFIX) || Branch (885:9): [True: 0, False: 279]
|
886 | !decode_to_dict(dict, "PYTHONPATH", PYTHONPATH) || Branch (886:9): [True: 0, False: 279]
|
887 | !decode_to_dict(dict, "VPATH", VPATH) || Branch (887:9): [True: 0, False: 279]
|
888 | !decode_to_dict(dict, "PLATLIBDIR", PLATLIBDIR) || Branch (888:9): [True: 0, False: 279]
|
889 | !decode_to_dict(dict, "PYDEBUGEXT", PYDEBUGEXT) || Branch (889:9): [True: 0, False: 279]
|
890 | !int_to_dict(dict, "VERSION_MAJOR", PY_MAJOR_VERSION) || Branch (890:9): [True: 0, False: 279]
|
891 | !int_to_dict(dict, "VERSION_MINOR", PY_MINOR_VERSION) || Branch (891:9): [True: 0, False: 279]
|
892 | !decode_to_dict(dict, "PYWINVER", PYWINVER) || Branch (892:9): [True: 0, False: 279]
|
893 | !wchar_to_dict(dict, "EXE_SUFFIX", EXE_SUFFIX) || Branch (893:9): [True: 0, False: 279]
|
894 | !env_to_dict(dict, "ENV_PATH", 0) || Branch (894:9): [True: 0, False: 279]
|
895 | !env_to_dict(dict, "ENV_PYTHONHOME", 0) || Branch (895:9): [True: 0, False: 279]
|
896 | !env_to_dict(dict, "ENV_PYTHONEXECUTABLE", 0) || Branch (896:9): [True: 0, False: 279]
|
897 | !env_to_dict(dict, "ENV___PYVENV_LAUNCHER__", 1) || Branch (897:9): [True: 0, False: 279]
|
898 | !progname_to_dict(dict, "real_executable") || Branch (898:9): [True: 0, False: 279]
|
899 | !library_to_dict(dict, "library") || Branch (899:9): [True: 0, False: 279]
|
900 | !wchar_to_dict(dict, "executable_dir", NULL) || Branch (900:9): [True: 0, False: 279]
|
901 | !wchar_to_dict(dict, "py_setpath", _PyPathConfig_GetGlobalModuleSearchPath()) || Branch (901:9): [True: 0, False: 279]
|
902 | !funcs_to_dict(dict, config->pathconfig_warnings) || Branch (902:9): [True: 0, False: 279]
|
903 | #ifndef MS_WINDOWS |
904 | PyDict_SetItemString(dict, "winreg", Py_None) < 0 || Branch (904:9): [True: 0, False: 279]
|
905 | #endif |
906 | PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0 Branch (906:9): [True: 0, False: 279]
|
907 | ) { |
908 | Py_DECREF(co); |
909 | Py_DECREF(dict); |
910 | _PyErr_WriteUnraisableMsg("error evaluating initial values", NULL); |
911 | return PyStatus_Error("error evaluating initial values"); |
912 | } |
913 | |
914 | PyObject *r = PyEval_EvalCode(co, dict, dict); |
915 | Py_DECREF(co); |
916 | |
917 | if (!r) { Branch (917:9): [True: 0, False: 279]
|
918 | Py_DECREF(dict); |
919 | _PyErr_WriteUnraisableMsg("error evaluating path", NULL); |
920 | return PyStatus_Error("error evaluating path"); |
921 | } |
922 | 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 | if (_PyConfig_FromDict(config, configDict) < 0) { Branch (941:9): [True: 0, False: 279]
|
942 | _PyErr_WriteUnraisableMsg("reading getpath results", NULL); |
943 | Py_DECREF(dict); |
944 | return PyStatus_Error("error getting getpath results"); |
945 | } |
946 | |
947 | Py_DECREF(dict); |
948 | |
949 | return _PyStatus_OK(); |
950 | } |
951 | |