commit - af57b12ab516c7fa5ecc8bd00db5637240411ed7
commit + 3d9a4ec407702ad2b932c522001f1b88a36571de
blob - fa3eec221ff24961d74441b2e25a3a6186877ecd
blob + cf8a72840c0b31087b00b5d1bfe09ed1eb4479ad
--- lib/object_create.c
+++ lib/object_create.c
SHA1Init(&sha1_ctx);
fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW);
- if (fd == -1)
- return got_error_from_errno2("open", ondisk_path);
+ if (fd == -1) {
+ if (errno != ELOOP)
+ return got_error_from_errno2("open", ondisk_path);
- if (fstat(fd, &sb) == -1) {
+ if (lstat(ondisk_path, &sb) == -1) {
+ err = got_error_from_errno2("lstat", ondisk_path);
+ goto done;
+ }
+ } else if (fstat(fd, &sb) == -1) {
err = got_error_from_errno2("fstat", ondisk_path);
goto done;
}
goto done;
}
for (;;) {
- char buf[8192];
+ char buf[PATH_MAX];
ssize_t inlen;
- inlen = read(fd, buf, sizeof(buf));
- if (inlen == -1) {
- err = got_error_from_errno("read");
- goto done;
+ if (S_ISLNK(sb.st_mode)) {
+ inlen = readlink(ondisk_path, buf, sizeof(buf));
+ if (inlen == -1) {
+ err = got_error_from_errno("readlink");
+ goto done;
+ }
+ } else {
+ inlen = read(fd, buf, sizeof(buf));
+ if (inlen == -1) {
+ err = got_error_from_errno("read");
+ goto done;
+ }
}
if (inlen == 0)
break; /* EOF */
err = got_ferror(blobfile, GOT_ERR_IO);
goto done;
}
+ if (S_ISLNK(sb.st_mode))
+ break;
}
*id = malloc(sizeof(**id));
mode |= S_IXUSR | S_IXGRP | S_IXOTH;
} else if (got_object_tree_entry_is_submodule(te))
mode = S_IFDIR | S_IFLNK;
+ else if (S_ISLNK(te->mode))
+ mode = S_IFLNK; /* Git leaves all the other bits unset. */
else if (S_ISDIR(te->mode))
mode = S_IFDIR; /* Git leaves all the other bits unset. */
else
blob - 18b7915d9fcf0ce6358373186138b917bbf2f1ba
blob + 4f2a83243d33c26ba5cf655c2b3e82a61f8d5517
--- lib/worktree.c
+++ lib/worktree.c
static mode_t
get_ct_file_mode(struct got_commitable *ct)
{
+ if (S_ISLNK(ct->mode))
+ return S_IFLNK;
+
return S_IFREG | (ct->mode & ((S_IRWXU | S_IRWXG | S_IRWXO)));
}
blob - 190d9e7cedd9ad2b17f54f971ebcf4cc3acd7c3f
blob + 9bf3085d0b6f3078e98d58aaff1f4e4e4525bff9
--- regress/cmdline/commit.sh
+++ regress/cmdline/commit.sh
local head_rev=`git_show_head $testroot/repo`
echo "M alpha" > $testroot/stdout.expected
echo "Created commit $head_rev" >> $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"
+}
+
+function test_commit_symlink {
+ local testroot=`test_init commit_symlink`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && ln -s alpha alpha.link)
+ (cd $testroot/wt && ln -s epsilon epsilon.link)
+ (cd $testroot/wt && ln -s /etc/passwd passwd.link)
+ (cd $testroot/wt && ln -s ../beta epsilon/beta.link)
+ (cd $testroot/wt && ln -s nonexistent nonexistent.link)
+ (cd $testroot/wt && got add alpha.link epsilon.link passwd.link \
+ epsilon/beta.link nonexistent.link > /dev/null)
+
+ (cd $testroot/wt && got commit -m 'test commit_symlink' > $testroot/stdout)
+
+ local head_rev=`git_show_head $testroot/repo`
+ echo "A alpha.link" > $testroot/stdout.expected
+ echo "A epsilon.link" >> $testroot/stdout.expected
+ echo "A nonexistent.link" >> $testroot/stdout.expected
+ echo "A passwd.link" >> $testroot/stdout.expected
+ echo "A epsilon/beta.link" >> $testroot/stdout.expected
+ echo "Created commit $head_rev" >> $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
+
+ got checkout $testroot/repo $testroot/wt2 > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ if ! [ -h $testroot/wt2/alpha.link ]; then
+ echo "alpha.link is not a symlink"
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ readlink $testroot/wt2/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/wt2/epsilon.link ]; then
+ echo "epsilon.link is not a symlink"
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ readlink $testroot/wt2/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/wt2/passwd.link ]; then
+ echo -n "passwd.link symlink points outside of work tree: " >&2
+ readlink $testroot/wt2/passwd.link >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo -n "/etc/passwd" > $testroot/content.expected
+ cp $testroot/wt2/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/wt2/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/wt2/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
+ fi
test_done "$testroot" "$ret"
}
run_test test_commit_xbit_change
run_test test_commit_normalizes_filemodes
run_test test_commit_with_unrelated_submodule
+run_test test_commit_symlink