The "ndx" variable now holds the unique, over-the-wire value, not
[rsync/rsync.git] / generator.c
index e1a85cb..8c9577b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ extern int logfile_format_has_i;
 extern int am_root;
 extern int am_server;
 extern int am_daemon;
-extern int incremental;
+extern int inc_recurse;
 extern int do_progress;
 extern int relative_paths;
 extern int implied_dirs;
@@ -49,7 +49,7 @@ extern int delete_mode;
 extern int delete_before;
 extern int delete_during;
 extern int delete_after;
-extern int done_cnt;
+extern int msgdone_cnt;
 extern int ignore_errors;
 extern int remove_source_files;
 extern int delay_updates;
@@ -105,7 +105,10 @@ static int deletion_count = 0; /* used to implement --max-delete */
 static int deldelay_size = 0, deldelay_cnt = 0;
 static char *deldelay_buf = NULL;
 static int deldelay_fd = -1;
-static BOOL solo_file = 0;
+static int lull_mod;
+static int dir_tweaking;
+static int need_retouch_dir_times;
+static const char *solo_file = NULL;
 
 /* For calling delete_item() and delete_dir_contents(). */
 #define DEL_RECURSE            (1<<1) /* recurse */
@@ -282,10 +285,10 @@ static int start_delete_delay_temp(void)
        dry_run = 0;
        if (!get_tmpname(fnametmp, "deldelay")
         || (deldelay_fd = do_mkstemp(fnametmp, 0600)) < 0) {
-               rprintf(FINFO, "NOTE: Unable to create delete-delay temp file--"
-                       "switching to --delete-after.\n");
+               rprintf(FINFO, "NOTE: Unable to create delete-delay temp file%s.\n",
+                       inc_recurse ? "" : " -- switching to --delete-after");
                delete_during = 0;
-               delete_after = 1;
+               delete_after = !inc_recurse;
                dry_run = save_dry_run;
                return 0;
        }
