- Parse hard-link info as soon as we get it in inc_recurse mode.
[rsync/rsync.git] / io.c
diff --git a/io.c b/io.c
index be19b2c..62990b9 100644 (file)
--- a/io.c
+++ b/io.c
@@ -7,8 +7,9 @@
  * Copyright (C) 2003-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 version 3 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -49,7 +50,6 @@ extern int checksum_seed;
 extern int protocol_version;
 extern int remove_source_files;
 extern int preserve_hard_links;
-extern char *filesfrom_host;
 extern struct stats stats;
 extern struct file_list *cur_flist, *first_flist;
 #ifdef ICONV_OPTION
@@ -111,11 +111,11 @@ 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 */
 };
 
+enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND };
+
 static void readfd(int fd, char *buffer, size_t N);
 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 decrement_active_files(int ndx);
-static void decrement_flist_in_progress(int ndx, int redo);
 static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len, int convert);
 
 struct flist_ndx_item {
@@ -174,6 +174,42 @@ static int flist_ndx_pop(struct flist_ndx_list *lp)
        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);
+       assert(ndx >= flist->ndx_start);
+
+       if (remove_source_files) {
+               active_filecnt--;
+               active_bytecnt -= F_LENGTH(flist->files[ndx - flist->ndx_start]);
+       }
+
+       if (inc_recurse)
+               flist->in_progress--;
+
+       switch (status) {
+       case FES_SUCCESS:
+               if (remove_source_files)
+                       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))
+                               flist_ndx_push(&hlink_list, ndx);
+               }
+               break;
+       case FES_REDO:
+               if (inc_recurse)
+                       flist->to_redo++;
+               flist_ndx_push(&redo_list, ndx);
+               break;
+       case FES_NO_SEND:
+               break;
+       }
+}
+
 static void check_timeout(void)
 {
        time_t t;
@@ -326,11 +362,7 @@ static void read_msg_fd(void)
                if (len != 4 || !am_generator)
                        goto invalid_msg;
                readfd(fd, buf, 4);
-               if (remove_source_files)
-                       decrement_active_files(IVAL(buf,0));
-               flist_ndx_push(&redo_list, IVAL(buf,0));
-               if (inc_recurse)
-                       decrement_flist_in_progress(IVAL(buf,0), 1);
+               got_flist_entry_status(FES_REDO, buf);
                break;
        case MSG_FLIST:
                if (len != 4 || !am_generator || !inc_recurse)
@@ -345,6 +377,10 @@ static void read_msg_fd(void)
                }
                flist = recv_file_list(fd);
                flist->parent_ndx = IVAL(buf,0);
+#ifdef SUPPORT_HARD_LINKS
+               if (preserve_hard_links)
+                       match_hard_links(flist);
+#endif
                break;
        case MSG_FLIST_EOF:
                if (len != 0 || !am_generator || !inc_recurse)
@@ -360,22 +396,14 @@ static void read_msg_fd(void)
        case MSG_SUCCESS:
                if (len != 4 || !am_generator)
                        goto invalid_msg;
-               readfd(fd, buf, len);
-               if (remove_source_files) {
-                       decrement_active_files(IVAL(buf,0));
-                       send_msg(MSG_SUCCESS, buf, len, 0);
-               }
-               if (preserve_hard_links)
-                       flist_ndx_push(&hlink_list, IVAL(buf,0));
-               if (inc_recurse)
-                       decrement_flist_in_progress(IVAL(buf,0), 0);
+               readfd(fd, buf, 4);
+               got_flist_entry_status(FES_SUCCESS, buf);
                break;
        case MSG_NO_SEND:
                if (len != 4 || !am_generator)
                        goto invalid_msg;
-               readfd(fd, buf, len);
-               if (inc_recurse)
-                       decrement_flist_in_progress(IVAL(buf,0), 0);
+               readfd(fd, buf, 4);
+               got_flist_entry_status(FES_NO_SEND, buf);
                break;
        case MSG_SOCKERR:
        case MSG_CLIENT:
@@ -426,40 +454,6 @@ void increment_active_files(int ndx, int itemizing, enum logcode code)
        active_bytecnt += F_LENGTH(cur_flist->files[ndx - cur_flist->ndx_start]);
 }
 
