From d8b19178cb5e46b271214ab119b6f51cf3c797ce Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Dec 2016 12:12:50 +0100 Subject: [PATCH 1/2] mingw: demonstrate a regression pushing to UNC paths On Windows, there are "UNC paths" to access network (AKA shared) folders, of the form \\server\sharename\directory. This provides a convenient way for Windows developers to share their Git repositories without having to have a dedicated server. Git for Windows v2.11.0 introduced a regression where pushing to said UNC paths no longer works, although fetching and cloning still does. Demonstrate what is the problem, using so-called "administrative shares": disk volumes are automatically shared under certain circumstances, e.g. the C: drive is shared as \\localhost\c$. The test needs to be skipped if the current directory is inaccessible via said administrative share, of course. Original-report: https://github.com/git-for-windows/git/issues/979 Signed-off-by: Johannes Schindelin --- t/t5580-clone-push-unc.sh | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100755 t/t5580-clone-push-unc.sh diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh new file mode 100755 index 0000000000..77abeaf4bd --- /dev/null +++ b/t/t5580-clone-push-unc.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +test_description='various UNC path tests (Windows-only)' +. ./test-lib.sh + +if ! test_have_prereq MINGW; then + skip_all='skipping UNC path tests, requires Windows' + test_done +fi + +UNCPATH="$(pwd)" +case "$UNCPATH" in +[A-Z]:*) + # Use administrative share e.g. \\localhost\C$\git-sdk-64\usr\src\git + # (we use forward slashes here because MSYS2 and Git accept them, and + # they are easier on the eyes) + UNCPATH="//localhost/${UNCPATH%%:*}\$/${UNCPATH#?:}" + test -d "$UNCPATH" || { + skip_all='could not access administrative share; skipping' + test_done + } + ;; +*) + skip_all='skipping UNC path tests, cannot determine current path as UNC' + test_done + ;; +esac + +test_expect_success setup ' + test_commit initial +' + +test_expect_success clone ' + git clone "file://$UNCPATH" clone +' + +test_expect_failure push ' + ( + cd clone && + git checkout -b to-push && + test_commit to-push && + git push origin HEAD + ) +' + +test_done From dde06d10997ef5512f88122b6b75cb33b4a566eb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Dec 2016 20:37:38 +0100 Subject: [PATCH 2/2] fix pushing to //server/share/dir on Windows normalize_path_copy() is not prepared to keep the double-slash of a //server/share/dir kind of path, but treats it like a regular POSIX style path and transforms it to /server/share/dir. The bug manifests when 'git push //server/share/dir master' is run, because tmp_objdir_add_as_alternate() uses the path in normalized form when it registers the quarantine object database via link_alt_odb_entries(). Needless to say that the directory cannot be accessed using the wrongly normalized path. Fix it by skipping all of the root part, not just a potential drive prefix. offset_1st_component takes care of this, see the implementation in compat/mingw.c::mingw_offset_1st_component(). This fixes https://github.com/git-for-windows/git/issues/979 Signed-off-by: Johannes Sixt Signed-off-by: Johannes Schindelin --- path.c | 23 ++++++++++++++--------- t/t5580-clone-push-unc.sh | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/path.c b/path.c index 8e8e710507..fafbc47db4 100644 --- a/path.c +++ b/path.c @@ -996,7 +996,7 @@ const char *remove_leading_path(const char *in, const char *prefix) * * Performs the following normalizations on src, storing the result in dst: * - Ensures that components are separated by '/' (Windows only) - * - Squashes sequences of '/'. + * - Squashes sequences of '/' except "//server/share" on Windows * - Removes "." components. * - Removes ".." components, and the components the precede them. * Returns failure (non-zero) if a ".." component appears as first path @@ -1019,17 +1019,22 @@ const char *remove_leading_path(const char *in, const char *prefix) int normalize_path_copy_len(char *dst, const char *src, int *prefix_len) { char *dst0; - int i = has_unc_prefix(src); + const char *end; - for (i = i ? i : has_dos_drive_prefix(src); i > 0; i--) - *dst++ = *src++; + /* + * Copy initial part of absolute path: "/", "C:/", "//server/share/". + */ + end = src + offset_1st_component(src); + while (src < end) { + char c = *src++; + if (is_dir_sep(c)) + c = '/'; + *dst++ = c; + } dst0 = dst; - if (is_dir_sep(*src)) { - *dst++ = '/'; - while (is_dir_sep(*src)) - src++; - } + while (is_dir_sep(*src)) + src++; for (;;) { char c = *src; diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh index 77abeaf4bd..e06d230724 100755 --- a/t/t5580-clone-push-unc.sh +++ b/t/t5580-clone-push-unc.sh @@ -34,7 +34,7 @@ test_expect_success clone ' git clone "file://$UNCPATH" clone ' -test_expect_failure push ' +test_expect_success push ' ( cd clone && git checkout -b to-push &&