X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/ee6e80c7532696f04bd021a26b3b2e5178cf5f31..b3bf9b9df95137a3a43248be9599d919b04877af:/io.c diff --git a/io.c b/io.c index 819c17f4..12e648d4 100644 --- a/io.c +++ b/io.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2003-2007 Wayne Davison + * Copyright (C) 2003-2009 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ #include "rsync.h" #include "ifuncs.h" +#include "inums.h" /** If no timeout is specified then use a 60 second select timeout */ #define SELECT_TIMEOUT 60 @@ -36,7 +37,6 @@ extern int bwlimit; extern size_t bwlimit_writemax; extern int io_timeout; -extern int allowed_lull; extern int am_server; extern int am_daemon; extern int am_sender; @@ -45,8 +45,8 @@ extern int inc_recurse; extern int io_error; extern int eol_nulls; extern int flist_eof; +extern int list_only; extern int read_batch; -extern int csum_length; extern int protect_args; extern int checksum_seed; extern int protocol_version; @@ -59,7 +59,8 @@ extern int filesfrom_convert; extern iconv_t ic_send, ic_recv; #endif -const char phase_unknown[] = "unknown"; +int csum_length = SHORT_SUM_LENGTH; /* initial value */ +int allowed_lull = 0; int ignore_timeout = 0; int batch_fd = -1; int msgdone_cnt = 0; @@ -100,10 +101,11 @@ static char ff_lastchar; #ifdef ICONV_OPTION static xbuf iconv_buf = EMPTY_XBUF; #endif -static int defer_forwarding_messages = 0, defer_forwarding_keep = 0; +static int defer_forwarding_messages = 0, keep_defer_forwarding = 0; static int select_timeout = SELECT_TIMEOUT; static int active_filecnt = 0; static OFF_T active_bytecnt = 0; +static int first_message = 1; static char int_byte_extra[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* (00 - 3F)/4 */ @@ -112,6 +114,9 @@ static char int_byte_extra[64] = { 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, /* (C0 - FF)/4 */ }; +#define REMOTE_OPTION_ERROR "rsync: on remote machine: -" +#define REMOTE_OPTION_ERROR2 ": unknown option" + enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND }; static void readfd(int fd, char *buffer, size_t N); @@ -119,16 +124,7 @@ static void writefd(int fd, const char *buf, size_t len); static void writefd_unbuffered(int fd, const char *buf, size_t len); static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len, int convert); -struct flist_ndx_item { - struct flist_ndx_item *next; - int ndx; -}; - -struct flist_ndx_list { - struct flist_ndx_item *head, *tail; -}; - -static struct flist_ndx_list redo_list, hlink_list; +static flist_ndx_list redo_list, hlink_list; struct msg_list_item { struct msg_list_item *next; @@ -142,45 +138,10 @@ struct msg_list { static struct msg_list msg_queue; -static void flist_ndx_push(struct flist_ndx_list *lp, int ndx) -{ - struct flist_ndx_item *item; - - if (!(item = new(struct flist_ndx_item))) - out_of_memory("flist_ndx_push"); - item->next = NULL; - item->ndx = ndx; - if (lp->tail) - lp->tail->next = item; - else - lp->head = item; - lp->tail = item; -} - -static int flist_ndx_pop(struct flist_ndx_list *lp) -{ - struct flist_ndx_item *next; - int ndx; - - if (!lp->head) - return -1; - - ndx = lp->head->ndx; - next = lp->head->next; - free(lp->head); - lp->head = next; - if (!next) - lp->tail = NULL; - - return ndx; -} - static void got_flist_entry_status(enum festatus status, const char *buf) { int ndx = IVAL(buf, 0); - struct file_list *flist = flist_for_ndx(ndx); - - assert(flist != NULL); + struct file_list *flist = flist_for_ndx(ndx, "got_flist_entry_status"); if (remove_source_files) { active_filecnt--; @@ -203,6 +164,11 @@ static void got_flist_entry_status(enum festatus status, const char *buf) } break; case FES_REDO: + if (read_batch) { + if (inc_recurse) + flist->in_progress++; + break; + } if (inc_recurse) flist->to_redo++; flist_ndx_push(&redo_list, ndx); @@ -291,33 +257,62 @@ static void msg_list_add(struct msg_list *lst, int code, const char *buf, int le lst->tail = m; } +static inline int flush_a_msg(int fd) +{ + struct msg_list_item *m = msg_queue.head; + int len = IVAL(m->buf, 0) & 0xFFFFFF; + int tag = *((uchar*)m->buf+3) - MPLEX_BASE; + + if (!(msg_queue.head = m->next)) + msg_queue.tail = NULL; + + defer_forwarding_messages++; + mplex_write(fd, tag, m->buf + 4, len, m->convert); + defer_forwarding_messages--; + + free(m); + + return len; +} + static void msg_flush(void) { if (am_generator) { - while (msg_queue.head && io_multiplexing_out) { - struct msg_list_item *m = msg_queue.head; - int len = IVAL(m->buf, 0) & 0xFFFFFF; - int tag = *((uchar*)m->buf+3) - MPLEX_BASE; - if (!(msg_queue.head = m->next)) - msg_queue.tail = NULL; - stats.total_written += len + 4; - defer_forwarding_messages++; - mplex_write(sock_f_out, tag, m->buf + 4, len, m->convert); - defer_forwarding_messages--; - free(m); - } + while (msg_queue.head && io_multiplexing_out) + stats.total_written += flush_a_msg(sock_f_out) + 4; } else { - while (msg_queue.head) { - struct msg_list_item *m = msg_queue.head; - int len = IVAL(m->buf, 0) & 0xFFFFFF; - int tag = *((uchar*)m->buf+3) - MPLEX_BASE; - if (!(msg_queue.head = m->next)) - msg_queue.tail = NULL; - defer_forwarding_messages++; - mplex_write(msg_fd_out, tag, m->buf + 4, len, m->convert); - defer_forwarding_messages--; - free(m); - } + while (msg_queue.head) + (void)flush_a_msg(msg_fd_out); + } +} + +static void check_for_d_option_error(const char *msg) +{ + static char rsync263_opts[] = "BCDHIKLPRSTWabceghlnopqrtuvxz"; + char *colon; + int saw_d = 0; + + if (*msg != 'r' + || strncmp(msg, REMOTE_OPTION_ERROR, sizeof REMOTE_OPTION_ERROR - 1) != 0) + return; + + msg += sizeof REMOTE_OPTION_ERROR - 1; + if (*msg == '-' || (colon = strchr(msg, ':')) == NULL + || strncmp(colon, REMOTE_OPTION_ERROR2, sizeof REMOTE_OPTION_ERROR2 - 1) != 0) + return; + + for ( ; *msg != ':'; msg++) { + if (*msg == 'd') + saw_d = 1; + else if (*msg == 'e') + break; + else if (strchr(rsync263_opts, *msg) == NULL) + return; + } + + if (saw_d) { + rprintf(FWARNING, + "*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n"); } } @@ -373,7 +368,7 @@ static void read_msg_fd(void) /* Read extra file list from receiver. */ assert(iobuf_in != NULL); assert(iobuf_f_in == fd); - if (verbose > 3) { + if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), IVAL(buf,0)); } @@ -413,15 +408,18 @@ static void read_msg_fd(void) readfd(fd, buf, 4); got_flist_entry_status(FES_NO_SEND, buf); break; - case MSG_SOCKERR: + case MSG_ERROR_SOCKET: + case MSG_ERROR_UTF8: case MSG_CLIENT: if (!am_generator) goto invalid_msg; - if (tag == MSG_SOCKERR) + if (tag == MSG_ERROR_SOCKET) io_end_multiplex_out(); /* FALL THROUGH */ case MSG_INFO: case MSG_ERROR: + case MSG_ERROR_XFER: + case MSG_WARNING: case MSG_LOG: while (len) { n = len; @@ -449,9 +447,14 @@ static void read_msg_fd(void) * this, sender-side deletions were mostly happening at the end. */ void increment_active_files(int ndx, int itemizing, enum logcode code) { - /* TODO: tune these limits? */ - while (active_filecnt >= (active_bytecnt >= 128*1024 ? 10 : 50)) { + while (1) { + /* TODO: tune these limits? */ + int limit = active_bytecnt >= 128*1024 ? 10 : 50; + if (active_filecnt < limit) + break; check_for_finished_files(itemizing, code, 0); + if (active_filecnt < limit) + break; if (iobuf_out_cnt) io_flush(NORMAL_FLUSH); else @@ -475,7 +478,7 @@ static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len, xbuf outbuf, inbuf; INIT_XBUF(outbuf, buffer + 4, 0, sizeof buffer - 4); - INIT_XBUF(inbuf, (char*)buf, len, -1); + INIT_XBUF(inbuf, (char*)buf, len, (size_t)-1); iconvbufs(ic_send, &inbuf, &outbuf, ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE); @@ -494,9 +497,9 @@ static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len, SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len); - defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */ + keep_defer_forwarding++; /* defer_forwarding_messages++ on return */ writefd_unbuffered(fd, buffer, n+4); - defer_forwarding_keep = 0; + keep_defer_forwarding--; if (len > n) writefd_unbuffered(fd, buf+n, len-n); @@ -531,10 +534,9 @@ void send_msg_int(enum msgcode code, int num) void wait_for_receiver(void) { - if (iobuf_out_cnt) - io_flush(NORMAL_FLUSH); - else - read_msg_fd(); + if (io_flush(FULL_FLUSH)) + return; + read_msg_fd(); } int get_redo_num(void) @@ -592,8 +594,8 @@ static void whine_about_eof(int fd) } rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed " - "(%.0f bytes received so far) [%s]\n", - (double)stats.total_read, who_am_i()); + "(%s bytes received so far) [%s]\n", + big_num(stats.total_read), who_am_i()); exit_cleanup(RERR_STREAMIO); } @@ -751,7 +753,7 @@ static int read_timeout(int fd, char *buf, size_t len) /* Don't write errors on a dead socket. */ if (fd == sock_f_in) { io_end_multiplex_out(); - rsyserr(FSOCKERR, errno, "read error"); + rsyserr(FERROR_SOCKET, errno, "read error"); } else rsyserr(FERROR, errno, "read error"); exit_cleanup(RERR_STREAMIO); @@ -836,8 +838,8 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags) return s - buf; } -int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls, - char ***argv_p, int *argc_p, char **request_p) +void read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls, + char ***argv_p, int *argc_p, char **request_p) { int maxargs = MAX_ARGS; int dot_pos = 0; @@ -851,14 +853,14 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls, if (!(argv = new_array(char *, maxargs))) out_of_memory("read_args"); - if (mod_name) + if (mod_name && !protect_args) argv[argc++] = "rsyncd"; while (1) { if (read_line(f_in, buf, bufsiz, rl_flags) == 0) break; - if (argc == maxargs) { + if (argc == maxargs-1) { maxargs += MAX_ARGS; if (!(argv = realloc_array(argv, char *, maxargs))) out_of_memory("read_args"); @@ -881,11 +883,12 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls, dot_pos = argc; } } + argv[argc] = NULL; + + glob_expand(NULL, NULL, NULL, NULL); *argc_p = argc; *argv_p = argv; - - return dot_pos ? dot_pos : argc; } int io_start_buffering_out(int f_out) @@ -1054,10 +1057,9 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) xbuf outbuf, inbuf; char ibuf[512]; int add_null = 0; - int pos = 0; INIT_CONST_XBUF(outbuf, line); - INIT_XBUF(inbuf, ibuf, 0, -1); + INIT_XBUF(inbuf, ibuf, 0, (size_t)-1); while (msg_bytes) { inbuf.len = msg_bytes > sizeof ibuf @@ -1069,7 +1071,6 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE) < 0) goto overflow; - pos = -1; } if (add_null) { if (outbuf.len == outbuf.size) @@ -1106,6 +1107,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) break; case MSG_INFO: case MSG_ERROR: + case MSG_ERROR_XFER: + case MSG_WARNING: if (msg_bytes >= sizeof line) { overflow: rprintf(FERROR, @@ -1115,6 +1118,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) } read_loop(fd, line, msg_bytes); rwrite((enum logcode)tag, line, msg_bytes, 1); + if (first_message) { + if (list_only && !am_sender && tag == 1) { + line[msg_bytes] = '\0'; + check_for_d_option_error(line); + } + first_message = 0; + } break; default: rprintf(FERROR, "unexpected tag %d [%s]\n", @@ -1307,6 +1317,7 @@ int read_vstring(int f, char *buf, int bufsize) * called by both the sender and the receiver. */ void read_sum_head(int f, struct sum_struct *sum) { + int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE; sum->count = read_int(f); if (sum->count < 0) { rprintf(FERROR, "Invalid checksum count %ld [%s]\n", @@ -1314,7 +1325,7 @@ void read_sum_head(int f, struct sum_struct *sum) exit_cleanup(RERR_PROTOCOL); } sum->blength = read_int(f); - if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) { + if (sum->blength < 0 || sum->blength > max_blength) { rprintf(FERROR, "Invalid block length %ld [%s]\n", (long)sum->blength, who_am_i()); exit_cleanup(RERR_PROTOCOL); @@ -1507,24 +1518,34 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len) } no_flush--; - defer_inc -= defer_forwarding_keep; + if (keep_defer_forwarding) + defer_inc--; if (!(defer_forwarding_messages -= defer_inc) && !no_flush) msg_flush(); } -void io_flush(int flush_it_all) +int io_flush(int flush_it_all) { - if (!iobuf_out_cnt || no_flush) - return; + int flushed_something = 0; - if (io_multiplexing_out) - mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt, 0); - else - writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt); - iobuf_out_cnt = 0; + if (no_flush) + return 0; - if (flush_it_all && !defer_forwarding_messages) + if (iobuf_out_cnt) { + if (io_multiplexing_out) + mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt, 0); + else + writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt); + iobuf_out_cnt = 0; + flushed_something = 1; + } + + if (flush_it_all && !defer_forwarding_messages && msg_queue.head) { msg_flush(); + flushed_something = 1; + } + + return flushed_something; } static void writefd(int fd, const char *buf, size_t len)