X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/be21e29c351698b3f86caf13e446c5e4b19c9fde..ab3d6c6025162c19c082602aa1e488f22e40d392:/io.c diff --git a/io.c b/io.c index 915d21db..3b857bfe 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, 2004, 2005, 2006 Wayne Davison + * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 @@ -41,7 +41,7 @@ extern int am_server; extern int am_daemon; extern int am_sender; extern int am_generator; -extern int incremental; +extern int inc_recurse; extern int io_error; extern int eol_nulls; extern int flist_eof; @@ -58,7 +58,7 @@ extern struct file_list *cur_flist, *first_flist; const char phase_unknown[] = "unknown"; int ignore_timeout = 0; int batch_fd = -1; -int done_cnt = 0; +int msgdone_cnt = 0; /* Ignore an EOF error if non-zero. See whine_about_eof(). */ int kluge_around_eof = 0; @@ -134,7 +134,7 @@ struct msg_list { struct msg_list_item *head, *tail; }; -static struct msg_list msg2genr, msg2sndr; +static struct msg_list msg2sndr; static void flist_ndx_push(struct flist_ndx_list *lp, int ndx) { @@ -248,6 +248,20 @@ static void msg_list_add(struct msg_list *lst, int code, const char *buf, int le lst->tail = m; } +static void msg2sndr_flush(void) +{ + while (msg2sndr.head && io_multiplexing_out) { + struct msg_list_item *m = msg2sndr.head; + if (!(msg2sndr.head = m->next)) + msg2sndr.tail = NULL; + stats.total_written += m->len; + defer_forwarding_messages = 1; + writefd_unbuffered(sock_f_out, m->buf, m->len); + defer_forwarding_messages = 0; + free(m); + } +} + /* Read a message from the MSG_* fd and handle it. This is called either * during the early stages of being a local sender (up through the sending * of the file list) or when we're the generator (to fetch the messages @@ -262,6 +276,7 @@ static void read_msg_fd(void) /* Temporarily disable msg_fd_in. This is needed to avoid looping back * to this routine from writefd_unbuffered(). */ + no_flush++; msg_fd_in = -1; defer_forwarding_messages++; @@ -273,14 +288,18 @@ static void read_msg_fd(void) switch (tag) { case MSG_DONE: - if (len != 0 || !am_generator) { + if (len < 0 || len > 1 || !am_generator) { invalid_msg: rprintf(FERROR, "invalid message %d:%d [%s%s]\n", tag, len, who_am_i(), - incremental ? "/incremental" : ""); + inc_recurse ? "/inc" : ""); exit_cleanup(RERR_STREAMIO); } - done_cnt++; + if (len) { + readfd(fd, buf, len); + stats.total_read = read_longint(fd); + } + msgdone_cnt++; break; case MSG_REDO: if (len != 4 || !am_generator) @@ -289,11 +308,11 @@ static void read_msg_fd(void) if (remove_source_files) decrement_active_files(IVAL(buf,0)); flist_ndx_push(&redo_list, IVAL(buf,0)); - if (incremental) + if (inc_recurse) decrement_flist_in_progress(IVAL(buf,0), 1); break; case MSG_FLIST: - if (len != 4 || !am_generator || !incremental) + if (len != 4 || !am_generator || !inc_recurse) goto invalid_msg; readfd(fd, buf, 4); /* Read extra file list from receiver. */ @@ -303,7 +322,7 @@ static void read_msg_fd(void) flist->parent_ndx = IVAL(buf,0); break; case MSG_FLIST_EOF: - if (len != 0 || !am_generator || !incremental) + if (len != 0 || !am_generator || !inc_recurse) goto invalid_msg; flist_eof = 1; break; @@ -323,14 +342,14 @@ static void read_msg_fd(void) } if (preserve_hard_links) flist_ndx_push(&hlink_list, IVAL(buf,0)); - if (incremental) + if (inc_recurse) decrement_flist_in_progress(IVAL(buf,0), 0); break; case MSG_NO_SEND: if (len != 4 || !am_generator) goto invalid_msg; readfd(fd, buf, len); - if (incremental) + if (inc_recurse) decrement_flist_in_progress(IVAL(buf,0), 0); break; case MSG_SOCKERR: @@ -358,8 +377,10 @@ static void read_msg_fd(void) exit_cleanup(RERR_STREAMIO); } - defer_forwarding_messages--; + no_flush--; msg_fd_in = fd; + if (!--defer_forwarding_messages) + msg2sndr_flush(); } /* This is used by the generator to limit how many file transfers can @@ -369,15 +390,15 @@ void increment_active_files(int ndx, int itemizing, enum logcode code) { /* TODO: tune these limits? */ while (active_filecnt >= (active_bytecnt >= 128*1024 ? 10 : 50)) { -#ifdef SUPPORT_HARD_LINKS - if (hlink_list.head) - check_for_finished_hlinks(itemizing, code); -#endif - read_msg_fd(); + check_for_finished_files(itemizing, code, 0); + if (iobuf_out_cnt) + io_flush(NORMAL_FLUSH); + else + read_msg_fd(); } active_filecnt++; - active_bytecnt += F_LENGTH(cur_flist->files[ndx]); + active_bytecnt += F_LENGTH(cur_flist->files[ndx - cur_flist->ndx_start]); } static void decrement_active_files(int ndx) @@ -414,29 +435,30 @@ static void decrement_flist_in_progress(int ndx, int redo) flist->to_redo++; } -/* Try to push messages off the list onto the wire. If we leave with more - * to do, return 0. On error, return -1. If everything flushed, return 1. - * This is only active in the receiver. */ -static int msg2genr_flush(void) +/* Write an message to a multiplexed stream. If this fails, rsync exits. */ +static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len) { - if (msg_fd_out < 0 || no_flush || flist_forward_from >= 0) - return -1; + char buffer[1024]; + size_t n = len; - no_flush++; - while (msg2genr.head) { - struct msg_list_item *m = msg2genr.head; - writefd(msg_fd_out, m->buf, m->len); - msg2genr.head = m->next; - if (!msg2genr.head) - msg2genr.tail = NULL; - free(m); - } - if (iobuf_out_cnt) { - writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt); - iobuf_out_cnt = 0; + SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len); + + if (n > sizeof buffer - 4) + n = 0; + else + memcpy(buffer + 4, buf, n); + + writefd_unbuffered(fd, buffer, n+4); + + len -= n; + buf += n; + + if (len) { + defer_forwarding_messages++; + writefd_unbuffered(fd, buf, len); + if (!--defer_forwarding_messages) + msg2sndr_flush(); } - no_flush--; - return 1; } int send_msg(enum msgcode code, const char *buf, int len) @@ -449,8 +471,7 @@ int send_msg(enum msgcode code, const char *buf, int len) msg_list_add(&msg2sndr, code, buf, len); return 1; } - msg_list_add(&msg2genr, code, buf, len); - msg2genr_flush(); + mplex_write(msg_fd_out, code, buf, len); return 1; } @@ -463,7 +484,10 @@ void send_msg_int(enum msgcode code, int num) void wait_for_receiver(void) { - read_msg_fd(); + if (iobuf_out_cnt) + io_flush(NORMAL_FLUSH); + else + read_msg_fd(); } int get_redo_num(void) @@ -552,11 +576,6 @@ static int read_timeout(int fd, char *buf, size_t len) FD_ZERO(&r_fds); FD_ZERO(&w_fds); FD_SET(fd, &r_fds); - if (msg2genr.head) { - FD_SET(msg_fd_out, &w_fds); - if (msg_fd_out > maxfd) - maxfd = msg_fd_out; - } if (io_filesfrom_f_out >= 0) { int new_fd; if (io_filesfrom_buflen == 0) { @@ -583,15 +602,14 @@ static int read_timeout(int fd, char *buf, size_t len) count = select(maxfd + 1, &r_fds, &w_fds, NULL, &tv); if (count <= 0) { - if (errno == EBADF) + if (errno == EBADF) { + defer_forwarding_messages = 0; exit_cleanup(RERR_SOCKETIO); + } check_timeout(); continue; } - if (msg2genr.head && FD_ISSET(msg_fd_out, &w_fds)) - msg2genr_flush(); - if (io_filesfrom_f_out >= 0) { if (io_filesfrom_buflen) { if (FD_ISSET(io_filesfrom_f_out, &w_fds)) { @@ -1209,7 +1227,8 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len) int defer_save = defer_forwarding_messages; struct timeval tv; - no_flush++; + if (no_flush++) + defer_forwarding_messages = 1; while (total < len) { FD_ZERO(&w_fds); @@ -1270,6 +1289,9 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len) /* Don't try to write errors back across the stream. */ if (fd == sock_f_out) io_end_multiplex_out(); + /* Don't try to write errors down a failing msg pipe. */ + if (am_server && fd == msg_fd_out) + exit_cleanup(RERR_STREAMIO); rsyserr(FERROR, errno, "writefd_unbuffered failed to write %ld bytes [%s]", (long)len, who_am_i()); @@ -1294,68 +1316,21 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len) } } - defer_forwarding_messages = defer_save; no_flush--; -} - -static void msg2sndr_flush(void) -{ - if (defer_forwarding_messages) - return; - - while (msg2sndr.head && io_multiplexing_out) { - struct msg_list_item *m = msg2sndr.head; - if (!(msg2sndr.head = m->next)) - msg2sndr.tail = NULL; - stats.total_written += m->len; - defer_forwarding_messages = 1; - writefd_unbuffered(sock_f_out, m->buf, m->len); - defer_forwarding_messages = 0; - free(m); - } -} - -/** - * Write an message to a multiplexed stream. If this fails then rsync - * exits. - **/ -static void mplex_write(enum msgcode code, const char *buf, size_t len) -{ - char buffer[1024]; - size_t n = len; - - SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len); - - if (n > sizeof buffer - 4) - n = 0; - else - memcpy(buffer + 4, buf, n); - - writefd_unbuffered(sock_f_out, buffer, n+4); - - len -= n; - buf += n; - - if (len) { - defer_forwarding_messages = 1; - writefd_unbuffered(sock_f_out, buf, len); - defer_forwarding_messages = 0; + if (!(defer_forwarding_messages = defer_save)) msg2sndr_flush(); - } } void io_flush(int flush_it_all) { - if (flush_it_all) { - msg2genr_flush(); + if (flush_it_all && !defer_forwarding_messages) msg2sndr_flush(); - } if (!iobuf_out_cnt || no_flush) return; if (io_multiplexing_out) - mplex_write(MSG_DATA, iobuf_out, iobuf_out_cnt); + mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt); else writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt); iobuf_out_cnt = 0; @@ -1693,7 +1668,7 @@ int io_multiplex_write(enum msgcode code, const char *buf, size_t len) return 0; io_flush(NORMAL_FLUSH); stats.total_written += (len+4); - mplex_write(code, buf, len); + mplex_write(sock_f_out, code, buf, len); return 1; }