In order to extract the part of an absolute path which lies inside the
repo, it is not possible to directly use real_path, since that would
dereference symlinks both outside and inside the work tree.

Add an 'abspath_part_inside_repo' function which first checks if the
work tree is already the prefix, then incrementally checks each path
level by temporarily NUL-terminating at each '/' and comparing against
the work tree path. If a match is found, it overwrites the input path
with the remainder past the work tree (which will be the in-repo part).

The path being exactly equal to the work tree is handled separately,
since then there is no directory separator between the work tree and
in-repo part.

This function is currently only intended for use in
'prefix_path_gently'.

Signed-off-by: Martin Erik Werner <martinerikwer...@gmail.com>
---
 setup.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/setup.c b/setup.c
index 5432a31..e938785 100644
--- a/setup.c
+++ b/setup.c
@@ -6,6 +6,63 @@ static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 
 /*
+ * No checking if the path is in fact an absolute path is done, and it must
+ * already be normalized.
+ *
+ * Find the part of an absolute path that lies inside the work tree by
+ * dereferencing symlinks outside the work tree, for example:
+ * /dir1/repo/dir2/file   (work tree is /dir1/repo)      -> dir2/file
+ * /dir/file              (work tree is /)               -> dir/file
+ * /dir/symlink1/symlink2 (symlink1 points to work tree) -> symlink2
+ * /dir/repo              (exactly equal to work tree)   -> (empty string)
+ */
+static inline int abspath_part_inside_repo(char *path)
+{
+       size_t len;
+       size_t wtlen;
+       char *path0;
+
+       const char* work_tree = get_git_work_tree();
+       if (!work_tree)
+               return -1;
+       wtlen = strlen(work_tree);
+       len = strlen(path);
+
+       /* check if work tree is already the prefix */
+       if (strncmp(path, work_tree, wtlen) == 0) {
+               if (path[wtlen] == '/')
+                       memmove(path, path + wtlen + 1, len - wtlen);
+               else
+                       /* work tree is the root, or the whole path */
+                       memmove(path, path + wtlen, len - wtlen + 1);
+               return 0;
+       }
+       path0 = path;
+       path += offset_1st_component(path);
+
+       /* check each level */
+       while (*path != '\0') {
+               path++;
+               if (*path == '/') {
+                       *path = '\0';
+                       if (strcmp(real_path(path0), work_tree) == 0) {
+                               memmove(path0, path + 1, len - (path - path0));
+                               return 0;
+                       }
+                       *path = '/';
+               }
+       }
+
+       /* check whole path */
+       if (strcmp(real_path(path0), work_tree) == 0) {
+               *path0 = '\0';
+               return 0;
+       }
+
+       return -1;
+}
+
+/*
  * Normalize "path", prepending the "prefix" for relative paths. If
  * remaining_prefix is not NULL, return the actual prefix still
  * remains in the path. For example, prefix = sub1/sub2/ and path is
-- 
1.8.5.2

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

Reply via email to