]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
fix: update skips different file type
authorZen Dodd <mail@steadytao.com>
Wed, 3 Jun 2026 15:16:50 +0000 (01:16 +1000)
committerAndrew Tridgell <andrew@tridgell.net>
Thu, 4 Jun 2026 23:39:09 +0000 (09:39 +1000)
generator.c
testsuite/update_test.py

index 83c4c128b9add264423c7839f56c328664b5be17..674b340da1753b3560e9b02b11a6d1f34162f151 100644 (file)
@@ -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
index 4cc10048f2fee64534d70d4089873162e2f46882..2be222a01479b6d27432bb6a1f5b846a4a183245 100644 (file)
@@ -40,6 +40,22 @@ os.utime(TODIR / deep, (st.st_atime, st.st_mtime - 100))    # dest mtime older
 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)