@@ -554,7 +557,7 @@ void itemize(struct file_struct *file, int ndx, int statret,
          || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) {
                if (protocol_version >= 29) {
                        if (ndx >= 0)
-                               write_ndx(sock_f_out, ndx + cur_flist->ndx_start);
+                               write_ndx(sock_f_out, ndx);
                        write_shortint(sock_f_out, iflags);
                        if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
                                write_byte(sock_f_out, fnamecmp_type);
@@ -777,24 +780,6 @@ static int find_fuzzy(struct file_struct *file, struct file_list *dirlist)
        return lowest_j;
 }
 
-#ifdef SUPPORT_HARD_LINKS
-void check_for_finished_hlinks(int itemizing, enum logcode code)
-{
-       struct file_struct *file;
-       struct file_list *flist;
-       char fbuf[MAXPATHLEN];
-       int ndx;
-
-       while ((ndx = get_hlink_num()) != -1) {
-               flist = flist_for_ndx(ndx);
-               assert(flist != NULL);
-               file = flist->files[ndx];
-               assert(file->flags & FLAG_HLINKED);
-               finish_hard_link(file, f_name(file, fbuf), NULL, itemizing, code, -1);
-       }
-}
-#endif
-
 /* This is only called for regular files.  We return -2 if we've finished
  * handling the file, -1 if no dest-linking occurred, or a non-negative
  * value if we found an alternate basis file. */
@@ -1040,11 +1025,11 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
 
 static int phase = 0;
 
-/* Acts on cur_flist->file's ndx'th item, whose name is fname.  If a dir,
+/* Acts on the indicated item in cur_flist whose name is fname.  If a dir,
  * make sure it exists, and has the right permissions/timestamp info.  For
  * all other non-regular files (symlinks, etc.) we create them here.  For
  * regular files that have changed, we try to find a basis file and then
- * start sending checksums.
+ * start sending checksums.  The ndx is the file's unique index value.
  *
  * When fname is non-null, it must point to a MAXPATHLEN buffer!
  *
@@ -1221,7 +1206,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        rprintf(code, "%s/\n", fname);
                if (real_ret != 0 && one_file_system)
                        real_st.st_dev = filesystem_dev;
-               if (incremental) {
+               if (inc_recurse) {
                        if (one_file_system) {
                                uint32 *devp = F_DIRDEV_P(file);
                                DEV_MAJOR(devp) = major(real_st.st_dev);
@@ -1524,7 +1509,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        return;
          return_with_success:
                if (!dry_run)
-                       send_msg_int(MSG_SUCCESS, ndx + cur_flist->ndx_start);
+                       send_msg_int(MSG_SUCCESS, ndx);
                return;
        }
 
@@ -1599,13 +1584,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
   notify_others:
        if (remove_source_files && !delay_updates && !phase)
                increment_active_files(ndx, itemizing, code);
-       if (incremental && !dry_run)
+       if (inc_recurse && !dry_run)
                cur_flist->in_progress++;
 #ifdef SUPPORT_HARD_LINKS
        if (preserve_hard_links && F_IS_HLINKED(file))
                file->flags |= FLAG_FILE_SENT;
 #endif
-       write_ndx(f_out, ndx + cur_flist->ndx_start);
+       write_ndx(f_out, ndx);
        if (itemizing) {
                int iflags = ITEM_TRANSFER;
                if (always_checksum > 0)
@@ -1648,18 +1633,121 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        close(fd);
 }
 
-void generate_files(int f_out, char *local_name)
+static void touch_up_dirs(struct file_list *flist, int ndx)
+{
+       struct file_struct *file;
+       char *fname;
+       int i, j, start, end;
+
+       if (ndx < 0) {
+               start = 0;
+               end = flist->count - 1;
+       } else
+               start = end = ndx;
+
+       /* Fix any directory permissions that were modified during the
+        * transfer and/or re-set any tweaked modified-time values. */
+       for (i = start, j = 0; i <= end; i++) {
+               file = flist->files[i];
+               if (!F_IS_ACTIVE(file) || !S_ISDIR(file->mode)
+                || file->flags & FLAG_MISSING_DIR)
+                       continue;
+               if (!need_retouch_dir_times && file->mode & S_IWUSR)
+                       continue;
+               fname = f_name(file, NULL);
+               if (!(file->mode & S_IWUSR))
+                       do_chmod(fname, file->mode);
+               if (need_retouch_dir_times)
+                       set_modtime(fname, file->modtime, file->mode);
+               if (allowed_lull && !(++j % lull_mod))
+                       maybe_send_keepalive();
+               else if (!(j % 200))
+                       maybe_flush_socket();
+       }
+}
+
+void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
+{
+       struct file_struct *file;
+       struct file_list *flist;
+       char fbuf[MAXPATHLEN];
+       int ndx;
+
+#ifdef SUPPORT_HARD_LINKS
+       while (preserve_hard_links && (ndx = get_hlink_num()) != -1) {
+               flist = flist_for_ndx(ndx);
+               assert(flist != NULL);
+               file = flist->files[ndx];
+               assert(file->flags & FLAG_HLINKED);
+               finish_hard_link(file, f_name(file, fbuf), NULL, itemizing, code, -1);
+       }
+#endif
+
+       while (check_redo && (ndx = get_redo_num()) != -1) {
+               csum_length = SUM_LENGTH;
+               max_size = -max_size;
+               min_size = -min_size;
+               ignore_existing = -ignore_existing;
+               ignore_non_existing = -ignore_non_existing;
+               update_only = -update_only;
+               always_checksum = -always_checksum;
+               size_only = -size_only;
+               append_mode = -append_mode;
+               make_backups = -make_backups; /* avoid dup backup w/inplace */
+               ignore_times++;
+
+               flist = cur_flist;
+               cur_flist = flist_for_ndx(ndx);
+
+               file = cur_flist->files[ndx - cur_flist->ndx_start];
+               if (solo_file)
+                       strlcpy(fbuf, solo_file, sizeof fbuf);
+               else
+                       f_name(file, fbuf);
+               recv_generator(fbuf, file, ndx, itemizing, code, sock_f_out);
+               cur_flist->to_redo--;
+
+               cur_flist = flist;
+
+               csum_length = SHORT_SUM_LENGTH;
+               max_size = -max_size;
+               min_size = -min_size;
+               ignore_existing = -ignore_existing;
+               ignore_non_existing = -ignore_non_existing;
+               update_only = -update_only;
+               always_checksum = -always_checksum;
+               size_only = -size_only;
+               append_mode = -append_mode;
+               make_backups = -make_backups;
+               ignore_times--;
+       }
+
+       while (cur_flist != first_flist) { /* only possible with inc_recurse */
+               if (first_flist->in_progress || first_flist->to_redo)
+                       break;
+
+               if (!read_batch)
+                       write_ndx(sock_f_out, NDX_DONE);
+
+               if (delete_during == 2 || !dir_tweaking) {
+                       /* Skip directory touch-up. */
+               } else if (first_flist->ndx_start != 0)
+                       touch_up_dirs(dir_flist, first_flist->parent_ndx);
+               else if (relative_paths && implied_dirs)
+                       touch_up_dirs(first_flist, -1);
+
+               flist_free(first_flist); /* updates first_flist */
+       }
+}
+
+void generate_files(int f_out, const char *local_name)
 {
        int i;
        char fbuf[MAXPATHLEN];
        int itemizing;
        enum logcode code;
-       struct file_list *next_flist;
-       int lull_mod = allowed_lull * 5;
-       int need_retouch_dir_times = preserve_times && !omit_dir_times;
        int need_retouch_dir_perms = 0;
        int save_do_progress = do_progress;
-       int dir_tweaking = !(list_only || local_name || dry_run);
 
        if (protocol_version >= 29) {
                itemizing = 1;
@@ -1678,12 +1766,15 @@ void generate_files(int f_out, char *local_name)
                maybe_ATTRS_REPORT = ATTRS_REPORT;
                code = FINFO;
        }
-       solo_file = local_name != NULL;
+       solo_file = local_name;
+       dir_tweaking = !(list_only || solo_file || dry_run);
+       need_retouch_dir_times = preserve_times && !omit_dir_times;
+       lull_mod = allowed_lull * 5;
 
        if (verbose > 2)
                rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());
 
