From e2ba3d6f6d1c2b0e7e501ae01a0e839a6f537188 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Sep 2019 17:05:21 +0200 Subject: [PATCH 1/4] mingw: detect when MSYS2's sh is to be spawned more robustly Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0e14cab012..5dbaae981e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1391,7 +1391,10 @@ static inline int match_last_path_component(const char *path, size_t *len, static int is_msys2_sh(const char *cmd) { - if (cmd && !strcmp(cmd, "sh")) { + if (!cmd) + return 0; + + if (!strcmp(cmd, "sh")) { static int ret = -1; char *p; @@ -1411,6 +1414,16 @@ static int is_msys2_sh(const char *cmd) } return ret; } + + if (ends_with(cmd, "\\sh.exe")) { + static char *sh; + + if (!sh) + sh = path_lookup("sh", 0); + + return !fspathcmp(cmd, sh); + } + return 0; } From 49f7a76d57c78e55f2f72e44664824f3fecb8837 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Sep 2019 17:05:45 +0200 Subject: [PATCH 2/4] mingw: use MSYS2 quoting even when spawning shell scripts At the point where `mingw_spawn_fd()` is called, we already have a full path to the script interpreter in that scenario, and we pass it in as the executable to run, while the `argv` reflect what the script should receive as command-line. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5dbaae981e..32fc02e360 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1439,7 +1439,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen BOOL ret; HANDLE cons; const char *(*quote_arg)(const char *arg) = - is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc; + is_msys2_sh(cmd ? cmd : *argv) ? + quote_arg_msys2 : quote_arg_msvc; do_unset_environment_variables(); From 04522edbd4086cd9063a8e65664c11a87bb7d89e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Sep 2019 23:38:33 +0200 Subject: [PATCH 3/4] mingw: fix quoting of empty arguments for `sh` When constructing command-lines to spawn processes, it is an unfortunate but necessary decision to quote arguments differently: MSYS2 has different dequoting rules (inherited from Cygwin) than the rest of Windows. To accommodate that, Git's Windows compatibility layer has two separate quoting helpers, one for MSYS2 (which it uses exclusively when spawning `sh`) and the other for regular Windows executables. The MSYS2 one had an unfortunate bug where a `,` somehow slipped in, instead of the `;`. As a consequence, empty arguments would not be enclosed in a pair of double quotes, but the closing double quote was skipped. Let's fix this. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 32fc02e360..7635ad5152 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1136,7 +1136,7 @@ static const char *quote_arg_msys2(const char *arg) else if (!buf.len) return arg; else - strbuf_add(&buf, p2, p - p2), + strbuf_add(&buf, p2, p - p2); strbuf_addch(&buf, '"'); return strbuf_detach(&buf, 0); From 7d8b676992ba0418aeb78f0ad1f4e193ad979b2e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Sep 2019 23:43:03 +0200 Subject: [PATCH 4/4] mingw: sh arguments need quoting in more circumstances Previously, we failed to quote characters such as '*', '(' and the likes. Let's fix this. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7635ad5152..2c55c3426c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1120,13 +1120,14 @@ static const char *quote_arg_msys2(const char *arg) for (p = arg; *p; p++) { int ws = isspace(*p); - if (!ws && *p != '\\' && *p != '"' && *p != '{') + if (!ws && *p != '\\' && *p != '"' && *p != '{' && *p != '\'' && + *p != '?' && *p != '*' && *p != '~') continue; if (!buf.len) strbuf_addch(&buf, '"'); if (p != p2) strbuf_add(&buf, p2, p - p2); - if (!ws && *p != '{') + if (*p == '\\' || *p == '"') strbuf_addch(&buf, '\\'); p2 = p; }