Fix --remove-source-files sanity check w/--copy-links the right way.
[rsync.git] / sender.c
index 98612965adb0fadc2a10faab566b98d5b3839cf5..9b432ed9f8b5575d0a68df5e40b5769cc269acd4 100644 (file)
--- a/sender.c
+++ b/sender.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2003-2009 Wayne Davison
+ * Copyright (C) 2003-2018 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,8 +29,10 @@ extern int inc_recurse;
 extern int log_before_transfer;
 extern int stdout_format_has_i;
 extern int logfile_format_has_i;
+extern int want_xattr_optim;
 extern int csum_length;
 extern int append_mode;
+extern int copy_links;
 extern int io_error;
 extern int flist_eof;
 extern int allowed_lull;
@@ -42,6 +44,7 @@ extern int make_backups;
 extern int inplace;
 extern int batch_fd;
 extern int write_batch;
+extern int file_old_total;
 extern struct stats stats;
 extern struct file_list *cur_flist, *first_flist, *dir_flist;
 
@@ -62,7 +65,7 @@ static struct sum_struct *receive_sums(int f)
 {
        struct sum_struct *s;
        int32 i;
-       int lull_mod = allowed_lull * 5;
+       int lull_mod = protocol_version >= 31 ? 0 : allowed_lull * 5;
        OFF_T offset = 0;
 
        if (!(s = new(struct sum_struct)))
@@ -103,8 +106,8 @@ static struct sum_struct *receive_sums(int f)
                        s->sums[i].len = s->blength;
                offset += s->sums[i].len;
 
-               if (allowed_lull && !(i % lull_mod))
-                       maybe_send_keepalive();
+               if (lull_mod && !(i % lull_mod))
+                       maybe_send_keepalive(time(NULL), True);
 
                if (DEBUG_GTE(DELTASUM, 3)) {
                        rprintf(FINFO,
@@ -122,8 +125,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;
@@ -134,11 +139,31 @@ void successful_send(int ndx)
                return;
        f_name(file, fname);
 
-       if (do_unlink(fname) == 0) {
+       if ((copy_links ? do_stat(fname, &st) : 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_XFER, "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_XFER, 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,
@@ -154,7 +179,8 @@ static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
        if (iflags & ITEM_XNAME_FOLLOWS)
                write_vstring(f_out, buf, len);
 #ifdef SUPPORT_XATTRS
-       if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
+       if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
+        && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
                send_xattr_request(fname, file, f_out);
 #endif
 }
@@ -197,8 +223,11 @@ void send_files(int f_in, int f_out)
                                end_progress(0);
                        }
                        if (inc_recurse && first_flist) {
+                               file_old_total -= first_flist->used;
                                flist_free(first_flist);
                                if (first_flist) {
+                                       if (first_flist == cur_flist)
+                                               file_old_total = cur_flist->used;
                                        write_ndx(f_out, NDX_DONE);
                                        continue;
                                }
@@ -232,7 +261,8 @@ void send_files(int f_in, int f_out)
                        rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname);
 
 #ifdef SUPPORT_XATTRS
-               if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
+               if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
+                && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
                        recv_xattr_request(file, f_in);
 #endif
 
@@ -290,8 +320,7 @@ void send_files(int f_in, int f_out)
                stats.xferred_files++;
                stats.total_transferred_size += F_LENGTH(file);
 
-               if (!log_before_transfer)
-                       remember_initial_stats();
+               remember_initial_stats();
 
                if (!do_xfers) { /* log the transfer */
                        log_item(FCLIENT, file, iflags, NULL);
@@ -333,7 +362,7 @@ void send_files(int f_in, int f_out)
                        rsyserr(FERROR_XFER, errno, "fstat failed");
                        free_sums(s);
                        close(fd);
-                       exit_cleanup(RERR_PROTOCOL);
+                       exit_cleanup(RERR_FILEIO);
                }
 
                if (st.st_size) {