From afe9fc7a1ffad8f5054050ecdc79203359c55d60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?=
 <alexey.pawlow@gmail.com>
Date: Thu, 17 Jun 2021 18:51:47 +0530
Subject: [PATCH 039/N] mingw use posix getpath
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Алексей <alexey.pawlow@gmail.com>
Co-authored-by: Christoph Reiter <reiter.christoph@gmail.com>
---
 Include/cpython/fileutils.h |   3 +-
 Include/pylifecycle.h       |   2 +-
 Modules/getpath.c           | 131 +++++++++++++++++++++++++++++++++---
 Modules/posixmodule.c       |   2 +-
 Python/dynload_win.c        |   2 +
 Python/fileutils.c          |  22 +++++-
 6 files changed, 146 insertions(+), 16 deletions(-)

diff --git a/Include/cpython/fileutils.h b/Include/cpython/fileutils.h
index e79d03e..c222833 100644
--- a/Include/cpython/fileutils.h
+++ b/Include/cpython/fileutils.h
@@ -136,9 +136,8 @@ PyAPI_FUNC(wchar_t*) _Py_wrealpath(
     size_t resolved_path_len);
 #endif
 
-#ifndef MS_WINDOWS
 PyAPI_FUNC(int) _Py_isabs(const wchar_t *path);
-#endif
+PyAPI_FUNC(int) _Py_issep(const wchar_t ch);
 
 PyAPI_FUNC(int) _Py_abspath(const wchar_t *path, wchar_t **abspath_p);
 
diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h
index 4eec669..b34f110 100644
--- a/Include/pylifecycle.h
+++ b/Include/pylifecycle.h
@@ -55,7 +55,7 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
 PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
 PyAPI_FUNC(wchar_t *) Py_GetPath(void);
 PyAPI_FUNC(void)      Py_SetPath(const wchar_t *);
-#ifdef MS_WINDOWS
+#ifdef _MSC_VER
 int _Py_CheckPython3(void);
 #endif
 
diff --git a/Modules/getpath.c b/Modules/getpath.c
index 728ecad..3010182 100644
--- a/Modules/getpath.c
+++ b/Modules/getpath.c
@@ -13,6 +13,11 @@
 #  include <mach-o/dyld.h>
 #endif
 
+#ifdef MS_WINDOWS
+#include <windows.h>
+#include <shlwapi.h>
+#endif
+
 /* Search in some common locations for the associated Python libraries.
  *
  * Two directories must be found, the platform independent directory
@@ -129,6 +134,7 @@ typedef struct {
     wchar_t *prefix_macro;             /* PREFIX macro */
     wchar_t *exec_prefix_macro;        /* EXEC_PREFIX macro */
     wchar_t *vpath_macro;              /* VPATH macro */
+    wchar_t *dll_path;                 /* DLL Path */
 
     wchar_t *lib_python;               /* <platlibdir> / "pythonX.Y" */
 
@@ -146,7 +152,7 @@ typedef struct {
 } PyCalculatePath;
 
 static const wchar_t delimiter[2] = {DELIM, '\0'};
-static const wchar_t separator[2] = {SEP, '\0'};
+static wchar_t separator[2] = {SEP, '\0'};
 
 
 /* Get file status. Encode the path to the locale encoding. */
