Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 64d8c31

Browse files
committed
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
2 parents eea5913 + 6127ff6 commit 64d8c31

File tree

3 files changed

+112
-20
lines changed

3 files changed

+112
-20
lines changed

setup.c

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,70 @@
55
static int inside_git_dir = -1;
66
static int inside_work_tree = -1;
77

8+
/*
9+
* The input parameter must contain an absolute path, and it must already be
10+
* normalized.
11+
*
12+
* Find the part of an absolute path that lies inside the work tree by
13+
* dereferencing symlinks outside the work tree, for example:
14+
* /dir1/repo/dir2/file (work tree is /dir1/repo) -> dir2/file
15+
* /dir/file (work tree is /) -> dir/file
16+
* /dir/symlink1/symlink2 (symlink1 points to work tree) -> symlink2
17+
* /dir/repolink/file (repolink points to /dir/repo) -> file
18+
* /dir/repo (exactly equal to work tree) -> (empty string)
19+
*/
20+
static int abspath_part_inside_repo(char *path)
21+
{
22+
size_t len;
23+
size_t wtlen;
24+
char *path0;
25+
int off;
26+
const char *work_tree = get_git_work_tree();
27+
28+
if (!work_tree)
29+
return -1;
30+
wtlen = strlen(work_tree);
31+
len = strlen(path);
32+
off = offset_1st_component(path);
33+
34+
/* check if work tree is already the prefix */
35+
if (wtlen <= len && !strncmp(path, work_tree, wtlen)) {
36+
if (path[wtlen] == '/') {
37+
memmove(path, path + wtlen + 1, len - wtlen);
38+
return 0;
39+
} else if (path[wtlen - 1] == '/' || path[wtlen] == '\0') {
40+
/* work tree is the root, or the whole path */
41+
memmove(path, path + wtlen, len - wtlen + 1);
42+
return 0;
43+
}
44+
/* work tree might match beginning of a symlink to work tree */
45+
off = wtlen;
46+
}
47+
path0 = path;
48+
path += off;
49+
50+
/* check each '/'-terminated level */
51+
while (*path) {
52+
path++;
53+
if (*path == '/') {
54+
*path = '\0';
55+
if (strcmp(real_path(path0), work_tree) == 0) {
56+
memmove(path0, path + 1, len - (path - path0));
57+
return 0;
58+
}
59+
*path = '/';
60+
}
61+
}
62+
63+
/* check whole path */
64+
if (strcmp(real_path(path0), work_tree) == 0) {
65+
*path0 = '\0';
66+
return 0;
67+
}
68+
69+
return -1;
70+
}
71+
872
/*
973
* Normalize "path", prepending the "prefix" for relative paths. If
1074
* remaining_prefix is not NULL, return the actual prefix still
@@ -22,38 +86,28 @@ char *prefix_path_gently(const char *prefix, int len,
2286
const char *orig = path;
2387
char *sanitized;
2488
if (is_absolute_path(orig)) {
25-
const char *temp = real_path(path);
26-
sanitized = xmalloc(len + strlen(temp) + 1);
27-
strcpy(sanitized, temp);
89+
sanitized = xmalloc(strlen(path) + 1);
2890
if (remaining_prefix)
2991
*remaining_prefix = 0;
92+
if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
93+
free(sanitized);
94+
return NULL;
95+
}
96+
if (abspath_part_inside_repo(sanitized)) {
97+
free(sanitized);
98+
return NULL;
99+
}
30100
} else {
31101
sanitized = xmalloc(len + strlen(path) + 1);
32102
if (len)
33103
memcpy(sanitized, prefix, len);
34104
strcpy(sanitized + len, path);
35105
if (remaining_prefix)
36106
*remaining_prefix = len;
37-
}
38-
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
39-
goto error_out;
40-
if (is_absolute_path(orig)) {
41-
size_t root_len, len, total;
42-
const char *work_tree = get_git_work_tree();
43-
if (!work_tree)
44-
goto error_out;
45-
len = strlen(work_tree);
46-
root_len = offset_1st_component(work_tree);
47-
total = strlen(sanitized) + 1;
48-
if (strncmp(sanitized, work_tree, len) ||
49-
(len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
50-
error_out:
107+
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
51108
free(sanitized);
52109
return NULL;
53110
}
54-
if (sanitized[len] == '/')
55-
len++;
56-
memmove(sanitized, sanitized + len, total - len);
57111
}
58112
return sanitized;
59113
}

t/t0060-path-utils.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,27 @@ test_expect_success SYMLINKS 'real path works on symlinks' '
190190
test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
191191
'
192192

193+
test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' '
194+
ln -s target symlink &&
195+
test "$(test-path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink"
196+
'
197+
198+
test_expect_success 'prefix_path works with only absolute path to work tree' '
199+
echo "" >expected &&
200+
test-path-utils prefix_path prefix "$(pwd)" >actual &&
201+
test_cmp expected actual
202+
'
203+
204+
test_expect_success 'prefix_path rejects absolute path to dir with same beginning as work tree' '
205+
test_must_fail test-path-utils prefix_path prefix "$(pwd)a"
206+
'
207+
208+
test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' '
209+
git init repo &&
210+
ln -s repo repolink &&
211+
test "a" = "$(cd repo && test-path-utils prefix_path prefix "$(pwd)/../repolink/a")"
212+
'
213+
193214
relative_path /foo/a/b/c/ /foo/a/b/ c/
194215
relative_path /foo/a/b/c/ /foo/a/b c/
195216
relative_path /foo/a//b//c/ ///foo/a/b// c/ POSIX

t/t3004-ls-files-basic.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,21 @@ test_expect_success 'ls-files -h in corrupt repository' '
3636
test_i18ngrep "[Uu]sage: git ls-files " broken/usage
3737
'
3838

39+
test_expect_success SYMLINKS 'ls-files with absolute paths to symlinks' '
40+
mkdir subs &&
41+
ln -s nosuch link &&
42+
ln -s ../nosuch subs/link &&
43+
git add link subs/link &&
44+
git ls-files -s link subs/link >expect &&
45+
git ls-files -s "$(pwd)/link" "$(pwd)/subs/link" >actual &&
46+
test_cmp expect actual &&
47+
48+
(
49+
cd subs &&
50+
git ls-files -s link >../expect &&
51+
git ls-files -s "$(pwd)/link" >../actual
52+
) &&
53+
test_cmp expect actual
54+
'
55+
3956
test_done

0 commit comments

Comments
 (0)