commit - f35fa46a4c69eaeda5e106115e08b3cf8a0d3413
commit + 00bb5ea05eb54b4ec01ed195104765f7baf80169
blob - da56ac7df4e0636a6540fa7ee8fd9af961ec2f0a
blob + 9014f142cbca2af04a79adbc2efa7223ad338695
--- lib/worktree.c
+++ lib/worktree.c
}
}
- if (!S_ISREG(sb->st_mode)) {
+ if (!S_ISREG(sb->st_mode) && !S_ISLNK(sb->st_mode)) {
*status = GOT_STATUS_OBSTRUCTED;
goto done;
}
if (a->cancel_cb && a->cancel_cb(a->cancel_arg))
return got_error(GOT_ERR_CANCELLED);
- /* XXX ignore symlinks for now */
- if (de->d_type == DT_LNK)
- return NULL;
-
if (parent_path[0]) {
if (asprintf(&path, "%s/%s", parent_path, de->d_name) == -1)
return got_error_from_errno("asprintf");
return NULL;
}
- if (S_ISREG(sb.st_mode))
+ if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))
return (*status_cb)(status_arg, GOT_STATUS_UNVERSIONED,
GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
if (fd == -1) {
- if (errno != ENOTDIR && errno != ENOENT && errno != EACCES)
+ if (errno != ENOTDIR && errno != ENOENT && errno != EACCES &&
+ errno != ELOOP)
err = got_error_from_errno2("open", ondisk_path);
else
err = report_single_file_status(path, ondisk_path,
const char *arg)
{
const struct got_error *err = NULL;
- char *resolved, *cwd = NULL, *path = NULL;
+ char *resolved = NULL, *cwd = NULL, *path = NULL;
size_t len;
+ struct stat sb;
*wt_path = NULL;
- resolved = realpath(arg, NULL);
- if (resolved == NULL) {
- if (errno != ENOENT)
- return got_error_from_errno2("realpath", arg);
- cwd = getcwd(NULL, 0);
- if (cwd == NULL)
- return got_error_from_errno("getcwd");
- if (asprintf(&resolved, "%s/%s", cwd, arg) == -1) {
- err = got_error_from_errno("asprintf");
+ cwd = getcwd(NULL, 0);
+ if (cwd == NULL)
+ return got_error_from_errno("getcwd");
+
+ if (lstat(arg, &sb) == -1) {
+ if (errno != ENOENT) {
+ err = got_error_from_errno2("lstat", arg);
+ goto done;
+ }
+ }
+ if (S_ISLNK(sb.st_mode)) {
+ /*
+ * We cannot use realpath(3) with symlinks since we want to
+ * operate on the symlink itself.
+ * But we can make the path absolute, assuming it is relative
+ * to the current working directory, and then canonicalize it.
+ */
+ char *abspath = NULL;
+ char canonpath[PATH_MAX];
+ if (!got_path_is_absolute(arg)) {
+ if (asprintf(&abspath, "%s/%s", cwd, arg) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+
+ }
+ err = got_canonpath(abspath ? abspath : arg, canonpath,
+ sizeof(canonpath));
+ if (err)
goto done;
+ resolved = strdup(canonpath);
+ if (resolved == NULL) {
+ err = got_error_from_errno("strdup");
+ goto done;
+ }
+ } else {
+ resolved = realpath(arg, NULL);
+ if (resolved == NULL) {
+ if (errno != ENOENT) {
+ err = got_error_from_errno2("realpath", arg);
+ goto done;
+ }
+ if (asprintf(&resolved, "%s/%s", cwd, arg) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
}
}
blob - 030ece4e122124a89fa7523bf23c419719dcb231
blob + 789676b33649267773f4b3b3f09800cc68d7bb1b
--- regress/cmdline/add.sh
+++ regress/cmdline/add.sh
ret="$?"
if [ "$ret" != "0" ]; then
diff -u $testroot/stderr.expected $testroot/stderr
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_add_symlink {
+ local testroot=`test_init add_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)
+
+ echo "A alpha.link" > $testroot/stdout.expected
+ (cd $testroot/wt && got add alpha.link > $testroot/stdout)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "A epsilon.link" > $testroot/stdout.expected
+ (cd $testroot/wt && got add epsilon.link > $testroot/stdout)
+ 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
+
+ echo "A passwd.link" > $testroot/stdout.expected
+ (cd $testroot/wt && got add passwd.link > $testroot/stdout)
+ 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
+
+ echo "A epsilon/beta.link" > $testroot/stdout.expected
+ (cd $testroot/wt && got add epsilon/beta.link > $testroot/stdout)
+ 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
+
+ echo "A nonexistent.link" > $testroot/stdout.expected
+ (cd $testroot/wt && got add nonexistent.link > $testroot/stdout)
+ 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_add_deleted
run_test test_add_directory
run_test test_add_clashes_with_submodule
+run_test test_add_symlink
blob - bf27874f97a3459375523f37a2f63d9a83168936
blob + 580563c3ab5e905a482db9ff295dfb1eaaa2123e
--- regress/cmdline/status.sh
+++ regress/cmdline/status.sh
test_done "$testroot" "$ret"
}
-# 'got status' ignores symlinks at present; this might change eventually
-function test_status_ignores_symlink {
- local testroot=`test_init status_ignores_symlink 1`
+function test_status_symlink {
+ local testroot=`test_init status_symlink`
mkdir $testroot/repo/ramdisk/
touch $testroot/repo/ramdisk/Makefile
ln -s /usr/obj/distrib/i386/ramdisk $testroot/wt/ramdisk/obj
- echo -n > $testroot/stdout.expected
+ echo "? ramdisk/obj" > $testroot/stdout.expected
+
+ (cd $testroot/wt && got status > $testroot/stdout)
+
+ 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
+
+ (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)
+
+ echo 'A alpha.link' > $testroot/stdout.expected
+ echo 'A epsilon/beta.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 "? ramdisk/obj" >> $testroot/stdout.expected
(cd $testroot/wt && got status > $testroot/stdout)
run_test test_status_obstructed
run_test test_status_shows_local_mods_after_update
run_test test_status_unversioned_subdirs
-run_test test_status_ignores_symlink
+run_test test_status_symlink
run_test test_status_shows_no_mods_after_complete_merge
run_test test_status_shows_conflict
run_test test_status_empty_dir