Skip to content

Commit

Permalink
Merge branch 'unc-path-w-backslashes'
Browse files Browse the repository at this point in the history
This topic branch addresses a problem identified in
#439: while
cloning/fetching/pushing from "POSIX-ified UNC paths" (i.e. UNC paths
whose backslashes have been converted to forward slashes) works for some
time now, true UNC paths (with backslashes left intact) were handled
incorrectly. Example:

	git clone //myserver/folder/repo.git

works, but

	git clone \\myserver\folder\repo.git

(in CMD; in Git Bash, the backslashes would need to be doubled) used to
fail. The reason was an unexpected difference in command-line handling
between Win32 executables and MSYS2 ones (such as the shell that is used
by git-clone.exe to spawn git-upload-pack.exe).

This topic branch features a workaround *just* for the case where Git
passes stuff through sh.exe (which covers quite a few use cases,
though).

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Oct 4, 2018
2 parents e5b8511 + 1d7c573 commit b1d4dc7
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
63 changes: 62 additions & 1 deletion compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,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;
Expand Down Expand Up @@ -1204,6 +1204,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];
Expand Down Expand Up @@ -1514,6 +1545,34 @@ struct pinfo_t {
static struct pinfo_t *pinfo = NULL;
CRITICAL_SECTION pinfo_cs;

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 = len > 15 &&
is_dir_sep(p[len - 15]) &&
!strncasecmp(p + len - 14, "usr", 3) &&
is_dir_sep(p[len - 11]) &&
!strncasecmp(p + len - 10, "bin", 3) &&
is_dir_sep(p[len - 7]) &&
!strcasecmp(p + len - 6, "sh.exe");
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)
Expand All @@ -1526,6 +1585,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) =
is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;

do_unset_environment_variables();

Expand Down
10 changes: 10 additions & 0 deletions t/t0061-run-command.sh
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,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
7 changes: 6 additions & 1 deletion t/t5580-clone-push-unc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,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
'
Expand All @@ -49,6 +49,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 &&
Expand Down

0 comments on commit b1d4dc7

Please sign in to comment.