-static void decrement_active_files(int ndx)
-{
-       struct file_list *flist = flist_for_ndx(ndx);
-       assert(flist != NULL);
-       active_filecnt--;
-       active_bytecnt -= F_LENGTH(flist->files[ndx - flist->ndx_start]);
-}
-
-static void decrement_flist_in_progress(int ndx, int redo)
-{
-       struct file_list *flist = cur_flist ? cur_flist : first_flist;
-
-       while (ndx < flist->ndx_start) {
-               if (flist == first_flist) {
-                 invalid_ndx:
-                       rprintf(FERROR,
-                               "Invalid file index: %d (%d - %d) [%s]\n",
-                               ndx, first_flist->ndx_start,
-                               first_flist->prev->ndx_start + first_flist->prev->used - 1,
-                               who_am_i());
-                       exit_cleanup(RERR_PROTOCOL);
-               }
-               flist = flist->prev;
-       }
-       while (ndx >= flist->ndx_start + flist->used) {
-               if (!(flist = flist->next))
-                       goto invalid_ndx;
-       }
-
-       flist->in_progress--;
-       if (redo)
-               flist->to_redo++;
-}
-
 /* 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, int convert)
 {
@@ -762,17 +756,14 @@ static int read_timeout(int fd, char *buf, size_t len)
        return cnt;
 }
 
-/* Read a line into the "fname" buffer (which must be at least MAXPATHLEN
- * characters long). */
-int read_filesfrom_line(int fd, char *fname)
+/* Read a line into the "buf" buffer. */
+int read_line(int fd, char *buf, size_t bufsiz, int dump_comments, int rl_nulls)
 {
-       char ch, *s, *eob = fname + MAXPATHLEN - 1;
+       char ch, *s, *eob = buf + bufsiz - 1;
        int cnt;
-       int reading_remotely = filesfrom_host != NULL;
-       int nulls = eol_nulls || reading_remotely;
 
   start:
-       s = fname;
+       s = buf;
        while (1) {
                cnt = read(fd, &ch, 1);
                if (cnt < 0 && (errno == EWOULDBLOCK
@@ -787,17 +778,15 @@ int read_filesfrom_line(int fd, char *fname)
                        tv.tv_usec = 0;
                        if (!select(fd+1, &r_fds, NULL, &e_fds, &tv))
                                check_timeout();
-                       if (FD_ISSET(fd, &e_fds)) {
-                               rsyserr(FINFO, errno,
-                                       "select exception on fd %d", fd);
-                       }
+                       /*if (FD_ISSET(fd, &e_fds))
+                               rprintf(FINFO, "select exception on fd %d\n", fd); */
                        continue;
                }
                if (cnt != 1)
                        break;
-               if (nulls? !ch : (ch == '\r' || ch == '\n')) {
-                       /* Skip empty lines if reading locally. */
-                       if (!reading_remotely && s == fname)
+               if (rl_nulls ? ch == '\0' : (ch == '\r' || ch == '\n')) {
+                       /* Skip empty lines if dumping comments. */
+                       if (dump_comments && s == buf)
                                continue;
                        break;
                }
@@ -806,11 +795,57 @@ int read_filesfrom_line(int fd, char *fname)
        }
        *s = '\0';
 
-       /* Dump comments. */
-       if (*fname == '#' || *fname == ';')
+       if (dump_comments && (*buf == '#' || *buf == ';'))
                goto start;
 
-       return s - fname;
+       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)
+{
+       int maxargs = MAX_ARGS;
+       int dot_pos = 0;
+       int argc = 0;
+       char **argv, *p;
+
+       if (!(argv = new_array(char *, maxargs)))
+               out_of_memory("read_args");
+       if (mod_name)
+               argv[argc++] = "rsyncd";
+
+       while (1) {
+               if (read_line(f_in, buf, bufsiz, 0, rl_nulls) == 0)
+                       break;
+
+               if (argc == maxargs) {
+                       maxargs += MAX_ARGS;
+                       if (!(argv = realloc_array(argv, char *, maxargs)))
+                               out_of_memory("read_args");
+               }
+
+               if (dot_pos) {
+                       if (request_p) {
+                               *request_p = strdup(buf);
+                               request_p = NULL;
+                       }
+                       if (mod_name)
+                               glob_expand_module(mod_name, buf, &argv, &argc, &maxargs);
+                       else
+                               glob_expand(buf, &argv, &argc, &maxargs);
+               } else {
+                       if (!(p = strdup(buf)))
+                               out_of_memory("read_args");
+                       argv[argc++] = p;
+                       if (*p == '.' && p[1] == '\0')
+                               dot_pos = argc;
+               }
+       }
+
+       *argc_p = argc;
+       *argv_p = argv;
+
+       return dot_pos ? dot_pos : argc;
 }
 
 int io_start_buffering_out(int f_out)
@@ -1369,10 +1404,8 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
                        continue;
                }
 
-               if (FD_ISSET(fd, &e_fds)) {
-                       rsyserr(FINFO, errno,
-                               "select exception on fd %d", fd);
-               }
+               /*if (FD_ISSET(fd, &e_fds))
+                       rprintf(FINFO, "select exception on fd %d\n", fd); */
 
                if (using_r_fds && FD_ISSET(msg_fd_in, &r_fds))
                        read_msg_fd();
@@ -1406,7 +1439,7 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
                                (long)len, who_am_i());
                        /* If the other side is sending us error messages, try
                         * to grab any messages they sent before they died. */
-                       while (fd == sock_f_out && io_multiplexing_in) {
+                       while (!am_server && fd == sock_f_out && io_multiplexing_in) {
                                set_io_timeout(30);
                                ignore_timeout = 0;
                                readfd_unbuffered(sock_f_in, io_filesfrom_buf,
@@ -1685,16 +1718,13 @@ int32 read_ndx(int f)
        return num;
 }
 
-/**
- * Read a line of up to @p maxlen characters into @p buf (not counting
- * the trailing null).  Strips the (required) trailing newline and all
- * carriage returns.
- *
- * @return 1 for success; 0 for I/O error or truncation.
- **/
-int read_line(int f, char *buf, size_t maxlen)
+/* Read a line of up to bufsiz-1 characters into buf.  Strips
+ * the (required) trailing newline and all carriage returns.
+ * Returns 1 for success; 0 for I/O error or truncation. */
+int read_line_old(int f, char *buf, size_t bufsiz)
 {
-       while (maxlen) {
+       bufsiz--; /* leave room for the null */
+       while (bufsiz > 0) {
                buf[0] = 0;
                read_buf(f, buf, 1);
                if (buf[0] == 0)
@@ -1703,11 +1733,11 @@ int read_line(int f, char *buf, size_t maxlen)
                        break;
                if (buf[0] != '\r') {
                        buf++;
-                       maxlen--;
+                       bufsiz--;
                }
        }
        *buf = '\0';
-       return maxlen > 0;
+       return bufsiz > 0;
 }
 
 void io_printf(int fd, const char *format, ...)