X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/d1f66d8d796965d90552db75d63bdbbf0b98c3f9..b791d6802bad5c9403a6bb8aab8536c36ef90213:/flist.c diff --git a/flist.c b/flist.c index bbba3eeb..7c21f73e 100644 --- a/flist.c +++ b/flist.c @@ -25,14 +25,12 @@ #include "rounding.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 +65,8 @@ extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; extern int need_unsorted_flist; +extern int output_needs_newline; +extern int sender_keeps_checksum; extern int unsort_ndx; extern struct stats stats; extern char *filesfrom_host; @@ -129,7 +129,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 +140,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 +157,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 +197,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 +317,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, 0), (new_ptr == flist->files) ? " not" : ""); } @@ -399,7 +400,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 +475,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, 0), big_num(tmp_ino, 0)); + } + } } else { if (tmp_dev == dev) { if (protocol_version >= 28) @@ -518,11 +532,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)) { @@ -609,7 +625,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 +656,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; @@ -713,6 +731,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); @@ -837,8 +860,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 +900,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; @@ -1009,7 +1045,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) { @@ -1023,10 +1064,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, const char *basename; alloc_pool_t *pool; STRUCT_STAT st; - int excl_ret; char *bp; if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) { + io_error |= IOERR_GENERAL; rprintf(FINFO, "skipping overly long name: %s\n", fname); return NULL; } @@ -1078,7 +1119,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, return NULL; } - /* backup.c calls us with filter_level set to NO_FILTERS. */ if (filter_level == NO_FILTERS) goto skip_filters; @@ -1093,7 +1133,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); @@ -1106,17 +1146,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } else flags &= ~FLAG_CONTENT_DIR; - if (S_ISDIR(st.st_mode)) { - if (flags & FLAG_DOTDIR_NAME) { - /* A "." fname (or "/." fname in relative mode) is - * never excluded. No other trailing-dotdir names - * are possible. */ - excl_ret = 0; - } else - excl_ret = is_excluded(thisname, 1, filter_level); - } else - excl_ret = is_excluded(thisname, 0, filter_level); - if (excl_ret) { + if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) { if (ignore_perishable) non_perishable_cnt++; return NULL; @@ -1152,7 +1182,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); } @@ -1175,8 +1205,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)) @@ -1221,10 +1259,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; @@ -1239,9 +1279,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) @@ -1272,6 +1309,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; @@ -1336,15 +1376,19 @@ 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 @@ -1814,7 +1858,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) { @@ -1853,7 +1897,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) int64 start_write; int use_ff_fd = 0; int disable_buffering; - int arg_flags, flags = recurse ? FLAG_CONTENT_DIR : 0; + int flags = recurse ? FLAG_CONTENT_DIR : 0; int reading_remotely = filesfrom_host != NULL; int rl_flags = (reading_remotely ? 0 : RL_DUMP_COMMENTS) #ifdef ICONV_OPTION @@ -1865,7 +1909,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; @@ -2035,14 +2079,18 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) continue; } + /* A dot-dir should not be excluded! */ + if (name_type != DOTDIR_NAME + && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, ALL_FILTERS)) + continue; + if (S_ISDIR(st.st_mode) && !xfer_dirs) { rprintf(FINFO, "skipping directory %s\n", fbuf); continue; } if (inc_recurse && relative_paths && *fbuf) { - if ((p = strchr(fbuf+1, '/')) != NULL - && !is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, ALL_FILTERS)) { + if ((p = strchr(fbuf+1, '/')) != NULL) { if (p - fbuf == 1 && *fbuf == '.') { if ((fn = strchr(p+1, '/')) != NULL) p = fn; @@ -2052,8 +2100,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (fn == p) continue; } - } else if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf - && !is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, ALL_FILTERS)) { + } else if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf) { /* Send the implied directories at the start of the * source spec, so we get their permissions right. */ send_implied_dirs(f, flist, fbuf, fbuf, p, flags, 0); @@ -2062,13 +2109,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (one_file_system) filesystem_dev = st.st_dev; - arg_flags = name_type == DOTDIR_NAME ? FLAG_DOTDIR_NAME : 0; - if (recurse || (xfer_dirs && name_type != NORMAL_NAME)) { struct file_struct *file; - arg_flags |= FLAG_TOP_DIR | FLAG_CONTENT_DIR; file = send_file_name(f, flist, fbuf, &st, - arg_flags | flags, ALL_FILTERS); + FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags, + NO_FILTERS); if (!file) continue; if (inc_recurse) { @@ -2082,7 +2127,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) } else send_if_directory(f, flist, file, fbuf, len, flags); } else - send_file_name(f, flist, fbuf, &st, arg_flags | flags, ALL_FILTERS); + send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS); } gettimeofday(&end_tv, NULL); @@ -2139,16 +2184,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[0]->basename, ".") != 0) flist->parent_ndx = -1; flist_done_allocating(flist); if (send_dir_ndx < 0) { @@ -2172,12 +2217,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; @@ -2215,14 +2261,14 @@ struct file_list *recv_file_list(int f) maybe_emit_filelist_progress(flist->used); - if (verbose > 2) { + if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "recv_file_name(%s)\n", f_name(file, NULL)); } } file_total += flist->used; - if (verbose > 2) + if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "received %d names\n", flist->used); if (show_filelist_p()) @@ -2272,14 +2318,14 @@ struct file_list *recv_file_list(int f) else io_error |= read_int(f); } else if (inc_recurse && flist->ndx_start == 1) { - if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0) + if (!file_total || strcmp(flist->sorted[0]->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; @@ -2307,7 +2353,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); } @@ -2392,14 +2438,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); @@ -2529,7 +2577,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); @@ -2670,10 +2718,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, big_num(F_LENGTH(file), 0), uidbuf, gidbuf, file->flags); } } @@ -2887,7 +2935,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; @@ -2895,7 +2943,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;