@@ -370,12 +370,15 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
370
370
const wchar_t * argv0_path ,
371
371
wchar_t * prefix , size_t prefix_len , int * found )
372
372
{
373
+ wchar_t path [MAXPATHLEN + 1 ];
374
+ memset (path , 0 , sizeof (path ));
375
+ size_t path_len = Py_ARRAY_LENGTH (path );
376
+
373
377
PyStatus status ;
374
- size_t n ;
375
- wchar_t * vpath ;
376
378
377
379
/* If PYTHONHOME is set, we believe it unconditionally */
378
380
if (pathconfig -> home ) {
381
+ /* Path: <home> / <lib_python> */
379
382
if (safe_wcscpy (prefix , pathconfig -> home , prefix_len ) < 0 ) {
380
383
return PATHLEN_ERR ();
381
384
}
@@ -387,27 +390,25 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
387
390
if (_PyStatus_EXCEPTION (status )) {
388
391
return status ;
389
392
}
390
- status = joinpath (prefix , LANDMARK , prefix_len );
391
- if (_PyStatus_EXCEPTION (status )) {
392
- return status ;
393
- }
394
393
* found = 1 ;
395
394
return _PyStatus_OK ();
396
395
}
397
396
398
397
/* Check to see if argv[0] is in the build directory */
399
- if (safe_wcscpy (prefix , argv0_path , prefix_len ) < 0 ) {
398
+ if (safe_wcscpy (path , argv0_path , path_len ) < 0 ) {
400
399
return PATHLEN_ERR ();
401
400
}
402
- status = joinpath (prefix , L"Modules/Setup.local" , prefix_len );
401
+ status = joinpath (path , L"Modules/Setup.local" , path_len );
403
402
if (_PyStatus_EXCEPTION (status )) {
404
403
return status ;
405
404
}
406
405
407
- if (isfile (prefix )) {
408
- /* Check VPATH to see if argv0_path is in the build directory. */
409
- vpath = Py_DecodeLocale (VPATH , NULL );
406
+ if (isfile (path )) {
407
+ /* Check VPATH to see if argv0_path is in the build directory.
408
+ VPATH can be empty. */
409
+ wchar_t * vpath = Py_DecodeLocale (VPATH , NULL );
410
410
if (vpath != NULL ) {
411
+ /* Path: <argv0_path> / <vpath> / Lib / LANDMARK */
411
412
if (safe_wcscpy (prefix , argv0_path , prefix_len ) < 0 ) {
412
413
return PATHLEN_ERR ();
413
414
}
@@ -428,6 +429,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
428
429
429
430
if (ismodule (prefix , prefix_len )) {
430
431
* found = -1 ;
432
+ reduce (prefix );
431
433
return _PyStatus_OK ();
432
434
}
433
435
}
@@ -440,7 +442,8 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
440
442
}
441
443
442
444
do {
443
- n = wcslen (prefix );
445
+ /* Path: <argv0_path or substring> / <lib_python> / LANDMARK */
446
+ size_t n = wcslen (prefix );
444
447
status = joinpath (prefix , calculate -> lib_python , prefix_len );
445
448
if (_PyStatus_EXCEPTION (status )) {
446
449
return status ;
@@ -452,13 +455,15 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
452
455
453
456
if (ismodule (prefix , prefix_len )) {
454
457
* found = 1 ;
458
+ reduce (prefix );
455
459
return _PyStatus_OK ();
456
460
}
457
461
prefix [n ] = L'\0' ;
458
462
reduce (prefix );
459
463
} while (prefix [0 ]);
460
464
461
- /* Look at configure's PREFIX */
465
+ /* Look at configure's PREFIX.
466
+ Path: <PREFIX macro> / <lib_python> / LANDMARK */
462
467
if (safe_wcscpy (prefix , calculate -> prefix , prefix_len ) < 0 ) {
463
468
return PATHLEN_ERR ();
464
469
}
@@ -473,6 +478,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
473
478
474
479
if (ismodule (prefix , prefix_len )) {
475
480
* found = 1 ;
481
+ reduce (prefix );
476
482
return _PyStatus_OK ();
477
483
}
478
484
@@ -509,9 +515,6 @@ calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
509
515
return status ;
510
516
}
511
517
}
512
- else {
513
- reduce (prefix );
514
- }
515
518
return _PyStatus_OK ();
516
519
}
517
520
@@ -546,6 +549,67 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
546
549
}
547
550
548
551
552
+ static PyStatus
553
+ calculate_pybuilddir (const wchar_t * argv0_path ,
554
+ wchar_t * exec_prefix , size_t exec_prefix_len ,
555
+ int * found )
556
+ {
557
+ PyStatus status ;
558
+
559
+ wchar_t filename [MAXPATHLEN + 1 ];
560
+ memset (filename , 0 , sizeof (filename ));
561
+ size_t filename_len = Py_ARRAY_LENGTH (filename );
562
+
563
+ /* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
564
+ is written by setup.py and contains the relative path to the location
565
+ of shared library modules.
566
+
567
+ Filename: <argv0_path> / "pybuilddir.txt" */
568
+ if (safe_wcscpy (filename , argv0_path , filename_len ) < 0 ) {
569
+ return PATHLEN_ERR ();
570
+ }
571
+ status = joinpath (filename , L"pybuilddir.txt" , filename_len );
572
+ if (_PyStatus_EXCEPTION (status )) {
573
+ return status ;
574
+ }
575
+
576
+ if (!isfile (filename )) {
577
+ return _PyStatus_OK ();
578
+ }
579
+
580
+ FILE * fp = _Py_wfopen (filename , L"rb" );
581
+ if (fp == NULL ) {
582
+ errno = 0 ;
583
+ return _PyStatus_OK ();
584
+ }
585
+
586
+ char buf [MAXPATHLEN + 1 ];
587
+ size_t n = fread (buf , 1 , Py_ARRAY_LENGTH (buf ) - 1 , fp );
588
+ buf [n ] = '\0' ;
589
+ fclose (fp );
590
+
591
+ size_t dec_len ;
592
+ wchar_t * pybuilddir = _Py_DecodeUTF8_surrogateescape (buf , n , & dec_len );
593
+ if (!pybuilddir ) {
594
+ return DECODE_LOCALE_ERR ("pybuilddir.txt" , dec_len );
595
+ }
596
+
597
+ /* Path: <argv0_path> / <pybuilddir content> */
598
+ if (safe_wcscpy (exec_prefix , argv0_path , exec_prefix_len ) < 0 ) {
599
+ PyMem_RawFree (pybuilddir );
600
+ return PATHLEN_ERR ();
601
+ }
602
+ status = joinpath (exec_prefix , pybuilddir , exec_prefix_len );
603
+ PyMem_RawFree (pybuilddir );
604
+ if (_PyStatus_EXCEPTION (status )) {
605
+ return status ;
606
+ }
607
+
608
+ * found = -1 ;
609
+ return _PyStatus_OK ();
610
+ }
611
+
612
+
549
613
/* search_for_exec_prefix requires that argv0_path be no more than
550
614
MAXPATHLEN bytes long.
551
615
*/
@@ -556,10 +620,10 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
556
620
int * found )
557
621
{
558
622
PyStatus status ;
559
- size_t n ;
560
623
561
624
/* If PYTHONHOME is set, we believe it unconditionally */
562
625
if (pathconfig -> home ) {
626
+ /* Path: <home> / <lib_python> / "lib-dynload" */
563
627
wchar_t * delim = wcschr (pathconfig -> home , DELIM );
564
628
if (delim ) {
565
629
if (safe_wcscpy (exec_prefix , delim + 1 , exec_prefix_len ) < 0 ) {
@@ -583,47 +647,15 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
583
647
return _PyStatus_OK ();
584
648
}
585
649
586
- /* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
587
- is written by setup.py and contains the relative path to the location
588
- of shared library modules. */
589
- if (safe_wcscpy (exec_prefix , argv0_path , exec_prefix_len ) < 0 ) {
590
- return PATHLEN_ERR ();
591
- }
592
- status = joinpath (exec_prefix , L"pybuilddir.txt" , exec_prefix_len );
650
+ /* Check for pybuilddir.txt */
651
+ assert (* found == 0 );
652
+ status = calculate_pybuilddir (argv0_path , exec_prefix , exec_prefix_len ,
653
+ found );
593
654
if (_PyStatus_EXCEPTION (status )) {
594
655
return status ;
595
656
}
596
-
597
- if (isfile (exec_prefix )) {
598
- FILE * f = _Py_wfopen (exec_prefix , L"rb" );
599
- if (f == NULL ) {
600
- errno = 0 ;
601
- }
602
- else {
603
- char buf [MAXPATHLEN + 1 ];
604
- n = fread (buf , 1 , Py_ARRAY_LENGTH (buf ) - 1 , f );
605
- buf [n ] = '\0' ;
606
- fclose (f );
607
-
608
- wchar_t * pybuilddir ;
609
- size_t dec_len ;
610
- pybuilddir = _Py_DecodeUTF8_surrogateescape (buf , n , & dec_len );
611
- if (!pybuilddir ) {
612
- return DECODE_LOCALE_ERR ("pybuilddir.txt" , dec_len );
613
- }
614
-
615
- if (safe_wcscpy (exec_prefix , argv0_path , exec_prefix_len ) < 0 ) {
616
- return PATHLEN_ERR ();
617
- }
618
- status = joinpath (exec_prefix , pybuilddir , exec_prefix_len );
619
- PyMem_RawFree (pybuilddir );
620
- if (_PyStatus_EXCEPTION (status )) {
621
- return status ;
622
- }
623
-
624
- * found = -1 ;
625
- return _PyStatus_OK ();
626
- }
657
+ if (* found ) {
658
+ return _PyStatus_OK ();
627
659
}
628
660
629
661
/* Search from argv0_path, until root is found */
@@ -633,7 +665,8 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
633
665
}
634
666
635
667
do {
636
- n = wcslen (exec_prefix );
668
+ /* Path: <argv0_path or substring> / <lib_python> / "lib-dynload" */
669
+ size_t n = wcslen (exec_prefix );
637
670
status = joinpath (exec_prefix , calculate -> lib_python , exec_prefix_len );
638
671
if (_PyStatus_EXCEPTION (status )) {
639
672
return status ;
@@ -650,7 +683,9 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
650
683
reduce (exec_prefix );
651
684
} while (exec_prefix [0 ]);
652
685
653
- /* Look at configure's EXEC_PREFIX */
686
+ /* Look at configure's EXEC_PREFIX.
687
+
688
+ Path: <EXEC_PREFIX macro> / <lib_python> / "lib-dynload" */
654
689
if (safe_wcscpy (exec_prefix , calculate -> exec_prefix , exec_prefix_len ) < 0 ) {
655
690
return PATHLEN_ERR ();
656
691
}
@@ -962,43 +997,49 @@ calculate_read_pyenv(PyCalculatePath *calculate,
962
997
wchar_t * argv0_path , size_t argv0_path_len )
963
998
{
964
999
PyStatus status ;
965
- wchar_t tmpbuffer [MAXPATHLEN + 1 ];
966
- const size_t buflen = Py_ARRAY_LENGTH (tmpbuffer );
967
- wchar_t * env_cfg = L"pyvenv.cfg" ;
1000
+ const wchar_t * env_cfg = L"pyvenv.cfg" ;
968
1001
FILE * env_file ;
969
1002
970
- if (safe_wcscpy (tmpbuffer , argv0_path , buflen ) < 0 ) {
1003
+ wchar_t filename [MAXPATHLEN + 1 ];
1004
+ const size_t filename_len = Py_ARRAY_LENGTH (filename );
1005
+ memset (filename , 0 , sizeof (filename ));
1006
+
1007
+ /* Filename: <argv0_path_len> / "pyvenv.cfg" */
1008
+ if (safe_wcscpy (filename , argv0_path , filename_len ) < 0 ) {
971
1009
return PATHLEN_ERR ();
972
1010
}
973
1011
974
- status = joinpath (tmpbuffer , env_cfg , buflen );
1012
+ status = joinpath (filename , env_cfg , filename_len );
975
1013
if (_PyStatus_EXCEPTION (status )) {
976
1014
return status ;
977
1015
}
978
- env_file = _Py_wfopen (tmpbuffer , L"r" );
1016
+ env_file = _Py_wfopen (filename , L"r" );
979
1017
if (env_file == NULL ) {
980
1018
errno = 0 ;
981
1019
982
- reduce (tmpbuffer );
983
- reduce (tmpbuffer );
984
- status = joinpath (tmpbuffer , env_cfg , buflen );
1020
+ /* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
1021
+ reduce (filename );
1022
+ reduce (filename );
1023
+ status = joinpath (filename , env_cfg , filename_len );
985
1024
if (_PyStatus_EXCEPTION (status )) {
986
1025
return status ;
987
1026
}
988
1027
989
- env_file = _Py_wfopen (tmpbuffer , L"r" );
1028
+ env_file = _Py_wfopen (filename , L"r" );
990
1029
if (env_file == NULL ) {
991
1030
errno = 0 ;
1031
+ return _PyStatus_OK ();
992
1032
}
993
1033
}
994
1034
995
- if (env_file == NULL ) {
996
- return _PyStatus_OK ();
997
- }
998
-
999
1035
/* Look for a 'home' variable and set argv0_path to it, if found */
1000
- if (_Py_FindEnvConfigValue (env_file , L"home" , tmpbuffer , buflen )) {
1001
- if (safe_wcscpy (argv0_path , tmpbuffer , argv0_path_len ) < 0 ) {
1036
+ wchar_t home [MAXPATHLEN + 1 ];
1037
+ memset (home , 0 , sizeof (home ));
1038
+
1039
+ if (_Py_FindEnvConfigValue (env_file , L"home" ,
1040
+ home , Py_ARRAY_LENGTH (home ))) {
1041
+ if (safe_wcscpy (argv0_path , home , argv0_path_len ) < 0 ) {
1042
+ fclose (env_file );
1002
1043
return PATHLEN_ERR ();
1003
1044
}
1004
1045
}
@@ -1200,6 +1241,8 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
1200
1241
return status ;
1201
1242
}
1202
1243
1244
+ /* If a pyvenv.cfg configure file is found,
1245
+ argv0_path is overriden with its 'home' variable. */
1203
1246
status = calculate_read_pyenv (calculate ,
1204
1247
argv0_path , Py_ARRAY_LENGTH (argv0_path ));
1205
1248
if (_PyStatus_EXCEPTION (status )) {
0 commit comments