X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/902ee53ea44f661414202ccce775e846f514a2bd..5dd14f0c3388f69932d521915e039e32b9e6d970:/flist.c diff --git a/flist.c b/flist.c index c1898247..766f1b37 100644 --- a/flist.c +++ b/flist.c @@ -23,6 +23,7 @@ #include "rsync.h" #include "ifuncs.h" #include "rounding.h" +#include "inums.h" #include "io.h" extern int am_root; @@ -65,6 +66,7 @@ extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; extern int need_unsorted_flist; +extern int sender_symlink_iconv; extern int output_needs_newline; extern int sender_keeps_checksum; extern int unsort_ndx; @@ -320,7 +322,7 @@ static void flist_expand(struct file_list *flist, int extra) if (DEBUG_GTE(FLIST, 1) && flist->malloced != FLIST_START) { rprintf(FCLIENT, "[%s] expand file_list pointer array to %s bytes, did%s move\n", who_am_i(), - big_num(sizeof flist->files[0] * flist->malloced, 0), + big_num(sizeof flist->files[0] * flist->malloced), (new_ptr == flist->files) ? " not" : ""); } @@ -387,7 +389,11 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen) return 1; } -static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) +static void send_file_entry(int f, const char *fname, struct file_struct *file, +#ifdef SUPPORT_LINKS + const char *symlink_name, int symlink_len, +#endif + int ndx, int first_ndx) { static time_t modtime; static mode_t mode; @@ -483,7 +489,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, } else if (DEBUG_GTE(HLINK, 3)) { rprintf(FINFO, "[%s] dev:inode for #%d is %s:%s\n", who_am_i(), first_ndx + ndx, - big_num(tmp_dev, 0), big_num(tmp_ino, 0)); + big_num(tmp_dev), big_num(tmp_ino)); } } } else { @@ -591,11 +597,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, } #ifdef SUPPORT_LINKS - if (preserve_links && S_ISLNK(mode)) { - const char *sl = F_SYMLINK(file); - int len = strlen(sl); - write_varint30(f, len); - write_buf(f, sl, len); + if (symlink_len) { + write_varint30(f, symlink_len); + write_buf(f, symlink_name, symlink_len); } #endif @@ -693,12 +697,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) { io_error |= IOERR_GENERAL; - rprintf(FERROR_XFER, + rprintf(FERROR_UTF8, "[%s] cannot convert filename: %s (%s)\n", who_am_i(), lastname, strerror(errno)); outbuf.len = 0; } - outbuf.buf[outbuf.len] = '\0'; + thisname[outbuf.len] = '\0'; } #endif @@ -834,6 +838,13 @@ static struct file_struct *recv_file_entry(struct file_list *flist, linkname_len - 1); overflow_exit("recv_file_entry"); } +#ifdef ICONV_OPTION + /* We don't know how much extra room we need to convert + * the as-yet-unread symlink data, so let's hope that a + * double-size buffer is plenty. */ + if (sender_symlink_iconv) + linkname_len *= 2; +#endif if (munge_symlinks) linkname_len += SYMLINK_PREFIX_LEN; } @@ -968,14 +979,40 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; memcpy(bp, F_SYMLINK(first), linkname_len); - } else if (munge_symlinks) { - strlcpy(bp, SYMLINK_PREFIX, linkname_len); - bp += SYMLINK_PREFIX_LEN; - linkname_len -= SYMLINK_PREFIX_LEN; - read_sbuf(f, bp, linkname_len - 1); } else { - read_sbuf(f, bp, linkname_len - 1); - if (sanitize_paths) + if (munge_symlinks) { + strlcpy(bp, SYMLINK_PREFIX, linkname_len); + bp += SYMLINK_PREFIX_LEN; + linkname_len -= SYMLINK_PREFIX_LEN; + } +#ifdef ICONV_OPTION + if (sender_symlink_iconv) { + xbuf outbuf, inbuf; + + alloc_len = linkname_len; + linkname_len /= 2; + + /* Read the symlink data into the end of our double-sized + * buffer and then convert it into the right spot. */ + INIT_XBUF(inbuf, bp + alloc_len - linkname_len, + linkname_len - 1, (size_t)-1); + read_sbuf(f, inbuf.buf, inbuf.len); + INIT_XBUF(outbuf, bp, 0, alloc_len); + + if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) { + io_error |= IOERR_GENERAL; + rprintf(FERROR_XFER, + "[%s] cannot convert symlink data for: %s (%s)\n", + who_am_i(), full_fname(thisname), strerror(errno)); + bp = (char*)file->basename; + *bp++ = '\0'; + outbuf.len = 0; + } + bp[outbuf.len] = '\0'; + } else +#endif + read_sbuf(f, bp, linkname_len - 1); + if (sanitize_paths && !munge_symlinks && *bp) sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT); } } @@ -1113,7 +1150,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } } else { io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, save_errno, "readlink %s failed", + rsyserr(FERROR_XFER, save_errno, "readlink_stat(%s) failed", full_fname(thisname)); } return NULL; @@ -1339,10 +1376,27 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (f >= 0) { char fbuf[MAXPATHLEN]; +#ifdef SUPPORT_LINKS + const char *symlink_name; + int symlink_len; +#ifdef ICONV_OPTION + char symlink_buf[MAXPATHLEN]; +#endif +#endif #if defined SUPPORT_ACLS || defined SUPPORT_XATTRS stat_x sx; #endif +#ifdef SUPPORT_LINKS + if (preserve_links && S_ISLNK(file->mode)) { + symlink_name = F_SYMLINK(file); + symlink_len = strlen(symlink_name); + } else { + symlink_name = NULL; + symlink_len = 0; + } +#endif + #ifdef ICONV_OPTION if (ic_send != (iconv_t)-1) { xbuf outbuf, inbuf; @@ -1355,7 +1409,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) goto convert_error; outbuf.size += 2; - outbuf.buf[outbuf.len++] = '/'; + fbuf[outbuf.len++] = '/'; } INIT_XBUF_STRLEN(inbuf, (char*)file->basename); @@ -1367,7 +1421,26 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, who_am_i(), f_name(file, fbuf), strerror(errno)); return NULL; } - outbuf.buf[outbuf.len] = '\0'; + fbuf[outbuf.len] = '\0'; + +#ifdef SUPPORT_LINKS + if (symlink_len && sender_symlink_iconv) { + INIT_XBUF(inbuf, (char*)symlink_name, symlink_len, (size_t)-1); + INIT_CONST_XBUF(outbuf, symlink_buf); + if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { + io_error |= IOERR_GENERAL; + f_name(file, fbuf); + rprintf(FERROR_XFER, + "[%s] cannot convert symlink data for: %s (%s)\n", + who_am_i(), full_fname(fbuf), strerror(errno)); + return NULL; + } + symlink_buf[outbuf.len] = '\0'; + + symlink_name = symlink_buf; + symlink_len = outbuf.len; + } +#endif } else #endif f_name(file, fbuf); @@ -1392,7 +1465,11 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, } #endif - send_file_entry(f, fbuf, file, flist->used, flist->ndx_start); + send_file_entry(f, fbuf, file, +#ifdef SUPPORT_LINKS + symlink_name, symlink_len, +#endif + flist->used, flist->ndx_start); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { @@ -1840,7 +1917,12 @@ void send_extra_file_list(int f, int at_least) dp = F_DIR_NODE_P(file); } - write_byte(f, 0); + if (protocol_version < 31 || io_error == save_io_error || ignore_errors) + write_byte(f, 0); + else { + write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); + write_int(f, io_error); + } if (need_unsorted_flist) { if (!(flist->sorted = new_array(struct file_struct *, flist->used))) @@ -1881,7 +1963,7 @@ void send_extra_file_list(int f, int at_least) } finish: - if (io_error != save_io_error && !ignore_errors) + if (io_error != save_io_error && protocol_version == 30 && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); } @@ -2137,7 +2219,13 @@ 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 (protocol_version < 31 || io_error == 0 || ignore_errors) + write_byte(f, 0); + else { + write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); + write_int(f, io_error); + } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version >= 30 && !inc_recurse) @@ -2175,7 +2263,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 (io_error && protocol_version == 30 && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); if (disable_buffering) @@ -2246,10 +2334,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 (protocol_version < 31) { + rprintf(FERROR, "Invalid flist flag: %x\n", flags); + exit_cleanup(RERR_PROTOCOL); + } + err = read_int(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)) { @@ -2262,8 +2362,8 @@ struct file_list *recv_file_list(int f) maybe_emit_filelist_progress(flist->used); if (DEBUG_GTE(FLIST, 2)) { - rprintf(FINFO, "recv_file_name(%s)\n", - f_name(file, NULL)); + char *name = f_name(file, NULL); + rprintf(FINFO, "recv_file_name(%s)\n", NS(name)); } } file_total += flist->used; @@ -2313,10 +2413,9 @@ struct file_list *recv_file_list(int f) if (protocol_version < 30) { /* Recv the io_error flag */ - if (ignore_errors) - read_int(f); - else - io_error |= read_int(f); + int err = read_int(f); + if (!ignore_errors) + io_error |= err; } else if (inc_recurse && flist->ndx_start == 1) { if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0) flist->parent_ndx = -1; @@ -2721,7 +2820,7 @@ static void output_flist(struct file_list *flist) "[%s] i=%d %s %s%s%s%s mode=0%o len=%s%s%s flags=%x\n", who, i + flist->ndx_start, root, dir, slash, name, trail, - (int)file->mode, big_num(F_LENGTH(file), 0), + (int)file->mode, comma_num(F_LENGTH(file)), uidbuf, gidbuf, file->flags); } }