commit - 0ab20ee9ead0bcdb626ef9fb52d63f58e13082a5
commit + f35fa46a4c69eaeda5e106115e08b3cf8a0d3413
blob - 03438c0b820def82a8574d7f14c80d53cc19a1c7
blob + da56ac7df4e0636a6540fa7ee8fd9af961ec2f0a
--- lib/worktree.c
+++ lib/worktree.c
}
if (symlink(target_path, ondisk_path) == -1) {
- if (errno == ENOENT) {
- char *parent = dirname(ondisk_path);
- if (parent == NULL) {
- err = got_error_from_errno2("dirname",
- ondisk_path);
- goto done;
- }
- err = add_dir_on_disk(worktree, parent);
- if (err)
- goto done;
- /*
- * Retry, and fall through to error handling
- * below if this second attempt fails.
- */
- if (symlink(target_path, ondisk_path) != -1) {
- err = NULL; /* success */
- goto done;
- }
- }
-
- /* Handle errors from first or second creation attempt. */
if (errno == EEXIST) {
struct stat sb;
ssize_t elen;
goto done;
}
if (elen == target_len &&
- memcmp(etarget, target_path, target_len) == 0)
- err = NULL;
- else
- err = got_error_path(ondisk_path,
- GOT_ERR_FILE_OBSTRUCTED);
- } else if (errno == ENAMETOOLONG) {
+ memcmp(etarget, target_path, target_len) == 0) {
+ err = NULL; /* nothing to do */
+ goto done;
+ } else {
+ if (unlink(ondisk_path) == -1) {
+ err = got_error_from_errno2("unlink",
+ ondisk_path);
+ goto done;
+ }
+ if (symlink(target_path, ondisk_path) == -1) {
+ err = got_error_from_errno3("symlink",
+ target_path, ondisk_path);
+ goto done;
+ }
+
+ err = (*progress_cb)(progress_arg,
+ GOT_STATUS_UPDATE, path);
+ goto done;
+ }
+ }
+
+ if (errno == ENOENT) {
+ char *parent = dirname(ondisk_path);
+ if (parent == NULL) {
+ err = got_error_from_errno2("dirname",
+ ondisk_path);
+ goto done;
+ }
+ err = add_dir_on_disk(worktree, parent);
+ if (err)
+ goto done;
+ /*
+ * Retry, and fall through to error handling
+ * below if this second attempt fails.
+ */
+ if (symlink(target_path, ondisk_path) != -1) {
+ err = NULL; /* success */
+ goto done;
+ }
+ }
+
+ /* Handle errors from first or second creation attempt. */
+ if (errno == ENAMETOOLONG) {
/* bad target path; install as a regular file */
got_object_blob_rewind(blob);
err = install_blob(worktree, ondisk_path, path,
err = got_error_from_errno3("symlink",
target_path, ondisk_path);
}
- }
+ } else
+ err = (*progress_cb)(progress_arg, GOT_STATUS_ADD, path);
done:
free(resolved_path);
free(abspath);
blob - 60a1a2ab40ff159845a71f43bd69ec3145dfa795
blob + b61d2a00448a591d108d2209b91d0e762aea07f2
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
fi
test_done "$testroot" "$ret"
}
+
+function test_update_adds_symlink {
+ local testroot=`test_init update_adds_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/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 && git add .)
+ git_commit $testroot/repo -m "add symlinks"
+
+ 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 -n "Updated to commit " >> $testroot/stdout.expected
+ git_show_head $testroot/repo >> $testroot/stdout.expected
+ echo >> $testroot/stdout.expected
+
+ (cd $testroot/wt && got update > $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
+
+ 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
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_update_basic
run_test test_update_adds_file
run_test test_update_deletes_file
run_test test_update_modified_submodules
run_test test_update_adds_submodule
run_test test_update_conflict_wt_file_vs_repo_submodule
+run_test test_update_adds_symlink