fix replacing symlinks with files And add a test case which verifies that the inverse also works, i.e. a symlink being replaced with a regular file. problem reported and fix tested by jrick
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 139 140 141 142 143 144 145
diff --git a/lib/worktree.c b/lib/worktree.c
index cbef2cc..498ebaa 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -1496,7 +1496,8 @@ install_blob(struct got_worktree *worktree, const char *ondisk_path,
GOT_STATUS_UNVERSIONED, path);
goto done;
}
- if (!S_ISREG(st_mode) && !installing_bad_symlink) {
+ if (!(S_ISLNK(st_mode) && S_ISREG(te_mode)) &&
+ !S_ISREG(st_mode) && !installing_bad_symlink) {
/* TODO file is obstructed; do something */
err = got_error_path(ondisk_path,
GOT_ERR_FILE_OBSTRUCTED);
@@ -1558,6 +1559,10 @@ install_blob(struct got_worktree *worktree, const char *ondisk_path,
}
if (update) {
+ if (S_ISLNK(st_mode) && unlink(ondisk_path) == -1) {
+ err = got_error_from_errno2("unlink", ondisk_path);
+ goto done;
+ }
if (rename(tmppath, ondisk_path) != 0) {
err = got_error_from_errno3("rename", tmppath,
ondisk_path);
diff --git a/regress/cmdline/integrate.sh b/regress/cmdline/integrate.sh
index c347b9e..dcc2976 100755
--- a/regress/cmdline/integrate.sh
+++ b/regress/cmdline/integrate.sh
@@ -385,8 +385,8 @@ test_integrate_backwards_in_time() {
test_done "$testroot" "$ret"
}
-test_integrate_obstructed_symlink() {
- local testroot=`test_init update_replace_symlink`
+test_integrate_replace_symlink_with_file() {
+ local testroot=`test_init integrate_replace_symlink_with_file`
got checkout $testroot/repo $testroot/wt > /dev/null
ret="$?"
@@ -401,22 +401,90 @@ test_integrate_obstructed_symlink() {
(cd $testroot/wt && got commit -m "add regular file and symlink" \
>/dev/null)
- (cd $testroot/wt && got br replace_symlink >/dev/null)
+ (cd $testroot/wt && got br replace_symlink_with_file >/dev/null)
(cd $testroot/wt && rm alpha.link >/dev/null)
(cd $testroot/wt && cp alpha alpha.link)
(cd $testroot/wt && got stage alpha.link >/dev/null)
(cd $testroot/wt && got commit -m "replace symlink" >/dev/null)
(cd $testroot/wt && got up -b master >/dev/null)
- (cd $testroot/wt && got integrate replace_symlink \
- 2> $testroot/stderr)
+ (cd $testroot/wt && got integrate replace_symlink_with_file \
+ > $testroot/stdout)
- echo "got: $testroot/wt/alpha.link: file is obstructed" \
- > $testroot/stderr.expected
- cmp -s $testroot/stderr.expected $testroot/stderr
+ echo "U alpha.link" > $testroot/stdout.expected
+ echo -n "Integrated refs/heads/replace_symlink_with_file " \
+ >> $testroot/stdout.expected
+ echo "into refs/heads/master" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
ret="$?"
if [ "$ret" != "0" ]; then
- diff -u $testroot/stderr.expected $testroot/stderr
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ if [ -h $testroot/wt/alpha.link ]; then
+ echo "alpha.link is still a symlink"
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo "alpha" > $testroot/content.expected
+ cat $testroot/wt/alpha.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"
+}
+
+test_integrate_replace_file_with_symlink() {
+ local testroot=`test_init integrate_replace_file_with_symlink`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "checkout failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got br replace_file_with_symlink >/dev/null)
+ (cd $testroot/wt && rm alpha)
+ (cd $testroot/wt && ln -s beta alpha)
+ (cd $testroot/wt && got commit -m "replace regular file with symlink" \
+ >/dev/null)
+
+ (cd $testroot/wt && got up -b master >/dev/null)
+ (cd $testroot/wt && got integrate replace_file_with_symlink \
+ > $testroot/stdout)
+
+ echo "U alpha" > $testroot/stdout.expected
+ echo -n "Integrated refs/heads/replace_file_with_symlink " \
+ >> $testroot/stdout.expected
+ echo "into refs/heads/master" >> $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/alpha ]; then
+ echo "alpha is not a symlink"
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ readlink $testroot/wt/alpha > $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
fi
test_done "$testroot" "$ret"
}
@@ -426,4 +494,5 @@ run_test test_integrate_basic
run_test test_integrate_requires_rebase_first
run_test test_integrate_path_prefix
run_test test_integrate_backwards_in_time
-run_test test_integrate_obstructed_symlink
+run_test test_integrate_replace_symlink_with_file
+run_test test_integrate_replace_file_with_symlink