No need to check MIN_FILECNT_LOOKAHEAD w/extra_flist_sending_enabled.
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 8b08ff6..ac0a903 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -42,7 +42,6 @@ extern int xfer_dirs;
 extern int filesfrom_fd;
 extern int one_file_system;
 extern int copy_dirlinks;
-extern int keep_dirlinks;
 extern int preserve_uid;
 extern int preserve_gid;
 extern int preserve_acls;
@@ -87,6 +86,14 @@ extern int filesfrom_convert;
 extern iconv_t ic_send, ic_recv;
 #endif
 
+#ifdef HAVE_UTIMENSAT
+#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+#define ST_MTIME_NSEC st_mtim.tv_nsec
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
+#define ST_MTIME_NSEC st_mtimensec
+#endif
+#endif
+
 #define PTR_SIZE (sizeof (struct file_struct *))
 
 int io_error;
@@ -495,6 +502,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                xflags |= XMIT_SAME_TIME;
        else
                modtime = file->modtime;
+       if (NSEC_BUMP(file) && protocol_version >= 31)
+               xflags |= XMIT_MOD_NSEC;
 
 #ifdef SUPPORT_HARD_LINKS
        if (tmp_dev != 0) {
@@ -577,6 +586,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                else
                        write_int(f, modtime);
        }
+       if (xflags & XMIT_MOD_NSEC)
+               write_varint(f, F_MOD_NSEC(file));
        if (!(xflags & XMIT_SAME_MODE))
                write_int(f, to_wire_mode(mode));
        if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
@@ -662,8 +673,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
                stats.total_size += F_LENGTH(file);
 }
 
-static struct file_struct *recv_file_entry(struct file_list *flist,
-                                          int xflags, int f)
+static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
 {
        static int64 modtime;
        static mode_t mode;
@@ -685,6 +695,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
        int extra_len = file_extra_cnt * EXTRA_LEN;
        int first_hlink_ndx = -1;
        int64 file_length;
+       uint32 modtime_nsec;
        const char *basename;
        struct file_struct *file;
        alloc_pool_t *pool;
@@ -719,7 +730,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                INIT_CONST_XBUF(outbuf, thisname);
                INIT_XBUF(inbuf, lastname, basename_len, (size_t)-1);
 
-               if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) {
+               if (iconvbufs(ic_recv, &inbuf, &outbuf, ICB_INIT) < 0) {
                        io_error |= IOERR_GENERAL;
                        rprintf(FERROR_UTF8,
                            "[%s] cannot convert filename: %s (%s)\n",
@@ -768,6 +779,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                        struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
                        file_length = F_LENGTH(first);
                        modtime = first->modtime;
+                       modtime_nsec = F_MOD_NSEC(first);
                        mode = first->mode;
                        if (preserve_uid)
                                uid = F_OWNER(first);
@@ -801,6 +813,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                } else
                        modtime = read_int(f);
        }
+       if (xflags & XMIT_MOD_NSEC)
+               modtime_nsec = read_varint(f);
+       else
+               modtime_nsec = 0;
        if (!(xflags & XMIT_SAME_MODE))
                mode = from_wire_mode(read_int(f));
 
@@ -898,6 +914,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
 #if SIZEOF_INT64 >= 8
        if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
                extra_len += EXTRA_LEN;
+#endif
+#ifdef HAVE_UTIMENSAT
+       if (modtime_nsec)
+               extra_len += EXTRA_LEN;
 #endif
        if (file_length < 0) {
                rprintf(FERROR, "Offset underflow: file-length is negative\n");
@@ -934,6 +954,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                file->flags |= FLAG_HLINKED;
 #endif
        file->modtime = (time_t)modtime;
+#ifdef HAVE_UTIMENSAT
+       if (modtime_nsec) {
+               file->flags |= FLAG_MOD_NSEC;
+               OPT_EXTRA(file, 0)->unum = modtime_nsec;
+       }
+#endif
        file->len32 = (uint32)file_length;
 #if SIZEOF_INT64 >= 8
        if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) {
@@ -942,7 +968,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                exit_cleanup(RERR_UNSUPPORTED);
 #else
                file->flags |= FLAG_LENGTH64;
-               OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
+               OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(file_length >> 32);
 #endif
        }
 #endif
@@ -1022,7 +1048,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
                                read_sbuf(f, inbuf.buf, inbuf.len);
                                INIT_XBUF(outbuf, bp, 0, alloc_len);
 
-                               if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) {
+                               if (iconvbufs(ic_recv, &inbuf, &outbuf, ICB_INIT) < 0) {
                                        io_error |= IOERR_GENERAL;
                                        rprintf(FERROR_XFER,
                                            "[%s] cannot convert symlink data for: %s (%s)\n",
@@ -1088,11 +1114,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
 
 #ifdef SUPPORT_ACLS
        if (preserve_acls && !S_ISLNK(mode))
-               receive_acl(file, f);
+               receive_acl(f, file);
 #endif
 #ifdef SUPPORT_XATTRS
        if (preserve_xattrs)
-               receive_xattr(file, f );
+               receive_xattr(f, file);
 #endif
 
        if (S_ISREG(mode) || S_ISLNK(mode))
@@ -1272,6 +1298,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
        linkname_len = 0;
 #endif
 
+#ifdef ST_MTIME_NSEC
+       if (st.ST_MTIME_NSEC && protocol_version >= 31)
+               extra_len += EXTRA_LEN;
+#endif
 #if SIZEOF_CAPITAL_OFF_T >= 8
        if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode))
                extra_len += EXTRA_LEN;
@@ -1326,11 +1356,17 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
 
        file->flags = flags;
        file->modtime = st.st_mtime;
+#ifdef ST_MTIME_NSEC
+       if (st.ST_MTIME_NSEC && protocol_version >= 31) {
+               file->flags |= FLAG_MOD_NSEC;
+               OPT_EXTRA(file, 0)->unum = st.ST_MTIME_NSEC;
+       }
+#endif
        file->len32 = (uint32)st.st_size;
 #if SIZEOF_CAPITAL_OFF_T >= 8
        if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) {
                file->flags |= FLAG_LENGTH64;
-               OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
+               OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(st.st_size >> 32);
        }
 #endif
        file->mode = st.st_mode;
