Added logic to the receiving side to ensure that the --delete-during
authorWayne Davison <wayned@samba.org>
Sat, 2 Aug 2008 16:03:49 +0000 (09:03 -0700)
committerWayne Davison <wayned@samba.org>
Sat, 2 Aug 2008 16:03:49 +0000 (09:03 -0700)
code will not delete in a directory prior to receiving an I/O error
for that directory (or not receiving it, as the case may be).

NEWS
generator.c
io.c
main.c
rsync.c

diff --git a/NEWS b/NEWS
index 9cc9d488331f65638d38e8703989ec1c336c59cf..84aea20191a617b6d8488dec30fc16353783b0b9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,9 @@ Changes since 3.0.3:
     - When using --iconv, if a filename fails to convert on the receiving side,
       this no longer interferes with deletions in the root-dir of the transfer.
 
+    - Fixed a bug where --delete-during could delete in a directory before it
+      noticed that the sending side sent an I/O error for that directory.
+
     - Fixed a potential alignment issue in the IRIX ACL code when allocating
       the initial "struct acl" object.  Also, cast mallocs to avoid warnings.
 
index 26c6d170bfdbc1a4eea4847202db253d0c20af4d..86a48155d18532093d67ecb13b3bab144fbf7d95 100644 (file)
@@ -89,6 +89,7 @@ extern int unsort_ndx;
 extern int max_delete;
 extern int force_delete;
 extern int one_file_system;
+extern int check_for_io_err;
 extern struct stats stats;
 extern dev_t filesystem_dev;
 extern mode_t orig_umask;
@@ -2237,6 +2238,10 @@ void generate_files(int f_out, const char *local_name)
                                                dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
                                        } else
                                                dirdev = MAKEDEV(0, 0);
+                                       /* We must be sure we've had a chance to receive an I/O
+                                        * error for this directory before we delete in it. */
+                                       while (check_for_io_err && !cur_flist->next)
+                                               wait_for_receiver();
                                        delete_in_dir(fbuf, fp, &dirdev);
                                } else
                                        change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
diff --git a/io.c b/io.c
index 6a91ffd570598cb9cd55e2b7600cd7cd47fb7727..bc59c13deeb28a6d550f403536c7b34bb2996a0b 100644 (file)
--- a/io.c
+++ b/io.c
@@ -64,6 +64,7 @@ const char phase_unknown[] = "unknown";
 int ignore_timeout = 0;
 int batch_fd = -1;
 int msgdone_cnt = 0;
+int check_for_io_err = 0;
 
 /* Ignore an EOF error if non-zero. See whine_about_eof(). */
 int kluge_around_eof = 0;
@@ -380,6 +381,8 @@ static void read_msg_fd(void)
        len = tag & 0xFFFFFF;
        tag = (tag >> 24) - MPLEX_BASE;
 
+       check_for_io_err = 0;
+
        switch (tag) {
        case MSG_DONE:
                if (len < 0 || len > 1 || !am_generator) {
@@ -414,6 +417,9 @@ static void read_msg_fd(void)
                }
                flist = recv_file_list(fd);
                flist->parent_ndx = IVAL(buf,0);
+               /* If the sender is going to send us an MSG_IO_ERROR value, it
+                * will always be the very next message following MSG_FLIST. */
+               check_for_io_err = 1;
 #ifdef SUPPORT_HARD_LINKS
                if (preserve_hard_links)
                        match_hard_links(flist);
@@ -1061,6 +1067,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                msg_bytes = tag & 0xFFFFFF;
                tag = (tag >> 24) - MPLEX_BASE;
 
+               check_for_io_err = 0;
+
                switch (tag) {
                case MSG_DATA:
                        if (msg_bytes > iobuf_in_siz) {
diff --git a/main.c b/main.c
index 6881c8e65bc7c9f3e128e8c27dcca93fd07de60b..887f8d27022b208a37e74e670ab9601cea4a0db0 100644 (file)
--- a/main.c
+++ b/main.c
@@ -63,8 +63,11 @@ extern int whole_file;
 extern int read_batch;
 extern int write_batch;
 extern int batch_fd;
+extern int flist_eof;
 extern int filesfrom_fd;
+extern int delete_during;
 extern int connect_timeout;
+extern int check_for_io_err;
 extern pid_t cleanup_child_pid;
 extern unsigned int module_dirlen;
 extern struct stats stats;
@@ -759,6 +762,8 @@ static int do_recv(int f_in, int f_out, char *local_name)
                exit_cleanup(RERR_IPC);
        }
 
+       check_for_io_err = inc_recurse && delete_during && !flist_eof;
+
        if (pid == 0) {
                close(error_pipe[0]);
                if (f_in != f_out)
diff --git a/rsync.c b/rsync.c
index 85244c880da827ce222fd8db22334afd54076878..a9e655e4f430b1554102e4b285c2bdf3f23db6a7 100644 (file)
--- a/rsync.c
+++ b/rsync.c
@@ -48,6 +48,8 @@ extern int inplace;
 extern int flist_eof;
 extern int keep_dirlinks;
 extern int make_backups;
+extern int delete_during;
+extern int check_for_io_err;
 extern struct file_list *cur_flist, *first_flist, *dir_flist;
 extern struct chmod_mode_struct *daemon_chmod_modes;
 #ifdef ICONV_OPTION
@@ -253,8 +255,15 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
        while (1) {
                ndx = read_ndx(f_in);
 
-               if (ndx >= 0)
+               if (ndx >= 0) {
+                       if (check_for_io_err) {
+                               /* Let generator know there was no I/O error. */
+                               send_msg_int(MSG_IO_ERROR, 0);
+                               check_for_io_err = 0;
+                       }
                        break;
+               }
+               check_for_io_err = 0;
                if (ndx == NDX_DONE)
                        return ndx;
                if (!inc_recurse || am_sender)
@@ -286,6 +295,10 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
                flist->parent_ndx = ndx;
                stop_flist_forward();
                verbose = save_verbose;
+               /* If the sender is going to send us an MSG_IO_ERROR value, it
+                * will always be the very next message following a file list. */
+               if (delete_during)
+                       check_for_io_err = 1;
        }
 
        iflags = protocol_version >= 29 ? read_shortint(f_in)