From 167666124c41f20f696b063f03f27d94c38a6092 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 19 Jun 2017 17:09:43 +0200 Subject: [PATCH 1/3] mingw: use proper quoting of the tr argument in t5580 The use of a trailing backslash in an argument to the `tr` command is not portable. While this test case is very specific to Windows, anyway, we still should avoid that warning. Signed-off-by: Johannes Schindelin --- t/t5580-clone-push-unc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh index 7fd63b2c65..bcdcaae66c 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -25,7 +25,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 ' From a6777562edfd4066577e63c0aaab1356615f763b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 19 Jun 2017 17:11:16 +0200 Subject: [PATCH 2/3] mingw (t5580): document bug when cloning from backslashed UNC paths Due to a quirk in Git's method to spawn git-upload-pack, there is a problem when passing paths with backslashes in them: Git will force the command-line through the shell, which has different quoting semantics in Git for Windows (being an MSYS2 program) than regular Win32 executables such as git.exe itself. The symptom is that the first of the two backslashes in UNC paths of the form \\myserver\folder\repository.git is *stripped off*. Document this bug by introducing a test case. Signed-off-by: Johannes Schindelin --- t/t5580-clone-push-unc.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh index bcdcaae66c..3a11902355 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -43,6 +43,11 @@ test_expect_success clone ' git clone "file://$UNCPATH" clone ' +test_expect_failure 'clone with backslashed path' ' + BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" && + git clone "$BACKSLASHED" backslashed +' + test_expect_success push ' ( cd clone && From dcca30f06556c2563ed4065470f6af026162e193 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 19 Jun 2017 16:35:17 +0200 Subject: [PATCH 3/3] mingw: special-case arguments to `sh` The MSYS2 runtime does its best to emulate the command-line expansion and de-quoting which would otherwise be performed by the calling shell. However, in Git we pass arguments to subprocesses that we do *not* want to be handled that way, e.g. when passing Windows paths. Note: this is only a problem when calling MSYS2 executables, not when calling MINGW executables such as git.exe. But sometimes we do call MSYS2 executables, most notably when setting the use_shell flag in the child_process structure. There is no elegant way to determine whether the .exe file to be executed is an MSYS2 program or a MINGW one. But since the use case of passing a command line through the shell is so prevalent, we need to work around this issue at least when executing sh.exe. Let's introduce an ugly, hard-coded test whether argv[0] is "sh" to determine whether we need to quote the arguments differently than usual. That still does not fix the issue completely, but at least it is something. Incidentally, this also fixes the problem where `git clone \\server\repo` failed due to incorrect handling of the backslashes when handing the path to the git-upload-pack process. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 35 ++++++++++++++++++++++++++++++++++- t/t5580-clone-push-unc.sh | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 538bf95f44..0951be8df5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1066,7 +1066,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; @@ -1121,6 +1121,37 @@ static const char *quote_arg(const char *arg) return q; } +#include "quote.h" + +static const char *quote_arg_sh(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]; @@ -1547,6 +1578,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) = + *argv && !strcmp("sh", *argv) ? quote_arg_sh : 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 3a11902355..b3d66deaa5 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -43,7 +43,7 @@ test_expect_success clone ' git clone "file://$UNCPATH" clone ' -test_expect_failure 'clone with backslashed path' ' +test_expect_success 'clone with backslashed path' ' BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" && git clone "$BACKSLASHED" backslashed '