New logging categories added to allow differentiation between
[rsync/rsync.git] / io.c
diff --git a/io.c b/io.c
index 1899cb9..f886a55 100644 (file)
--- a/io.c
+++ b/io.c
@@ -28,6 +28,7 @@
  * io_start_multiplex_out() and io_start_multiplex_in(). */
 
 #include "rsync.h"
+#include "ifuncs.h"
 
 /** If no timeout is specified then use a 60 second select timeout */
 #define SELECT_TIMEOUT 60
@@ -52,7 +53,7 @@ extern int protocol_version;
 extern int remove_source_files;
 extern int preserve_hard_links;
 extern struct stats stats;
-extern struct file_list *cur_flist, *first_flist;
+extern struct file_list *cur_flist;
 #ifdef ICONV_OPTION
 extern int filesfrom_convert;
 extern iconv_t ic_send, ic_recv;
@@ -99,7 +100,7 @@ static char ff_lastchar;
 #ifdef ICONV_OPTION
 static xbuf iconv_buf = EMPTY_XBUF;
 #endif
-static int defer_forwarding_messages = 0;
+static int defer_forwarding_messages = 0, defer_forwarding_keep = 0;
 static int select_timeout = SELECT_TIMEOUT;
 static int active_filecnt = 0;
 static OFF_T active_bytecnt = 0;
@@ -180,7 +181,6 @@ static void got_flist_entry_status(enum festatus status, const char *buf)
        struct file_list *flist = flist_for_ndx(ndx);
 
        assert(flist != NULL);
-       assert(ndx >= flist->ndx_start);
 
        if (remove_source_files) {
                active_filecnt--;
@@ -196,8 +196,10 @@ static void got_flist_entry_status(enum festatus status, const char *buf)
                        send_msg(MSG_SUCCESS, buf, 4, 0);
                if (preserve_hard_links) {
                        struct file_struct *file = flist->files[ndx - flist->ndx_start];
-                       if (F_IS_HLINKED(file))
+                       if (F_IS_HLINKED(file)) {
                                flist_ndx_push(&hlink_list, ndx);
+                               flist->in_progress++;
+                       }
                }
                break;
        case FES_REDO:
@@ -387,6 +389,12 @@ static void read_msg_fd(void)
                        goto invalid_msg;
                flist_eof = 1;
                break;
+       case MSG_IO_ERROR:
+               if (len != 4)
+                       goto invalid_msg;
+               readfd(fd, buf, len);
+               io_error |= IVAL(buf, 0);
+               break;
        case MSG_DELETED:
                if (len >= (int)sizeof buf || !am_generator)
                        goto invalid_msg;
@@ -405,15 +413,17 @@ 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_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;
@@ -432,7 +442,7 @@ static void read_msg_fd(void)
 
        no_flush--;
        msg_fd_in = fd;
-       if (!--defer_forwarding_messages)
+       if (!--defer_forwarding_messages && !no_flush)
                msg_flush();
 }
 
@@ -460,46 +470,41 @@ static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len,
        char buffer[BIGPATHBUFLEN]; /* Oversized for use by iconv code. */
        size_t n = len;
 
-       SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
-
 #ifdef ICONV_OPTION
