/home/mdboom/Work/builds/cpython/Python/pathconfig.c
Line | Count | Source (jump to first uncovered line) |
1 | /* Path configuration like module_search_path (sys.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 | #ifdef MS_WINDOWS |
12 | # include <windows.h> // GetFullPathNameW(), MAX_PATH |
13 | # include <pathcch.h> |
14 | # include <shlwapi.h> |
15 | #endif |
16 | |
17 | #ifdef __cplusplus |
18 | extern "C" { |
19 | #endif |
20 | |
21 | |
22 | /* External interface */ |
23 | |
24 | /* Stored values set by C API functions */ |
25 | typedef struct _PyPathConfig { |
26 | /* Full path to the Python program */ |
27 | wchar_t *program_full_path; |
28 | wchar_t *prefix; |
29 | wchar_t *exec_prefix; |
30 | wchar_t *stdlib_dir; |
31 | /* Set by Py_SetPath */ |
32 | wchar_t *module_search_path; |
33 | /* Set by _PyPathConfig_UpdateGlobal */ |
34 | wchar_t *calculated_module_search_path; |
35 | /* Python program name */ |
36 | wchar_t *program_name; |
37 | /* Set by Py_SetPythonHome() or PYTHONHOME environment variable */ |
38 | wchar_t *home; |
39 | int _is_python_build; |
40 | } _PyPathConfig; |
41 | |
42 | # define _PyPathConfig_INIT \ |
43 | {.module_search_path = NULL, ._is_python_build = 0} |
44 | |
45 | |
46 | _PyPathConfig _Py_path_config = _PyPathConfig_INIT; |
47 | |
48 | |
49 | const wchar_t * |
50 | _PyPathConfig_GetGlobalModuleSearchPath(void) |
51 | { |
52 | return _Py_path_config.module_search_path; |
53 | } |
54 | |
55 | |
56 | void |
57 | _PyPathConfig_ClearGlobal(void) |
58 | { |
59 | PyMemAllocatorEx old_alloc; |
60 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
61 | |
62 | #define CLEAR(ATTR) \ |
63 | do { \ |
64 | PyMem_RawFree(_Py_path_config.ATTR); \ |
65 | _Py_path_config.ATTR = NULL; \ |
66 | } while (0) |
67 | |
68 | CLEAR(program_full_path); |
69 | CLEAR(prefix); |
70 | CLEAR(exec_prefix); |
71 | CLEAR(stdlib_dir); |
72 | CLEAR(module_search_path); |
73 | CLEAR(calculated_module_search_path); |
74 | CLEAR(program_name); |
75 | CLEAR(home); |
76 | _Py_path_config._is_python_build = 0; |
77 | |
78 | #undef CLEAR |
79 | |
80 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
81 | } |
82 | |
83 | PyStatus |
84 | _PyPathConfig_ReadGlobal(PyConfig *config) |
85 | { |
86 | PyStatus status = _PyStatus_OK(); |
87 | |
88 | #define COPY(ATTR) \ |
89 | do { \ |
90 | if (_Py_path_config.ATTR && !config->ATTR932 ) { \ |
91 | status = PyConfig_SetString(config, &config->ATTR, _Py_path_config.ATTR); \ |
92 | if (_PyStatus_EXCEPTION(status)) goto done0 ; \ |
93 | } \ |
94 | } while (0) |
95 | |
96 | #define COPY2(ATTR, SRCATTR) \ |
97 | do { \ |
98 | if (_Py_path_config.SRCATTR && !config->ATTR227 ) { \ |
99 | status = PyConfig_SetString(config, &config->ATTR, _Py_path_config.SRCATTR); \ |
100 | if (_PyStatus_EXCEPTION(status)) goto done0 ; \ |
101 | } \ |
102 | } while (0) |
103 | |
104 | #define COPY_INT(ATTR) \ |
105 | do { \ |
106 | assert(_Py_path_config.ATTR >= 0); \ |
107 | if ((_Py_path_config.ATTR >= 0) && (config->ATTR <= 0)) { \ |
108 | config->ATTR = _Py_path_config.ATTR; \ |
109 | } \ |
110 | } while (0) |
111 | |
112 | COPY(prefix); |
113 | COPY(exec_prefix); |
114 | COPY(stdlib_dir); |
115 | COPY(program_name); |
116 | COPY(home); |
117 | COPY2(executable, program_full_path); |
118 | COPY_INT(_is_python_build); |
119 | // module_search_path must be initialised - not read |
120 | #undef COPY |
121 | #undef COPY2 |
122 | #undef COPY_INT |
123 | |
124 | done: |
125 | return status; |
126 | } |
127 | |
128 | PyStatus |
129 | _PyPathConfig_UpdateGlobal(const PyConfig *config) |
130 | { |
131 | PyMemAllocatorEx old_alloc; |
132 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
133 | |
134 | #define COPY(ATTR) \ |
135 | do { \ |
136 | if (config->ATTR) { \ |
137 | PyMem_RawFree(_Py_path_config.ATTR); \ |
138 | _Py_path_config.ATTR = _PyMem_RawWcsdup(config->ATTR); \ |
139 | if (!_Py_path_config.ATTR) goto error0 ; \ |
140 | } \ |
141 | } while (0) |
142 | |
143 | #define COPY2(ATTR, SRCATTR) \ |
144 | do { \ |
145 | if (config->SRCATTR) { \ |
146 | PyMem_RawFree(_Py_path_config.ATTR); \ |
147 | _Py_path_config.ATTR = _PyMem_RawWcsdup(config->SRCATTR); \ |
148 | if (!_Py_path_config.ATTR) goto error0 ; \ |
149 | } \ |
150 | } while (0) |
151 | |
152 | #define COPY_INT(ATTR) \ |
153 | do { \ |
154 | if (config->ATTR > 0) { \ |
155 | _Py_path_config.ATTR = config->ATTR; \ |
156 | } \ |
157 | } while (0) |
158 | |
159 | COPY(prefix); |
160 | COPY(exec_prefix); |
161 | COPY(stdlib_dir); |
162 | COPY(program_name); |
163 | COPY(home); |
164 | COPY2(program_full_path, executable); |
165 | COPY_INT(_is_python_build); |
166 | #undef COPY |
167 | #undef COPY2 |
168 | #undef COPY_INT |
169 | |
170 | PyMem_RawFree(_Py_path_config.module_search_path); |
171 | _Py_path_config.module_search_path = NULL; |
172 | PyMem_RawFree(_Py_path_config.calculated_module_search_path); |
173 | _Py_path_config.calculated_module_search_path = NULL; |
174 | |
175 | do { |
176 | size_t cch = 1; |
177 | for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i435 ) { Branch (177:32): [True: 435, False: 139]
|
178 | cch += 1 + wcslen(config->module_search_paths.items[i]); |
179 | } |
180 | |
181 | wchar_t *path = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t) * cch); |
182 | if (!path) { Branch (182:13): [True: 0, False: 139]
|
183 | goto error; |
184 | } |
185 | wchar_t *p = path; |
186 | for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i435 ) { Branch (186:32): [True: 435, False: 139]
|
187 | wcscpy(p, config->module_search_paths.items[i]); |
188 | p = wcschr(p, L'\0'); |
189 | *p++ = DELIM; |
190 | *p = L'\0'; |
191 | } |
192 | |
193 | do { |
194 | *p = L'\0'; |
195 | } while (p != path && *--p == 272 DELIM272 ); Branch (195:18): [True: 272, False: 3]
Branch (195:31): [True: 136, False: 136]
|
196 | _Py_path_config.calculated_module_search_path = path; |
197 | } while (0); Branch (197:14): [Folded - Ignored]
|
198 | |
199 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
200 | return _PyStatus_OK(); |
201 | |
202 | error: |
203 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
204 | return _PyStatus_NO_MEMORY(); |
205 | } |
206 | |
207 | |
208 | static void _Py_NO_RETURN |
209 | path_out_of_memory(const char *func) |
210 | { |
211 | _Py_FatalErrorFunc(func, "out of memory"); |
212 | } |
213 | |
214 | void |
215 | Py_SetPath(const wchar_t *path) |
216 | { |
217 | if (path == NULL) { Branch (217:9): [True: 0, False: 2]
|
218 | _PyPathConfig_ClearGlobal(); |
219 | return; |
220 | } |
221 | |
222 | PyMemAllocatorEx old_alloc; |
223 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
224 | |
225 | PyMem_RawFree(_Py_path_config.prefix); |
226 | PyMem_RawFree(_Py_path_config.exec_prefix); |
227 | PyMem_RawFree(_Py_path_config.stdlib_dir); |
228 | PyMem_RawFree(_Py_path_config.module_search_path); |
229 | PyMem_RawFree(_Py_path_config.calculated_module_search_path); |
230 | |
231 | _Py_path_config.prefix = _PyMem_RawWcsdup(L""); |
232 | _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L""); |
233 | // XXX Copy this from the new module_search_path? |
234 | if (_Py_path_config.home != NULL) { Branch (234:9): [True: 0, False: 2]
|
235 | _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(_Py_path_config.home); |
236 | } |
237 | else { |
238 | _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(L""); |
239 | } |
240 | _Py_path_config.module_search_path = _PyMem_RawWcsdup(path); |
241 | _Py_path_config.calculated_module_search_path = NULL; |
242 | |
243 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
244 | |
245 | if (_Py_path_config.prefix == NULL Branch (245:9): [True: 0, False: 2]
|
246 | || _Py_path_config.exec_prefix == NULL Branch (246:12): [True: 0, False: 2]
|
247 | || _Py_path_config.stdlib_dir == NULL Branch (247:12): [True: 0, False: 2]
|
248 | || _Py_path_config.module_search_path == NULL) Branch (248:12): [True: 0, False: 2]
|
249 | { |
250 | path_out_of_memory(__func__); |
251 | } |
252 | } |
253 | |
254 | |
255 | void |
256 | Py_SetPythonHome(const wchar_t *home) |
257 | { |
258 | int has_value = home && home[0]; Branch (258:21): [True: 1, False: 0]
Branch (258:29): [True: 1, False: 0]
|
259 | |
260 | PyMemAllocatorEx old_alloc; |
261 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
262 | |
263 | PyMem_RawFree(_Py_path_config.home); |
264 | if (has_value) { Branch (264:9): [True: 1, False: 0]
|
265 | _Py_path_config.home = _PyMem_RawWcsdup(home); |
266 | } |
267 | |
268 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
269 | |
270 | if (has_value && _Py_path_config.home == NULL) { Branch (270:9): [True: 1, False: 0]
Branch (270:22): [True: 0, False: 1]
|
271 | path_out_of_memory(__func__); |
272 | } |
273 | } |
274 | |
275 | |
276 | void |
277 | Py_SetProgramName(const wchar_t *program_name) |
278 | { |
279 | int has_value = program_name && program_name[0]; Branch (279:21): [True: 3, False: 0]
Branch (279:37): [True: 3, False: 0]
|
280 | |
281 | PyMemAllocatorEx old_alloc; |
282 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
283 | |
284 | PyMem_RawFree(_Py_path_config.program_name); |
285 | if (has_value) { Branch (285:9): [True: 3, False: 0]
|
286 | _Py_path_config.program_name = _PyMem_RawWcsdup(program_name); |
287 | } |
288 | |
289 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
290 | |
291 | if (has_value && _Py_path_config.program_name == NULL) { Branch (291:9): [True: 3, False: 0]
Branch (291:22): [True: 0, False: 3]
|
292 | path_out_of_memory(__func__); |
293 | } |
294 | } |
295 | |
296 | void |
297 | _Py_SetProgramFullPath(const wchar_t *program_full_path) |
298 | { |
299 | int has_value = program_full_path && program_full_path[0]; Branch (299:21): [True: 0, False: 0]
Branch (299:42): [True: 0, False: 0]
|
300 |
|
301 | PyMemAllocatorEx old_alloc; |
302 | _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
303 |
|
304 | PyMem_RawFree(_Py_path_config.program_full_path); |
305 | if (has_value) { Branch (305:9): [True: 0, False: 0]
|
306 | _Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path); |
307 | } |
308 |
|
309 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); |
310 |
|
311 | if (has_value && _Py_path_config.program_full_path == NULL) { Branch (311:9): [True: 0, False: 0]
Branch (311:22): [True: 0, False: 0]
|
312 | path_out_of_memory(__func__); |
313 | } |
314 | } |
315 | |
316 | |
317 | wchar_t * |
318 | Py_GetPath(void) |
319 | { |
320 | /* If the user has provided a path, return that */ |
321 | if (_Py_path_config.module_search_path) { Branch (321:9): [True: 0, False: 1]
|
322 | return _Py_path_config.module_search_path; |
323 | } |
324 | /* If we have already done calculations, return the calculated path */ |
325 | return _Py_path_config.calculated_module_search_path; |
326 | } |
327 | |
328 | |
329 | wchar_t * |
330 | _Py_GetStdlibDir(void) |
331 | { |
332 | wchar_t *stdlib_dir = _Py_path_config.stdlib_dir; |
333 | if (stdlib_dir != NULL && stdlib_dir[0] != L'\0') { Branch (333:9): [True: 280, False: 0]
Branch (333:31): [True: 278, False: 2]
|
334 | return stdlib_dir; |
335 | } |
336 | return NULL; |
337 | } |
338 | |
339 | |
340 | wchar_t * |
341 | Py_GetPrefix(void) |
342 | { |
343 | return _Py_path_config.prefix; |
344 | } |
345 | |
346 | |
347 | wchar_t * |
348 | Py_GetExecPrefix(void) |
349 | { |
350 | return _Py_path_config.exec_prefix; |
351 | } |
352 | |
353 | |
354 | wchar_t * |
355 | Py_GetProgramFullPath(void) |
356 | { |
357 | return _Py_path_config.program_full_path; |
358 | } |
359 | |
360 | |
361 | wchar_t* |
362 | Py_GetPythonHome(void) |
363 | { |
364 | return _Py_path_config.home; |
365 | } |
366 | |
367 | |
368 | wchar_t * |
369 | Py_GetProgramName(void) |
370 | { |
371 | return _Py_path_config.program_name; |
372 | } |
373 | |
374 | |
375 | |
376 | /* Compute module search path from argv[0] or the current working |
377 | directory ("-m module" case) which will be prepended to sys.argv: |
378 | sys.path[0]. |
379 | |
380 | Return 1 if the path is correctly resolved and written into *path0_p. |
381 | |
382 | Return 0 if it fails to resolve the full path. For example, return 0 if the |
383 | current working directory has been removed (bpo-36236) or if argv is empty. |
384 | |
385 | Raise an exception and return -1 on error. |
386 | */ |
387 | int |
388 | _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p) |
389 | { |
390 | assert(_PyWideStringList_CheckConsistency(argv)); |
391 | |
392 | if (argv->length == 0) { Branch (392:9): [True: 0, False: 25]
|
393 | /* Leave sys.path unchanged if sys.argv is empty */ |
394 | return 0; |
395 | } |
396 | |
397 | wchar_t *argv0 = argv->items[0]; |
398 | int have_module_arg = (wcscmp(argv0, L"-m") == 0); |
399 | int have_script_arg = (!have_module_arg && (wcscmp(argv0, L"-c") != 0)24 ); Branch (399:28): [True: 24, False: 1]
Branch (399:48): [True: 4, False: 20]
|
400 | |
401 | wchar_t *path0 = argv0; |
402 | Py_ssize_t n = 0; |
403 | |
404 | #ifdef HAVE_REALPATH |
405 | wchar_t fullpath[MAXPATHLEN]; |
406 | #elif defined(MS_WINDOWS) |
407 | wchar_t fullpath[MAX_PATH]; |
408 | #endif |
409 | |
410 | if (have_module_arg) { Branch (410:9): [True: 1, False: 24]
|
411 | #if defined(HAVE_REALPATH) || defined(MS_WINDOWS) |
412 | if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) { Branch (412:13): [True: 0, False: 1]
|
413 | return 0; |
414 | } |
415 | path0 = fullpath; |
416 | #else |
417 | path0 = L"."; |
418 | #endif |
419 | n = wcslen(path0); |
420 | } |
421 | |
422 | #ifdef HAVE_READLINK |
423 | wchar_t link[MAXPATHLEN + 1]; |
424 | int nr = 0; |
425 | wchar_t path0copy[2 * MAXPATHLEN + 1]; |
426 | |
427 | if (have_script_arg) { Branch (427:9): [True: 4, False: 21]
|
428 | nr = _Py_wreadlink(path0, link, Py_ARRAY_LENGTH(link)); |
429 | } |
430 | if (nr > 0) { Branch (430:9): [True: 0, False: 25]
|
431 | /* It's a symlink */ |
432 | link[nr] = '\0'; |
433 | if (link[0] == SEP) { Branch (433:13): [True: 0, False: 0]
|
434 | path0 = link; /* Link to absolute path */ |
435 | } |
436 | else if (wcschr(link, SEP) == NULL) { Branch (436:18): [True: 0, False: 0]
|
437 | /* Link without path */ |
438 | } |
439 | else { |
440 | /* Must join(dirname(path0), link) */ |
441 | wchar_t *q = wcsrchr(path0, SEP); |
442 | if (q == NULL) { Branch (442:17): [True: 0, False: 0]
|
443 | /* path0 without path */ |
444 | path0 = link; |
445 | } |
446 | else { |
447 | /* Must make a copy, path0copy has room for 2 * MAXPATHLEN */ |
448 | wcsncpy(path0copy, path0, MAXPATHLEN); |
449 | q = wcsrchr(path0copy, SEP); |
450 | wcsncpy(q+1, link, MAXPATHLEN); |
451 | q[MAXPATHLEN + 1] = L'\0'; |
452 | path0 = path0copy; |
453 | } |
454 | } |
455 | } |
456 | #endif /* HAVE_READLINK */ |
457 | |
458 | wchar_t *p = NULL; |
459 | |
460 | #if SEP == '\\' |
461 | /* Special case for Microsoft filename syntax */ |
462 | if (have_script_arg) { |
463 | wchar_t *q; |
464 | #if defined(MS_WINDOWS) |
465 | /* Replace the first element in argv with the full path. */ |
466 | wchar_t *ptemp; |
467 | if (GetFullPathNameW(path0, |
468 | Py_ARRAY_LENGTH(fullpath), |
469 | fullpath, |
470 | &ptemp)) { |
471 | path0 = fullpath; |
472 | } |
473 | #endif |
474 | p = wcsrchr(path0, SEP); |
475 | /* Test for alternate separator */ |
476 | q = wcsrchr(p ? p : path0, '/'); |
477 | if (q != NULL) |
478 | p = q; |
479 | if (p != NULL) { |
480 | n = p + 1 - path0; |
481 | if (n > 1 && p[-1] != ':') |
482 | n--; /* Drop trailing separator */ |
483 | } |
484 | } |
485 | #else |
486 | /* All other filename syntaxes */ |
487 | if (have_script_arg) { Branch (487:9): [True: 4, False: 21]
|
488 | #if defined(HAVE_REALPATH) |
489 | if (_Py_wrealpath(path0, fullpath, Py_ARRAY_LENGTH(fullpath))) { Branch (489:13): [True: 0, False: 4]
|
490 | path0 = fullpath; |
491 | } |
492 | #endif |
493 | p = wcsrchr(path0, SEP); |
494 | } |
495 | if (p != NULL) { Branch (495:9): [True: 0, False: 25]
|
496 | n = p + 1 - path0; |
497 | #if SEP == '/' /* Special case for Unix filename syntax */ |
498 | if (n > 1) { Branch (498:13): [True: 0, False: 0]
|
499 | /* Drop trailing separator */ |
500 | n--; |
501 | } |
502 | #endif /* Unix */ |
503 | } |
504 | #endif /* All others */ |
505 | |
506 | PyObject *path0_obj = PyUnicode_FromWideChar(path0, n); |
507 | if (path0_obj == NULL) { Branch (507:9): [True: 0, False: 25]
|
508 | return -1; |
509 | } |
510 | |
511 | *path0_p = path0_obj; |
512 | return 1; |
513 | } |
514 | |
515 | |
516 | #ifdef __cplusplus |
517 | } |
518 | #endif |