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 <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2017-06-19 16:35:17 +02:00
parent 445189298f
commit 967133e62a
2 changed files with 35 additions and 2 deletions

View File

@@ -1068,7 +1068,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;
@@ -1123,6 +1123,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];
@@ -1509,6 +1540,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;

View File

@@ -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
'