normalize_path_copy(): 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(). Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Sixt committed Dec 14, 2016 at 20:37 UTC 7814fbe3f1e7cea1a675408df7b5dd1f5be731cc
1 file changed +14 -9
path.c
+14 -9
@@ -961,7 +961,7 @@ const char *remove_leading_path(const char *in, const char *prefix)
961 *
962 * Performs the following normalizations on src, storing the result in dst:
963 * - Ensures that components are separated by '/' (Windows only)
964 - * - Squashes sequences of '/'.
964 + * - Squashes sequences of '/' except "//server/share" on Windows
965 * - Removes "." components.
966 * - Removes ".." components, and the components the precede them.
967 * Returns failure (non-zero) if a ".." component appears as first path
@@ -984,17 +984,22 @@ const char *remove_leading_path(const char *in, const char *prefix)
984 int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
985 {
986 char *dst0;
987 - int i;
987 + const char *end;
988
989 - for (i = has_dos_drive_prefix(src); i > 0; i--)
990 - *dst++ = *src++;
989 + /*
990 + * Copy initial part of absolute path: "/", "C:/", "//server/share/".
991 + */
992 + end = src + offset_1st_component(src);
993 + while (src < end) {
994 + char c = *src++;
995 + if (is_dir_sep(c))
996 + c = '/';
997 + *dst++ = c;
998 + }
999 dst0 = dst;
1000
993 - if (is_dir_sep(*src)) {
994 - *dst++ = '/';
995 - while (is_dir_sep(*src))
996 - src++;
997 - }
1001 + while (is_dir_sep(*src))
1002 + src++;
1003
1004 for (;;) {
1005 char c = *src;