Split code out into separate files and remove some global variables to
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 341dcf4..3d0ff53 100644 (file)
--- 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);