diff --git a/generator.c b/generator.c index 83c4c128b..674b340da 100644 --- a/generator.c +++ b/generator.c @@ -1718,7 +1718,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } - if (update_only > 0 && statret == 0 && file->modtime - sx.st.st_mtime < modify_window) { + if (update_only > 0 && statret == 0 && stype == ftype + && file->modtime - sx.st.st_mtime < modify_window) { if (INFO_GTE(SKIP, 1)) rprintf(FINFO, "%s is newer\n", fname); #ifdef SUPPORT_HARD_LINKS diff --git a/testsuite/update_test.py b/testsuite/update_test.py index 4cc10048f..2be222a01 100644 --- a/testsuite/update_test.py +++ b/testsuite/update_test.py @@ -40,6 +40,22 @@ run_rsync('-a', '-u', f'{src}/', f'{TODIR}/') assert_same(TODIR / deep, src / deep, label='-u updated an older dest file') +# A newer destination symlink is still replaced by a source regular file +# because a file-format difference is always important enough to update. +rmtree(src) +rmtree(TODIR) +makepath(src, TODIR) +(src / 'foo').write_text("regular source file\n") +os.symlink('/should/not/exist', TODIR / 'foo') +st = os.stat(src / 'foo') +os.utime(TODIR / 'foo', (st.st_atime, st.st_mtime + 100), + follow_symlinks=False) +run_rsync('-a', '-u', f'{src}/', f'{TODIR}/') +if os.path.islink(TODIR / 'foo'): + test_fail("-u skipped a source file over a newer destination symlink") +assert_same(TODIR / 'foo', src / 'foo', + label='-u replaced a newer dest symlink with a regular file') + # --- --force replaces a non-empty dest directory with a file at depth ------- rmtree(src) rmtree(TODIR)