Updated to work with latest CVS.
[rsync/rsync-patches.git] / delete-during.diff
1 This patch creates a --delete-during functionality that deletes files on
2 the receiving side incrementally as we traverse the directories.  It also
3 defines a --delete-before option, for the traditional way that --delete
4 has worked before.
5
6 This patch chooses to make --delete into a synonym for --delete-during, and
7 hide --delete-during, but that can be easily changed if we want to preserve
8 the old functionality (and indeed, the support for popt aliases that is now
9 in CVS will let the user easily choose which method they'd like --delete to
10 invoke, either personally or site-wide, without having to recompile rsync).
11
12 Be sure to run "make proto" before "make".
13
14 --- orig/flist.c        2005-01-22 22:48:52
15 +++ flist.c     2005-01-23 07:14:40
16 @@ -35,6 +35,7 @@ extern int am_root;
17  extern int am_server;
18  extern int am_daemon;
19  extern int am_sender;
20 +extern int delete_during;
21  extern int always_checksum;
22  extern int module_id;
23  extern int ignore_errors;
24 @@ -45,6 +46,8 @@ extern int cvs_exclude;
25  extern int recurse;
26  extern int keep_dirs;
27  extern char curr_dir[MAXPATHLEN];
28 +extern char *backup_dir;
29 +extern char *backup_suffix;
30  extern int filesfrom_fd;
31  
32  extern int one_file_system;
33 @@ -57,11 +60,14 @@ extern int preserve_uid;
34  extern int preserve_gid;
35  extern int relative_paths;
36  extern int implied_dirs;
37 +extern int make_backups;
38 +extern int backup_suffix_len;
39  extern int copy_links;
40  extern int copy_unsafe_links;
41  extern int protocol_version;
42  extern int sanitize_paths;
43  extern int delete_excluded;
44 +extern int max_delete;
45  extern int orig_umask;
46  extern int list_only;
47  
48 @@ -534,6 +540,8 @@ void receive_file_entry(struct file_stru
49         static gid_t gid;
50         static char lastname[MAXPATHLEN], *lastdir;
51         static int lastdir_depth, lastdir_len = -1;
52 +       static unsigned int del_heir_name_len = -1;
53 +       static int in_del_hier = 0;
54         char thisname[MAXPATHLEN];
55         unsigned int l1 = 0, l2 = 0;
56         int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
57 @@ -547,7 +555,8 @@ void receive_file_entry(struct file_stru
58                 rdev_major = 0;
59                 uid = 0, gid = 0;
60                 *lastname = '\0';
61 -               lastdir_len = -1;
62 +               del_heir_name_len = lastdir_len = -1;
63 +               in_del_hier = 0;
64                 return;
65         }
66  
67 @@ -645,13 +654,27 @@ void receive_file_entry(struct file_stru
68         memset(bp, 0, file_struct_len);
69         bp += file_struct_len;
70  
71 -       file->flags = flags & XMIT_DEL_START ? FLAG_DEL_START : 0;
72 +       file->flags = 0;
73         file->modtime = modtime;
74         file->length = file_length;
75         file->mode = mode;
76         file->uid = uid;
77         file->gid = gid;
78  
79 +       if (S_ISDIR(mode)) {
80 +               if (flags & XMIT_DEL_START) {
81 +                       in_del_hier = 1;
82 +                       del_heir_name_len = l1 + l2;
83 +                       file->flags |= FLAG_DEL_START;
84 +               } else if (delete_during && in_del_hier) {
85 +                       if (!relative_paths || (l1 >= del_heir_name_len
86 +                           && thisname[del_heir_name_len] == '/'))
87 +                               file->flags |= FLAG_DEL_START;
88 +                       else
89 +                               in_del_hier = 0;
90 +               }
91 +       }
92 +
93         if (dirname_len) {
94                 file->dirname = lastdir = bp;
95                 lastdir_len = dirname_len - 1;
96 @@ -1129,7 +1152,9 @@ struct file_list *send_file_list(int f, 
97                                 fname[l] = '\0';
98                         }
99                 }
100 -               if (fname[l-1] == '.' && (l == 1 || fname[l-2] == '/')) {
101 +               if (relative_paths < 0)
102 +                       ; /* recurse is pre-set */
103 +               else if (fname[l-1] == '.' && (l == 1 || fname[l-2] == '/')) {
104                         if (!recurse && keep_dirs)
105                                 recurse = 1; /* allow one level */
106                 } else if (recurse > 0)
107 @@ -1644,3 +1669,75 @@ char *f_name(struct file_struct *f)
108  
109         return f_name_to(f, names[n]);
110  }
111 +
112 +static int is_backup_file(char *fn)
113 +{
114 +       int k = strlen(fn) - backup_suffix_len;
115 +       return k > 0 && strcmp(fn+k, backup_suffix) == 0;
116 +}
117 +
118 +void delete_in_dir(struct file_list *flist, char *fname, int do_subdirs)
119 +{
120 +       static int deletion_count = 0;
121 +       struct file_list *del_flist;
122 +       int save_recurse = recurse;
123 +       int save_keep_dirs = keep_dirs;
124 +       int save_implied_dirs = implied_dirs;
125 +       int save_relative_paths = relative_paths;
126 +       char *argv[1];
127 +       int i, j, mode;
128 +
129 +       if (max_delete && deletion_count >= max_delete)
130 +               return;
131 +
132 +       if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
133 +               rprintf(FINFO, "IO error encountered - skipping file deletion\n");
134 +               max_delete = -1; /* avoid duplicating the above warning */
135 +               return;
136 +       }
137 +
138 +       recurse = do_subdirs ? -1 : 1;
139 +       keep_dirs = 1;
140 +       implied_dirs = 0;
141 +       relative_paths = -1;
142 +
143 +       argv[0] = fname;
144 +       del_flist = send_file_list(-1, 1, argv);
145 +
146 +       relative_paths = save_relative_paths;
147 +       implied_dirs = save_implied_dirs;
148 +       keep_dirs = save_keep_dirs;
149 +       recurse = save_recurse;
150 +
151 +       if (!del_flist)
152 +               return;
153 +
154 +       if (verbose > 1)
155 +               rprintf(FINFO, "deleting in %s\n", safe_fname(fname));
156 +
157 +       for (i = del_flist->count-1; i >= 0; i--) {
158 +               if (max_delete && deletion_count >= max_delete)
159 +                       break;
160 +               if (!del_flist->files[i]->basename)
161 +                       continue;
162 +               mode = del_flist->files[i]->mode;
163 +               if ((j = flist_find(flist, del_flist->files[i])) < 0
164 +                   || (delete_during && S_ISDIR(mode)
165 +                    && !S_ISDIR(flist->files[j]->mode))) {
166 +                       char *f = f_name(del_flist->files[i]);
167 +                       if (make_backups && (backup_dir || !is_backup_file(f))
168 +                         && !S_ISDIR(mode)) {
169 +                               make_backup(f);
170 +                               if (verbose) {
171 +                                       rprintf(FINFO, "deleting %s\n",
172 +                                               safe_fname(f));
173 +                               }
174 +                       } else {
175 +                               delete_file(f, S_ISDIR(mode)
176 +                                               ? DEL_DIR | DEL_RECURSE : 0);
177 +                       }
178 +                       deletion_count++;
179 +               }
180 +       }
181 +       flist_free(del_flist);
182 +}
183 --- orig/generator.c    2005-01-20 23:05:34
184 +++ generator.c 2005-01-21 10:21:39
185 @@ -34,6 +34,7 @@ extern int preserve_hard_links;
186  extern int preserve_perms;
187  extern int preserve_uid;
188  extern int preserve_gid;
189 +extern int delete_during;
190  extern int update_only;
191  extern int opt_ignore_existing;
192  extern int inplace;
193 @@ -233,7 +234,8 @@ static void generate_and_send_sums(int f
194   * @note This comment was added later by mbp who was trying to work it
195   * out.  It might be wrong.
196   */
197 -static void recv_generator(char *fname, struct file_struct *file, int i,
198 +static void recv_generator(char *fname, struct file_list *flist,
199 +                          struct file_struct *file, int i,
200                            int f_out, int f_out_name)
201  {
202         int fd = -1, f_copy = -1;
203 @@ -308,6 +310,11 @@ static void recv_generator(char *fname, 
204                 }
205                 /* f_out is set to -1 when doing final directory-permission
206                  * and modification-time repair. */
207 +               if (delete_during && f_out != -1
208 +                   && (file->flags & FLAG_DEL_START)) {
209 +                       delete_in_dir(flist, fname, 0);
210 +                       statret = 1;
211 +               }
212                 if (set_perms(fname, file, statret ? NULL : &st, 0)
213                     && verbose && f_out != -1)
214                         rprintf(FINFO, "%s/\n", safe_fname(fname));
215 @@ -641,7 +648,7 @@ void generate_files(int f_out, struct fi
216                 }
217  
218                 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
219 -                              file, i, f_out, f_out_name);
220 +                              flist, file, i, f_out, f_out_name);
221         }
222  
223         phase++;
224 @@ -658,7 +665,7 @@ void generate_files(int f_out, struct fi
225         while ((i = get_redo_num()) != -1) {
226                 struct file_struct *file = flist->files[i];
227                 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
228 -                              file, i, f_out, f_out_name);
229 +                              flist, file, i, f_out, f_out_name);
230         }
231  
232         phase++;
233 @@ -680,7 +687,7 @@ void generate_files(int f_out, struct fi
234                 if (!file->basename || !S_ISDIR(file->mode))
235                         continue;
236                 recv_generator(local_name ? local_name : f_name(file),
237 -                              file, i, -1, -1);
238 +                              flist, file, i, -1, -1);
239         }
240  
241         if (verbose > 2)
242 --- orig/main.c 2005-01-22 22:48:52
243 +++ main.c      2005-01-23 01:48:52
244 @@ -737,6 +737,8 @@ int client_run(int f_in, int f_out, pid_
245  
246         if (!read_batch)
247                 send_exclude_list(f_out);
248 +       if (cvs_exclude)
249 +               add_cvs_excludes();
250  
251         if (filesfrom_fd >= 0) {
252                 io_set_filesfrom_fds(filesfrom_fd, f_out);
253 --- orig/options.c      2005-01-23 01:45:43
254 +++ options.c   2005-01-23 01:53:35
255 @@ -54,6 +54,7 @@ int dry_run = 0;
256  int local_server = 0;
257  int ignore_times = 0;
258  int delete_mode = 0;
259 +int delete_during = 0;
260  int delete_before = 0;
261  int delete_after = 0;
262  int delete_excluded = 0;
263 @@ -274,7 +275,8 @@ void usage(enum logcode F)
264    rprintf(F,"     --existing              only update files that already exist\n");
265    rprintf(F,"     --ignore-existing       ignore files that already exist on receiving side\n");
266    rprintf(F,"     --delete                delete files that don't exist on the sending side\n");
267 -  rprintf(F,"     --delete-after          receiver deletes after transferring, not before\n");
268 +  rprintf(F,"     --delete-before         receiver deletes before transfer, not during\n");
269 +  rprintf(F,"     --delete-after          receiver deletes after transfer, not during\n");
270    rprintf(F,"     --delete-excluded       also delete excluded files on the receiving side\n");
271    rprintf(F,"     --ignore-errors         delete even if there are I/O errors\n");
272    rprintf(F,"     --force                 force deletion of directories even if not empty\n");
273 @@ -340,7 +342,9 @@ static struct poptOption long_options[] 
274    {"one-file-system", 'x', POPT_ARG_NONE,   &one_file_system, 0, 0, 0 },
275    {"existing",         0,  POPT_ARG_NONE,   &only_existing, 0, 0, 0 },
276    {"ignore-existing",  0,  POPT_ARG_NONE,   &opt_ignore_existing, 0, 0, 0 },
277 -  {"delete",           0,  POPT_ARG_NONE,   &delete_before, 0, 0, 0 },
278 +  {"delete",           0,  POPT_ARG_NONE,   &delete_during, 0, 0, 0 },
279 +  {"delete-during",    0,  POPT_ARG_NONE,   &delete_during, 0, 0, 0 },
280 +  {"delete-before",    0,  POPT_ARG_NONE,   &delete_before, 0, 0, 0 },
281    {"delete-after",     0,  POPT_ARG_NONE,   &delete_after, 0, 0, 0 },
282    {"delete-excluded",  0,  POPT_ARG_NONE,   &delete_excluded, 0, 0, 0 },
283    {"force",            0,  POPT_ARG_NONE,   &force_delete, 0, 0, 0 },
284 @@ -853,10 +857,10 @@ int parse_arguments(int *argc, const cha
285         if (relative_paths < 0)
286                 relative_paths = files_from? 1 : 0;
287  
288 -       if (delete_before || delete_after)
289 +       if (delete_during || delete_before || delete_after)
290                 delete_mode = 1;
291         if (delete_excluded && !delete_mode)
292 -               delete_mode = delete_before = 1;
293 +               delete_mode = delete_during = 1;
294  
295         *argv = poptGetArgs(pc);
296         *argc = count_args(*argv);
297 @@ -1159,7 +1163,9 @@ void server_options(char **args,int *arg
298         if (am_sender) {
299                 if (delete_excluded)
300                         args[ac++] = "--delete-excluded";
301 -               else if (delete_before || delete_after)
302 +               else if (delete_before)
303 +                       args[ac++] = "--delete-before";
304 +               else if (delete_during || delete_after)
305                         args[ac++] = "--delete";
306  
307                 if (delete_after)
308 --- orig/receiver.c     2005-01-22 22:48:52
309 +++ receiver.c  2005-01-23 01:50:42
310 @@ -21,8 +21,8 @@
311  #include "rsync.h"
312  
313  extern int verbose;
314 +extern int recurse;
315  extern int delete_after;
316 -extern int max_delete;
317  extern int csum_length;
318  extern struct stats stats;
319  extern int dry_run;
320 @@ -35,7 +35,6 @@ extern int keep_dirs;
321  extern int keep_dirlinks;
322  extern int preserve_hard_links;
323  extern int preserve_perms;
324 -extern int cvs_exclude;
325  extern int io_error;
326  extern char *tmpdir;
327  extern char *partial_dir;
328 @@ -43,9 +42,6 @@ extern char *basis_dir[];
329  extern int basis_dir_cnt;
330  extern int make_backups;
331  extern int do_progress;
332 -extern char *backup_dir;
333 -extern char *backup_suffix;
334 -extern int backup_suffix_len;
335  extern int cleanup_got_literal;
336  extern int module_id;
337  extern int ignore_errors;
338 @@ -57,66 +53,19 @@ extern int inplace;
339  extern struct exclude_list_struct server_exclude_list;
340  
341  
342 -static int is_backup_file(char *fn)
343 -{
344 -       int k = strlen(fn) - backup_suffix_len;
345 -       return k > 0 && strcmp(fn+k, backup_suffix) == 0;
346 -}
347 -
348 -
349 -/* This deletes any files on the receiving side that are not present
350 - * on the sending side. */
351 +/* This deletes any files on the receiving side that are not present on the
352 + * sending side.  This is used by --delete-before and --delete-after. */
353  void delete_files(struct file_list *flist)
354  {
355 -       struct file_list *local_file_list;
356 -       int i, j;
357 -       char *argv[1], fbuf[MAXPATHLEN];
358 -       static int deletion_count;
359 -
360 -       if (cvs_exclude)
361 -               add_cvs_excludes();
362 -
363 -       if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
364 -               rprintf(FINFO,"IO error encountered - skipping file deletion\n");
365 -               return;
366 -       }
367 +       char fbuf[MAXPATHLEN];
368 +       int j;
369  
370         for (j = 0; j < flist->count; j++) {
371                 if (!(flist->files[j]->flags & FLAG_DEL_START)
372                     || !S_ISDIR(flist->files[j]->mode))
373                         continue;
374  
375 -               argv[0] = f_name_to(flist->files[j], fbuf);
376 -
377 -               if (!(local_file_list = send_file_list(-1, 1, argv)))
378 -                       continue;
379 -
380 -               if (verbose > 1)
381 -                       rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
382 -
383 -               for (i = local_file_list->count-1; i >= 0; i--) {
384 -                       if (max_delete && deletion_count >= max_delete)
385 -                               break;
386 -                       if (!local_file_list->files[i]->basename)
387 -                               continue;
388 -                       if (flist_find(flist,local_file_list->files[i]) < 0) {
389 -                               char *f = f_name(local_file_list->files[i]);
390 -                               int mode = local_file_list->files[i]->mode;
391 -                               if (make_backups && (backup_dir || !is_backup_file(f))
392 -                                 && !S_ISDIR(mode)) {
393 -                                       make_backup(f);
394 -                                       if (verbose) {
395 -                                               rprintf(FINFO, "deleting %s\n",
396 -                                                       safe_fname(f));
397 -                                       }
398 -                               } else {
399 -                                       delete_file(f, S_ISDIR(mode)
400 -                                               ? DEL_DIR | DEL_RECURSE : 0);
401 -                               }
402 -                               deletion_count++;
403 -                       }
404 -               }
405 -               flist_free(local_file_list);
406 +               delete_in_dir(flist, f_name_to(flist->files[j], fbuf), recurse);
407         }
408  }
409  
410 --- orig/rsync.yo       2005-01-22 22:48:52
411 +++ rsync.yo    2005-01-23 02:57:49
412 @@ -341,7 +341,8 @@ verb(
413       --existing              only update files that already exist
414       --ignore-existing       ignore files that already exist on receiver
415       --delete                delete files that don't exist on sender
416 -     --delete-after          receiver deletes after transfer, not before
417 +     --delete-before         receiver deletes before xfer, not during
418 +     --delete-after          receiver deletes after transfer, not during
419       --delete-excluded       also delete excluded files on receiver
420       --ignore-errors         delete even if there are I/O errors
421       --force                 force deletion of dirs even if not empty
422 @@ -681,14 +682,23 @@ prevent temporary filesystem failures (s
423  sending side causing a massive deletion of files on the
424  destination.  You can override this with the --ignore-errors option.
425  
426 -dit(bf(--delete-after)) By default rsync does file deletions on the
427 -receiving side before transferring files to try to ensure that there is
428 -sufficient space on the receiving filesystem. If you want to delete
429 -after transferring, use the --delete-after switch. Implies --delete.
430 -
431 -One reason to use --delete-after is to avoid a delay before the start of
432 -the transfer (while the receiving side is scanned for deletions) as this
433 -delay might cause the transfer to timeout.  
434 +By default rsync does file deletions on the receiving side during the
435 +transfer of files to try make it as efficient as possible.  For other
436 +options, see --delete-before and --delte-after.
437 +
438 +dit(bf(--delete-before)) Request that the file-deletions on the receving
439 +side be done prior to starting the transfer, not incrementally as the
440 +transfer happens.  Implies --delete.
441 +
442 +One reason to use --delete-before is if the filesystem is tight for space
443 +and removing extraneous files would help to make the transfer possible.
444 +However, it does introduce a delay before the start of the transfer (while
445 +the receiving side is being scanned for deletions) and this delay might
446 +cause the transfer to timeout.  
447 +
448 +dit(bf(--delete-after)) Request that the file-deletions on the receving
449 +side be done after the transfer has completed, not incrementally as the
450 +transfer happens.  Implies --delete.
451  
452  dit(bf(--delete-excluded)) In addition to deleting the files on the
453  receiving side that are not on the sending side, this tells rsync to also