-       if (convert && ic_send == (iconv_t)-1)
-#endif
-               convert = 0;
+       /* We need to convert buf before doing anything else so that we
+        * can include the (converted) byte length in the message header. */
+       if (convert && ic_send != (iconv_t)-1) {
+               xbuf outbuf, inbuf;
+
+               INIT_XBUF(outbuf, buffer + 4, 0, sizeof buffer - 4);
+               INIT_XBUF(inbuf, (char*)buf, len, -1);
 
-       if (convert || n > 1024 - 4) /* BIGPATHBUFLEN can handle 1024 bytes */
-               n = 0;
+               iconvbufs(ic_send, &inbuf, &outbuf,
+                         ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
+               if (inbuf.len > 0) {
+                       rprintf(FERROR, "overflowed conversion buffer in mplex_write");
+                       exit_cleanup(RERR_UNSUPPORTED);
+               }
+
+               n = len = outbuf.len;
+       } else
+#endif
+       if (n > 1024 - 4) /* BIGPATHBUFLEN can handle 1024 bytes */
+               n = 0;    /* We'd rather do 2 writes than too much memcpy(). */
        else
                memcpy(buffer + 4, buf, n);
 
-       writefd_unbuffered(fd, buffer, n+4);
-
-       len -= n;
-       buf += n;
+       SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
 
-#ifdef ICONV_OPTION
-       if (convert) {
-               xbuf outbuf, inbuf;
+       defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */
+       writefd_unbuffered(fd, buffer, n+4);
+       defer_forwarding_keep = 0;
 
-               INIT_CONST_XBUF(outbuf, buffer);
-               INIT_XBUF(inbuf, (char*)buf, len, -1);
+       if (len > n)
+               writefd_unbuffered(fd, buf+n, len-n);
 
-               defer_forwarding_messages++;
-               do {
-                       iconvbufs(ic_send, &inbuf, &outbuf,
-                                 ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
-                       writefd_unbuffered(fd, outbuf.buf, outbuf.len);
-               } while (inbuf.len);
-               if (!--defer_forwarding_messages)
-                       msg_flush();
-       } else
-#endif
-       if (len) {
-               defer_forwarding_messages++;
-               writefd_unbuffered(fd, buf, len);
-               if (!--defer_forwarding_messages)
-                       msg_flush();
-       }
+       if (!--defer_forwarding_messages && !no_flush)
+               msg_flush();
 }
 
 int send_msg(enum msgcode code, const char *buf, int len, int convert)
@@ -674,7 +679,11 @@ static int read_timeout(int fd, char *buf, size_t len)
                                }
                        } else if (io_filesfrom_f_in >= 0) {
                                if (FD_ISSET(io_filesfrom_f_in, &r_fds)) {
+#ifdef ICONV_OPTION
                                        xbuf *ibuf = filesfrom_convert ? &iconv_buf : &ff_buf;
+#else
+                                       xbuf *ibuf = &ff_buf;
+#endif
                                        int l = read(io_filesfrom_f_in, ibuf->buf, ibuf->size);
                                        if (l <= 0) {
                                                if (l == 0 || errno != EINTR) {
@@ -685,6 +694,7 @@ static int read_timeout(int fd, char *buf, size_t len)
                                                        io_filesfrom_f_in = -1;
                                                }
                                        } else {
+#ifdef ICONV_OPTION
                                                if (filesfrom_convert) {
                                                        iconv_buf.pos = 0;
                                                        iconv_buf.len = l;
@@ -692,6 +702,7 @@ static int read_timeout(int fd, char *buf, size_t len)
                                                            ICB_EXPAND_OUT|ICB_INCLUDE_BAD|ICB_INCLUDE_INCOMPLETE);
                                                        l = ff_buf.len;
                                                }
+#endif
                                                if (!eol_nulls) {
                                                        char *s = ff_buf.buf + l;
                                                        /* Transform CR and/or LF into '\0' */
@@ -742,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);
@@ -771,7 +782,11 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags)
 #endif
 
   start:
+#ifdef ICONV_OPTION
        s = flags & RL_CONVERT ? iconv_buf.buf : buf;
+#else
+       s = buf;
+#endif
        eob = s + bufsiz - 1;
        while (1) {
                cnt = read(fd, &ch, 1);
@@ -830,8 +845,11 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
        int dot_pos = 0;
        int argc = 0;
        char **argv, *p;
-       int rl_flags = (rl_nulls ? RL_EOL_NULLS : 0)
-                    | (protect_args && ic_recv != (iconv_t)-1 ? RL_CONVERT : 0);
+       int rl_flags = (rl_nulls ? RL_EOL_NULLS : 0);
+
+#ifdef ICONV_OPTION
+       rl_flags |= (protect_args && ic_recv != (iconv_t)-1 ? RL_CONVERT : 0);
+#endif
 
        if (!(argv = new_array(char *, maxargs)))
                out_of_memory("read_args");
@@ -1027,6 +1045,7 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                        if (msg_bytes != 4)
                                goto invalid_msg;
                        read_loop(fd, line, msg_bytes);
+                       send_msg_int(MSG_IO_ERROR, IVAL(line, 0));
                        io_error |= IVAL(line, 0);
                        break;
                case MSG_DELETED:
@@ -1040,7 +1059,7 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
                                int pos = 0;
 
                                INIT_CONST_XBUF(outbuf, line);
-                               inbuf.buf = ibuf;
+                               INIT_XBUF(inbuf, ibuf, 0, -1);
 
                                while (msg_bytes) {
                                        inbuf.len = msg_bytes > sizeof ibuf
@@ -1089,6 +1108,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,
@@ -1490,7 +1511,8 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
        }
 
        no_flush--;
-       if (!(defer_forwarding_messages -= defer_inc))
+       defer_inc -= defer_forwarding_keep;
+       if (!(defer_forwarding_messages -= defer_inc) && !no_flush)
                msg_flush();
 }
 
@@ -1840,6 +1862,8 @@ void start_write_batch(int fd)
         * actual communication so far depends on whether a daemon
         * is involved. */
        write_int(batch_fd, protocol_version);
+       if (protocol_version >= 30)
+               write_byte(batch_fd, inc_recurse);
        write_int(batch_fd, checksum_seed);
 
        if (am_sender)