From 852585b1fced8d0df35b14c17f26c4aac633313b Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 18 Jun 2011 12:06:44 -0700 Subject: [PATCH] Check if sender file changed before allowing a remove. Fixes bug 7691. --- flist.c | 8 -------- rsync.h | 8 ++++++++ rsync.yo | 13 +++++++++++++ sender.c | 28 +++++++++++++++++++++++++--- tls.c | 8 -------- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/flist.c b/flist.c index 0758f896..7a6ab342 100644 --- a/flist.c +++ b/flist.c @@ -86,14 +86,6 @@ extern int filesfrom_convert; extern iconv_t ic_send, ic_recv; #endif -#ifdef HAVE_UTIMENSAT -#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC -#define ST_MTIME_NSEC st_mtim.tv_nsec -#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) -#define ST_MTIME_NSEC st_mtimensec -#endif -#endif - #define PTR_SIZE (sizeof (struct file_struct *)) int io_error; diff --git a/rsync.h b/rsync.h index 84d1287c..f55e2f79 100644 --- a/rsync.h +++ b/rsync.h @@ -383,6 +383,14 @@ enum delret { #define CAN_CHMOD_SYMLINK 1 #endif +#ifdef HAVE_UTIMENSAT +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC +#define ST_MTIME_NSEC st_mtim.tv_nsec +#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) +#define ST_MTIME_NSEC st_mtimensec +#endif +#endif + #ifdef HAVE_SYS_SELECT_H #include #endif diff --git a/rsync.yo b/rsync.yo index a1cac988..3174ca37 100644 --- a/rsync.yo +++ b/rsync.yo @@ -1261,6 +1261,19 @@ dit(bf(--remove-source-files)) This tells rsync to remove from the sending side the files (meaning non-directories) that are a part of the transfer and have been successfully duplicated on the receiving side. +Note that you should only use this option on source files that are quiescent. +If you are using this to move files that show up in a particular directory over +to another host, make sure that the finished files get renamed into the source +directory, not directly written into it, so that rsync can't possibly transfer +a file that is not yet fully written. If you can't first write the files into +a different directory, you should use a naming idiom that lets rsync avoid +transferring files that are not yet finished (e.g. name the file "foo.new" when +it is written, rename it to "foo" when it is done, and then use the option +bf(--exclude='*.new') for the rsync transfer). + +Starting with 3.1.0, rsync will skip the sender-side removal (and output an +error) if the file's size or modify time has not stayed unchanged. + dit(bf(--delete)) This tells rsync to delete extraneous files from the receiving side (ones that aren't on the sending side), but only for the directories that are being synchronized. You must have asked rsync to diff --git a/sender.c b/sender.c index 7b6d3133..ebc8839f 100644 --- a/sender.c +++ b/sender.c @@ -123,8 +123,10 @@ static struct sum_struct *receive_sums(int f) void successful_send(int ndx) { char fname[MAXPATHLEN]; + char *failed_op; struct file_struct *file; struct file_list *flist; + STRUCT_STAT st; if (!remove_source_files) return; @@ -135,11 +137,31 @@ void successful_send(int ndx) return; f_name(file, fname); - if (do_unlink(fname) == 0) { + if (do_lstat(fname, &st) < 0) { + failed_op = "re-lstat"; + goto failed; + } + + if (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime +#ifdef ST_MTIME_NSEC + || (NSEC_BUMP(file) && (uint32)st.ST_MTIME_NSEC != F_MOD_NSEC(file)) +#endif + ) { + rprintf(FERROR, "ERROR: Skipping sender remove for changed file: %s\n", fname); + return; + } + + if (do_unlink(fname) < 0) { + failed_op = "remove"; + failed: + if (errno == ENOENT) + rprintf(FINFO, "sender file already removed: %s\n", fname); + else + rsyserr(FERROR, errno, "sender failed to %s %s", failed_op, fname); + } else { if (INFO_GTE(REMOVE, 1)) rprintf(FINFO, "sender removed %s\n", fname); - } else - rsyserr(FERROR, errno, "sender failed to remove %s", fname); + } } static void write_ndx_and_attrs(int f_out, int ndx, int iflags, diff --git a/tls.c b/tls.c index aa43b912..2dec0590 100644 --- a/tls.c +++ b/tls.c @@ -53,14 +53,6 @@ int preserve_perms = 0; int preserve_executability = 0; char number_separator; -#ifdef HAVE_UTIMENSAT -#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC -#define ST_MTIME_NSEC st_mtim.tv_nsec -#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) -#define ST_MTIME_NSEC st_mtimensec -#endif -#endif - #ifdef SUPPORT_XATTRS #ifdef HAVE_LINUX_XATTRS -- 2.34.1