X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/1a2e41af941573e69c02370329afe0192b61f213..5692657757a6c0e3ba60320719ef51af6f78c909:/rsync.c diff --git a/rsync.c b/rsync.c index db7abcc5..a3f9b950 100644 --- a/rsync.c +++ b/rsync.c @@ -46,7 +46,6 @@ extern int inc_recurse; extern int inplace; extern int flist_eof; extern int file_old_total; -extern int msgs2stderr; extern int keep_dirlinks; extern int make_backups; extern struct file_list *cur_flist, *first_flist, *dir_flist; @@ -134,11 +133,23 @@ void setup_iconv(void) # endif } +/* Move any bytes in the overflow space to the start. This avoids any issue + * with a multibyte sequence that needs to span the end of the buffer. */ +static void wrap_overflow(xbuf *out, int siz) +{ + if (DEBUG_GTE(IO, 4)) + rprintf(FINFO, "[%s] wrap-bytes moved: %d (iconvbufs)\n", who_am_i(), siz); + memcpy(out->buf, out->buf + out->size, siz); +} + /* This function converts the characters in the "in" xbuf into characters * in the "out" xbuf. The "len" of the "in" xbuf is used starting from its * "pos". The "size" of the "out" xbuf restricts how many characters can be * stored, starting at its "pos+len" position. Note that the last byte of * the buffer is never used, which reserves space for a terminating '\0'. + * If ICB_CIRCULAR_OUT is set, the output data can wrap around to the start, + * and the buf IS ASSUMED TO HAVE AN EXTRA 4 BYTES OF OVERFLOW SPACE at the + * end (the buffer will also not be expanded if it is already allocated). * We return a 0 on success or a -1 on error. An error also sets errno to * E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0. * The "in" xbuf is altered to update "pos" and "len". The "out" xbuf has @@ -148,25 +159,37 @@ void setup_iconv(void) * "flags", any badly-encoded chars are included verbatim in the "out" xbuf, * so EILSEQ will not be returned. Likewise for ICB_INCLUDE_INCOMPLETE with * respect to an incomplete multi-byte char at the end, which ensures that - * EINVAL is not returned. Anytime "in.pos" is 0 we will reset the iconv() - * state prior to processing the characters. */ + * EINVAL is not returned. If ICB_INIT is set, the iconv() conversion state + * is initialized prior to processing the characters. */ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags) { ICONV_CONST char *ibuf; - size_t icnt, ocnt; + size_t icnt, ocnt, opos; char *obuf; if (!out->size && flags & ICB_EXPAND_OUT) alloc_xbuf(out, 1024); - if (!in->pos) + if (flags & ICB_INIT) iconv(ic, NULL, 0, NULL, 0); ibuf = in->buf + in->pos; icnt = in->len; - obuf = out->buf + (out->pos + out->len); - ocnt = out->size - (out->pos + out->len) - 1; + opos = out->pos + out->len; + if (flags & ICB_CIRCULAR_OUT) { + if (opos >= out->size) { + opos -= out->size; + ocnt = out->pos - opos - 1; + } else { + /* We only make use of the 4 bytes of overflow buffer + * if there is room to move the bytes to the start of + * the circular buffer. */ + ocnt = out->size - opos + MIN((ssize_t)out->pos - 1, 4); + } + } else + ocnt = out->size - opos - 1; + obuf = out->buf + opos; while (icnt) { while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) { @@ -179,8 +202,14 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags) if (!(flags & ICB_INCLUDE_BAD)) goto finish; } else { - size_t opos = obuf - out->buf; - if (!(flags & ICB_EXPAND_OUT)) { + opos = obuf - out->buf; + if (flags & ICB_CIRCULAR_OUT && opos > out->size) { + wrap_overflow(out, opos -= out->size); + obuf = out->buf + opos; + if ((ocnt = out->pos - opos - 1) > 0) + continue; + } + if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) { errno = E2BIG; goto finish; } @@ -197,9 +226,17 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags) errno = 0; finish: + opos = obuf - out->buf; + if (flags & ICB_CIRCULAR_OUT) { + if (opos > out->size) + wrap_overflow(out, opos - out->size); + else if (opos < out->pos) + opos += out->size; + } + out->len = opos - out->pos; + in->len = icnt; in->pos = ibuf - in->buf; - out->len = obuf - out->buf - out->pos; return errno ? -1 : 0; } @@ -227,7 +264,7 @@ void send_protected_args(int fd, char *args[]) else if (convert) { INIT_XBUF_STRLEN(inbuf, args[i]); iconvbufs(ic_send, &inbuf, &outbuf, - ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE); + ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_INIT); outbuf.buf[outbuf.len] = '\0'; write_buf(fd, outbuf.buf, outbuf.len + 1); outbuf.len = 0; @@ -244,7 +281,7 @@ void send_protected_args(int fd, char *args[]) #endif } -int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr, +int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr) { int len, iflags = 0; @@ -260,6 +297,12 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr, break; if (ndx == NDX_DONE) return ndx; + if (ndx == NDX_DEL_STATS) { + read_del_stats(f_in); + if (am_sender && am_server) + write_del_stats(f_out); + continue; + } if (!inc_recurse || am_sender) { int last; if (first_flist) @@ -273,7 +316,9 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr, } if (ndx == NDX_FLIST_EOF) { flist_eof = 1; - send_msg(MSG_FLIST_EOF, "", 0, 0); + if (DEBUG_GTE(FLIST, 3)) + rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); + write_int(f_out, NDX_FLIST_EOF); continue; } ndx = NDX_FLIST_OFFSET - ndx; @@ -287,20 +332,15 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr, exit_cleanup(RERR_PROTOCOL); } - /* Send everything read from f_in to msg_fd_out. */ if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } - if (!msgs2stderr) - negate_output_levels(); /* turn off all info/debug output */ - send_msg_int(MSG_FLIST, ndx); - start_flist_forward(f_in); + /* Send all the data we read for this flist to the generator. */ + start_flist_forward(ndx); flist = recv_file_list(f_in); flist->parent_ndx = ndx; stop_flist_forward(); - if (!msgs2stderr) - negate_output_levels(); /* restore info/debug output */ } iflags = protocol_version >= 29 ? read_shortint(f_in) @@ -497,8 +537,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, * If set_acl() changes permission bits in the process of setting * an access ACL, it changes sxp->st.st_mode so we know whether we * need to chmod(). */ - if (preserve_acls && !S_ISLNK(new_mode) && set_acl(fname, file, sxp) == 0) - updated = 1; + if (preserve_acls && !S_ISLNK(new_mode)) { + if (set_acl(fname, file, sxp, new_mode) > 0) + updated = 1; + } #endif #ifdef HAVE_CHMOD