diff --git a/compat/mingw.c b/compat/mingw.c index 6fd5e9c48b..1f567cc69a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1069,7 +1069,7 @@ char *mingw_getcwd(char *pointer, int len) * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx * (Parsing C++ Command-Line Arguments) */ -static const char *quote_arg(const char *arg) +static const char *quote_arg_msvc(const char *arg) { /* count chars to quote */ int len = 0, n = 0; @@ -1124,6 +1124,37 @@ static const char *quote_arg(const char *arg) return q; } +#include "quote.h" + +static const char *quote_arg_msys2(const char *arg) +{ + struct strbuf buf = STRBUF_INIT; + const char *p2 = arg, *p; + + for (p = arg; *p; p++) { + int ws = isspace(*p); + if (!ws && *p != '\\' && *p != '"') + continue; + if (!buf.len) + strbuf_addch(&buf, '"'); + if (p != p2) + strbuf_add(&buf, p2, p - p2); + if (!ws) + strbuf_addch(&buf, '\\'); + p2 = p; + } + + if (p == arg) + strbuf_addch(&buf, '"'); + else if (!buf.len) + return arg; + else + strbuf_add(&buf, p2, p - p2), + + strbuf_addch(&buf, '"'); + return strbuf_detach(&buf, 0); +} + static const char *parse_interpreter(const char *cmd) { static char buf[100]; @@ -1467,6 +1498,34 @@ static void kill_child_processes_on_signal(void) LeaveCriticalSection(&pinfo_cs); } +static int is_msys2_sh(const char *cmd) +{ + if (cmd && !strcmp(cmd, "sh")) { + static int ret = -1; + char *p; + + if (ret >= 0) + return ret; + + p = path_lookup(cmd, 0); + if (!p) + ret = 0; + else { + size_t len = strlen(p); + ret = len > 15 && + is_dir_sep(p[len - 15]) && + !strncasecmp(p + len - 14, "usr", 3) && + is_dir_sep(p[len - 11]) && + !strncasecmp(p + len - 10, "bin", 3) && + is_dir_sep(p[len - 7]) && + !strcasecmp(p + len - 6, "sh.exe"); + free(p); + } + return ret; + } + return 0; +} + static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv, const char *dir, int prepend_cmd, int fhin, int fhout, int fherr) @@ -1480,6 +1539,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen BOOL ret; HANDLE cons; const char *strace_env; + const char *(*quote_arg)(const char *arg) = + is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc; if (!atexit_handler_initialized) { atexit_handler_initialized = 1; diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh index f932bf88d6..d9fe012de4 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -31,7 +31,7 @@ esac test_expect_success 'clone into absolute path lacking a drive prefix' ' USINGBACKSLASHES="$(echo "$WITHOUTDRIVE"/without-drive-prefix | - tr / \\)" && + tr / \\\\)" && git clone . "$USINGBACKSLASHES" && test -f without-drive-prefix/.git/HEAD ' @@ -49,6 +49,11 @@ test_expect_success clone ' git clone "file://$UNCPATH" clone ' +test_expect_success 'clone with backslashed path' ' + BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" && + git clone "$BACKSLASHED" backslashed +' + test_expect_success push ' ( cd clone &&