Bug 10494 - remove-source-files fails with symlinks
Summary: remove-source-files fails with symlinks
Status: RESOLVED FIXED
Alias: None
Product: rsync
Classification: Unclassified
Component: core (show other bugs)
Version: 3.1.0
Hardware: x64 Linux
: P5 major (vote)
Target Milestone: ---
Assignee: Wayne Davison
QA Contact: Rsync QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-10 22:04 UTC by afried
Modified: 2019-03-20 13:18 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description afried 2014-03-10 22:04:17 UTC
Up thru 3.0.9 transferring symlinks using "-L --remove-source-files" properly transferred the files and removed the symlinks.

Beginning with 3.1.0 this no longer works; the files transfer properly but the symlinks on the source server fail to get deleted. This error message is displayed:

ERROR: Skipping sender remove for changed file: [transferred file name]

I have not been able to find a workaround to this problem, other than downgrading from 3.1.0 back to 3.0.9.
Comment 1 Wayne Davison 2015-07-12 20:28:51 UTC
That's weird, as it means that the source symlink must differ in size or modify time from what rsync put into the source file list.  However, since that safety check is only really needed for regular files, I've added some code that should avoid this failure for symlinks and devices.
Comment 2 Adrian Torregrosa 2019-03-14 15:29:57 UTC
We have found this same problem using rsync 3.1.2.

I have downloaded the source code for version 3.1.3, and found the following lines in sender.c:

146         if (S_ISREG(file->mode) /* Symlinks & devices don't need this check: */
147          && (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime
148 #ifdef ST_MTIME_NSEC
149          || (NSEC_BUMP(file) && (uint32)st.ST_MTIME_NSEC != F_MOD_NSEC(file))
150 #endif
151         )) {
152                 rprintf(FERROR_XFER, "ERROR: Skipping sender remove for changed file: %s\n", fname);
153                 return;
154         }

I added some debugging info, compiled and tested, and found out that when trying to retrieve symlinks the "file" pointer refers to the hard file, whereas the "st" register refers to the symlink. Therefore "S_ISREG(file->mode)" will be true, so will be "st.st_size != F_LENGTH(file)" and most likely "st.st_mtime != file->modtime" too. As a result the error gets printed and the symlink is not deleted, as intended.

I have tried modifying the first condition and it worked as expected:
146         if (S_ISREG(st.st_mode) /* Symlinks & devices don't need this check: */

Best regards.
Comment 3 Adrian Torregrosa 2019-03-14 16:36:22 UTC
Another option that I tried and verified, and that could make more sense, would be to replace

141         if (do_lstat(fname, &st) < 0) {

with

141         if (do_stat(fname, &st) < 0) {
Comment 4 Wayne Davison 2019-03-16 16:20:42 UTC
In my prior testing I apparently missed that the symlink verification issue was caused by -L (--copy-links).  I have amended the change to use do_stat() when --copy-links is enabled.
Comment 5 Adrian Torregrosa 2019-03-20 13:18:10 UTC
I embedded the modified sender.c into 3.1.3's original source code, compiled and tested, and I found it to have solved the problem: first I tried uploading a softlink and deleting, then I tried uploading a normal file and deleting. It worked the two times.