Hello Joel,

> https://www.mail-archive.com/ccache@lists.samba.org/msg00802.html

Thank you.  It is trickier than I thought.

> ccache has a test suite and it fails like this with your patch:

Sorry, I missed the test directory.  Attached is a modified patch, which
fixes this issue and includes tests as well.

> If I understand your setup correctly, would it be possible to instead put
> /reference, /user1 and /user2 under a /common directory and then let the
> users set basedir to /common?

Technically, yes, however, the file system layout is not under my
control.  It also would be tedious, as there are many more users, their
individual directories can be huge, and the ability to benefit from
ccache is just a minor issue in the overall picture.

Andreas

>From 8cf16d90cadebdf354c0cdd71f247af71941a413 Mon Sep 17 00:00:00 2001
From: Andreas Wettstein <wetts...@gmail.com>
Date: Tue, 2 Jan 2018 13:37:02 +0100
Subject: [PATCH] When computing a relative path with respect to the current
 working directory, use the original path, without making it canonical.

Signed-off-by: Andreas Wettstein <wetts...@gmail.com>
---
 ccache.c         | 23 ++++++++---------------
 ccache.h         |  1 +
 test.sh          | 10 ++++++++++
 test/test_util.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 util.c           | 29 +++++++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 15 deletions(-)

diff --git a/ccache.c b/ccache.c
index edbc5cc..f8b8976 100644
--- a/ccache.c
+++ b/ccache.c
@@ -709,23 +709,16 @@ make_relative_path(char *path)
 		free(p);
 	}
 
-	char *canon_path = x_realpath(path);
-	if (canon_path) {
-		free(path);
-		char *relpath = get_relative_path(get_current_working_dir(), canon_path);
-		free(canon_path);
-		if (path_suffix) {
-			path = format("%s/%s", relpath, path_suffix);
-			free(relpath);
-			free(path_suffix);
-			return path;
-		} else {
-			return relpath;
-		}
-	} else {
-		// path doesn't exist, so leave it as it is.
+	remove_redunant_path_components(path);
+	char *relpath = get_relative_path(get_current_working_dir(), path);
+	free(path);
+	if (path_suffix) {
+		path = format("%s/%s", relpath, path_suffix);
+		free(relpath);
 		free(path_suffix);
 		return path;
+	} else {
+		return relpath;
 	}
 }
 
diff --git a/ccache.h b/ccache.h
index b282907..78e1eea 100644
--- a/ccache.h
+++ b/ccache.h
@@ -172,6 +172,7 @@ char *get_cwd(void);
 bool same_executable_name(const char *s1, const char *s2);
 size_t common_dir_prefix_length(const char *s1, const char *s2);
 char *get_relative_path(const char *from, const char *to);
+void remove_redunant_path_components(char *path);
 bool is_absolute_path(const char *path);
 bool is_full_path(const char *path);
 bool is_symlink(const char *path);
diff --git a/test.sh b/test.sh
index b3bdab3..9c7faec 100755
--- a/test.sh
+++ b/test.sh
@@ -2335,6 +2335,10 @@ int test;
 EOF
     cp -r dir1 dir2
     backdate dir1/include/test.h dir2/include/test.h
+
+    mkdir dir3
+    cp -R dir1/src dir3/src
+    ln -s `pwd`/dir1/include dir3/include
 }
 
 SUITE_basedir() {
@@ -2384,6 +2388,12 @@ SUITE_basedir() {
     expect_stat 'cache hit (preprocessed)' 0
     expect_stat 'cache miss' 1
 
+    cd ../dir3
+    CCACHE_BASEDIR="`pwd`" $CCACHE_COMPILE -I`pwd`/include -c src/test.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+
     # -------------------------------------------------------------------------
     TEST "Rewriting in stderr"
 
diff --git a/test/test_util.c b/test/test_util.c
index dca718c..b367aae 100644
--- a/test/test_util.c
+++ b/test/test_util.c
@@ -85,6 +85,49 @@ TEST(get_relative_path)
 #endif
 }
 
+TEST(remove_redunant_path_components)
+{
+	char *str0 = strdup("");
+	remove_redunant_path_components(str0);
+	CHECK_STR_EQ_FREE2("", str0);
+
+	char *str1 = strdup("//");
+	remove_redunant_path_components(str1);
+	CHECK_STR_EQ_FREE2("/", str1);
+
+	char *str2 = strdup("x//.//");
+	remove_redunant_path_components(str2);
+	CHECK_STR_EQ_FREE2("x/", str2);
+
+	char *str3 = strdup("//x");
+	remove_redunant_path_components(str3);
+	CHECK_STR_EQ("/x", str3);
+
+	char *str4 = strdup("//x//.");
+	remove_redunant_path_components(str4);
+	CHECK_STR_EQ("/x/", str4);
+
+	char *str5 = strdup("//x//./");
+	remove_redunant_path_components(str5);
+	CHECK_STR_EQ("/x/", str5);
+
+	char *str6 = strdup("/x//..");
+	remove_redunant_path_components(str6);
+	CHECK_STR_EQ("/x/..", str6);
+
+	char *str7 = strdup("/");
+	remove_redunant_path_components(str7);
+	CHECK_STR_EQ_FREE2("/", str7);
+
+	char *str8 = strdup(".");
+	remove_redunant_path_components(str8);
+	CHECK_STR_EQ_FREE2("", str8);
+
+	char *str9 = strdup("./x");
+	remove_redunant_path_components(str9);
+	CHECK_STR_EQ_FREE2("x", str9);
+}
+
 TEST(format_hash_as_string)
 {
 	unsigned char hash[16] = {
diff --git a/util.c b/util.c
index e3889b6..af26ca8 100644
--- a/util.c
+++ b/util.c
@@ -1367,6 +1367,35 @@ get_relative_path(const char *from, const char *to)
 	return result;
 }
 
+// Removes redundant (empty and '.') path components.
+void
+remove_redunant_path_components(char *path)
+{
+	assert(path);
+	char c = *path;
+	char *laststart = (c == '/' ? path+1 : path);
+
+	char *writeptr = path+1;
+	const char *readptr = path+1;
+	while (c) {
+		c = *readptr++;
+		*writeptr = c;
+		if(c == '/' || c == 0) {
+			if(writeptr != laststart) {
+				if(writeptr == laststart+1 && *laststart == '.') {
+					writeptr = laststart;
+					*writeptr = c;
+				} else {
+					writeptr++;
+					laststart = writeptr;
+				}
+			}
+		} else {
+			writeptr++;
+		}
+	};
+}
+
 // Return whether path is absolute.
 bool
 is_absolute_path(const char *path)
-- 
2.15.1

_______________________________________________
ccache mailing list
ccache@lists.samba.org
https://lists.samba.org/mailman/listinfo/ccache

Reply via email to