mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
Merge branch 'mw/symlinks'
All subcommands that take pathspecs mishandled an in-tree symbolic link when given it as a full path from the root (which arguably is a sick way to use pathspecs). "git ls-files -s $(pwd)/RelNotes" in our tree is an easy reproduction recipe. * mw/symlinks: 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:
commit
8a342058f6
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 = 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -190,6 +190,27 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
|
|||
test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
|
||||
'
|
||||
|
||||
test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
|
||||
ln -s target symlink &&
|
||||
test "$(test-path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink"
|
||||
'
|
||||
|
||||
test_expect_success 'prefix_path works with only absolute path to work tree' '
|
||||
echo "" >expected &&
|
||||
test-path-utils prefix_path prefix "$(pwd)" >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'prefix_path rejects absolute path to dir with same beginning as work tree' '
|
||||
test_must_fail test-path-utils prefix_path prefix "$(pwd)a"
|
||||
'
|
||||
|
||||
test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' '
|
||||
git init repo &&
|
||||
ln -s repo repolink &&
|
||||
test "a" = "$(cd repo && test-path-utils prefix_path prefix "$(pwd)/../repolink/a")"
|
||||
'
|
||||
|
||||
relative_path /foo/a/b/c/ /foo/a/b/ c/
|
||||
relative_path /foo/a/b/c/ /foo/a/b c/
|
||||
relative_path /foo/a//b//c/ ///foo/a/b// c/ POSIX
|
||||
|
|
|
@ -36,4 +36,21 @@ test_expect_success 'ls-files -h in corrupt repository' '
|
|||
test_i18ngrep "[Uu]sage: git ls-files " broken/usage
|
||||
'
|
||||
|
||||
test_expect_success SYMLINKS 'ls-files with absolute paths to symlinks' '
|
||||
mkdir subs &&
|
||||
ln -s nosuch link &&
|
||||
ln -s ../nosuch subs/link &&
|
||||
git add link subs/link &&
|
||||
git ls-files -s link subs/link >expect &&
|
||||
git ls-files -s "$(pwd)/link" "$(pwd)/subs/link" >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
(
|
||||
cd subs &&
|
||||
git ls-files -s link >../expect &&
|
||||
git ls-files -s "$(pwd)/link" >../actual
|
||||
) &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in a new issue