Commit f7c6795f48850eec94793d22b5fd621b61cd2466

Patrick Steinhardt 2019-06-07T10:20:35

path: only treat paths starting with '\' as absolute on Win32 Windows-based systems treat paths starting with '\' as absolute, either referring to the current drive's root (e.g. "\foo" might refer to "C:\foo") or to a network path (e.g. "\\host\foo"). On the other hand, (most?) systems that are not based on Win32 accept backslashes as valid characters that may be part of the filename, and thus we cannot treat them to identify absolute paths. Change the logic to only paths starting with '\' as absolute on the Win32 platform. Add tests to avoid regressions and document behaviour.

diff --git a/src/path.c b/src/path.c
index 197efb7..af18edc 100644
--- a/src/path.c
+++ b/src/path.c
@@ -276,9 +276,12 @@ int git_path_root(const char *path)
 		while (path[offset] && path[offset] != '/' && path[offset] != '\\')
 			offset++;
 	}
+
+	if (path[offset] == '\\')
+		return offset;
 #endif
 
-	if (path[offset] == '/' || path[offset] == '\\')
+	if (path[offset] == '/')
 		return offset;
 
 	return -1;	/* Not a real error - signals that path is not rooted */
diff --git a/tests/path/core.c b/tests/path/core.c
index bbcded0..3a68a93 100644
--- a/tests/path/core.c
+++ b/tests/path/core.c
@@ -343,6 +343,16 @@ void test_path_core__join_unrooted(void)
 	test_join_unrooted("c:/foo", 2, "c:/foo", "c:/asdf");
 	test_join_unrooted("c:/foo/bar", 2, "c:/foo/bar", "c:/asdf");
 
+#ifdef GIT_WIN32
+	/* Paths starting with '\\' are absolute */
+	test_join_unrooted("\\bar", 0, "\\bar", "c:/foo/");
+	test_join_unrooted("\\\\network\\bar", 9, "\\\\network\\bar", "c:/foo/");
+#else
+	/* Paths starting with '\\' are not absolute on non-Windows systems */
+	test_join_unrooted("/foo/\\bar", 4, "\\bar", "/foo");
+	test_join_unrooted("c:/foo/\\bar", 7, "\\bar", "c:/foo/");
+#endif
+
 	/* Base is returned when it's provided and is the prefix */
 	test_join_unrooted("c:/foo/bar/foobar", 6, "c:/foo/bar/foobar", "c:/foo");
 	test_join_unrooted("c:/foo/bar/foobar", 10, "c:/foo/bar/foobar", "c:/foo/bar");