@@ -1427,14 +1463,14 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
                        if (file->dirname) {
                                INIT_XBUF_STRLEN(inbuf, (char*)file->dirname);
                                outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */
-                               if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0)
+                               if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INIT) < 0)
                                        goto convert_error;
                                outbuf.size += 2;
                                fbuf[outbuf.len++] = '/';
                        }
 
                        INIT_XBUF_STRLEN(inbuf, (char*)file->basename);
-                       if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) {
+                       if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INIT) < 0) {
                          convert_error:
                                io_error |= IOERR_GENERAL;
                                rprintf(FERROR_XFER,
@@ -1448,7 +1484,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
                        if (symlink_len && sender_symlink_iconv) {
                                INIT_XBUF(inbuf, (char*)symlink_name, symlink_len, (size_t)-1);
                                INIT_CONST_XBUF(outbuf, symlink_buf);
-                               if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) {
+                               if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INIT) < 0) {
                                        io_error |= IOERR_GENERAL;
                                        f_name(file, fbuf);
                                        rprintf(FERROR_XFER,
@@ -1493,13 +1529,13 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
 
 #ifdef SUPPORT_ACLS
                if (preserve_acls && !S_ISLNK(file->mode)) {
-                       send_acl(&sx, f);
+                       send_acl(f, &sx);
                        free_acl(&sx);
                }
 #endif
 #ifdef SUPPORT_XATTRS
                if (preserve_xattrs) {
-                       F_XATTR(file) = send_xattr(&sx, f);
+                       F_XATTR(file) = send_xattr(f, &sx);
                        free_xattr(&sx);
                }
 #endif
@@ -1985,6 +2021,8 @@ void send_extra_file_list(int f, int at_least)
                                if ((send_dir_ndx = DIR_PARENT(dp)) < 0) {
                                        write_ndx(f, NDX_FLIST_EOF);
                                        flist_eof = 1;
+                                       if (DEBUG_GTE(FLIST, 3))
+                                               rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
                                        change_local_filter_dir(NULL, 0, 0);
                                        goto finish;
                                }
@@ -2012,7 +2050,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        struct timeval start_tv, end_tv;
        int64 start_write;
        int use_ff_fd = 0;
-       int disable_buffering;
+       int disable_buffering, reenable_multiplex = -1;
        int flags = recurse ? FLAG_CONTENT_DIR : 0;
        int reading_remotely = filesfrom_host != NULL;
        int rl_flags = (reading_remotely ? 0 : RL_DUMP_COMMENTS)
@@ -2053,6 +2091,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                                full_fname(argv[0]));
                        exit_cleanup(RERR_FILESELECT);
                }
+               if (protocol_version < 31) {
+                       /* Older protocols send the files-from data w/o packaging
+                        * it in multiplexed I/O packets, so temporarily switch
+                        * to buffered I/O to match this behavior. */
+                       reenable_multiplex = io_end_multiplex_in(MPLX_TO_BUFFERED);
+               }
                use_ff_fd = 1;
        }
 