-       if (delete_before && !local_name && cur_flist->count > 0)
+       if (delete_before && !solo_file && cur_flist->count > 0)
                do_delete_pass(cur_flist);
        if (delete_during == 2) {
                deldelay_size = BIGPATHBUFLEN * 4;
@@ -1709,7 +1800,7 @@ void generate_files(int f_out, char *local_name)
        ignore_timeout = 1;
 
        do {
-               if (incremental && delete_during && cur_flist->ndx_start) {
+               if (inc_recurse && delete_during && cur_flist->ndx_start) {
                        struct file_struct *fp = dir_flist->files[cur_flist->parent_ndx];
                        if (BITS_SETnUNSET(fp->flags, FLAG_XFER_DIR, FLAG_MISSING_DIR)) {
                                dev_t dirdev;
@@ -1727,11 +1818,12 @@ void generate_files(int f_out, char *local_name)
                        if (!F_IS_ACTIVE(file))
                                continue;
 
-                       if (local_name)
-                               strlcpy(fbuf, local_name, sizeof fbuf);
+                       if (solo_file)
+                               strlcpy(fbuf, solo_file, sizeof fbuf);
                        else
                                f_name(file, fbuf);
-                       recv_generator(fbuf, file, i, itemizing, code, f_out);
+                       recv_generator(fbuf, file, i + cur_flist->ndx_start,
+                                      itemizing, code, f_out);
 
                        /* We need to ensure that any dirs we create have
                         * writeable permissions during the time we are putting
@@ -1741,7 +1833,7 @@ void generate_files(int f_out, char *local_name)
                        if (!am_root && S_ISDIR(file->mode)
                         && !(file->mode & S_IWUSR) && dir_tweaking) {
                                mode_t mode = file->mode | S_IWUSR;
-                               char *fname = local_name ? local_name : fbuf;
+                               const char *fname = solo_file ? solo_file : fbuf;
                                if (do_chmod(fname, mode) < 0) {
                                        rsyserr(FERROR, errno,
                                            "failed to modify permissions on %s",
@@ -1751,10 +1843,7 @@ void generate_files(int f_out, char *local_name)
                        }
 #endif
 
-#ifdef SUPPORT_HARD_LINKS
-                       if (preserve_hard_links)
-                               check_for_finished_hlinks(itemizing, code);
-#endif
+                       check_for_finished_files(itemizing, code, 0);
 
                        if (allowed_lull && !(i % lull_mod))
                                maybe_send_keepalive();
@@ -1762,115 +1851,27 @@ void generate_files(int f_out, char *local_name)
                                maybe_flush_socket();
                }
 
-               if (!incremental) {
-                       if (delete_during)
-                               delete_in_dir(NULL, NULL, NULL, &dev_zero);
-                       phase++;
-                       if (verbose > 2) {
-                               rprintf(FINFO, "generate_files phase=%d\n",
-                                       phase);
-                       }
-
+               if (!inc_recurse) {
                        write_ndx(f_out, NDX_DONE);
-               }
-
-               csum_length = SUM_LENGTH;
-               max_size = -max_size;
-               min_size = -min_size;
-               ignore_existing = -ignore_existing;
-               ignore_non_existing = -ignore_non_existing;
-               update_only = -update_only;
-               always_checksum = -always_checksum;
-               size_only = -size_only;
-               append_mode = -append_mode;
-               make_backups = -make_backups; /* avoid dup backup w/inplace */
-               ignore_times++;
-
-               /* Files can cycle through the system more than once
-                * to catch initial checksum errors. */
-               while (!done_cnt) {
-                       struct file_struct *file;
-                       struct file_list *save_flist;
-
-                       check_for_finished_hlinks(itemizing, code);
-
-                       if ((i = get_redo_num()) == -1) {
-                               if (incremental)
-                                       break;
-                               wait_for_receiver();
-                               continue;
-                       }
-
-                       save_flist = cur_flist;
-                       cur_flist = flist_for_ndx(i);
-                       file = cur_flist->files[i];
-                       if (local_name)
-                               strlcpy(fbuf, local_name, sizeof fbuf);
-                       else
-                               f_name(file, fbuf);
-                       recv_generator(fbuf, file, i, itemizing, code, f_out);
-                       cur_flist->to_redo--;
-                       cur_flist = save_flist;
-               }
-
-               csum_length = SHORT_SUM_LENGTH;
-               max_size = -max_size;
-               min_size = -min_size;
-               ignore_existing = -ignore_existing;
-               ignore_non_existing = -ignore_non_existing;
-               update_only = -update_only;
-               always_checksum = -always_checksum;
-               size_only = -size_only;
-               append_mode = -append_mode;
-               make_backups = -make_backups;
-               ignore_times--;
-
-               if (!incremental)
                        break;
+               }
 
-               while (!cur_flist->next && !flist_eof)
+               while (!cur_flist->next && !flist_eof) {
+                       check_for_finished_files(itemizing, code, 1);
                        wait_for_receiver();
-               next_flist = cur_flist->next;
-               while (first_flist != next_flist) {
-                       struct file_struct *fp;
-                       if (first_flist->in_progress || first_flist->to_redo) {
-                               if (next_flist)
-                                       break;
-                               wait_for_receiver();
-                               continue;
-                       }
-
-                       cur_flist = first_flist;
-                       if (cur_flist->ndx_start != 0) {
-                               fp = dir_flist->files[cur_flist->parent_ndx];
-                               if (!(fp->flags & FLAG_MISSING_DIR)) {
-                                       f_name(fp, fbuf);
-                                       if (!(fp->mode & S_IWUSR))
-                                               do_chmod(fbuf, fp->mode);
-                                       if (preserve_times && !omit_dir_times) {
-                                               set_modtime(fbuf, fp->modtime,
-                                                           fp->mode);
-                                       }
-                               }
-                       } else if (relative_paths && implied_dirs
-                           && preserve_times && !omit_dir_times) {
-                               /* Set mtime on implied dirs */
-                               for (i = 0; i < cur_flist->count; i++) {
-                                       fp = cur_flist->files[i];
-                                       if (!S_ISDIR(fp->mode)
-                                        || fp->flags & (FLAG_XFER_DIR|FLAG_MISSING_DIR))
-                                               continue;
-                                       f_name(fp, fbuf);
-                                       set_modtime(fbuf, fp->modtime, fp->mode);
-                               }
-                       }
+               }
+       } while ((cur_flist = cur_flist->next) != NULL);
 
-                       flist_free(first_flist); /* updates cur_flist & first_flist */
+       if (delete_during)
+               delete_in_dir(NULL, NULL, NULL, &dev_zero);
+       phase++;
+       if (verbose > 2)
+               rprintf(FINFO, "generate_files phase=%d\n", phase);
 
-                       if (!read_batch)
-                               write_ndx(f_out, NDX_DONE);
-               }
-       } while ((cur_flist = next_flist) != NULL);
+       while (!msgdone_cnt) {
+               check_for_finished_files(itemizing, code, 1);
+               wait_for_receiver();
+       }
 
        phase++;
        if (verbose > 2)
@@ -1882,8 +1883,8 @@ void generate_files(int f_out, char *local_name)
                write_ndx(f_out, NDX_DONE);
 
        /* Read MSG_DONE for the redo phase (and any prior messages). */
-       while (done_cnt <= 1) {
-               check_for_finished_hlinks(itemizing, code);
+       while (msgdone_cnt <= 1) {
+               check_for_finished_files(itemizing, code, 0);
                wait_for_receiver();
        }
 
@@ -1894,46 +1895,19 @@ void generate_files(int f_out, char *local_name)
                if (delay_updates)
                        write_ndx(f_out, NDX_DONE);
                /* Read MSG_DONE for delay-updates phase & prior messages. */
-               while (done_cnt == 2)
+               while (msgdone_cnt == 2)
                        wait_for_receiver();
        }
 
        do_progress = save_do_progress;
        if (delete_during == 2)
                do_delayed_deletions(fbuf);
-       if (delete_after && !local_name && file_total > 0)
+       if (delete_after && !solo_file && file_total > 0)
                do_delete_pass(cur_flist);
 
        if ((need_retouch_dir_perms || need_retouch_dir_times)
-        && dir_tweaking && !incremental) {
-               int j = 0;
-               /* Now we need to fix any directory permissions that were
-                * modified during the transfer and/or re-set any tweaked
-                * modified-time values. */
-               for (i = 0; i < cur_flist->count; i++) {
-                       struct file_struct *file = cur_flist->files[i];
-                       if (!F_IS_ACTIVE(file) || !S_ISDIR(file->mode))
-                               continue;
-                       if (!need_retouch_dir_times && file->mode & S_IWUSR)
-                               continue;
-                       if (file->flags & FLAG_MISSING_DIR) {
-                               int missing = F_DEPTH(file);
-                               while (++i < cur_flist->count) {
-                                       file = cur_flist->files[i];
-                                       if (F_DEPTH(file) <= missing)
-                                               break;
-                               }
-                               i--;
-                               continue;
-                       }
-                       recv_generator(f_name(file, NULL), file, i, itemizing,
-                                      code, -1);
-                       if (allowed_lull && !(++j % lull_mod))
-                               maybe_send_keepalive();
-                       else if (!(j % 200))
-                               maybe_flush_socket();
-               }
-       }
+        && dir_tweaking && (!inc_recurse || delete_during == 2))
+               touch_up_dirs(inc_recurse ? dir_flist : cur_flist, -1);
 
        if (max_delete >= 0 && deletion_count > max_delete) {
                rprintf(FINFO,