From 7790ee3684c6b17a400ab8f1779092892dfde8c5 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 2 Aug 2008 09:03:49 -0700 Subject: [PATCH] Added logic to the receiving side to ensure that the --delete-during 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 | 3 +++ generator.c | 5 +++++ io.c | 8 ++++++++ main.c | 5 +++++ rsync.c | 15 ++++++++++++++- 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 9cc9d488..84aea201 100644 --- 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. diff --git a/generator.c b/generator.c index 26c6d170..86a48155 100644 --- a/generator.c +++ b/generator.c @@ -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 6a91ffd5..bc59c13d 100644 --- 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 6881c8e6..887f8d27 100644 --- 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 85244c88..a9e655e4 100644 --- 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) -- 2.34.1