-
Notifications
You must be signed in to change notification settings - Fork 459
Description
According to the manual for --update:
This forces rsync to skip any files which exist on the destination and have a modified time that is
newer than the source file. (If an existing destination file has a modification time equal to the
source file's, it will be updated if the sizes are different.)
Note that this does not affect the copying of dirs, symlinks, or other special files. Also, a differ‐
ence of file format between the sender and receiver is always considered to be important enough for an
update, no matter what date is on the objects. In other words, if the source has a directory where the
destination has a file, the transfer would occur regardless of the timestamps.
From what I understood in there, this means that if files are not the same format, it will always overwrite the destination. In this case, a file and a symlink are not the same format. But this is currently not the case if the destination is a symlink.
You can easily reproduce this with the following code:
rm -rf /tmp/rsynctest_src /tmp/rsynctest_dst
mkdir -p /tmp/rsynctest_src
echo "Hello world" > /tmp/rsynctest_src/foo
mkdir -p /tmp/rsynctest_dst
ln -s /should/not/exist /tmp/rsynctest_dst/foo
touch -h -d 'tomorrow' /tmp/rsynctest_dst/foo
stat /tmp/rsynctest_src/foo
stat /tmp/rsynctest_dst/foo
rsync -auvvv /tmp/rsynctest_src/ /tmp/rsynctest_dst/
stat /tmp/rsynctest_dst/foo
ls -l /tmp/rsynctest_dst/foo
file /tmp/rsynctest_dst/fooFrom this I would expect the destination file to be overwritten as its not the same format, but it is fully skipped:
sending incremental file list
[sender] make_file(.,*,0)
[sender] pushing local filters for /tmp/rsynctest_src/
[sender] make_file(foo,*,2)
send_file_list done
send_files starting
server_recv(2) starting pid=3773048
recv_file_name(.)
recv_file_name(foo)
received 2 names
recv_file_list done
get_local_name count=2 /tmp/rsynctest_dst/
generator starting pid=3773048
delta-transmission disabled for local transfer or --whole-file
recv_generator(.,0)
recv_generator(.,1)
recv_generator(foo,2)
foo is newer
send_files(0, /tmp/rsynctest_src/.)
recv_files(2) starting
recv_files(.)
generate_files phase=1
send_files phase=1
recv_files phase=1
generate_files phase=2
send_files phase=2
send files finished
total: matches=0 hash_hits=0 false_alarms=0 data=0
recv_files phase=2
recv_files finished
generate_files phase=3
generate_files finished
sent 80 bytes received 512 bytes 1.184,00 bytes/sec
total size is 12 speedup is 0,02
[sender] _exit_cleanup(code=0, file=main.c, line=1338): about to call exit(0)
But somehow, doing it the other way does respect what the manual says. Doing source symlink and destination file, does overwrite, even if destination has a newer mtime:
rm -rf /tmp/rsynctest_src /tmp/rsynctest_dst
mkdir -p /tmp/rsynctest_src
ln -s /some/target/path /tmp/rsynctest_src/foo
mkdir -p /tmp/rsynctest_dst
echo "old data" > /tmp/rsynctest_dst/foo
touch -d 'tomorrow' /tmp/rsynctest_dst/foo
# Confirm initial file types:
stat /tmp/rsynctest_src/foo
stat /tmp/rsynctest_dst/foo
# Run rsync:
rsync -auvvv /tmp/rsynctest_src/ /tmp/rsynctest_dst/
stat /tmp/rsynctest_dst/foo
ls -l /tmp/rsynctest_dst/foo
file /tmp/rsynctest_dst/foosending incremental file list
[sender] make_file(.,*,0)
[sender] pushing local filters for /tmp/rsynctest_src/
[sender] make_file(foo,*,2)
send_file_list done
send_files starting
server_recv(2) starting pid=3772021
recv_file_name(.)
recv_file_name(foo)
received 2 names
recv_file_list done
get_local_name count=2 /tmp/rsynctest_dst/
generator starting pid=3772021
delta-transmission disabled for local transfer or --whole-file
recv_generator(.,0)
recv_generator(.,1)
recv_generator(foo,2)
send_files(0, /tmp/rsynctest_src/.)
send_files(2, /tmp/rsynctest_src/foo)
foo -> /some/target/path
recv_files(2) starting
recv_files(.)
recv_files(foo)
generate_files phase=1
send_files phase=1
recv_files phase=1
generate_files phase=2
send_files phase=2
send files finished
total: matches=0 hash_hits=0 false_alarms=0 data=0
recv_files phase=2
recv_files finished
generate_files phase=3
generate_files finished
So Im not sure whats the correct behavior here, I would expect what the docs say but the reality differs.
Not sure if this is a bug or I'm doing something wrong?
rsync version 3.4.1 protocol version 32
Copyright (C) 1996-2025 by Andrew Tridgell, Wayne Davison, and others.
Web site: https://rsync.samba.org/
Capabilities:
64-bit files, 64-bit inums, 64-bit timestamps, 64-bit long ints,
socketpairs, symlinks, symtimes, hardlinks, hardlink-specials,
hardlink-symlinks, IPv6, atimes, batchfiles, inplace, append, ACLs,
xattrs, optional secluded-args, iconv, prealloc, stop-at, no crtimes
Optimizations:
SIMD-roll, no asm-roll, openssl-crypto, no asm-MD5
Checksum list:
xxh128 xxh3 xxh64 (xxhash) md5 md4 sha1 none
Compress list:
zstd lz4 zlibx zlib none
Daemon auth list:
sha512 sha256 sha1 md5 md4
rsync comes with ABSOLUTELY NO WARRANTY. This is free software, and you
are welcome to redistribute it under certain conditions. See the GNU
General Public Licence for details.
Thanks!