X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/0d9eba0312d01b7c893e74f585b8214845610145..5dd14f0c3388f69932d521915e039e32b9e6d970:/flist.c diff --git a/flist.c b/flist.c index f485aca4..766f1b37 100644 --- a/flist.c +++ b/flist.c @@ -23,16 +23,15 @@ #include "rsync.h" #include "ifuncs.h" #include "rounding.h" +#include "inums.h" #include "io.h" -extern int verbose; extern int am_root; extern int am_server; extern int am_daemon; extern int am_sender; extern int am_generator; extern int inc_recurse; -extern int do_progress; extern int always_checksum; extern int module_id; extern int ignore_errors; @@ -67,6 +66,9 @@ extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; extern int need_unsorted_flist; +extern int sender_symlink_iconv; +extern int output_needs_newline; +extern int sender_keeps_checksum; extern int unsort_ndx; extern struct stats stats; extern char *filesfrom_host; @@ -129,7 +131,7 @@ static void output_flist(struct file_list *flist); void init_flist(void) { - if (verbose > 4) { + if (DEBUG_GTE(FLIST, 4)) { rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n", (int)FILE_STRUCT_LEN, (int)EXTRA_LEN); } @@ -140,14 +142,13 @@ void init_flist(void) static int show_filelist_p(void) { - return verbose && xfer_dirs && !am_server && !inc_recurse; + return INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse; } static void start_filelist_progress(char *kind) { rprintf(FCLIENT, "%s ... ", kind); - if (verbose > 1 || do_progress) - rprintf(FCLIENT, "\n"); + output_needs_newline = 1; rflush(FINFO); } @@ -158,18 +159,20 @@ static void emit_filelist_progress(int count) static void maybe_emit_filelist_progress(int count) { - if (do_progress && show_filelist_p() && (count % 100) == 0) + if (INFO_GTE(FLIST, 2) && show_filelist_p() && (count % 100) == 0) emit_filelist_progress(count); } static void finish_filelist_progress(const struct file_list *flist) { - if (do_progress) { + if (INFO_GTE(FLIST, 2)) { /* This overwrites the progress line */ rprintf(FINFO, "%d file%sto consider\n", flist->used, flist->used == 1 ? " " : "s "); - } else + } else { + output_needs_newline = 0; rprintf(FINFO, "done\n"); + } } void show_flist_stats(void) @@ -196,7 +199,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) return -1; linkbuf[llen] = '\0'; if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) { - if (verbose > 1) { + if (INFO_GTE(SYMSAFE, 1)) { rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n", path, linkbuf); } @@ -316,10 +319,10 @@ static void flist_expand(struct file_list *flist, int extra) new_ptr = realloc_array(flist->files, struct file_struct *, flist->malloced); - if (verbose >= 2 && flist->malloced != FLIST_START) { - rprintf(FCLIENT, "[%s] expand file_list pointer array to %.0f bytes, did%s move\n", + if (DEBUG_GTE(FLIST, 1) && flist->malloced != FLIST_START) { + rprintf(FCLIENT, "[%s] expand file_list pointer array to %s bytes, did%s move\n", who_am_i(), - (double)sizeof flist->files[0] * flist->malloced, + big_num(sizeof flist->files[0] * flist->malloced), (new_ptr == flist->files) ? " not" : ""); } @@ -375,7 +378,7 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen) if (!change_dir(dir, CD_NORMAL)) { chdir_error: io_error |= IOERR_GENERAL; - rsyserr(FERROR, errno, "change_dir %s failed", full_fname(dir)); + rsyserr(FERROR_XFER, errno, "change_dir %s failed", full_fname(dir)); if (dir != orig_dir) change_dir(orig_dir, CD_NORMAL); pathname = NULL; @@ -386,7 +389,11 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen) return 1; } -static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) +static void send_file_entry(int f, const char *fname, struct file_struct *file, +#ifdef SUPPORT_LINKS + const char *symlink_name, int symlink_len, +#endif + int ndx, int first_ndx) { static time_t modtime; static mode_t mode; @@ -399,7 +406,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, static gid_t gid; static const char *user_name, *group_name; static char lastname[MAXPATHLEN]; +#ifdef SUPPORT_HARD_LINKS int first_hlink_ndx = -1; +#endif int l1, l2; int xflags; @@ -472,6 +481,17 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, np->data = (void*)(long)(first_ndx + ndx + 1); xflags |= XMIT_HLINK_FIRST; } + if (DEBUG_GTE(HLINK, 1)) { + if (first_hlink_ndx >= 0) { + rprintf(FINFO, "[%s] #%d hard-links #%d (%sabbrev)\n", + who_am_i(), first_ndx + ndx, first_hlink_ndx, + first_hlink_ndx >= first_ndx ? "" : "un"); + } else if (DEBUG_GTE(HLINK, 3)) { + rprintf(FINFO, "[%s] dev:inode for #%d is %s:%s\n", + who_am_i(), first_ndx + ndx, + big_num(tmp_dev), big_num(tmp_ino)); + } + } } else { if (tmp_dev == dev) { if (protocol_version >= 28) @@ -518,11 +538,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, write_byte(f, l2); write_buf(f, fname + l1, l2); +#ifdef SUPPORT_HARD_LINKS if (first_hlink_ndx >= 0) { write_varint(f, first_hlink_ndx); if (first_hlink_ndx >= first_ndx) goto the_end; } +#endif write_varlong30(f, F_LENGTH(file), 3); if (!(xflags & XMIT_SAME_TIME)) { @@ -575,11 +597,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, } #ifdef SUPPORT_LINKS - if (preserve_links && S_ISLNK(mode)) { - const char *sl = F_SYMLINK(file); - int len = strlen(sl); - write_varint30(f, len); - write_buf(f, sl, len); + if (symlink_len) { + write_varint30(f, symlink_len); + write_buf(f, symlink_name, symlink_len); } #endif @@ -609,7 +629,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, write_buf(f, sum, checksum_len); } +#ifdef SUPPORT_HARD_LINKS the_end: +#endif strlcpy(lastname, fname, MAXPATHLEN); if (S_ISREG(mode) || S_ISLNK(mode)) @@ -638,7 +660,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, int alloc_len, basename_len, linkname_len; int extra_len = file_extra_cnt * EXTRA_LEN; int first_hlink_ndx = -1; - OFF_T file_length; + int64 file_length; const char *basename; struct file_struct *file; alloc_pool_t *pool; @@ -671,16 +693,16 @@ static struct file_struct *recv_file_entry(struct file_list *flist, xbuf outbuf, inbuf; INIT_CONST_XBUF(outbuf, thisname); - INIT_XBUF(inbuf, lastname, basename_len, -1); + INIT_XBUF(inbuf, lastname, basename_len, (size_t)-1); if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) { io_error |= IOERR_GENERAL; - rprintf(FINFO, + rprintf(FERROR_UTF8, "[%s] cannot convert filename: %s (%s)\n", who_am_i(), lastname, strerror(errno)); outbuf.len = 0; } - outbuf.buf[outbuf.len] = '\0'; + thisname[outbuf.len] = '\0'; } #endif @@ -713,6 +735,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist, first_hlink_ndx, flist->ndx_start + flist->used); exit_cleanup(RERR_PROTOCOL); } + if (DEBUG_GTE(HLINK, 1)) { + rprintf(FINFO, "[%s] #%d hard-links #%d (%sabbrev)\n", + who_am_i(), flist->used+flist->ndx_start, first_hlink_ndx, + first_hlink_ndx >= flist->ndx_start ? "" : "un"); + } if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; file_length = F_LENGTH(first); @@ -811,6 +838,13 @@ static struct file_struct *recv_file_entry(struct file_list *flist, linkname_len - 1); overflow_exit("recv_file_entry"); } +#ifdef ICONV_OPTION + /* We don't know how much extra room we need to convert + * the as-yet-unread symlink data, so let's hope that a + * double-size buffer is plenty. */ + if (sender_symlink_iconv) + linkname_len *= 2; +#endif if (munge_symlinks) linkname_len += SYMLINK_PREFIX_LEN; } @@ -837,8 +871,14 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if (always_checksum && S_ISREG(mode)) extra_len += SUM_EXTRA_CNT * EXTRA_LEN; +#if SIZEOF_INT64 >= 8 if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) extra_len += EXTRA_LEN; +#endif + if (file_length < 0) { + rprintf(FERROR, "Offset underflow: file-length is negative\n"); + exit_cleanup(RERR_UNSUPPORTED); + } if (inc_recurse && S_ISDIR(mode)) { if (one_file_system) { @@ -871,10 +911,17 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #endif file->modtime = (time_t)modtime; file->len32 = (uint32)file_length; +#if SIZEOF_INT64 >= 8 if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) { +#if SIZEOF_CAPITAL_OFF_T < 8 + rprintf(FERROR, "Offset overflow: attempted 64-bit file-length\n"); + exit_cleanup(RERR_UNSUPPORTED); +#else file->flags |= FLAG_LENGTH64; OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32); +#endif } +#endif file->mode = mode; if (preserve_uid) F_OWNER(file) = uid; @@ -932,14 +979,40 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; memcpy(bp, F_SYMLINK(first), linkname_len); - } else if (munge_symlinks) { - strlcpy(bp, SYMLINK_PREFIX, linkname_len); - bp += SYMLINK_PREFIX_LEN; - linkname_len -= SYMLINK_PREFIX_LEN; - read_sbuf(f, bp, linkname_len - 1); } else { - read_sbuf(f, bp, linkname_len - 1); - if (sanitize_paths) + if (munge_symlinks) { + strlcpy(bp, SYMLINK_PREFIX, linkname_len); + bp += SYMLINK_PREFIX_LEN; + linkname_len -= SYMLINK_PREFIX_LEN; + } +#ifdef ICONV_OPTION + if (sender_symlink_iconv) { + xbuf outbuf, inbuf; + + alloc_len = linkname_len; + linkname_len /= 2; + + /* Read the symlink data into the end of our double-sized + * buffer and then convert it into the right spot. */ + INIT_XBUF(inbuf, bp + alloc_len - linkname_len, + linkname_len - 1, (size_t)-1); + read_sbuf(f, inbuf.buf, inbuf.len); + INIT_XBUF(outbuf, bp, 0, alloc_len); + + if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) { + io_error |= IOERR_GENERAL; + rprintf(FERROR_XFER, + "[%s] cannot convert symlink data for: %s (%s)\n", + who_am_i(), full_fname(thisname), strerror(errno)); + bp = (char*)file->basename; + *bp++ = '\0'; + outbuf.len = 0; + } + bp[outbuf.len] = '\0'; + } else +#endif + read_sbuf(f, bp, linkname_len - 1); + if (sanitize_paths && !munge_symlinks && *bp) sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT); } } @@ -1009,7 +1082,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist, * and performing extensive checks against global options. * * Returns a pointer to the new file struct, or NULL if there was an error - * or this file should be excluded. */ + * or this file should be excluded. + * + * Note: Any error (here or in send_file_name) that results in the omission of + * an existent source file from the file list should set + * "io_error |= IOERR_GENERAL" to avoid deletion of the file from the + * destination if --delete is on. */ struct file_struct *make_file(const char *fname, struct file_list *flist, STRUCT_STAT *stp, int flags, int filter_level) { @@ -1026,7 +1104,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, char *bp; if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) { - rprintf(FINFO, "skipping overly long name: %s\n", fname); + io_error |= IOERR_GENERAL; + rprintf(FERROR_XFER, "skipping overly long name: %s\n", fname); return NULL; } clean_fname(thisname, 0); @@ -1071,7 +1150,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } } else { io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, save_errno, "readlink %s failed", + rsyserr(FERROR_XFER, save_errno, "readlink_stat(%s) failed", full_fname(thisname)); } return NULL; @@ -1091,7 +1170,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (one_file_system && st.st_dev != filesystem_dev && BITS_SETnUNSET(flags, FLAG_CONTENT_DIR, FLAG_TOP_DIR)) { if (one_file_system > 1) { - if (verbose > 1) { + if (INFO_GTE(MOUNT, 1)) { rprintf(FINFO, "[%s] skipping mount-point dir %s\n", who_am_i(), thisname); @@ -1140,7 +1219,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, pool = NULL; } - if (verbose > 2) { + if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] make_file(%s,*,%d)\n", who_am_i(), thisname, filter_level); } @@ -1163,8 +1242,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, linkname_len = 0; #endif +#if SIZEOF_CAPITAL_OFF_T >= 8 if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) extra_len += EXTRA_LEN; +#endif + + if (always_checksum && am_sender && S_ISREG(st.st_mode)) { + file_checksum(thisname, tmp_sum, st.st_size); + if (sender_keeps_checksum) + extra_len += SUM_EXTRA_CNT * EXTRA_LEN; + } #if EXTRA_ROUNDING > 0 if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) @@ -1192,8 +1279,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (protocol_version >= 28 ? (!S_ISDIR(st.st_mode) && st.st_nlink > 1) : S_ISREG(st.st_mode)) { - tmp_dev = st.st_dev; - tmp_ino = st.st_ino; + tmp_dev = (int64)st.st_dev + 1; + tmp_ino = (int64)st.st_ino; } else tmp_dev = 0; } @@ -1209,10 +1296,12 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, file->flags = flags; file->modtime = st.st_mtime; 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); } +#endif file->mode = st.st_mode; if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */ F_OWNER(file) = st.st_uid; @@ -1227,9 +1316,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, memcpy(bp + basename_len, linkname, linkname_len); #endif - if (always_checksum && am_sender && S_ISREG(st.st_mode)) - file_checksum(thisname, tmp_sum, st.st_size); - if (am_sender) F_PATHNAME(file) = pathname; else if (!pool) @@ -1260,6 +1346,9 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, return NULL; } + if (sender_keeps_checksum && S_ISREG(st.st_mode)) + memcpy(F_SUM(file), tmp_sum, checksum_len); + if (unsort_ndx) F_NDX(file) = dir_count; @@ -1287,10 +1376,27 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (f >= 0) { char fbuf[MAXPATHLEN]; +#ifdef SUPPORT_LINKS + const char *symlink_name; + int symlink_len; +#ifdef ICONV_OPTION + char symlink_buf[MAXPATHLEN]; +#endif +#endif #if defined SUPPORT_ACLS || defined SUPPORT_XATTRS stat_x sx; #endif +#ifdef SUPPORT_LINKS + if (preserve_links && S_ISLNK(file->mode)) { + symlink_name = F_SYMLINK(file); + symlink_len = strlen(symlink_name); + } else { + symlink_name = NULL; + symlink_len = 0; + } +#endif + #ifdef ICONV_OPTION if (ic_send != (iconv_t)-1) { xbuf outbuf, inbuf; @@ -1303,19 +1409,38 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) goto convert_error; outbuf.size += 2; - outbuf.buf[outbuf.len++] = '/'; + fbuf[outbuf.len++] = '/'; } INIT_XBUF_STRLEN(inbuf, (char*)file->basename); if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { convert_error: io_error |= IOERR_GENERAL; - rprintf(FINFO, + rprintf(FERROR_XFER, "[%s] cannot convert filename: %s (%s)\n", who_am_i(), f_name(file, fbuf), strerror(errno)); return NULL; } - outbuf.buf[outbuf.len] = '\0'; + fbuf[outbuf.len] = '\0'; + +#ifdef SUPPORT_LINKS + 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) { + io_error |= IOERR_GENERAL; + f_name(file, fbuf); + rprintf(FERROR_XFER, + "[%s] cannot convert symlink data for: %s (%s)\n", + who_am_i(), full_fname(fbuf), strerror(errno)); + return NULL; + } + symlink_buf[outbuf.len] = '\0'; + + symlink_name = symlink_buf; + symlink_len = outbuf.len; + } +#endif } else #endif f_name(file, fbuf); @@ -1324,19 +1449,27 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (preserve_acls && !S_ISLNK(file->mode)) { sx.st.st_mode = file->mode; sx.acc_acl = sx.def_acl = NULL; - if (get_acl(fname, &sx) < 0) + if (get_acl(fname, &sx) < 0) { + io_error |= IOERR_GENERAL; return NULL; + } } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { sx.xattr = NULL; - if (get_xattr(fname, &sx) < 0) + if (get_xattr(fname, &sx) < 0) { + io_error |= IOERR_GENERAL; return NULL; + } } #endif - send_file_entry(f, fbuf, file, flist->used, flist->ndx_start); + send_file_entry(f, fbuf, file, +#ifdef SUPPORT_LINKS + symlink_name, symlink_len, +#endif + flist->used, flist->ndx_start); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { @@ -1531,14 +1664,14 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, continue; if (strlcpy(p, dname, remainder) >= remainder) { io_error |= IOERR_GENERAL; - rprintf(FINFO, + rprintf(FERROR_XFER, "cannot send long-named file %s\n", full_fname(fbuf)); continue; } if (dname[0] == '\0') { io_error |= IOERR_GENERAL; - rprintf(FINFO, + rprintf(FERROR_XFER, "cannot send file with empty name in %s\n", full_fname(fbuf)); continue; @@ -1784,7 +1917,12 @@ void send_extra_file_list(int f, int at_least) dp = F_DIR_NODE_P(file); } - write_byte(f, 0); + if (protocol_version < 31 || io_error == save_io_error || ignore_errors) + write_byte(f, 0); + else { + write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); + write_int(f, io_error); + } if (need_unsorted_flist) { if (!(flist->sorted = new_array(struct file_struct *, flist->used))) @@ -1802,7 +1940,7 @@ void send_extra_file_list(int f, int at_least) file_total += flist->used; stats.flist_size += stats.total_written - start_write; stats.num_files += flist->used; - if (verbose > 3) + if (DEBUG_GTE(FLIST, 3)) output_flist(flist); if (DIR_FIRST_CHILD(dp) >= 0) { @@ -1825,7 +1963,7 @@ void send_extra_file_list(int f, int at_least) } finish: - if (io_error != save_io_error && !ignore_errors) + if (io_error != save_io_error && protocol_version == 30 && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); } @@ -1853,7 +1991,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) rprintf(FLOG, "building file list\n"); if (show_filelist_p()) start_filelist_progress("building file list"); - else if (inc_recurse && verbose && !am_server) + else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server) rprintf(FCLIENT, "sending incremental file list\n"); start_write = stats.total_written; @@ -2081,7 +2219,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) stats.flist_buildtime = 1; start_tv = end_tv; - write_byte(f, 0); /* Indicate end of file list */ + /* Indicate end of file list */ + if (protocol_version < 31 || io_error == 0 || ignore_errors) + write_byte(f, 0); + else { + write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); + write_int(f, io_error); + } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version >= 30 && !inc_recurse) @@ -2119,7 +2263,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) /* send the io_error flag */ if (protocol_version < 30) write_int(f, ignore_errors ? 0 : io_error); - else if (io_error && !ignore_errors) + else if (io_error && protocol_version == 30 && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); if (disable_buffering) @@ -2128,16 +2272,16 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) stats.flist_size = stats.total_written - start_write; stats.num_files = flist->used; - if (verbose > 3) + if (DEBUG_GTE(FLIST, 3)) output_flist(flist); - if (verbose > 2) + if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "send_file_list done\n"); if (inc_recurse) { send_dir_depth = 1; add_dirs_to_tree(-1, flist, dir_count); - if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0) + if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0) flist->parent_ndx = -1; flist_done_allocating(flist); if (send_dir_ndx < 0) { @@ -2161,12 +2305,13 @@ struct file_list *recv_file_list(int f) int dstart, flags; int64 start_read; - if (!first_flist) + if (!first_flist) { + if (show_filelist_p()) + start_filelist_progress("receiving file list"); + else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server) + rprintf(FCLIENT, "receiving incremental file list\n"); rprintf(FLOG, "receiving file list\n"); - if (show_filelist_p()) - start_filelist_progress("receiving file list"); - else if (inc_recurse && verbose && !am_server && !first_flist) - rprintf(FCLIENT, "receiving incremental file list\n"); + } start_read = stats.total_read; @@ -2189,10 +2334,22 @@ struct file_list *recv_file_list(int f) while ((flags = read_byte(f)) != 0) { struct file_struct *file; - flist_expand(flist, 1); - if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS)) flags |= read_byte(f) << 8; + + if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) { + int err; + if (protocol_version < 31) { + rprintf(FERROR, "Invalid flist flag: %x\n", flags); + exit_cleanup(RERR_PROTOCOL); + } + err = read_int(f); + if (!ignore_errors) + io_error |= err; + break; + } + + flist_expand(flist, 1); file = recv_file_entry(flist, flags, f); if (inc_recurse && S_ISDIR(file->mode)) { @@ -2204,14 +2361,14 @@ struct file_list *recv_file_list(int f) maybe_emit_filelist_progress(flist->used); - if (verbose > 2) { - rprintf(FINFO, "recv_file_name(%s)\n", - f_name(file, NULL)); + if (DEBUG_GTE(FLIST, 2)) { + char *name = f_name(file, NULL); + rprintf(FINFO, "recv_file_name(%s)\n", NS(name)); } } file_total += flist->used; - if (verbose > 2) + if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "received %d names\n", flist->used); if (show_filelist_p()) @@ -2256,19 +2413,18 @@ struct file_list *recv_file_list(int f) if (protocol_version < 30) { /* Recv the io_error flag */ - if (ignore_errors) - read_int(f); - else - io_error |= read_int(f); + int err = read_int(f); + if (!ignore_errors) + io_error |= err; } else if (inc_recurse && flist->ndx_start == 1) { - if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0) + if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0) flist->parent_ndx = -1; } - if (verbose > 3) + if (DEBUG_GTE(FLIST, 3)) output_flist(flist); - if (verbose > 2) + if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "recv_file_list done\n"); stats.flist_size += stats.total_read - start_read; @@ -2296,7 +2452,7 @@ void recv_additional_file_list(int f) NDX_FLIST_OFFSET - dir_flist->used + 1); exit_cleanup(RERR_PROTOCOL); } - if (verbose > 3) { + if (DEBUG_GTE(FLIST, 3)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } @@ -2381,14 +2537,16 @@ struct file_list *flist_new(int flags, char *msg) if (flags & FLIST_TEMP) { if (!(flist->file_pool = pool_create(SMALL_EXTENT, 0, - out_of_memory, POOL_INTERN))) + out_of_memory, + POOL_INTERN))) out_of_memory(msg); } else { /* This is a doubly linked list with prev looping back to * the end of the list, but the last next pointer is NULL. */ if (!first_flist) { flist->file_pool = pool_create(NORMAL_EXTENT, 0, - out_of_memory, POOL_INTERN); + out_of_memory, + POOL_INTERN); if (!flist->file_pool) out_of_memory(msg); @@ -2518,7 +2676,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root) keep = j, drop = i; if (!am_sender) { - if (verbose > 1) { + if (DEBUG_GTE(DUP, 1)) { rprintf(FINFO, "removing duplicate name %s from file list (%d)\n", f_name(file, fbuf), drop + flist->ndx_start); @@ -2659,10 +2817,10 @@ static void output_flist(struct file_list *flist) } else root = dir = slash = name = trail = ""; rprintf(FINFO, - "[%s] i=%d %s %s%s%s%s mode=0%o len=%.0f%s%s flags=%x\n", + "[%s] i=%d %s %s%s%s%s mode=0%o len=%s%s%s flags=%x\n", who, i + flist->ndx_start, root, dir, slash, name, trail, - (int)file->mode, (double)F_LENGTH(file), + (int)file->mode, comma_num(F_LENGTH(file)), uidbuf, gidbuf, file->flags); } } @@ -2876,7 +3034,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules) send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, 0); xfer_dirs = save_xfer_dirs; recurse = save_recurse; - if (do_progress) + if (INFO_GTE(PROGRESS, 1)) flist_count_offset += dirlist->used; prune_empty_dirs = 0; @@ -2884,7 +3042,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules) flist_sort_and_clean(dirlist, 0); prune_empty_dirs = save_prune_empty_dirs; - if (verbose > 3) + if (DEBUG_GTE(FLIST, 3)) output_flist(dirlist); return dirlist;