From: Wayne Davison Date: Mon, 21 Dec 2009 22:27:55 +0000 (-0800) Subject: Ensure that the generator gets notified about an I/O error for the dir X-Git-Tag: v3.0.7pre1~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c11a77894b1284a05650d6f89d4e838c36945593;p=thirdparty%2Frsync.git Ensure that the generator gets notified about an I/O error for the dir that generated the error. This ensures that a --delete-during avoids deleting in a newly transferred inc-recurse directory. Requires 3.0.7 or greater on both sides of the transfer. --- diff --git a/NEWS b/NEWS index 87ffb2a5..7f9bf188 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,10 @@ Changes since 3.0.6: - Fixed a problem with --compress (-z) where the receiving side could return the error "inflate (token) returned -5". + - 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 (both + sides of the transfer must be at least 3.0.7). + - Improved --skip-compress's error handling of bad character-sets and got rid of a lingering debug fprintf(). diff --git a/compat.c b/compat.c index b921d4e9..c2b475ba 100644 --- a/compat.c +++ b/compat.c @@ -24,6 +24,7 @@ int remote_protocol = 0; int file_extra_cnt = 0; /* count of file-list extras that everyone gets */ int inc_recurse = 0; +int use_safe_inc_flist = 0; extern int verbose; extern int am_server; @@ -73,6 +74,7 @@ int filesfrom_convert = 0; #define CF_INC_RECURSE (1<<0) #define CF_SYMLINK_TIMES (1<<1) #define CF_SYMLINK_ICONV (1<<2) +#define CF_SAFE_FLIST (1<<3) static const char *client_info; @@ -255,6 +257,8 @@ void setup_protocol(int f_out,int f_in) #ifdef ICONV_OPTION compat_flags |= CF_SYMLINK_ICONV; #endif + if (local_server || strchr(client_info, 'f') != NULL) + compat_flags |= CF_SAFE_FLIST; write_byte(f_out, compat_flags); } else compat_flags = read_byte(f_in); @@ -281,6 +285,7 @@ void setup_protocol(int f_out,int f_in) read_batch ? "batch file" : "connection"); exit_cleanup(RERR_SYNTAX); } + use_safe_inc_flist = !!(compat_flags & CF_SAFE_FLIST); need_messages_from_generator = 1; #if defined HAVE_LUTIMES && defined HAVE_UTIMES } else if (!am_sender) { diff --git a/flist.c b/flist.c index 7b8d55f5..7139b101 100644 --- a/flist.c +++ b/flist.c @@ -51,6 +51,7 @@ extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_specials; +extern int delete_during; extern int uid_ndx; extern int gid_ndx; extern int eol_nulls; @@ -65,6 +66,7 @@ extern int copy_unsafe_links; extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; +extern int use_safe_inc_flist; extern int need_unsorted_flist; extern int sender_symlink_iconv; extern int unsort_ndx; @@ -1784,6 +1786,15 @@ done: filter_list = save_filter_list; } +static NORETURN void fatal_unsafe_io_error(void) +{ + /* This (sadly) can only happen when pushing data because + * the sender does not know about what kind of delete + * is in effect on the receiving side when pulling. */ + rprintf(FERROR_XFER, "FATAL I/O ERROR: dying to avoid a --delete-during issue with a pre-3.0.7 receiver.\n"); + exit_cleanup(RERR_UNSUPPORTED); +} + static void send1extra(int f, struct file_struct *file, struct file_list *flist) { char fbuf[MAXPATHLEN]; @@ -1899,7 +1910,16 @@ void send_extra_file_list(int f, int at_least) dp = F_DIR_NODE_P(file); } - write_byte(f, 0); + if (io_error == save_io_error || ignore_errors) + write_byte(f, 0); + else if (use_safe_inc_flist) { + write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); + write_varint(f, io_error); + } else { + if (delete_during) + fatal_unsafe_io_error(); + write_byte(f, 0); + } if (need_unsorted_flist) { if (!(flist->sorted = new_array(struct file_struct *, flist->used))) @@ -2196,7 +2216,17 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) stats.flist_buildtime = 1; start_tv = end_tv; - write_byte(f, 0); /* Indicate end of file list */ + /* Indicate end of file list */ + if (io_error == 0 || ignore_errors) + write_byte(f, 0); + else if (use_safe_inc_flist) { + write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); + write_varint(f, io_error); + } else { + if (delete_during && inc_recurse) + fatal_unsafe_io_error(); + write_byte(f, 0); + } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version >= 30 && !inc_recurse) @@ -2236,7 +2266,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) /* send the io_error flag */ if (protocol_version < 30) write_int(f, ignore_errors ? 0 : io_error); - else if (io_error && !ignore_errors) + else if (!use_safe_inc_flist && io_error && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); if (disable_buffering) @@ -2309,10 +2339,22 @@ struct file_list *recv_file_list(int f) while ((flags = read_byte(f)) != 0) { struct file_struct *file; - flist_expand(flist, 1); - if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS)) flags |= read_byte(f) << 8; + + if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) { + int err; + if (!use_safe_inc_flist) { + rprintf(FERROR, "Invalid flist flag: %x\n", flags); + exit_cleanup(RERR_PROTOCOL); + } + err = read_varint(f); + if (!ignore_errors) + io_error |= err; + break; + } + + flist_expand(flist, 1); file = recv_file_entry(flist, flags, f); if (inc_recurse && S_ISDIR(file->mode)) { diff --git a/options.c b/options.c index 5f0e8fc5..2daaa677 100644 --- a/options.c +++ b/options.c @@ -1837,6 +1837,7 @@ void server_options(char **args, int *argc_p) #ifdef ICONV_OPTION argstr[x++] = 's'; #endif + argstr[x++] = 'f'; } if (x >= (int)sizeof argstr) { /* Not possible... */ diff --git a/rsync.h b/rsync.h index c75fbc24..5b20c5f3 100644 --- a/rsync.h +++ b/rsync.h @@ -60,6 +60,7 @@ #define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */ #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */ #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */ +#define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */ /* These flags are used in the live flist data. */