mingw: support spawning programs containing spaces in their names

On some older Windows versions (e.g. Windows 7), the CreateProcessW() function does not really support spaces in its first argument, lpApplicationName. But it supports passing NULL as lpApplicationName, which makes it figure out the application from the (possibly quoted) first argument of lpCommandLine. Let's use that trick (if we are certain that the first argument matches the executable's path) to support launching programs whose path contains spaces. We will abuse the test-fake-ssh.exe helper to verify that this works and does not regress. This fixes https://github.com/git-for-windows/git/issues/692 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Jul 16, 2019 at 07:03 UTC eb7c78631445f35737d059bea23174d972cf7ca3
2 files changed +11 -3
compat/mingw.c
+5 -3
@@ -1437,7 +1437,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1437 si.hStdOutput = winansi_get_osfhandle(fhout);
1438 si.hStdError = winansi_get_osfhandle(fherr);
1439
1440 - if (xutftowcs_path(wcmd, cmd) < 0)
1440 + if (*argv && !strcmp(cmd, *argv))
1441 + wcmd[0] = L'\0';
1442 + else if (xutftowcs_path(wcmd, cmd) < 0)
1443 return -1;
1444 if (dir && xutftowcs_path(wdir, dir) < 0)
1445 return -1;
@@ -1466,8 +1468,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1468 wenvblk = make_environment_block(deltaenv);
1469
1470 memset(&pi, 0, sizeof(pi));
1469 - ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
1470 - wenvblk, dir ? wdir : NULL, &si, &pi);
1471 + ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
1472 + flags, wenvblk, dir ? wdir : NULL, &si, &pi);
1473
1474 free(wenvblk);
1475 free(wargs);
t/t0061-run-command.sh
+6
@@ -210,4 +210,10 @@ test_expect_success MINGW 'verify curlies are quoted properly' '
210 test_cmp expect actual
211 '
212
213 +test_expect_success MINGW 'can spawn with argv[0] containing spaces' '
214 + cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" ./ &&
215 + test_must_fail "$PWD/test-fake-ssh$X" 2>err &&
216 + grep TRASH_DIRECTORY err
217 +'
218 +
219 test_done