@@ -2258,6 +2302,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                        send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS);
        }
 
+       if (reenable_multiplex >= 0)
+               io_start_multiplex_in(reenable_multiplex);
+
        gettimeofday(&end_tv, NULL);
        stats.flist_buildtime = (int64)(end_tv.tv_sec - start_tv.tv_sec) * 1000
                              + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
@@ -2302,12 +2349,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                flist->sorted = flist->files;
        flist_sort_and_clean(flist, 0);
        file_total += flist->used;
+       file_old_total += flist->used;
 
        if (numeric_ids <= 0 && !inc_recurse)
                send_id_list(f);
 
-       set_msg_fd_in(-1);
-
        /* send the io_error flag */
        if (protocol_version < 30)
                write_int(f, ignore_errors ? 0 : io_error);
@@ -2315,7 +2361,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                send_msg_int(MSG_IO_ERROR, io_error);
 
        if (disable_buffering)
-               io_end_buffering_out();
+               io_end_buffering_out(IOBUF_FREE_BUFS);
 
        stats.flist_size = stats.total_written - start_write;
        stats.num_files = flist->used;
@@ -2335,6 +2381,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                if (send_dir_ndx < 0) {
                        write_ndx(f, NDX_FLIST_EOF);
                        flist_eof = 1;
+                       if (DEBUG_GTE(FLIST, 3))
+                               rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
                }
                else if (file_total == 1) {
                        /* If we're creating incremental file-lists and there
@@ -2342,8 +2390,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
                         * file-list to check if this is a 1-file xfer. */
                        send_extra_file_list(f, 1);
                }
-       } else
+       } else {
                flist_eof = 1;
+               if (DEBUG_GTE(FLIST, 3))
+                       rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
+       }
 
        return flist;
 }
@@ -2403,7 +2454,7 @@ struct file_list *recv_file_list(int f)
                }
 
                flist_expand(flist, 1);
-               file = recv_file_entry(flist, flags, f);
+               file = recv_file_entry(f, flist, flags);
 
                if (S_ISREG(file->mode)) {
                        /* Already counted */
@@ -2472,6 +2523,8 @@ struct file_list *recv_file_list(int f)
        else if (f >= 0) {
                recv_id_list(f, flist);
                flist_eof = 1;
+               if (DEBUG_GTE(FLIST, 3))
+                       rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
        }
 
        flist_sort_and_clean(flist, relative_paths);
@@ -2506,6 +2559,8 @@ void recv_additional_file_list(int f)
        int ndx = read_ndx(f);
        if (ndx == NDX_FLIST_EOF) {
                flist_eof = 1;
+               if (DEBUG_GTE(FLIST, 3))
+                       rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
                change_local_filter_dir(NULL, 0, 0);
        } else {
                ndx = NDX_FLIST_OFFSET - ndx;