commit - 7d61d89137e4704e685dacfcfb71a42a87ba9f78
commit + 39449a05d564e098f638d1be356d1efbba3ab38c
blob - d2353a4d430b6ae349341d2bfac864d65c2a9a7a
blob + 8d5e78e2dc5a7a5aabb308726b8319e56d4a3ab9
--- got/got.c
+++ got/got.c
int diff_staged;
int ignore_whitespace;
};
+
+/*
+ * Create a file which contains the target path of a symlink so we can feed
+ * it as content to the diff engine.
+ */
+static const struct got_error *
+get_symlink_target_file(int *fd, int dirfd, const char *de_name,
+ const char *abspath)
+{
+ const struct got_error *err = NULL;
+ char target_path[PATH_MAX];
+ ssize_t target_len, outlen;
+
+ *fd = -1;
+
+ if (dirfd != -1) {
+ target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
+ if (target_len == -1)
+ return got_error_from_errno2("readlinkat", abspath);
+ } else {
+ target_len = readlink(abspath, target_path, PATH_MAX);
+ if (target_len == -1)
+ return got_error_from_errno2("readlink", abspath);
+ }
+
+ *fd = got_opentempfd();
+ if (*fd == -1)
+ return got_error_from_errno("got_opentempfd");
+
+ outlen = write(*fd, target_path, target_len);
+ if (outlen == -1) {
+ err = got_error_from_errno("got_opentempfd");
+ goto done;
+ }
+
+ if (lseek(*fd, 0, SEEK_SET) == -1) {
+ err = got_error_from_errno2("lseek", abspath);
+ goto done;
+ }
+done:
+ if (err) {
+ close(*fd);
+ *fd = -1;
+ }
+ return err;
+}
static const struct got_error *
print_diff(void *arg, unsigned char status, unsigned char staged_status,
if (dirfd != -1) {
fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
- err = got_error_from_errno2("openat", abspath);
- goto done;
+ if (errno != ELOOP) {
+ err = got_error_from_errno2("openat",
+ abspath);
+ goto done;
+ }
+ err = get_symlink_target_file(&fd, dirfd,
+ de_name, abspath);
+ if (err)
+ goto done;
}
} else {
fd = open(abspath, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
- err = got_error_from_errno2("open", abspath);
- goto done;
+ if (errno != ELOOP) {
+ err = got_error_from_errno2("open",
+ abspath);
+ goto done;
+ }
+ err = get_symlink_target_file(&fd, dirfd,
+ de_name, abspath);
+ if (err)
+ goto done;
}
}
if (fstat(fd, &sb) == -1) {
blob - a3f99c8779d3bd933ae0f0f14741563fad6794a7
blob + b29b40b95fb58c581c7b24ef325ee920470bb0cf
--- regress/cmdline/diff.sh
+++ regress/cmdline/diff.sh
fi
test_done "$testroot" "$ret"
}
+
+function test_diff_symlinks_in_work_tree {
+ local testroot=`test_init diff_symlinks_in_work_tree`
+
+ (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"
+ local commit_id1=`git_show_head $testroot/repo`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && ln -sf beta alpha.link)
+ (cd $testroot/wt && ln -sf gamma epsilon.link)
+ (cd $testroot/wt && ln -sf ../gamma/delta epsilon/beta.link)
+ echo -n '.got/bar' > $testroot/wt/dotgotfoo.link
+ (cd $testroot/wt && got rm nonexistent.link > /dev/null)
+ (cd $testroot/wt && ln -sf epsilon/zeta zeta.link)
+ (cd $testroot/wt && got add zeta.link > /dev/null)
+ (cd $testroot/wt && got diff > $testroot/stdout)
+ echo "diff $commit_id1 $testroot/wt" > $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'alpha.link@ -> alpha$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo 'file + alpha.link' >> $testroot/stdout.expected
+ echo '--- alpha.link' >> $testroot/stdout.expected
+ echo '+++ alpha.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-alpha' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+beta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'dotgotfoo.link@ -> .got/foo$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo 'file + dotgotfoo.link' >> $testroot/stdout.expected
+ echo '--- dotgotfoo.link' >> $testroot/stdout.expected
+ echo '+++ dotgotfoo.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-.got/foo' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+.got/bar' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i epsilon | \
+ grep 'beta.link@ -> ../beta$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo 'file + epsilon/beta.link' >> $testroot/stdout.expected
+ echo '--- epsilon/beta.link' >> $testroot/stdout.expected
+ echo '+++ epsilon/beta.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-../beta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+../gamma/delta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'nonexistent.link@ -> nonexistent$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo 'file + /dev/null' >> $testroot/stdout.expected
+ echo '--- nonexistent.link' >> $testroot/stdout.expected
+ echo '+++ nonexistent.link' >> $testroot/stdout.expected
+ echo '@@ -1 +0,0 @@' >> $testroot/stdout.expected
+ echo '-nonexistent' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo 'blob - /dev/null' >> $testroot/stdout.expected
+ echo 'file + zeta.link' >> $testroot/stdout.expected
+ echo '--- zeta.link' >> $testroot/stdout.expected
+ echo '+++ zeta.link' >> $testroot/stdout.expected
+ echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected
+ echo '+epsilon/zeta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $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"
+}
+
run_test test_diff_basic
run_test test_diff_shows_conflict
run_test test_diff_tag
run_test test_diff_lightweight_tag
run_test test_diff_ignore_whitespace
run_test test_diff_submodule_of_same_repo
+run_test test_diff_symlinks_in_work_tree