pathconfig.c 13 KB

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