Merge branch 'mw/symlinks' into maint
* mw/symlinks: setup: fix windows path buffer over-stepping setup: don't dereference in-tree symlinks for absolute paths setup: add abspath_part_inside_repo() function t0060: add tests for prefix_path when path begins with work tree t0060: add test for prefix_path when path == work tree t0060: add test for prefix_path on symlinks via absolute paths t3004: add test for ls-files on symlinks via absolute paths
This commit is contained in:
94
setup.c
94
setup.c
@ -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 = offset_1st_component(path);
|
||||
|
||||
/* 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 += 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
|
||||
@ -22,11 +86,17 @@ char *prefix_path_gently(const char *prefix, int len,
|
||||
const char *orig = path;
|
||||
char *sanitized;
|
||||
if (is_absolute_path(orig)) {
|
||||
const char *temp = real_path(path);
|
||||
sanitized = xmalloc(len + strlen(temp) + 1);
|
||||
strcpy(sanitized, temp);
|
||||
sanitized = xmalloc(strlen(path) + 1);
|
||||
if (remaining_prefix)
|
||||
*remaining_prefix = 0;
|
||||
if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
|
||||
free(sanitized);
|
||||
return NULL;
|
||||
}
|
||||
if (abspath_part_inside_repo(sanitized)) {
|
||||
free(sanitized);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
sanitized = xmalloc(len + strlen(path) + 1);
|
||||
if (len)
|
||||
@ -34,26 +104,10 @@ char *prefix_path_gently(const char *prefix, int len,
|
||||
strcpy(sanitized + len, path);
|
||||
if (remaining_prefix)
|
||||
*remaining_prefix = len;
|
||||
}
|
||||
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
|
||||
goto error_out;
|
||||
if (is_absolute_path(orig)) {
|
||||
size_t root_len, len, total;
|
||||
const char *work_tree = get_git_work_tree();
|
||||
if (!work_tree)
|
||||
goto error_out;
|
||||
len = strlen(work_tree);
|
||||
root_len = offset_1st_component(work_tree);
|
||||
total = strlen(sanitized) + 1;
|
||||
if (strncmp(sanitized, work_tree, len) ||
|
||||
(len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
|
||||
error_out:
|
||||
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
|
||||
free(sanitized);
|
||||
return NULL;
|
||||
}
|
||||
if (sanitized[len] == '/')
|
||||
len++;
|
||||
memmove(sanitized, sanitized + len, total - len);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user