setup: add abspath_part_inside_repo() function

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 part inside the
work tree).

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

Signed-off-by: Martin Erik Werner <martinerikwerner@gmail.com>
Reviewed-by: Duy Nguyen <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Martin Erik Werner 2014-02-04 15:25:19 +01:00 committed by Junio C Hamano
parent e131daa4c6
commit ddc2a62815

64
setup.c
View File

@ -5,6 +5,70 @@
static int inside_git_dir = -1;
static int inside_work_tree = -1;
/*
* The input parameter must contain an absolute path, 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/repolink/file (repolink points to /dir/repo) -> file
* /dir/repo (exactly equal to work tree) -> (empty string)
*/
static int abspath_part_inside_repo(char *path)
{
size_t len;
size_t wtlen;
char *path0;
int off;
const char *work_tree = get_git_work_tree();
if (!work_tree)
return -1;
wtlen = strlen(work_tree);
len = strlen(path);
off = 0;
/* check if work tree is already the prefix */
if (wtlen <= len && !strncmp(path, work_tree, wtlen)) {
if (path[wtlen] == '/') {
memmove(path, path + wtlen + 1, len - wtlen);
return 0;
} else if (path[wtlen - 1] == '/' || path[wtlen] == '\0') {
/* work tree is the root, or the whole path */
memmove(path, path + wtlen, len - wtlen + 1);
return 0;
}
/* work tree might match beginning of a symlink to work tree */
off = wtlen;
}
path0 = path;
path += offset_1st_component(path) + off;
/* check each '/'-terminated level */
while (*path) {
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