diff options
| author | Junio C Hamano <gitster@pobox.com> | 2019-02-05 14:26:13 -0800 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2019-02-05 14:26:13 -0800 |
| commit | f5dd919064c30fb8f22f022455eeaf975eff57c6 (patch) | |
| tree | ad52ea8c0ab7f1d17c8b6b17e1e10035c35fcd1a | |
| parent | e91a1b1ade3ea07bdf8cdd8cd4fa126caac12a36 (diff) | |
| parent | 9e9da23c2765050ff30d34540fbab62a1b4e5d01 (diff) | |
| download | git-f5dd919064c30fb8f22f022455eeaf975eff57c6.tar.gz | |
Merge branch 'js/mingw-unc-path-w-backslashes'
In Git for Windows, "git clone \\server\share\path" etc. that uses
UNC paths from command line had bad interaction with its shell
emulation.
* js/mingw-unc-path-w-backslashes:
mingw: special-case arguments to `sh`
mingw (t5580): document bug when cloning from backslashed UNC paths
| -rw-r--r-- | compat/mingw.c | 77 | ||||
| -rwxr-xr-x | t/t0061-run-command.sh | 10 | ||||
| -rwxr-xr-x | t/t5580-clone-push-unc.sh | 5 |
3 files changed, 91 insertions, 1 deletions
diff --git a/compat/mingw.c b/compat/mingw.c index b459e1a291..0af8684019 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -7,6 +7,7 @@ #include "../cache.h" #include "win32/lazyload.h" #include "../config.h" +#include "dir.h" #define HCAST(type, handle) ((type)(intptr_t)handle) @@ -1031,7 +1032,7 @@ char *mingw_getcwd(char *pointer, int len) * See "Parsing C++ Command-Line Arguments" at Microsoft's Docs: * https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-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; @@ -1086,6 +1087,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 != '"' && *p != '{') + continue; + if (!buf.len) + strbuf_addch(&buf, '"'); + if (p != p2) + strbuf_add(&buf, p2, p - p2); + if (!ws && *p != '{') + 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]; @@ -1317,6 +1349,47 @@ struct pinfo_t { static struct pinfo_t *pinfo = NULL; CRITICAL_SECTION pinfo_cs; +/* Used to match and chomp off path components */ +static inline int match_last_path_component(const char *path, size_t *len, + const char *component) +{ + size_t component_len = strlen(component); + if (*len < component_len + 1 || + !is_dir_sep(path[*len - component_len - 1]) || + fspathncmp(path + *len - component_len, component, component_len)) + return 0; + *len -= component_len + 1; + /* chomp off repeated dir separators */ + while (*len > 0 && is_dir_sep(path[*len - 1])) + (*len)--; + return 1; +} + +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 = match_last_path_component(p, &len, "sh.exe") && + match_last_path_component(p, &len, "bin") && + match_last_path_component(p, &len, "usr"); + 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) @@ -1328,6 +1401,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen unsigned flags = CREATE_UNICODE_ENVIRONMENT; BOOL ret; HANDLE cons; + const char *(*quote_arg)(const char *arg) = + is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc; do_unset_environment_variables(); diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh index 99a614bc7c..9c7604dcab 100755 --- a/t/t0061-run-command.sh +++ b/t/t0061-run-command.sh @@ -199,4 +199,14 @@ test_expect_success 'GIT_TRACE with environment variables' ' ) ' +test_expect_success MINGW 'verify curlies are quoted properly' ' + : force the rev-parse through the MSYS2 Bash && + git -c alias.r="!git rev-parse" r -- a{b}c >actual && + cat >expect <<-\EOF && + -- + a{b}c + EOF + test_cmp expect actual +' + test_done diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh index ba548df4a9..217adf3a63 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -40,6 +40,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 && |
