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
This commit is contained in:
Junio C Hamano 2019-02-05 14:26:13 -08:00
commit f5dd919064
3 changed files with 91 additions and 1 deletions

View File

@ -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();

View File

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

View File

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