Make rsync() recreate symlinks only on request

Fixing LITE_FOPT_COPYFILE_SYM in copyfile() also changed rsync(), which
has always passed that flag.  Every caller would start getting links in
the destination where they used to get a copy of the file.

Keep following links by default and add LITE_FOPT_RSYNC_LINKS for
callers that want them recreated.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-11-14 12:46:48 +01:00
1 parent 666a8ef7cd
commit 4609c53ddd
5 files changed
+42 -12

No files matched your search

+11 -7
View File
@@ -65,29 +65,33 @@ int main(void)
check_link("copied", "file");
fail_unless(lstat("copied", &dst_st) == 0 && dst_st.st_mtime == times[1].tv_sec);
fail_unless(unlink("copied") == 0);
/* Exercise the existing rsync file caller, which requests SYM. */
/* rsync() follows links unless asked to recreate them. */
fail_unless(rsync("link", "copied", 0, NULL) == 0);
fail_unless(lstat("copied", &dst_st) == 0 && S_ISREG(dst_st.st_mode));
fail_unless(dst_st.st_size == sizeof(payload));
fail_unless(unlink("copied") == 0);
fail_unless(rsync("link", "copied", LITE_FOPT_RSYNC_LINKS, NULL) == 0);
check_link("copied", "file");
/* Reuse the destination after changing the source link. */
fail_unless(unlink("link") == 0 && symlink("file", "link") == 0);
fail_unless(rsync("link", "out", 0, NULL) == 0);
fail_unless(rsync("link", "out", LITE_FOPT_RSYNC_LINKS, NULL) == 0);
check_link("out/link", "file");
fail_unless(unlink("link") == 0 && symlink("copied", "link") == 0);
fail_unless(rsync("link", "out", 0, NULL) == 0);
fail_unless(rsync("link", "out", LITE_FOPT_RSYNC_LINKS, NULL) == 0);
check_link("out/link", "copied");
/* A same-path copy must not unlink its source. */
fail_unless(rsync("link", "link", 0, NULL) == 0);
fail_unless(rsync("link", "link", LITE_FOPT_RSYNC_LINKS, NULL) == 0);
check_link("link", "copied");
fail_unless(unlink("out/link") == 0);
/* Replacing a regular destination must also retain the source link. */
fail_unless(touch("out/link") == 0);
fail_unless(rsync("link", "out", 0, NULL) == 0);
fail_unless(rsync("link", "out", LITE_FOPT_RSYNC_LINKS, NULL) == 0);
check_link("out/link", "copied");
fail_unless(unlink("out/link") == 0);
/* A failed replacement must keep both the destination and source. */
fail_unless(mkdir("out/link", 0700) == 0);
fail_unless(touch("out/link/keep") == 0);
fail_unless(rsync("link", "out", 0, NULL) != 0);
fail_unless(rsync("link", "out", LITE_FOPT_RSYNC_LINKS, NULL) != 0);
fail_unless(fexist("out/link/keep"));
check_link("link", "copied");
fail_unless(unlink("out/link/keep") == 0 && rmdir("out/link") == 0);
@@ -95,7 +99,7 @@ int main(void)
fail_unless(mkdir("protected", 0700) == 0);
fail_unless(symlink("original", "protected/link") == 0);
fail_unless(chmod("protected", 0500) == 0);
fail_unless(rsync("link", "protected", 0, NULL) != 0);
fail_unless(rsync("link", "protected", LITE_FOPT_RSYNC_LINKS, NULL) != 0);
check_link("protected/link", "original");
check_link("link", "copied");
fail_unless(chmod("protected", 0700) == 0);