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