[PATCH v3 2/3] relative_path should honor DOS and UNC paths

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Tvangeste found that the "relative_path" function could not work
properly on Windows if "in" and "prefix" have DOS driver prefix
(such as "C:/windows"). And the "relative_path" function won't
work properly if either "in" or "prefix" is a UNC path (like
"//host/share"). ($gmane/234434)

E.g., When execute: test-path-utils relative_path "C:/a/b" "D:/x/y",
should return "C:/a/b", but returns "../../C:/a/b", which is wrong.

So make relative_path honor DOS and UNC paths, and add test cases
for it in t0060.

Reported-by: Tvangeste <i.4m.l33t@xxxxxxxxx>
Helped-by: Johannes Sixt <j6t@xxxxxxxx>
Signed-off-by: Jiang Xin <worldhello.net@xxxxxxxxx>
---
 compat/mingw.h        |  9 +++++++++
 git-compat-util.h     |  4 ++++
 path.c                | 25 +++++++++++++++++++++++++
 t/t0060-path-utils.sh |  8 ++++++++
 4 files changed, 46 insertions(+)

diff --git a/compat/mingw.h b/compat/mingw.h
index bd0a88b..06e9f49 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -311,6 +311,15 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format
 
 #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
 #define is_dir_sep(c) ((c) == '/' || (c) == '\\')
+static inline int is_unc_path(const char *path)
+{
+	if (!is_dir_sep(*path) || !is_dir_sep(*(path+1)) || is_dir_sep(*(path+2)))
+		return 0;
+	for (path += 2; *path; path++)
+		if (is_dir_sep(*path))
+			return 1;
+	return 0;
+}
 static inline char *mingw_find_last_dir_sep(const char *path)
 {
 	char *ret = NULL;
diff --git a/git-compat-util.h b/git-compat-util.h
index 9549de6..93c2206 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -274,6 +274,10 @@ extern char *gitbasename(char *);
 #define is_dir_sep(c) ((c) == '/')
 #endif
 
+#ifndef is_unc_path
+#define is_unc_path(path) 0
+#endif
+
 #ifndef find_last_dir_sep
 #define find_last_dir_sep(path) strrchr(path, '/')
 #endif
diff --git a/path.c b/path.c
index 9fd28bcd..544d10d 100644
--- a/path.c
+++ b/path.c
@@ -434,6 +434,21 @@ int adjust_shared_perm(const char *path)
 	return 0;
 }
 
+static int have_same_root(const char *path1, const char *path2)
+{
+	int is_abs1, is_abs2;
+
+	is_abs1 = is_absolute_path(path1);
+	is_abs2 = is_absolute_path(path2);
+	if (is_abs1 && is_abs2) {
+		if (is_unc_path(path1) ^ is_unc_path(path2))
+			return 0;
+		return tolower(path1[0]) == tolower(path2[0]);
+	} else {
+		return !is_abs1 && !is_abs2;
+	}
+}
+
 /*
  * Give path as relative to prefix.
  *
@@ -454,6 +469,16 @@ const char *relative_path(const char *in, const char *prefix,
 	else if (!prefix_len)
 		return in;
 
+	if (have_same_root(in, prefix)) {
+		/* bypass dos_drive, for "c:" is identical to "C:" */
+		if (has_dos_drive_prefix(in)) {
+			i = 2;
+			j = 2;
+		}
+	} else {
+		return in;
+	}
+
 	while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
 		if (is_dir_sep(prefix[i])) {
 			while (is_dir_sep(prefix[i]))
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 92976e0..830b6d5 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -210,6 +210,14 @@ relative_path foo/a/b/		foo/a/b		./
 relative_path foo/a		foo/a/b		../
 relative_path foo/x/y		foo/a/b		../../x/y
 relative_path foo/a/c		foo/a/b		../c
+relative_path foo/a/b		/foo/x/y	foo/a/b
+relative_path /foo/a/b		foo/x/y		/foo/a/b
+relative_path d:/a/b		D:/a/c		../b		MINGW
+relative_path C:/a/b		D:/a/c		C:/a/b		MINGW
+relative_path //host1/a/b	//host1/a/c	../b
+relative_path //host1/a/b	//host2/a/c	../../../host1/a/b
+relative_path //host1/a/b	/foo/a/c	//host1/a/b	MINGW
+relative_path /foo/a/b		//host2/a/c	/foo/a/b	MINGW
 relative_path foo/a/b		"<empty>"	foo/a/b
 relative_path foo/a/b 		"<null>"	foo/a/b
 relative_path "<empty>"		/foo/a/b	./
-- 
1.8.4.460.g2f083d1

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]