X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/c6816b9444da40d45b7c3060f4c23654201e29bc..f2a4853c93136bfa282cff767873064db3ebb28c:/io.c diff --git a/io.c b/io.c index f26b48da..f8b908e3 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; @@ -111,7 +115,7 @@ struct flist_ndx_list { struct flist_ndx_item *head, *tail; }; -static struct flist_ndx_list redo_list; +static struct flist_ndx_list redo_list, hlink_list; struct msg_list { struct msg_list *next; @@ -284,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: @@ -346,15 +353,24 @@ int msg_list_push(int flush_it_all) return 1; } -int get_redo_num(void) +int get_redo_num(int itemizing, enum logcode code) { - while (!redo_list.head) { + while (1) { + if (hlink_list.head) + check_for_finished_hlinks(itemizing, code); + if (redo_list.head) + break; read_msg_fd(); } return flist_ndx_pop(&redo_list); } +int get_hlink_num(void) +{ + return flist_ndx_pop(&hlink_list); +} + /** * When we're the receiver and we have a local --files-from list of names * that needs to be sent over the socket to the sender, we have to do two @@ -558,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); } @@ -649,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) @@ -689,8 +712,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) { static size_t remaining; static size_t iobuf_in_ndx; + size_t msg_bytes; 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); @@ -713,60 +741,56 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) read_loop(fd, line, 4); tag = IVAL(line, 0); - remaining = tag & 0xFFFFFF; + msg_bytes = tag & 0xFFFFFF; tag = (tag >> 24) - MPLEX_BASE; switch (tag) { case MSG_DATA: - if (remaining > iobuf_in_siz) { + if (msg_bytes > iobuf_in_siz) { if (!(iobuf_in = realloc_array(iobuf_in, char, - remaining))) + msg_bytes))) out_of_memory("readfd_unbuffered"); - iobuf_in_siz = remaining; + iobuf_in_siz = msg_bytes; } - read_loop(fd, iobuf_in, remaining); + read_loop(fd, iobuf_in, msg_bytes); + remaining = msg_bytes; iobuf_in_ndx = 0; break; case MSG_DELETED: - if (remaining >= sizeof line) { - rprintf(FERROR, "invalid multi-message %d:%ld\n", - tag, (long)remaining); - exit_cleanup(RERR_STREAMIO); - } - read_loop(fd, line, remaining); - line[remaining] = '\0'; + if (msg_bytes >= sizeof line) + goto overflow; + read_loop(fd, line, msg_bytes); + line[msg_bytes] = '\0'; /* A directory name was sent with the trailing null */ - if (remaining > 0 && !line[remaining-1]) + if (msg_bytes > 0 && !line[msg_bytes-1]) log_delete(line, S_IFDIR); else log_delete(line, S_IFREG); - remaining = 0; break; case MSG_SUCCESS: - if (remaining != 4) { - rprintf(FERROR, "invalid multi-message %d:%ld\n", - tag, (long)remaining); + if (msg_bytes != 4) { + rprintf(FERROR, "invalid multi-message %d:%ld [%s]\n", + tag, (long)msg_bytes, who_am_i()); exit_cleanup(RERR_STREAMIO); } - read_loop(fd, line, remaining); + read_loop(fd, line, msg_bytes); successful_send(IVAL(line, 0)); - remaining = 0; break; case MSG_INFO: case MSG_ERROR: - if (remaining >= sizeof line) { + if (msg_bytes >= sizeof line) { + overflow: rprintf(FERROR, - "[%s] multiplexing overflow %d:%ld\n\n", - who_am_i(), tag, (long)remaining); + "multiplexing overflow %d:%ld [%s]\n", + tag, (long)msg_bytes, who_am_i()); exit_cleanup(RERR_STREAMIO); } - read_loop(fd, line, remaining); - rwrite((enum logcode)tag, line, remaining); - remaining = 0; + read_loop(fd, line, msg_bytes); + rwrite((enum logcode)tag, line, msg_bytes); 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); } } @@ -872,7 +896,7 @@ int read_vstring(int f, char *buf, int bufsize) if (len >= bufsize) { rprintf(FERROR, "over-long vstring received (%d > %d)\n", len, bufsize - 1); - exit_cleanup(RERR_PROTOCOL); + return -1; } if (len) @@ -888,20 +912,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); } } @@ -990,7 +1014,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++; @@ -1005,18 +1029,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) { @@ -1026,17 +1047,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) @@ -1073,7 +1088,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); }