X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/23a0d1e200c7f23c4d8ca236f807c253a666009a..57edc4808f566fbaa58ec96bc7e543b1ccb92ab9:/flist.c diff --git a/flist.c b/flist.c index 70abe611..f90c286c 100644 --- a/flist.c +++ b/flist.c @@ -50,13 +50,11 @@ extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_specials; +extern int delete_during; extern int missing_args; -extern int uid_ndx; -extern int gid_ndx; extern int eol_nulls; extern int relative_paths; extern int implied_dirs; -extern int file_extra_cnt; extern int ignore_perishable; extern int non_perishable_cnt; extern int prune_empty_dirs; @@ -65,11 +63,13 @@ 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 output_needs_newline; extern int sender_keeps_checksum; extern int unsort_ndx; +extern uid_t our_uid; extern struct stats stats; extern char *filesfrom_host; extern char *usermap, *groupmap; @@ -128,7 +128,7 @@ int flist_eof = 0; /* all the file-lists are now known */ * will survive just long enough to be used by send_file_entry(). */ static dev_t tmp_rdev; #ifdef SUPPORT_HARD_LINKS -static int64 tmp_dev, tmp_ino; +static int64 tmp_dev = -1, tmp_ino; #endif static char tmp_sum[MAX_DIGEST_LEN]; @@ -506,7 +506,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, xflags |= XMIT_MOD_NSEC; #ifdef SUPPORT_HARD_LINKS - if (tmp_dev != 0) { + if (tmp_dev != -1) { if (protocol_version >= 30) { struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino); first_hlink_ndx = (int32)(long)np->data - 1; @@ -639,15 +639,17 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, #endif #ifdef SUPPORT_HARD_LINKS - if (tmp_dev != 0 && protocol_version < 30) { + if (tmp_dev != -1 && protocol_version < 30) { + /* Older protocols expect the dev number to be transmitted + * 1-incremented so that it is never zero. */ if (protocol_version < 26) { /* 32-bit dev_t and ino_t */ - write_int(f, (int32)dev); + write_int(f, (int32)(dev+1)); write_int(f, (int32)tmp_ino); } else { /* 64-bit dev_t and ino_t */ if (!(xflags & XMIT_SAME_DEV_pre30)) - write_longint(f, dev); + write_longint(f, dev+1); write_longint(f, tmp_ino); } } @@ -1339,10 +1341,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (protocol_version >= 28 ? (!S_ISDIR(st.st_mode) && st.st_nlink > 1) : S_ISREG(st.st_mode)) { - tmp_dev = (int64)st.st_dev + 1; + tmp_dev = (int64)st.st_dev; tmp_ino = (int64)st.st_ino; } else - tmp_dev = 0; + tmp_dev = -1; } #endif @@ -1370,10 +1372,12 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } #endif file->mode = st.st_mode; - if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */ + if (preserve_uid) F_OWNER(file) = st.st_uid; - if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ + if (preserve_gid) F_GROUP(file) = st.st_gid; + if (am_generator && st.st_uid == our_uid) + file->flags |= FLAG_OWNED_BY_US; if (basename != thisname) file->dirname = lastdir; @@ -1562,12 +1566,6 @@ static void send_if_directory(int f, struct file_list *flist, unsigned int len = strlen(fbuf); if (len > 1 && fbuf[len-1] == '/') fbuf[--len] = '\0'; - if (len >= MAXPATHLEN - 1) { - io_error |= IOERR_GENERAL; - rprintf(FERROR_XFER, "skipping long-named directory: %s\n", - full_fname(fbuf)); - return; - } save_filters = push_local_filters(fbuf, len); send_directory(f, flist, fbuf, len, flags); pop_local_filters(save_filters); @@ -1726,21 +1724,29 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, } p = fbuf + len; - if (len != 1 || *fbuf != '/') + if (len == 1 && *fbuf == '/') + remainder = MAXPATHLEN - 1; + else if (len < MAXPATHLEN-1) { *p++ = '/'; - *p = '\0'; - remainder = MAXPATHLEN - (p - fbuf); + *p = '\0'; + remainder = MAXPATHLEN - (len + 1); + } else + remainder = 0; for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { char *dname = d_name(di); if (dname[0] == '.' && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))) continue; - if (strlcpy(p, dname, remainder) >= remainder) { + unsigned name_len = strlcpy(p, dname, remainder); + if (name_len >= remainder) { + char save = fbuf[len]; + fbuf[len] = '\0'; io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, - "cannot send long-named file %s\n", - full_fname(fbuf)); + "filename overflows max-path len by %u: %s/%s\n", + name_len - remainder + 1, fbuf, dname); + fbuf[len] = save; continue; } if (dname[0] == '\0') { @@ -1872,6 +1878,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]; @@ -1987,11 +2002,15 @@ void send_extra_file_list(int f, int at_least) dp = F_DIR_NODE_P(file); } - if (protocol_version < 31 || io_error == save_io_error || ignore_errors) + if (io_error == save_io_error || ignore_errors) write_byte(f, 0); - else { + 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) { @@ -2313,11 +2332,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) start_tv = end_tv; /* Indicate end of file list */ - if (protocol_version < 31 || io_error == 0 || ignore_errors) + if (io_error == 0 || ignore_errors) write_byte(f, 0); - else { + 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 @@ -2349,6 +2372,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) flist->sorted = flist->files; flist_sort_and_clean(flist, 0); file_total += flist->used; + file_old_total += flist->used; if (numeric_ids <= 0 && !inc_recurse) send_id_list(f); @@ -2356,7 +2380,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 && protocol_version == 30 && !ignore_errors) + else if (!use_safe_inc_flist && io_error && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); if (disable_buffering) @@ -2442,7 +2466,7 @@ struct file_list *recv_file_list(int f) if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) { int err; - if (protocol_version < 31) { + if (!use_safe_inc_flist) { rprintf(FERROR, "Invalid flist flag: %x\n", flags); exit_cleanup(RERR_PROTOCOL); } @@ -3153,13 +3177,14 @@ char *f_name(const struct file_struct *f, char *fbuf) * of the dirname string, and also indicates that "dirname" is a MAXPATHLEN * buffer (the functions we call will append names onto the end, but the old * dir value will be restored on exit). */ -struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules) +struct file_list *get_dirlist(char *dirname, int dlen, int flags) { struct file_list *dirlist; char dirbuf[MAXPATHLEN]; int save_recurse = recurse; int save_xfer_dirs = xfer_dirs; int save_prune_empty_dirs = prune_empty_dirs; + int senddir_fd = flags & GDL_IGNORE_FILTER_RULES ? -2 : -1; if (dlen < 0) { dlen = strlcpy(dirbuf, dirname, MAXPATHLEN); @@ -3172,7 +3197,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules) recurse = 0; xfer_dirs = 1; - send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, FLAG_CONTENT_DIR); + send_directory(senddir_fd, dirlist, dirname, dlen, FLAG_CONTENT_DIR); xfer_dirs = save_xfer_dirs; recurse = save_recurse; if (INFO_GTE(PROGRESS, 1))