Fixed a failing hunk.
[rsync/rsync-patches.git] / delay-renames.diff
1 Delay the renaming of all the temp files until the end of the transfer.
2
3 --- orig/options.c      2005-01-17 23:11:45
4 +++ options.c   2005-01-17 23:15:13
5 @@ -97,6 +97,7 @@ int modify_window = 0;
6  int blocking_io = -1;
7  int checksum_seed = 0;
8  int inplace = 0;
9 +int delay_renames = 0;
10  long block_size = 0; /* "long" because popt can't set an int32. */
11  
12  
13 @@ -278,6 +279,7 @@ void usage(enum logcode F)
14    rprintf(F,"     --max-size=SIZE         don't transfer any file larger than SIZE\n");
15    rprintf(F,"     --partial               keep partially transferred files\n");
16    rprintf(F,"     --partial-dir=DIR       put a partially transferred file into DIR\n");
17 +  rprintf(F,"     --delay-renames         renames transferred files into place at end\n");
18    rprintf(F,"     --force                 force deletion of directories even if not empty\n");
19    rprintf(F,"     --numeric-ids           don't map uid/gid values by user/group name\n");
20    rprintf(F,"     --timeout=TIME          set I/O timeout in seconds\n");
21 @@ -390,6 +392,7 @@ static struct poptOption long_options[] 
22    {"progress",         0,  POPT_ARG_NONE,   &do_progress, 0, 0, 0 },
23    {"partial",          0,  POPT_ARG_NONE,   &keep_partial, 0, 0, 0 },
24    {"partial-dir",      0,  POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
25 +  {"delay-renames",    0,  POPT_ARG_NONE,   &delay_renames, 0, 0, 0 },
26    {"ignore-errors",    0,  POPT_ARG_NONE,   &ignore_errors, 0, 0, 0 },
27    {"blocking-io",      0,  POPT_ARG_VAL,    &blocking_io, 1, 0, 0 },
28    {"no-blocking-io",   0,  POPT_ARG_VAL,    &blocking_io, 0, 0, 0 },
29 @@ -944,11 +947,15 @@ int parse_arguments(int *argc, const cha
30                         bwlimit_writemax = 512;
31         }
32  
33 +       if (delay_renames && !partial_dir)
34 +               partial_dir = ".~tmp~";
35 +
36         if (inplace) {
37  #if HAVE_FTRUNCATE
38 -               if (partial_dir) {
39 +               if (partial_dir || delay_renames) {
40                         snprintf(err_buf, sizeof err_buf,
41 -                                "--inplace cannot be used with --partial-dir\n");
42 +                                "--inplace cannot be used with --%s\n",
43 +                                delay_renames ? "delay-renames" : "partial-dir");
44                         return 0;
45                 }
46                 keep_partial = 0;
47 @@ -1179,6 +1186,8 @@ void server_options(char **args,int *arg
48         if (partial_dir && am_sender) {
49                 args[ac++] = "--partial-dir";
50                 args[ac++] = partial_dir;
51 +               if (delay_renames)
52 +                       args[ac++] = "--delay-renames";
53         } else if (keep_partial)
54                 args[ac++] = "--partial";
55  
56 --- orig/receiver.c     2005-01-17 23:11:45
57 +++ receiver.c  2005-01-10 10:16:54
58 @@ -53,6 +53,7 @@ extern int orig_umask;
59  extern int keep_partial;
60  extern int checksum_seed;
61  extern int inplace;
62 +extern int delay_renames;
63  
64  extern struct exclude_list_struct server_exclude_list;
65  
66 @@ -345,6 +346,7 @@ int recv_files(int f_in, struct file_lis
67         char fnametmp[MAXPATHLEN];
68         char *fnamecmp, *partialptr;
69         char fnamecmpbuf[MAXPATHLEN];
70 +       uchar *delayed_bits = NULL;
71         struct file_struct *file;
72         struct stats initial_stats;
73         int save_make_backups = make_backups;
74 @@ -358,6 +360,12 @@ int recv_files(int f_in, struct file_lis
75                 flist->hlink_pool = NULL;
76         }
77  
78 +       if (delay_renames) {
79 +               if (!(delayed_bits = new_array(char, (flist->count + 7) / 8)))
80 +                       out_of_memory("recv_files");
81 +               memset(delayed_bits, 0, (flist->count + 7) / 8);
82 +       }
83 +
84         while (1) {
85                 cleanup_disable();
86  
87 @@ -572,7 +580,7 @@ int recv_files(int f_in, struct file_lis
88                         exit_cleanup(RERR_FILEIO);
89                 }
90  
91 -               if (recv_ok || inplace) {
92 +               if ((recv_ok && !delay_renames) || inplace) {
93                         finish_transfer(fname, fnametmp, file, recv_ok, 1);
94                         if (partialptr != fname && fnamecmp == partialptr) {
95                                 do_unlink(partialptr);
96 @@ -582,6 +590,8 @@ int recv_files(int f_in, struct file_lis
97                     && handle_partial_dir(partialptr, PDIR_CREATE)) {
98                         finish_transfer(partialptr, fnametmp, file, recv_ok,
99                                         !partial_dir);
100 +                       if (delay_renames && recv_ok)
101 +                               delayed_bits[i/8] |= 1 << (i % 8);
102                 } else {
103                         partialptr = NULL;
104                         do_unlink(fnametmp);
105 @@ -621,6 +631,33 @@ int recv_files(int f_in, struct file_lis
106         }
107         make_backups = save_make_backups;
108  
109 +       if (delay_renames) {
110 +               for (i = 0; i < flist->count; i++) {
111 +                       struct file_struct *file = flist->files[i];
112 +                       if (!file->basename
113 +                        || !(delayed_bits[i/8] & (1 << (i % 8))))
114 +                               continue;
115 +                       fname = local_name ? local_name : f_name(file);
116 +                       partialptr = partial_dir_fname(fname);
117 +                       if (partialptr) {
118 +                               if (make_backups && !make_backup(fname))
119 +                                       continue;
120 +                               if (verbose > 2) {
121 +                                       rprintf(FINFO, "renaming %s to %s\n",
122 +                                               partialptr, fname);
123 +                               }
124 +                               if (do_rename(partialptr, fname) < 0) {
125 +                                       rsyserr(FERROR, errno,
126 +                                               "rename failed for %s (from %s)",
127 +                                               fname, partialptr);
128 +                               } else {
129 +                                       handle_partial_dir(partialptr,
130 +                                                          PDIR_DELETE);
131 +                               }
132 +                       }
133 +               }
134 +       }
135 +
136         if (delete_after && recurse && !local_name && flist->count > 0)
137                 delete_files(flist);
138  
139 --- orig/rsync.yo       2005-01-17 23:11:46
140 +++ rsync.yo    2005-01-17 23:13:23
141 @@ -348,6 +348,7 @@ verb(
142       --max-size=SIZE         don't transfer any file larger than SIZE
143       --partial               keep partially transferred files
144       --partial-dir=DIR       put a partially transferred file into DIR
145 +     --delay-renames         renames transferred files into place at end
146       --force                 force deletion of dirs even if not empty
147       --numeric-ids           don't map uid/gid values by user/group name
148       --timeout=TIME          set I/O timeout in seconds
149 @@ -546,9 +547,9 @@ or appended data, and also on systems th
150  bound.
151  
152  The option implies --partial (since an interrupted transfer does not delete
153 -the file), but conflicts with --partial-dir.  Prior to rsync 2.6.4
154 ---inplace was also incompatible with --compare-dest, --copy-dest, and
155 ---link-dest.
156 +the file), but conflicts with --partial-dir and --delay-renames.
157 +Prior to rsync 2.6.4 --inplace was also incompatible with --compare-dest,
158 +--copy-dest, and --link-dest.
159  
160  WARNING: The file's data will be in an inconsistent state during the
161  transfer (and possibly afterward if the transfer gets interrupted), so you
162 @@ -978,6 +979,17 @@ environment and then just use the -P opt
163  does not look for this environment value is when --inplace was also
164  specified (since --inplace conflicts with --partial-dir).
165  
166 +dit(bf(--delay-renames)) This option puts the temporary file from each
167 +updated file into the file's partial-dir (see above) until the end of the
168 +transfer, at which time all the files are renamed into place in rapid
169 +succession.  This attempts to make the updating of the files a little more
170 +atomic.  If you don't specify the --partial-dir option, this option will
171 +cause it to default to ".~tmp~" (RSYNC_PARTIAL_DIR is not consulted for
172 +this value).  Conflicts with --inplace.
173 +
174 +See also the "atomic-rsync" perl script in the "support" subdir for an
175 +update algorithm that is even more atomic (it uses --link-dest).
176 +
177  dit(bf(--progress)) This option tells rsync to print information
178  showing the progress of the transfer. This gives a bored user
179  something to watch.