fix checkout of symlinks when a relative work tree path is given
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
diff --git a/lib/worktree.c b/lib/worktree.c
index 879e8cb..365bc04 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -376,9 +376,9 @@ open_worktree(struct got_worktree **worktree, const char *path)
}
(*worktree)->lockfd = -1;
- (*worktree)->root_path = strdup(path);
+ (*worktree)->root_path = realpath(path, NULL);
if ((*worktree)->root_path == NULL) {
- err = got_error_from_errno("strdup");
+ err = got_error_from_errno2("realpath", path);
goto done;
}
err = read_meta_file(&(*worktree)->repo_path, path_got,
diff --git a/regress/cmdline/checkout.sh b/regress/cmdline/checkout.sh
index a7cf834..3cf2ade 100755
--- a/regress/cmdline/checkout.sh
+++ b/regress/cmdline/checkout.sh
@@ -609,6 +609,112 @@ function test_checkout_symlink {
test_done "$testroot" "$ret"
}
+function test_checkout_symlink_relative_wtpath {
+ local testroot=`test_init checkout_symlink_with_wtpath`
+
+ (cd $testroot/repo && ln -s alpha alpha.link)
+ (cd $testroot/repo && ln -s epsilon epsilon.link)
+ (cd $testroot/repo && ln -s /etc/passwd passwd.link)
+ (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
+ (cd $testroot/repo && ln -s nonexistent nonexistent.link)
+ (cd $testroot/repo && ln -s .got/foo dotgotfoo.link)
+ (cd $testroot/repo && git add .)
+ git_commit $testroot/repo -m "add symlinks"
+
+ (cd $testroot && got checkout $testroot/repo wt > /dev/null)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ if ! [ -h $testroot/wt/alpha.link ]; then
+ echo "alpha.link is not a symlink"
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ readlink $testroot/wt/alpha.link > $testroot/stdout
+ echo "alpha" > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ if ! [ -h $testroot/wt/epsilon.link ]; then
+ echo "epsilon.link is not a symlink"
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ readlink $testroot/wt/epsilon.link > $testroot/stdout
+ echo "epsilon" > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ if [ -h $testroot/wt/passwd.link ]; then
+ echo -n "passwd.link symlink points outside of work tree: " >&2
+ readlink $testroot/wt/passwd.link >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo -n "/etc/passwd" > $testroot/content.expected
+ cp $testroot/wt/passwd.link $testroot/content
+
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ readlink $testroot/wt/epsilon/beta.link > $testroot/stdout
+ echo "../beta" > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ readlink $testroot/wt/nonexistent.link > $testroot/stdout
+ echo "nonexistent" > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ fi
+
+ if [ -h $testroot/wt/dotgotfoo.link ]; then
+ echo -n "dotgotfoo.link symlink points into .got dir: " >&2
+ readlink $testroot/wt/dotgotfoo.link >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo -n ".got/foo" > $testroot/content.expected
+ cp $testroot/wt/dotgotfoo.link $testroot/content
+
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_checkout_basic
run_test test_checkout_dir_exists
run_test test_checkout_dir_not_empty
@@ -619,3 +725,4 @@ run_test test_checkout_ignores_submodules
run_test test_checkout_read_only
run_test test_checkout_into_nonempty_dir
run_test test_checkout_symlink
+run_test test_checkout_symlink_relative_wtpath