@@ -170,7 +176,7 @@ static void
 reduce(wchar_t *dir)
 {
     size_t i = wcslen(dir);
-    while (i > 0 && dir[i] != SEP) {
+    while (i > 0 && !_Py_issep(dir[i])) {
         --i;
     }
     dir[i] = '\0';
@@ -224,6 +230,9 @@ isdir(const wchar_t *filename)
     return 1;
 }
 
+/*
+x86_64-w64-mingw32-gcc -c -Wno-unused-result -Wsign-compare -DNDEBUG  -march=x86-64 -mtune=generic -O2 -pipe -fwrapv -D__USE_MINGW_ANSI_STDIO=1 -D_WIN32_WINNT=0x0601 -DNDEBUG  -DMS_DLL_ID="\"3.9\""   -flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none -g -std=c99 -Wextra -Wno-unused-result -Wno-unused-parameter -Wno-missing-field-initializers -Wstrict-prototypes -Werror=implicit-function-declaration -fvisibility=hidden -fprofile-generate -I../Python-3.9.4/Include/internal -IObjects -IInclude -IPython -I. -I../Python-3.9.4/Include -I../Python-3.9.4/PC -D__USE_MINGW_ANSI_STDIO=1 -IC:/msys64/mingw64/include/ncurses  -I.   -DPy_BUILD_CORE -DPYTHONPATH='""' -DPREFIX='"/mingw64"' -DEXEC_PREFIX='"/mingw64"' -DVERSION='"3.9"' -DVPATH='"../Python-3.9.4"' -o Modules/getpath.o ../Python-3.9.4/Modules/getpath.c
+*/
 
 /* Add a path component, by appending stuff to buffer.
    buflen: 'buffer' length in characters including trailing NUL.
@@ -242,8 +251,8 @@ joinpath(wchar_t *path, const wchar_t *path2, size_t path_len)
             return PATHLEN_ERR();
         }
 
-        if (n > 0 && path[n-1] != SEP) {
-            path[n++] = SEP;
+        if (n > 0 && !_Py_issep(path[n-1])) {
+            path[n++] = Py_GetSepW(path);
         }
     }
     else {
@@ -285,7 +294,7 @@ joinpath2(const wchar_t *path, const wchar_t *path2)
     }
 
     size_t len = wcslen(path);
-    int add_sep = (len > 0 && path[len - 1] != SEP);
+    int add_sep = (len > 0 && !_Py_issep(path[len - 1]));
     len += add_sep;
     len += wcslen(path2);
 
@@ -334,7 +343,7 @@ copy_absolute(wchar_t *abs_path, const wchar_t *path, size_t abs_path_len)
             }
             return _PyStatus_OK();
         }
-        if (path[0] == '.' && path[1] == SEP) {
+        if (path[0] == '.' && _Py_issep(path[1])) {
             path += 2;
         }
         PyStatus status = joinpath(abs_path, path, abs_path_len);
@@ -478,6 +487,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
         return _PyStatus_NO_MEMORY();
     }
 
+    Py_NormalizeSepsW(path);
     int is_build_dir = isfile(path);
     PyMem_RawFree(path);
 
@@ -502,6 +512,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
         }
 
         int module;
+        Py_NormalizeSepsW(prefix);
         status = ismodule(prefix, &module);
         if (_PyStatus_EXCEPTION(status)) {
             return status;
@@ -528,6 +539,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
         }
 
         int module;
+        Py_NormalizeSepsW(prefix);
         status = ismodule(prefix, &module);
         if (_PyStatus_EXCEPTION(status)) {
             return status;
@@ -551,6 +563,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
     }
 
     int module;
+    Py_NormalizeSepsW(prefix);
     status = ismodule(prefix, &module);
     if (_PyStatus_EXCEPTION(status)) {
         return status;
@@ -610,6 +623,11 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
      * return the compiled-in defaults instead.
      */
     if (calculate->prefix_found > 0) {
+#ifdef MS_WINDOWS
+        wchar_t drive_root[3];
+        memset(drive_root, 0, sizeof(drive_root));
+        wcsncpy(drive_root, calculate->prefix, 3);
+#endif
         wchar_t *prefix = _PyMem_RawWcsdup(calculate->prefix);
         if (prefix == NULL) {
             return _PyStatus_NO_MEMORY();
@@ -625,7 +643,11 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
 
             /* The prefix is the root directory, but reduce() chopped
                off the "/". */
+#ifdef MS_WINDOWS
+            pathconfig->prefix = _PyMem_RawWcsdup(drive_root);
+#else
             pathconfig->prefix = _PyMem_RawWcsdup(separator);
+#endif
             if (pathconfig->prefix == NULL) {
                 return _PyStatus_NO_MEMORY();
             }
@@ -682,6 +704,7 @@ calculate_pybuilddir(const wchar_t *argv0_path,
         return PATHLEN_ERR();
     }
     status = joinpath(exec_prefix, pybuilddir, exec_prefix_len);
+    Py_NormalizeSepsW(exec_prefix);
     PyMem_RawFree(pybuilddir);
     if (_PyStatus_EXCEPTION(status)) {
         return status;
@@ -730,6 +753,7 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
 
     /* Check for pybuilddir.txt */
     assert(*found == 0);
+    Py_NormalizeSepsW(exec_prefix);
     status = calculate_pybuilddir(calculate->argv0_path,
                                   exec_prefix, exec_prefix_len, found);
     if (_PyStatus_EXCEPTION(status)) {
@@ -804,6 +828,7 @@ calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
         return status;
     }
 
+    Py_NormalizeSepsW(exec_prefix);
     if (!calculate->exec_prefix_found) {
         if (calculate->warnings) {
             fprintf(stderr,
@@ -836,6 +861,47 @@ calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
 }
 
 
+#ifdef MS_WINDOWS
+wchar_t *
+GetWindowsModulePaths(void)
+{
+    int result = 0;
+    wchar_t program_full_path[MAXPATHLEN+1];
+    memset(program_full_path, 0, sizeof(program_full_path));
+
+    if (GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
+        result = 1;
+        Py_NormalizeSepsW(program_full_path);
+    }
+
+    return _PyMem_RawWcsdup(program_full_path);
+}
+
+
+wchar_t*
+_Py_GetDLLPath(void)
+{
+    wchar_t dll_path[MAXPATHLEN+1];
+    memset(dll_path, 0, sizeof(dll_path));
+
+#ifdef Py_ENABLE_SHARED
+    extern HANDLE PyWin_DLLhModule;
+    if (PyWin_DLLhModule) {
+        if (GetModuleFileNameW(PyWin_DLLhModule, dll_path, MAXPATHLEN)) {
+            Py_NormalizeSepsW(dll_path);
+        } else {
+            dll_path[0] = 0;
+        }
+    }
+#else
+    dll_path[0] = 0;
+#endif
+
+    return _PyMem_RawWcsdup(dll_path);
+}
+#endif /* MS_WINDOWS */
+
+
 static PyStatus
 calculate_set_exec_prefix(PyCalculatePath *calculate,
                           _PyPathConfig *pathconfig)
@@ -846,6 +912,12 @@ calculate_set_exec_prefix(PyCalculatePath *calculate,
             return _PyStatus_NO_MEMORY();
         }
 
+#ifdef MS_WINDOWS
+        wchar_t drive_root[3];
+        memset(drive_root, 0, sizeof(drive_root));
+        wcsncpy(drive_root, calculate->exec_prefix, 3);
+#endif
+
         reduce(exec_prefix);
         reduce(exec_prefix);
         reduce(exec_prefix);
@@ -859,7 +931,11 @@ calculate_set_exec_prefix(PyCalculatePath *calculate,
 
             /* The exec_prefix is the root directory, but reduce() chopped
                off the "/". */
+#ifdef MS_WINDOWS
+            pathconfig->exec_prefix = _PyMem_RawWcsdup(drive_root);
+#else
             pathconfig->exec_prefix = _PyMem_RawWcsdup(separator);
+#endif
             if (pathconfig->exec_prefix == NULL) {
                 return _PyStatus_NO_MEMORY();
             }
@@ -964,13 +1040,22 @@ calculate_program_impl(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
      * other way to find a directory to start the search from.  If
      * $PATH isn't exported, you lose.
      */
-    if (wcschr(pathconfig->program_name, SEP)) {
+    if (wcschr(pathconfig->program_name, Py_GetSepW(pathconfig->program_name))) {
         pathconfig->program_full_path = _PyMem_RawWcsdup(pathconfig->program_name);
         if (pathconfig->program_full_path == NULL) {
             return _PyStatus_NO_MEMORY();
         }
         return _PyStatus_OK();
     }
+#ifdef MS_WINDOWS
+    else if(pathconfig->program_full_path == NULL) {
+         pathconfig->program_full_path = GetWindowsModulePaths();
+         if (pathconfig->program_full_path == NULL) {
+             return _PyStatus_NO_MEMORY();
+         }
+         return _PyStatus_OK();
+    }
+#endif /* MS_WINDOWS */
 
 #ifdef __APPLE__
     wchar_t *abs_path = NULL;
@@ -1007,7 +1092,7 @@ calculate_program_impl(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
 
 
 /* Calculate pathconfig->program_full_path */
-static PyStatus
+PyStatus
 calculate_program(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
 {
     PyStatus status;
@@ -1173,7 +1258,7 @@ done:
 #endif
 
 
-static PyStatus
+PyStatus
 calculate_argv0_path(PyCalculatePath *calculate,
                      _PyPathConfig *pathconfig)
 {
@@ -1191,10 +1276,12 @@ calculate_argv0_path(PyCalculatePath *calculate,
     }
 #endif
 
+#if defined(HAVE_READLINK)
     status = resolve_symlinks(&calculate->argv0_path);
     if (_PyStatus_EXCEPTION(status)) {
         return status;
     }
+#endif
 
     reduce(calculate->argv0_path);
 
@@ -1329,6 +1416,8 @@ calculate_zip_path(PyCalculatePath *calculate)
     calculate->zip_path[len - 6] = VERSION[0];
     calculate->zip_path[len - 5] = VERSION[2];
 
+    Py_NormalizeSepsW(calculate->zip_path);
+
     res = _PyStatus_OK();
 
 done:
@@ -1368,7 +1457,14 @@ calculate_module_search_path(PyCalculatePath *calculate,
     }
 
     bufsz += wcslen(calculate->zip_path) + 1;
+/* TODO :: The MS_WINDOWS bit may be unnecessary. */
+#ifdef MS_WINDOWS
+    if (_Py_isabs(calculate->exec_prefix)) {
+        bufsz += wcslen(calculate->exec_prefix) + 1;
+    }
+#else
     bufsz += wcslen(calculate->exec_prefix) + 1;
+#endif
 
     /* Allocate the buffer */
     wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
@@ -1396,7 +1492,7 @@ calculate_module_search_path(PyCalculatePath *calculate,
 
         if (!_Py_isabs(defpath)) {
             wcscat(buf, calculate->prefix);
-            if (prefixsz >= 2 && calculate->prefix[prefixsz - 2] != SEP &&
+            if (prefixsz >= 2 && !_Py_issep(calculate->prefix[prefixsz - 2]) &&
                 defpath[0] != (delim ? DELIM : L'\0'))
             {
                 /* not empty */
@@ -1418,8 +1514,15 @@ calculate_module_search_path(PyCalculatePath *calculate,
     }
     wcscat(buf, delimiter);
 
+#ifdef MS_WINDOWS
+    if (_Py_isabs(calculate->exec_prefix)) {
+        wcscat(buf, calculate->exec_prefix);
+        wcscat(buf, delimiter);
+    }
+#else
     /* Finally, on goes the directory for dynamic-load modules */
     wcscat(buf, calculate->exec_prefix);
+#endif
 
     pathconfig->module_search_path = buf;
     return _PyStatus_OK();
@@ -1448,14 +1551,17 @@ calculate_init(PyCalculatePath *calculate, const PyConfig *config)
     if (!calculate->pythonpath_macro) {
         return DECODE_LOCALE_ERR("PYTHONPATH macro", len);
     }
+    Py_NormalizeSepsW(calculate->pythonpath_macro);
     calculate->prefix_macro = Py_DecodeLocale(PREFIX, &len);
     if (!calculate->prefix_macro) {
         return DECODE_LOCALE_ERR("PREFIX macro", len);
     }
+    Py_NormalizeSepsW(calculate->prefix_macro);
     calculate->exec_prefix_macro = Py_DecodeLocale(EXEC_PREFIX, &len);
     if (!calculate->exec_prefix_macro) {
         return DECODE_LOCALE_ERR("EXEC_PREFIX macro", len);
     }
+    Py_NormalizeSepsW(calculate->exec_prefix_macro);
     calculate->vpath_macro = Py_DecodeLocale(VPATH, &len);
     if (!calculate->vpath_macro) {
         return DECODE_LOCALE_ERR("VPATH macro", len);
@@ -1466,6 +1572,7 @@ calculate_init(PyCalculatePath *calculate, const PyConfig *config)
     if (!pyversion) {
         return DECODE_LOCALE_ERR("VERSION macro", len);
     }
+
     calculate->lib_python = joinpath2(config->platlibdir, pyversion);
     PyMem_RawFree(pyversion);
     if (calculate->lib_python == NULL) {
@@ -1482,6 +1589,7 @@ calculate_free(PyCalculatePath *calculate)
     PyMem_RawFree(calculate->pythonpath_macro);
     PyMem_RawFree(calculate->prefix_macro);
     PyMem_RawFree(calculate->exec_prefix_macro);
+    PyMem_RawFree(calculate->dll_path);
     PyMem_RawFree(calculate->vpath_macro);
     PyMem_RawFree(calculate->lib_python);
     PyMem_RawFree(calculate->path_env);
@@ -1497,6 +1605,8 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
 {
     PyStatus status;
 
+    calculate->dll_path = _Py_GetDLLPath();
+
     if (pathconfig->program_full_path == NULL) {
         status = calculate_program(calculate, pathconfig);
         if (_PyStatus_EXCEPTION(status)) {
@@ -1597,6 +1707,7 @@ _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
 {
     PyStatus status;
     PyCalculatePath calculate;
+    separator[0] = Py_GetSepW(NULL);
     memset(&calculate, 0, sizeof(calculate));
 
     status = calculate_init(&calculate, config);
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 1e61545..40fc270 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -4049,7 +4049,7 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list)
         Py_END_ALLOW_THREADS
         /* FindNextFile sets error to ERROR_NO_MORE_FILES if
            it got to the end of the directory. */
-        if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
+        if (!result && GetLastError() != 0 && GetLastError() != ERROR_NO_MORE_FILES) {
             Py_DECREF(list);
             list = path_error(path);
             goto exit;
diff --git a/Python/dynload_win.c b/Python/dynload_win.c
index 9d7690e..bd34310 100644
--- a/Python/dynload_win.c
+++ b/Python/dynload_win.c
@@ -174,7 +174,9 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
     char funcname[258], *import_python;
     const wchar_t *wpathname;
 
+#if defined(_MSC_VER)
     _Py_CheckPython3();
+#endif
 
 _Py_COMP_DIAG_PUSH
 _Py_COMP_DIAG_IGNORE_DEPR_DECLS
diff --git a/Python/fileutils.c b/Python/fileutils.c
index 45ea204..d5f8b79 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -1924,13 +1924,31 @@ _Py_wrealpath(const wchar_t *path,
 #endif
 
 
-#ifndef MS_WINDOWS
 int
 _Py_isabs(const wchar_t *path)
 {
-    return (path[0] == SEP);
+#ifdef MS_WINDOWS
+    size_t i = wcslen(path);
+    if (i >= 3) {
+        if (iswalpha(path[0]) && path[1] == L':' && _Py_issep(path[2])) {
+            return 1;
+        }
+    }
+    return 0;
+#else
+    return _Py_issep(path[0]);
+#endif
 }
+
+int
+_Py_issep(const wchar_t ch)
+{
+#ifdef MS_WINDOWS
+    return ch == SEP || ch == ALTSEP;
+#else
+    return ch == SEP;
 #endif
+}
 
 
 /* Get an absolute path.
-- 
2.32.0

