X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/ebed4c3af07f87648db56fa864aade583144e772..b35d0d8e9ae9c5407c9f781b545f8a66b9caa9d0:/flist.c diff --git a/flist.c b/flist.c index 341dcf40..3d0ff535 100644 --- a/flist.c +++ b/flist.c @@ -34,6 +34,7 @@ extern struct stats stats; extern int verbose; +extern int do_progress; extern int am_server; extern int always_checksum; @@ -69,31 +70,49 @@ static struct file_struct null_file; static void clean_flist(struct file_list *flist, int strip_root); -static int show_build_progress_p(void) +static int show_filelist_p(void) { - extern int do_progress; + return verbose && recurse && !am_server; +} - return do_progress && verbose && recurse && !am_server; +static void start_filelist_progress(char *kind) +{ + rprintf(FINFO, "%s ... ", kind); + if ((verbose > 1) || do_progress) + rprintf(FINFO, "\n"); + rflush(FINFO); } -/** - * True if we're local, etc, and should emit progress emssages. - **/ -static void emit_build_progress(const struct file_list *flist) + +static void emit_filelist_progress(const struct file_list *flist) { rprintf(FINFO, " %d files...\r", flist->count); } -static void finish_build_progress(const struct file_list *flist) +static void maybe_emit_filelist_progress(const struct file_list *flist) +{ + if (do_progress && show_filelist_p() && ((flist->count % 100) == 0)) + emit_filelist_progress(flist); +} + + +static void finish_filelist_progress(const struct file_list *flist) { - if (verbose && recurse && !am_server) { - /* This overwrites the progress line, if any. */ - rprintf(FINFO, RSYNC_NAME ": %d files to consider.\n", - flist->count); + if (do_progress) { + /* This overwrites the progress line */ + rprintf(FINFO, "%d file%sto consider\n", + flist->count, flist->count == 1 ? " " : "s "); + } else { + rprintf(FINFO, "done\n"); } } +void show_flist_stats(void) +{ + /* Nothing yet */ +} + static struct string_area *string_area_new(int size) { @@ -173,6 +192,13 @@ static void list_file_entry(struct file_struct *f) } +/** + * Stat either a symlink or its referent, depending on the settings of + * copy_links, copy_unsafe_links, etc. + * + * @return -1 on error; or 0. If a symlink, then @p Linkbuf (of size + * MAXPATHLEN) contains the symlink target. + **/ int readlink_stat(const char *Path, STRUCT_STAT * Buffer, char *Linkbuf) { #if SUPPORT_LINKS @@ -266,13 +292,49 @@ static void send_directory(int f, struct file_list *flist, char *dir); static char *flist_dir; +/** + * Make sure @p flist is big enough to hold at least @p flist->count + * entries. + **/ +static void flist_expand(struct file_list *flist) +{ + if (flist->count >= flist->malloced) { + size_t new_bytes; + void *new_ptr; + + if (flist->malloced < 1000) + flist->malloced += 1000; + else + flist->malloced *= 2; + + new_bytes = sizeof(flist->files[0]) * flist->malloced; + + if (flist->files) + new_ptr = realloc(flist->files, new_bytes); + else + new_ptr = malloc(new_bytes); + + if (verbose >= 2) { + rprintf(FINFO, "expand file_list to %.0f bytes, did%s move\n", + (double) new_bytes, + (new_ptr == flist->files) ? " not" : ""); + } + + flist->files = (struct file_struct **) new_ptr; + + if (!flist->files) + out_of_memory("flist_expand"); + } +} + + static void send_file_entry(struct file_struct *file, int f, unsigned base_flags) { unsigned char flags; static time_t last_time; static mode_t last_mode; - static dev_t last_rdev; + static DEV64_T last_rdev; static uid_t last_uid; static gid_t last_gid; static char lastname[MAXPATHLEN]; @@ -391,7 +453,7 @@ static void receive_file_entry(struct file_struct **fptr, { static time_t last_time; static mode_t last_mode; - static dev_t last_rdev; + static DEV64_T last_rdev; static uid_t last_uid; static gid_t last_gid; static char lastname[MAXPATHLEN]; @@ -551,7 +613,21 @@ static int skip_filesystem(char *fname, STRUCT_STAT * st) /* IRIX cc cares that the operands to the ternary have the same type. */ #define MALLOC(ap, i) (ap ? (void*) string_area_malloc(ap, i) : malloc(i)) -/* create a file_struct for a named file */ +/** + * Create a file_struct for a named file by reading its stat() + * information and performing extensive checks against global + * options. + * + * @return the new file, or NULL if there was an error or this file + * should be excluded. + * + * @todo There is a small optimization opportunity here to avoid + * stat()ing the file in some circumstances, which has a certain cost. + * We are called immediately after doing readdir(), and so we may + * already know the d_type of the file. We could for example avoid + * statting directories if we're not recursing, but this is not a very + * important case. Some systems may not have d_type. + **/ struct file_struct *make_file(int f, char *fname, struct string_area **ap, int noexcludes) { @@ -643,7 +719,7 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap, file->gid = st.st_gid; file->dev = st.st_dev; file->inode = st.st_ino; -#ifdef HAVE_ST_RDEV +#ifdef HAVE_STRUCT_STAT_ST_RDEV file->rdev = st.st_rdev; #endif @@ -697,22 +773,9 @@ void send_file_name(int f, struct file_list *flist, char *fname, if (!file) return; - if (show_build_progress_p() & !(flist->count % 100)) - emit_build_progress(flist); + maybe_emit_filelist_progress(flist); - if (flist->count >= flist->malloced) { - if (flist->malloced < 1000) - flist->malloced += 1000; - else - flist->malloced *= 2; - flist->files = - (struct file_struct **) realloc(flist->files, - sizeof(flist-> - files[0]) * - flist->malloced); - if (!flist->files) - out_of_memory("send_file_name"); - } + flist_expand(flist); if (write_batch) /* dw */ file->flags = FLAG_DELETE; @@ -809,12 +872,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) struct file_list *flist; int64 start_write; - if (verbose && recurse && !am_server && f != -1) { - rprintf(FINFO, RSYNC_NAME ": building file list...\n"); - if (verbose > 1) - rprintf(FINFO, "\n"); - rflush(FINFO); - } + if (show_filelist_p() && f != -1) + start_filelist_progress("building file list"); start_write = stats.total_written; @@ -936,7 +995,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) send_file_entry(NULL, f, 0); } - finish_build_progress(flist); + if (show_filelist_p() && f != -1) { + finish_filelist_progress(flist); + } clean_flist(flist, 0); @@ -953,7 +1014,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) } if (f != -1) { - io_end_buffering(f); + io_end_buffering(); stats.flist_size = stats.total_written - start_write; stats.num_files = flist->count; if (write_batch) /* dw */ @@ -974,10 +1035,8 @@ struct file_list *recv_file_list(int f) int64 start_read; extern int list_only; - if (verbose && recurse && !am_server) { - rprintf(FINFO, "receiving file list ... "); - rflush(FINFO); - } + if (show_filelist_p()) + start_filelist_progress("receiving file list"); start_read = stats.total_read; @@ -996,22 +1055,8 @@ struct file_list *recv_file_list(int f) for (flags = read_byte(f); flags; flags = read_byte(f)) { int i = flist->count; - - if (i >= flist->malloced) { - if (flist->malloced < 1000) - flist->malloced += 1000; - else - flist->malloced *= 2; - flist->files = - (struct file_struct **) realloc(flist->files, - sizeof(flist-> - files - [0]) * - flist-> - malloced); - if (!flist->files) - goto oom; - } + + flist_expand(flist); receive_file_entry(&flist->files[i], flags, f); @@ -1020,6 +1065,8 @@ struct file_list *recv_file_list(int f) flist->count++; + maybe_emit_filelist_progress(flist); + if (verbose > 2) rprintf(FINFO, "recv_file_name(%s)\n", f_name(flist->files[i])); @@ -1031,8 +1078,8 @@ struct file_list *recv_file_list(int f) clean_flist(flist, relative_paths); - if (verbose && recurse && !am_server) { - rprintf(FINFO, "done\n"); + if (show_filelist_p()) { + finish_filelist_progress(flist); } /* now recv the uid/gid list. This was introduced in protocol version 15 */ @@ -1146,12 +1193,9 @@ struct file_list *flist_new() out_of_memory("send_file_list"); flist->count = 0; - flist->malloced = 1000; - flist->files = - (struct file_struct **) malloc(sizeof(flist->files[0]) * - flist->malloced); - if (!flist->files) - out_of_memory("send_file_list"); + flist->malloced = 0; + flist->files = NULL; + #if ARENA_SIZE > 0 flist->string_area = string_area_new(0); #else @@ -1171,6 +1215,10 @@ void flist_free(struct file_list *flist) free_file(flist->files[i]); free(flist->files[i]); } + /* FIXME: I don't think we generally need to blank the flist + * since it's about to be freed. This will just cause more + * memory traffic. If you want a freed-memory debugger, you + * know where to get it. */ memset((char *) flist->files, 0, sizeof(flist->files[0]) * flist->count); free(flist->files);