X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/af436313a05bd40ccc08df05dbf22c46e51882bf..e65154085cd6b58fada9b8f3070448e8bbad6111:/io.c diff --git a/io.c b/io.c index a53b347c..2dd6d41f 100644 --- a/io.c +++ b/io.c @@ -43,6 +43,7 @@ extern int bwlimit; extern size_t bwlimit_writemax; extern int verbose; extern int io_timeout; +extern int allowed_lull; extern int am_server; extern int am_daemon; extern int am_sender; @@ -51,8 +52,11 @@ extern int eol_nulls; extern int csum_length; extern int checksum_seed; extern int protocol_version; +extern int remove_sent_files; +extern int preserve_hard_links; extern char *filesfrom_host; extern struct stats stats; +extern struct file_list *the_file_list; const char phase_unknown[] = "unknown"; int select_timeout = SELECT_TIMEOUT; @@ -81,11 +85,11 @@ int kluge_around_eof = 0; int msg_fd_in = -1; int msg_fd_out = -1; +int sock_f_in = -1; +int sock_f_out = -1; static int io_multiplexing_out; static int io_multiplexing_in; -static int sock_f_in = -1; -static int sock_f_out = -1; static time_t last_io; static int no_flush; @@ -102,13 +106,16 @@ static size_t contiguous_write_len = 0; static void read_loop(int fd, char *buf, size_t len); -struct redo_list { - struct redo_list *next; - int num; +struct flist_ndx_item { + struct flist_ndx_item *next; + int ndx; }; -static struct redo_list *redo_list_head; -static struct redo_list *redo_list_tail; +struct flist_ndx_list { + struct flist_ndx_item *head, *tail; +}; + +static struct flist_ndx_list redo_list, hlink_list; struct msg_list { struct msg_list *next; @@ -119,19 +126,37 @@ struct msg_list { static struct msg_list *msg_list_head; static struct msg_list *msg_list_tail; -static void redo_list_add(int num) +static void flist_ndx_push(struct flist_ndx_list *lp, int ndx) { - struct redo_list *rl; - - if (!(rl = new(struct redo_list))) - exit_cleanup(RERR_MALLOC); - rl->next = NULL; - rl->num = num; - if (redo_list_tail) - redo_list_tail->next = rl; + 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 - redo_list_head = rl; - redo_list_tail = rl; + 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 check_timeout(void) @@ -188,10 +213,10 @@ static void msg_list_add(int code, char *buf, int len) struct msg_list *ml; if (!(ml = new(struct msg_list))) - exit_cleanup(RERR_MALLOC); + out_of_memory("msg_list_add"); ml->next = NULL; if (!(ml->buf = new_array(char, len+4))) - exit_cleanup(RERR_MALLOC); + out_of_memory("msg_list_add"); SIVAL(ml->buf, 0, ((code+MPLEX_BASE)<<24) | len); memcpy(ml->buf+4, buf, len); ml->len = len+4; @@ -239,7 +264,7 @@ static void read_msg_fd(void) rprintf(FERROR, "invalid message %d:%d\n", tag, len); exit_cleanup(RERR_STREAMIO); } - redo_list_add(-1); + flist_ndx_push(&redo_list, -1); break; case MSG_REDO: if (len != 4 || !am_generator) { @@ -247,7 +272,7 @@ static void read_msg_fd(void) exit_cleanup(RERR_STREAMIO); } read_loop(fd, buf, 4); - redo_list_add(IVAL(buf,0)); + flist_ndx_push(&redo_list, IVAL(buf,0)); break; case MSG_DELETED: if (len >= (int)sizeof buf || !am_generator) { @@ -263,7 +288,10 @@ static void read_msg_fd(void) exit_cleanup(RERR_STREAMIO); } read_loop(fd, buf, len); - io_multiplex_write(MSG_SUCCESS, buf, len); + if (remove_sent_files) + io_multiplex_write(MSG_SUCCESS, buf, len); + if (preserve_hard_links) + flist_ndx_push(&hlink_list, IVAL(buf,0)); break; case MSG_INFO: case MSG_ERROR: @@ -325,22 +353,22 @@ int msg_list_push(int flush_it_all) return 1; } -int get_redo_num(void) +int get_redo_num(int itemizing, enum logcode code) { - struct redo_list *next; - int num; - - while (!redo_list_head) + while (1) { + if (hlink_list.head) + check_for_finished_hlinks(itemizing, code); + if (redo_list.head) + break; read_msg_fd(); + } - num = redo_list_head->num; - next = redo_list_head->next; - free(redo_list_head); - redo_list_head = next; - if (!next) - redo_list_tail = NULL; + return flist_ndx_pop(&redo_list); +} - return num; +int get_hlink_num(void) +{ + return flist_ndx_pop(&hlink_list); } /** @@ -546,7 +574,7 @@ static int read_timeout(int fd, char *buf, size_t len) len -= n; ret += n; - if (io_timeout && fd == sock_f_in) + if (fd == sock_f_in && (io_timeout || am_generator)) last_io = time(NULL); } @@ -637,13 +665,20 @@ void io_end_buffering(void) } -void maybe_send_keepalive(int allowed_lull, int ndx) +void maybe_flush_socket(void) +{ + if (iobuf_out && iobuf_out_cnt && time(NULL) - last_io >= 5) + io_flush(NORMAL_FLUSH); +} + + +void maybe_send_keepalive(void) { if (time(NULL) - last_io >= allowed_lull) { if (!iobuf_out || !iobuf_out_cnt) { if (protocol_version < 29) return; /* there's nothing we can do */ - write_int(sock_f_out, ndx); + write_int(sock_f_out, the_file_list->count); write_shortint(sock_f_out, ITEM_IS_NEW); } if (iobuf_out) @@ -678,7 +713,11 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) static size_t remaining; static size_t iobuf_in_ndx; int tag, ret = 0; - char line[MAXPATHLEN+1]; +#if MAXPATHLEN < 4096 + char line[4096+1024]; +#else + char line[MAXPATHLEN+1024]; +#endif if (!iobuf_in || fd != sock_f_in) return read_timeout(fd, buf, len); @@ -732,8 +771,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) break; case MSG_SUCCESS: if (remaining != 4) { - rprintf(FERROR, "invalid multi-message %d:%ld\n", - tag, (long)remaining); + rprintf(FERROR, "invalid multi-message %d:%ld [%s]\n", + tag, (long)remaining, who_am_i()); exit_cleanup(RERR_STREAMIO); } read_loop(fd, line, remaining); @@ -744,8 +783,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) case MSG_ERROR: if (remaining >= sizeof line) { rprintf(FERROR, - "[%s] multiplexing overflow %d:%ld\n\n", - who_am_i(), tag, (long)remaining); + "multiplexing overflow %d:%ld [%s]\n", + tag, (long)remaining, who_am_i()); exit_cleanup(RERR_STREAMIO); } read_loop(fd, line, remaining); @@ -753,8 +792,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) remaining = 0; break; default: - rprintf(FERROR, "[%s] unexpected tag %d\n", - who_am_i(), tag); + rprintf(FERROR, "unexpected tag %d [%s]\n", + tag, who_am_i()); exit_cleanup(RERR_STREAMIO); } } @@ -850,6 +889,25 @@ uchar read_byte(int f) return c; } +int read_vstring(int f, char *buf, int bufsize) +{ + int len = read_byte(f); + + if (len & 0x80) + len = (len & ~0x80) * 0x100 + read_byte(f); + + if (len >= bufsize) { + rprintf(FERROR, "over-long vstring received (%d > %d)\n", + len, bufsize - 1); + return -1; + } + + if (len) + readfd(f, buf, len); + buf[len] = '\0'; + return len; +} + /* Populate a sum_struct with values from the socket. This is * called by both the sender and the receiver. */ void read_sum_head(int f, struct sum_struct *sum) @@ -857,20 +915,20 @@ void read_sum_head(int f, struct sum_struct *sum) sum->count = read_int(f); sum->blength = read_int(f); if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) { - rprintf(FERROR, "[%s] Invalid block length %ld\n", - who_am_i(), (long)sum->blength); + rprintf(FERROR, "Invalid block length %ld [%s]\n", + (long)sum->blength, who_am_i()); exit_cleanup(RERR_PROTOCOL); } sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f); if (sum->s2length < 0 || sum->s2length > MD4_SUM_LENGTH) { - rprintf(FERROR, "[%s] Invalid checksum length %d\n", - who_am_i(), sum->s2length); + rprintf(FERROR, "Invalid checksum length %d [%s]\n", + sum->s2length, who_am_i()); exit_cleanup(RERR_PROTOCOL); } sum->remainder = read_int(f); if (sum->remainder < 0 || sum->remainder > sum->blength) { - rprintf(FERROR, "[%s] Invalid remainder length %ld\n", - who_am_i(), (long)sum->remainder); + rprintf(FERROR, "Invalid remainder length %ld [%s]\n", + (long)sum->remainder, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } @@ -959,7 +1017,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) { size_t n, total = 0; fd_set w_fds, r_fds; - int maxfd, count, ret; + int maxfd, count, ret, using_r_fds; struct timeval tv; no_flush++; @@ -974,18 +1032,15 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) FD_SET(msg_fd_in,&r_fds); if (msg_fd_in > maxfd) maxfd = msg_fd_in; - } - if (fd != sock_f_out && iobuf_out_cnt && no_flush == 1) { - FD_SET(sock_f_out, &w_fds); - if (sock_f_out > maxfd) - maxfd = sock_f_out; - } + using_r_fds = 1; + } else + using_r_fds = 0; tv.tv_sec = select_timeout; tv.tv_usec = 0; errno = 0; - count = select(maxfd + 1, msg_fd_in >= 0 ? &r_fds : NULL, + count = select(maxfd + 1, using_r_fds ? &r_fds : NULL, &w_fds, NULL, &tv); if (count <= 0) { @@ -995,17 +1050,11 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) continue; } - if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds)) + if (using_r_fds && FD_ISSET(msg_fd_in, &r_fds)) read_msg_fd(); - if (!FD_ISSET(fd, &w_fds)) { - if (fd != sock_f_out && iobuf_out_cnt) { - no_flush--; - io_flush(NORMAL_FLUSH); - no_flush++; - } + if (!FD_ISSET(fd, &w_fds)) continue; - } n = len - total; if (bwlimit && n > bwlimit_writemax) @@ -1042,7 +1091,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) total += ret; if (fd == sock_f_out) { - if (io_timeout) + if (io_timeout || am_generator) last_io = time(NULL); sleep_for_bwlimit(ret); } @@ -1203,6 +1252,26 @@ void write_byte(int f, uchar c) writefd(f, (char *)&c, 1); } +void write_vstring(int f, char *str, int len) +{ + uchar lenbuf[3], *lb = lenbuf; + + if (len > 0x7F) { + if (len > 0x7FFF) { + rprintf(FERROR, + "attempting to send over-long vstring (%d > %d)\n", + len, 0x7FFF); + exit_cleanup(RERR_PROTOCOL); + } + *lb++ = len / 0x100 + 0x80; + } + *lb = len; + + writefd(f, (char*)lenbuf, lb - lenbuf + 1); + if (len) + writefd(f, str, len); +} + /** * Read a line of up to @p maxlen characters into @p buf (not counting