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
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).
12 --- orig/flist.c 2005-01-21 00:35:26
13 +++ flist.c 2005-01-21 02:08:54
14 @@ -35,6 +35,7 @@ extern int am_root;
18 +extern int delete_during;
19 extern int always_checksum;
21 extern int ignore_errors;
22 @@ -45,6 +46,8 @@ extern int cvs_exclude;
25 extern char curr_dir[MAXPATHLEN];
26 +extern char *backup_dir;
27 +extern char *backup_suffix;
28 extern int filesfrom_fd;
30 extern int one_file_system;
31 @@ -57,11 +60,14 @@ extern int preserve_uid;
32 extern int preserve_gid;
33 extern int relative_paths;
34 extern int implied_dirs;
35 +extern int make_backups;
36 +extern int backup_suffix_len;
37 extern int copy_links;
38 extern int copy_unsafe_links;
39 extern int protocol_version;
40 extern int sanitize_paths;
41 extern int delete_excluded;
42 +extern int max_delete;
43 extern int orig_umask;
46 @@ -534,6 +540,8 @@ void receive_file_entry(struct file_stru
48 static char lastname[MAXPATHLEN], *lastdir;
49 static int lastdir_depth, lastdir_len = -1;
50 + static unsigned int del_heir_name_len = -1;
51 + static int in_del_hier = 0;
52 char thisname[MAXPATHLEN];
53 unsigned int l1 = 0, l2 = 0;
54 int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
55 @@ -547,7 +555,8 @@ void receive_file_entry(struct file_stru
60 + del_heir_name_len = lastdir_len = -1;
65 @@ -645,13 +654,27 @@ void receive_file_entry(struct file_stru
66 memset(bp, 0, file_struct_len);
67 bp += file_struct_len;
69 - file->flags = flags & XMIT_DEL_START ? FLAG_DEL_START : 0;
71 file->modtime = modtime;
72 file->length = file_length;
77 + if (S_ISDIR(mode)) {
78 + if (flags & XMIT_DEL_START) {
80 + del_heir_name_len = l1 + l2;
81 + file->flags |= FLAG_DEL_START;
82 + } else if (delete_during && in_del_hier) {
83 + if (!relative_paths || (l1 >= del_heir_name_len
84 + && thisname[del_heir_name_len] == '/'))
85 + file->flags |= FLAG_DEL_START;
92 file->dirname = lastdir = bp;
93 lastdir_len = dirname_len - 1;
94 @@ -1044,7 +1067,8 @@ static void send_directory(int f, struct
95 || (dname[1] == '.' && dname[2] == '\0')))
97 if (strlcpy(p, dname, MAXPATHLEN - offset) < MAXPATHLEN - offset) {
98 - send_file_name(f, flist, fname, recurse, 0);
99 + int do_subdirs = recurse >= 1 ? recurse-- : recurse;
100 + send_file_name(f, flist, fname, do_subdirs, 0);
102 io_error |= IOERR_GENERAL;
104 @@ -1102,6 +1126,7 @@ struct file_list *send_file_list(int f,
106 char fname2[MAXPATHLEN];
107 char *fname = fname2;
111 if (read_filesfrom_line(filesfrom_fd, fname) == 0)
112 @@ -1143,7 +1168,7 @@ struct file_list *send_file_list(int f,
116 - if (!relative_paths) {
117 + if (!relative_paths && recurse <= 0) {
118 p = strrchr(fname, '/');
121 @@ -1212,7 +1237,8 @@ struct file_list *send_file_list(int f,
123 set_filesystem(fname);
125 - send_file_name(f, flist, fname, recurse, XMIT_DEL_START);
126 + do_subdirs = recurse >= 1 ? recurse-- : recurse;
127 + send_file_name(f, flist, fname, do_subdirs, XMIT_DEL_START);
131 @@ -1634,3 +1660,91 @@ char *f_name(struct file_struct *f)
133 return f_name_to(f, names[n]);
136 +static int is_backup_file(char *fn)
138 + int k = strlen(fn) - backup_suffix_len;
139 + return k > 0 && strcmp(fn+k, backup_suffix) == 0;
142 +void delete_in_dir(struct file_list *flist, char *fname, int do_subdirs)
144 + static int deletion_count = 0;
145 + struct file_list *del_flist;
146 + int save_recurse = recurse;
147 + int save_keep_dirs = keep_dirs;
148 + int save_implied_dirs = implied_dirs;
152 + if (max_delete && deletion_count >= max_delete)
155 + if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
156 + rprintf(FINFO, "IO error encountered - skipping file deletion\n");
157 + max_delete = -1; /* avoid duplicating the above warning */
161 + recurse = do_subdirs ? -1 : 1;
166 + del_flist = send_file_list(-1, 1, argv);
168 + implied_dirs = save_implied_dirs;
169 + keep_dirs = save_keep_dirs;
170 + recurse = save_recurse;
176 + rprintf(FINFO, "deleting in %s\n", safe_fname(fname));
178 + for (i = del_flist->count-1; i >= 0; i--) {
179 + if (max_delete && deletion_count >= max_delete)
181 + if (!del_flist->files[i]->basename)
183 + mode = del_flist->files[i]->mode;
184 + if ((j = flist_find(flist, del_flist->files[i])) < 0
185 + || (delete_during && S_ISDIR(mode)
186 + && !S_ISDIR(flist->files[j]->mode))) {
187 + char *f = f_name(del_flist->files[i]);
188 + if (make_backups && (backup_dir || !is_backup_file(f))
189 + && !S_ISDIR(mode)) {
192 + rprintf(FINFO, "deleting %s\n",
196 + delete_file(f, S_ISDIR(mode)
197 + ? DEL_DIR | DEL_RECURSE : 0);
202 + flist_free(del_flist);
205 +/* This deletes any files on the receiving side that are not present on the
206 + * sending side. This is used by --delete-before and --delete-after. */
207 +void delete_files(struct file_list *flist)
209 + char fbuf[MAXPATHLEN];
213 + add_cvs_excludes();
215 + for (j = 0; j < flist->count; j++) {
216 + if (!(flist->files[j]->flags & FLAG_DEL_START)
217 + || !S_ISDIR(flist->files[j]->mode))
220 + delete_in_dir(flist, f_name_to(flist->files[j], fbuf), recurse);
223 --- orig/generator.c 2005-01-20 23:05:34
224 +++ generator.c 2005-01-21 01:59:39
225 @@ -34,6 +34,8 @@ extern int preserve_hard_links;
226 extern int preserve_perms;
227 extern int preserve_uid;
228 extern int preserve_gid;
229 +extern int delete_during;
230 +extern int cvs_exclude;
231 extern int update_only;
232 extern int opt_ignore_existing;
234 @@ -233,7 +235,8 @@ static void generate_and_send_sums(int f
235 * @note This comment was added later by mbp who was trying to work it
236 * out. It might be wrong.
238 -static void recv_generator(char *fname, struct file_struct *file, int i,
239 +static void recv_generator(char *fname, struct file_list *flist,
240 + struct file_struct *file, int i,
241 int f_out, int f_out_name)
243 int fd = -1, f_copy = -1;
244 @@ -308,6 +311,11 @@ static void recv_generator(char *fname,
246 /* f_out is set to -1 when doing final directory-permission
247 * and modification-time repair. */
248 + if (delete_during && f_out != -1
249 + && (file->flags & FLAG_DEL_START)) {
250 + delete_in_dir(flist, fname, 0);
253 if (set_perms(fname, file, statret ? NULL : &st, 0)
254 && verbose && f_out != -1)
255 rprintf(FINFO, "%s/\n", safe_fname(fname));
256 @@ -618,6 +626,9 @@ void generate_files(int f_out, struct fi
257 : "delta transmission enabled\n");
260 + if (delete_during && cvs_exclude)
261 + add_cvs_excludes();
263 /* we expect to just sit around now, so don't exit on a
264 timeout. If we really get a timeout then the other process should
266 @@ -641,7 +652,7 @@ void generate_files(int f_out, struct fi
269 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
270 - file, i, f_out, f_out_name);
271 + flist, file, i, f_out, f_out_name);
275 @@ -658,7 +669,7 @@ void generate_files(int f_out, struct fi
276 while ((i = get_redo_num()) != -1) {
277 struct file_struct *file = flist->files[i];
278 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
279 - file, i, f_out, f_out_name);
280 + flist, file, i, f_out, f_out_name);
284 @@ -680,7 +691,7 @@ void generate_files(int f_out, struct fi
285 if (!file->basename || !S_ISDIR(file->mode))
287 recv_generator(local_name ? local_name : f_name(file),
289 + flist, file, i, -1, -1);
293 --- orig/main.c 2005-01-17 23:11:45
294 +++ main.c 2005-01-18 21:56:05
295 @@ -33,6 +33,7 @@ extern int verbose;
296 extern int blocking_io;
297 extern int cvs_exclude;
298 extern int delete_mode;
299 +extern int delete_before;
300 extern int delete_excluded;
301 extern int delete_after;
302 extern int daemon_over_rsh;
303 @@ -473,9 +474,9 @@ static int do_recv(int f_in,int f_out,st
304 if (preserve_hard_links)
305 init_hard_links(flist);
307 - if (!delete_after) {
308 + if (delete_before) {
309 /* I moved this here from recv_files() to prevent a race condition */
310 - if (recurse && delete_mode && !local_name && flist->count > 0)
311 + if (recurse && !local_name && flist->count > 0)
315 --- orig/options.c 2005-01-20 23:05:34
316 +++ options.c 2005-01-20 23:06:33
317 @@ -54,6 +54,8 @@ int dry_run = 0;
318 int local_server = 0;
319 int ignore_times = 0;
321 +int delete_during = 0;
322 +int delete_before = 0;
323 int delete_excluded = 0;
324 int one_file_system = 0;
325 int protocol_version = PROTOCOL_VERSION;
326 @@ -272,14 +274,15 @@ void usage(enum logcode F)
327 rprintf(F," --existing only update files that already exist\n");
328 rprintf(F," --ignore-existing ignore files that already exist on receiving side\n");
329 rprintf(F," --delete delete files that don't exist on the sending side\n");
330 + rprintf(F," --delete-before receiver deletes before transfer, not during\n");
331 + rprintf(F," --delete-after receiver deletes after transfer, not during\n");
332 rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
333 - rprintf(F," --delete-after receiver deletes after transferring, not before\n");
334 rprintf(F," --ignore-errors delete even if there are I/O errors\n");
335 + rprintf(F," --force force deletion of directories even if not empty\n");
336 rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
337 rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n");
338 rprintf(F," --partial keep partially transferred files\n");
339 rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n");
340 - rprintf(F," --force force deletion of directories even if not empty\n");
341 rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
342 rprintf(F," --timeout=TIME set I/O timeout in seconds\n");
343 rprintf(F," -I, --ignore-times turn off mod time & file size quick check\n");
344 @@ -321,7 +324,6 @@ void usage(enum logcode F)
347 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
348 - OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED,
349 OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
350 OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
351 OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
352 @@ -337,11 +339,13 @@ static struct poptOption long_options[]
353 {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
354 {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
355 {"one-file-system", 'x', POPT_ARG_NONE, &one_file_system, 0, 0, 0 },
356 - {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 },
357 + {"delete", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 },
358 + {"delete-during", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 },
359 + {"delete-before", 0, POPT_ARG_NONE, &delete_before, 0, 0, 0 },
360 {"existing", 0, POPT_ARG_NONE, &only_existing, 0, 0, 0 },
361 {"ignore-existing", 0, POPT_ARG_NONE, &opt_ignore_existing, 0, 0, 0 },
362 - {"delete-after", 0, POPT_ARG_NONE, 0, OPT_DELETE_AFTER, 0, 0 },
363 - {"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED, 0, 0 },
364 + {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 },
365 + {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 },
366 {"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 },
367 {"numeric-ids", 0, POPT_ARG_NONE, &numeric_ids, 0, 0, 0 },
368 {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
369 @@ -613,16 +617,6 @@ int parse_arguments(int *argc, const cha
370 modify_window_set = 1;
373 - case OPT_DELETE_AFTER:
378 - case OPT_DELETE_EXCLUDED:
379 - delete_excluded = 1;
384 add_exclude(&exclude_list, poptGetOptArg(pc), 0);
386 @@ -851,13 +845,20 @@ int parse_arguments(int *argc, const cha
388 preserve_devices = 1;
392 + recurse = -1; /* unlimited recursion */
396 if (relative_paths < 0)
397 relative_paths = files_from? 1 : 0;
399 + if (delete_during || delete_before || delete_after)
401 + if (delete_excluded && !delete_mode)
402 + delete_mode = delete_during = 1;
404 *argv = poptGetArgs(pc);
405 *argc = count_args(*argv);
407 @@ -1156,7 +1157,9 @@ void server_options(char **args,int *arg
410 args[ac++] = "--delete-excluded";
411 - else if (delete_mode)
412 + else if (delete_before)
413 + args[ac++] = "--delete-before";
414 + else if (delete_during || delete_after)
415 args[ac++] = "--delete";
418 --- orig/receiver.c 2005-01-21 00:35:26
419 +++ receiver.c 2005-01-18 22:47:38
423 extern int delete_after;
424 -extern int max_delete;
425 extern int csum_length;
426 extern struct stats stats;
428 @@ -35,7 +34,6 @@ extern int relative_paths;
429 extern int keep_dirlinks;
430 extern int preserve_hard_links;
431 extern int preserve_perms;
432 -extern int cvs_exclude;
435 extern char *partial_dir;
436 @@ -43,9 +41,6 @@ extern char *basis_dir[];
437 extern int basis_dir_cnt;
438 extern int make_backups;
439 extern int do_progress;
440 -extern char *backup_dir;
441 -extern char *backup_suffix;
442 -extern int backup_suffix_len;
443 extern int cleanup_got_literal;
444 extern int module_id;
445 extern int ignore_errors;
446 @@ -57,70 +52,6 @@ extern int inplace;
447 extern struct exclude_list_struct server_exclude_list;
450 -static int is_backup_file(char *fn)
452 - int k = strlen(fn) - backup_suffix_len;
453 - return k > 0 && strcmp(fn+k, backup_suffix) == 0;
457 -/* This deletes any files on the receiving side that are not present
458 - * on the sending side. */
459 -void delete_files(struct file_list *flist)
461 - struct file_list *local_file_list;
463 - char *argv[1], fbuf[MAXPATHLEN];
464 - static int deletion_count;
467 - add_cvs_excludes();
469 - if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
470 - rprintf(FINFO,"IO error encountered - skipping file deletion\n");
474 - for (j = 0; j < flist->count; j++) {
475 - if (!(flist->files[j]->flags & FLAG_DEL_START)
476 - || !S_ISDIR(flist->files[j]->mode))
479 - argv[0] = f_name_to(flist->files[j], fbuf);
481 - if (!(local_file_list = send_file_list(-1, 1, argv)))
485 - rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
487 - for (i = local_file_list->count-1; i >= 0; i--) {
488 - if (max_delete && deletion_count >= max_delete)
490 - if (!local_file_list->files[i]->basename)
492 - if (flist_find(flist,local_file_list->files[i]) < 0) {
493 - char *f = f_name(local_file_list->files[i]);
494 - int mode = local_file_list->files[i]->mode;
495 - if (make_backups && (backup_dir || !is_backup_file(f))
496 - && !S_ISDIR(mode)) {
499 - rprintf(FINFO, "deleting %s\n",
503 - delete_file(f, S_ISDIR(mode)
504 - ? DEL_DIR | DEL_RECURSE : 0);
509 - flist_free(local_file_list);
515 * get_tmpname() - create a tmp filename for a given filename
517 --- orig/rsync.yo 2005-01-20 19:47:08
518 +++ rsync.yo 2005-01-19 01:05:05
519 @@ -341,14 +341,15 @@ verb(
520 --existing only update files that already exist
521 --ignore-existing ignore files that already exist on receiver
522 --delete delete files that don't exist on sender
523 + --delete-before receiver deletes before xfer, not during
524 + --delete-after receiver deletes after transfer, not during
525 --delete-excluded also delete excluded files on receiver
526 - --delete-after receiver deletes after transfer, not before
527 --ignore-errors delete even if there are I/O errors
528 + --force force deletion of dirs even if not empty
529 --max-delete=NUM don't delete more than NUM files
530 --max-size=SIZE don't transfer any file larger than SIZE
531 --partial keep partially transferred files
532 --partial-dir=DIR put a partially transferred file into DIR
533 - --force force deletion of dirs even if not empty
534 --numeric-ids don't map uid/gid values by user/group name
535 --timeout=TIME set I/O timeout in seconds
536 -I, --ignore-times turn off mod time & file size quick check
537 @@ -669,7 +670,7 @@ by the shell and rsync thus gets a reque
538 the files' parent directory. Files that are excluded from transfer are
539 excluded from being deleted unless you use --delete-excluded.
541 -This option has no effect if directory recursion is not selected.
542 +This option has no effect unless directory recursion is selected.
544 This option can be dangerous if used incorrectly! It is a very good idea
545 to run first using the --dry-run option (-n) to see what files would be
546 @@ -681,20 +682,29 @@ prevent temporary filesystem failures (s
547 sending side causing a massive deletion of files on the
548 destination. You can override this with the --ignore-errors option.
550 +By default rsync does file deletions on the receiving side during the
551 +transfer of files to try make it as efficient as possible. For other
552 +options, see --delete-before and --delte-after.
554 +dit(bf(--delete-before)) Request that the file-deletions on the receving
555 +side be done prior to starting the transfer, not incrementally as the
556 +transfer happens. Implies --delete.
558 +One reason to use --delete-before is if the filesystem is tight for space
559 +and removing extraneous files would help to make the transfer possible.
560 +However, it does introduce a delay before the start of the transfer (while
561 +the receiving side is being scanned for deletions) and this delay might
562 +cause the transfer to timeout.
564 +dit(bf(--delete-after)) Request that the file-deletions on the receving
565 +side be done after the transfer has completed, not incrementally as the
566 +transfer happens. Implies --delete.
568 dit(bf(--delete-excluded)) In addition to deleting the files on the
569 receiving side that are not on the sending side, this tells rsync to also
570 delete any files on the receiving side that are excluded (see --exclude).
573 -dit(bf(--delete-after)) By default rsync does file deletions on the
574 -receiving side before transferring files to try to ensure that there is
575 -sufficient space on the receiving filesystem. If you want to delete
576 -after transferring, use the --delete-after switch. Implies --delete.
578 -One reason to use --delete-after is to avoid a delay before the start of
579 -the transfer (while the receiving side is scanned for deletions) as this
580 -delay might cause the transfer to timeout.
582 dit(bf(--ignore-errors)) Tells --delete to go ahead and delete files
583 even when there are I/O errors.