- Fixed some deletion problems where a non-empty directory was
[rsync/rsync-patches.git] / delete-during.diff
CommitLineData
91cf5188
WD
1This patch creates a --delete-during functionality that deletes files on
2the receiving side incrementally as we traverse the directories. It also
3defines a --delete-before option, for the traditional way that --delete
4has worked before.
5
6This patch chooses to make --delete into a synonym for --delete-during, and
7hide --delete-during, but that can be easily changed if we want to preserve
8the old functionality (and indeed, the support for popt aliases that is now
9in CVS will let the user easily choose which method they'd like --delete to
10invoke, either personally or site-wide, without having to recompile rsync).
11
b5bbf19c
WD
12--- orig/flist.c 2005-01-20 23:57:44
13+++ flist.c 2005-01-20 23:42:36
14@@ -35,6 +35,7 @@ extern int am_root;
15 extern int am_server;
16 extern int am_daemon;
17 extern int am_sender;
18+extern int delete_during;
19 extern int always_checksum;
20 extern int module_id;
21 extern int ignore_errors;
22@@ -45,6 +46,8 @@ extern int cvs_exclude;
91cf5188
WD
23 extern int recurse;
24 extern int keep_dirs;
25 extern char curr_dir[MAXPATHLEN];
26+extern char *backup_dir;
27+extern char *backup_suffix;
28 extern int filesfrom_fd;
29
30 extern int one_file_system;
b5bbf19c 31@@ -57,11 +60,14 @@ extern int preserve_uid;
91cf5188
WD
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;
44 extern int list_only;
45
b5bbf19c 46@@ -1044,7 +1050,8 @@ static void send_directory(int f, struct
91cf5188
WD
47 || (dname[1] == '.' && dname[2] == '\0')))
48 continue;
49 if (strlcpy(p, dname, MAXPATHLEN - offset) < MAXPATHLEN - offset) {
50- send_file_name(f, flist, fname, recurse, 0);
51+ int do_subdirs = recurse >= 1 ? recurse-- : recurse;
52+ send_file_name(f, flist, fname, do_subdirs, 0);
53 } else {
54 io_error |= IOERR_GENERAL;
55 rprintf(FINFO,
b5bbf19c 56@@ -1102,6 +1109,7 @@ struct file_list *send_file_list(int f,
91cf5188
WD
57 while (1) {
58 char fname2[MAXPATHLEN];
59 char *fname = fname2;
60+ int do_subdirs;
61
62 if (use_ff_fd) {
63 if (read_filesfrom_line(filesfrom_fd, fname) == 0)
b5bbf19c 64@@ -1143,7 +1151,7 @@ struct file_list *send_file_list(int f,
91cf5188
WD
65 dir = NULL;
66 olddir[0] = '\0';
67
68- if (!relative_paths) {
69+ if (!relative_paths && recurse <= 0) {
70 p = strrchr(fname, '/');
71 if (p) {
72 *p = 0;
b5bbf19c 73@@ -1212,7 +1220,8 @@ struct file_list *send_file_list(int f,
91cf5188
WD
74 if (one_file_system)
75 set_filesystem(fname);
76
77- send_file_name(f, flist, fname, recurse, XMIT_TOP_DIR);
78+ do_subdirs = recurse >= 1 ? recurse-- : recurse;
79+ send_file_name(f, flist, fname, do_subdirs, XMIT_TOP_DIR);
80
81 if (olddir[0]) {
82 flist_dir = NULL;
b5bbf19c 83@@ -1634,3 +1643,91 @@ char *f_name(struct file_struct *f)
91cf5188
WD
84
85 return f_name_to(f, names[n]);
86 }
87+
91cf5188
WD
88+static int is_backup_file(char *fn)
89+{
90+ int k = strlen(fn) - backup_suffix_len;
91+ return k > 0 && strcmp(fn+k, backup_suffix) == 0;
92+}
93+
94+void delete_in_dir(struct file_list *flist, char *fname, int do_subdirs)
95+{
96+ static int deletion_count = 0;
97+ struct file_list *del_flist;
98+ int save_recurse = recurse;
99+ int save_keep_dirs = keep_dirs;
100+ int save_implied_dirs = implied_dirs;
101+ char *argv[1];
b5bbf19c 102+ int i, j, mode;
91cf5188
WD
103+
104+ if (max_delete && deletion_count >= max_delete)
105+ return;
106+
107+ if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
108+ rprintf(FINFO, "IO error encountered - skipping file deletion\n");
109+ max_delete = -1; /* avoid duplicating the above warning */
110+ return;
111+ }
112+
113+ recurse = do_subdirs ? -1 : 1;
114+ keep_dirs = 1;
115+ implied_dirs = 0;
116+
117+ argv[0] = fname;
118+ del_flist = send_file_list(-1, 1, argv);
119+
120+ implied_dirs = save_implied_dirs;
121+ keep_dirs = save_keep_dirs;
122+ recurse = save_recurse;
123+
124+ if (!del_flist)
125+ return;
126+
127+ if (verbose > 1)
128+ rprintf(FINFO, "deleting in %s\n", safe_fname(fname));
129+
130+ for (i = del_flist->count-1; i >= 0; i--) {
131+ if (max_delete && deletion_count >= max_delete)
132+ break;
133+ if (!del_flist->files[i]->basename)
134+ continue;
b5bbf19c
WD
135+ mode = del_flist->files[i]->mode;
136+ if ((j = flist_find(flist, del_flist->files[i])) < 0
137+ || (delete_during && S_ISDIR(mode)
138+ && !S_ISDIR(flist->files[j]->mode))) {
91cf5188 139+ char *f = f_name(del_flist->files[i]);
91cf5188
WD
140+ if (make_backups && (backup_dir || !is_backup_file(f))
141+ && !S_ISDIR(mode)) {
142+ make_backup(f);
143+ if (verbose) {
144+ rprintf(FINFO, "deleting %s\n",
145+ safe_fname(f));
146+ }
65a73542
WD
147+ } else {
148+ delete_file(f, S_ISDIR(mode)
b5bbf19c 149+ ? DEL_DIR | DEL_RECURSE : 0);
65a73542 150+ }
91cf5188
WD
151+ deletion_count++;
152+ }
153+ }
154+ flist_free(del_flist);
155+}
156+
157+/* This deletes any files on the receiving side that are not present on the
158+ * sending side. This is used by --delete-before and --delete-after. */
159+void delete_files(struct file_list *flist)
160+{
161+ char fbuf[MAXPATHLEN];
162+ int j;
163+
164+ if (cvs_exclude)
165+ add_cvs_excludes();
166+
167+ for (j = 0; j < flist->count; j++) {
168+ if (!(flist->files[j]->flags & FLAG_TOP_DIR)
169+ || !S_ISDIR(flist->files[j]->mode))
170+ continue;
171+
172+ delete_in_dir(flist, f_name_to(flist->files[j], fbuf), recurse);
173+ }
174+}
b5bbf19c
WD
175--- orig/generator.c 2005-01-20 23:05:34
176+++ generator.c 2005-01-20 23:08:38
91cf5188
WD
177@@ -34,6 +34,8 @@ extern int preserve_hard_links;
178 extern int preserve_perms;
179 extern int preserve_uid;
180 extern int preserve_gid;
181+extern int delete_during;
182+extern int cvs_exclude;
183 extern int update_only;
184 extern int opt_ignore_existing;
185 extern int inplace;
65a73542 186@@ -233,7 +235,8 @@ static void generate_and_send_sums(int f
91cf5188
WD
187 * @note This comment was added later by mbp who was trying to work it
188 * out. It might be wrong.
189 */
190-static void recv_generator(char *fname, struct file_struct *file, int i,
191+static void recv_generator(char *fname, struct file_list *flist,
192+ struct file_struct *file, int i,
193 int f_out, int f_out_name)
194 {
195 int fd = -1, f_copy = -1;
b5bbf19c 196@@ -308,6 +311,8 @@ static void recv_generator(char *fname,
91cf5188
WD
197 }
198 /* f_out is set to -1 when doing final directory-permission
199 * and modification-time repair. */
200+ if (delete_during && f_out != -1)
201+ delete_in_dir(flist, fname, 0);
202 if (set_perms(fname, file, statret ? NULL : &st, 0)
203 && verbose && f_out != -1)
204 rprintf(FINFO, "%s/\n", safe_fname(fname));
b5bbf19c 205@@ -618,6 +623,9 @@ void generate_files(int f_out, struct fi
91cf5188
WD
206 : "delta transmission enabled\n");
207 }
208
209+ if (delete_during && cvs_exclude)
210+ add_cvs_excludes();
211+
212 /* we expect to just sit around now, so don't exit on a
213 timeout. If we really get a timeout then the other process should
214 exit */
b5bbf19c 215@@ -641,7 +649,7 @@ void generate_files(int f_out, struct fi
91cf5188
WD
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++;
b5bbf19c 224@@ -658,7 +666,7 @@ void generate_files(int f_out, struct fi
91cf5188
WD
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++;
b5bbf19c 233@@ -680,7 +688,7 @@ void generate_files(int f_out, struct fi
91cf5188
WD
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-17 23:11:45
243+++ main.c 2005-01-18 21:56:05
244@@ -33,6 +33,7 @@ extern int verbose;
245 extern int blocking_io;
246 extern int cvs_exclude;
247 extern int delete_mode;
248+extern int delete_before;
249 extern int delete_excluded;
250 extern int delete_after;
251 extern int daemon_over_rsh;
252@@ -473,9 +474,9 @@ static int do_recv(int f_in,int f_out,st
253 if (preserve_hard_links)
254 init_hard_links(flist);
255
256- if (!delete_after) {
257+ if (delete_before) {
258 /* I moved this here from recv_files() to prevent a race condition */
259- if (recurse && delete_mode && !local_name && flist->count > 0)
260+ if (recurse && !local_name && flist->count > 0)
261 delete_files(flist);
262 }
263
b5bbf19c
WD
264--- orig/options.c 2005-01-20 23:05:34
265+++ options.c 2005-01-20 23:06:33
91cf5188
WD
266@@ -54,6 +54,8 @@ int dry_run = 0;
267 int local_server = 0;
268 int ignore_times = 0;
269 int delete_mode = 0;
270+int delete_during = 0;
271+int delete_before = 0;
272 int delete_excluded = 0;
273 int one_file_system = 0;
274 int protocol_version = PROTOCOL_VERSION;
275@@ -272,14 +274,15 @@ void usage(enum logcode F)
276 rprintf(F," --existing only update files that already exist\n");
277 rprintf(F," --ignore-existing ignore files that already exist on receiving side\n");
278 rprintf(F," --delete delete files that don't exist on the sending side\n");
919b037d
WD
279+ rprintf(F," --delete-before receiver deletes before transfer, not during\n");
280+ rprintf(F," --delete-after receiver deletes after transfer, not during\n");
91cf5188
WD
281 rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
282- rprintf(F," --delete-after receiver deletes after transferring, not before\n");
283 rprintf(F," --ignore-errors delete even if there are I/O errors\n");
284+ rprintf(F," --force force deletion of directories even if not empty\n");
285 rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
286 rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n");
287 rprintf(F," --partial keep partially transferred files\n");
288 rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n");
289- rprintf(F," --force force deletion of directories even if not empty\n");
290 rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
291 rprintf(F," --timeout=TIME set I/O timeout in seconds\n");
292 rprintf(F," -I, --ignore-times turn off mod time & file size quick check\n");
b5bbf19c 293@@ -321,7 +324,6 @@ void usage(enum logcode F)
91cf5188
WD
294 }
295
b5bbf19c 296 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
91cf5188 297- OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED,
91cf5188
WD
298 OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
299 OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
300 OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
b5bbf19c 301@@ -337,11 +339,13 @@ static struct poptOption long_options[]
91cf5188
WD
302 {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
303 {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
304 {"one-file-system", 'x', POPT_ARG_NONE, &one_file_system, 0, 0, 0 },
305- {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 },
b5bbf19c
WD
306+ {"delete", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 },
307+ {"delete-during", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 },
308+ {"delete-before", 0, POPT_ARG_NONE, &delete_before, 0, 0, 0 },
91cf5188
WD
309 {"existing", 0, POPT_ARG_NONE, &only_existing, 0, 0, 0 },
310 {"ignore-existing", 0, POPT_ARG_NONE, &opt_ignore_existing, 0, 0, 0 },
311- {"delete-after", 0, POPT_ARG_NONE, 0, OPT_DELETE_AFTER, 0, 0 },
312- {"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED, 0, 0 },
b5bbf19c
WD
313+ {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 },
314+ {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 },
91cf5188
WD
315 {"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 },
316 {"numeric-ids", 0, POPT_ARG_NONE, &numeric_ids, 0, 0, 0 },
317 {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
b5bbf19c 318@@ -613,16 +617,6 @@ int parse_arguments(int *argc, const cha
91cf5188
WD
319 modify_window_set = 1;
320 break;
321
322- case OPT_DELETE_AFTER:
323- delete_after = 1;
324- delete_mode = 1;
325- break;
326-
327- case OPT_DELETE_EXCLUDED:
328- delete_excluded = 1;
b5bbf19c
WD
329- delete_mode = 1;
330- break;
331-
332 case OPT_EXCLUDE:
333 add_exclude(&exclude_list, poptGetOptArg(pc), 0);
91cf5188 334 break;
b5bbf19c 335@@ -851,13 +845,20 @@ int parse_arguments(int *argc, const cha
91cf5188
WD
336 preserve_uid = 1;
337 preserve_devices = 1;
338 }
339+
340 if (recurse) {
341+ recurse = -1; /* unlimited recursion */
342 keep_dirs = 1;
343 }
344
345 if (relative_paths < 0)
346 relative_paths = files_from? 1 : 0;
347
b5bbf19c
WD
348+ if (delete_during || delete_before || delete_after)
349+ delete_mode = 1;
350+ if (delete_excluded && !delete_mode)
351+ delete_mode = delete_during = 1;
91cf5188
WD
352+
353 *argv = poptGetArgs(pc);
354 *argc = count_args(*argv);
355
b5bbf19c 356@@ -1156,7 +1157,9 @@ void server_options(char **args,int *arg
91cf5188
WD
357 if (am_sender) {
358 if (delete_excluded)
359 args[ac++] = "--delete-excluded";
360- else if (delete_mode)
361+ else if (delete_before)
362+ args[ac++] = "--delete-before";
363+ else if (delete_during || delete_after)
364 args[ac++] = "--delete";
365
366 if (delete_after)
b5bbf19c 367--- orig/receiver.c 2005-01-20 23:52:09
91cf5188
WD
368+++ receiver.c 2005-01-18 22:47:38
369@@ -23,7 +23,6 @@
370 extern int verbose;
371 extern int recurse;
372 extern int delete_after;
373-extern int max_delete;
374 extern int csum_length;
375 extern struct stats stats;
376 extern int dry_run;
377@@ -35,7 +34,6 @@ extern int relative_paths;
378 extern int keep_dirlinks;
379 extern int preserve_hard_links;
380 extern int preserve_perms;
381-extern int cvs_exclude;
382 extern int io_error;
383 extern char *tmpdir;
384 extern char *partial_dir;
385@@ -43,9 +41,6 @@ extern char *basis_dir[];
386 extern int basis_dir_cnt;
387 extern int make_backups;
388 extern int do_progress;
389-extern char *backup_dir;
390-extern char *backup_suffix;
391-extern int backup_suffix_len;
392 extern int cleanup_got_literal;
393 extern int module_id;
394 extern int ignore_errors;
65a73542 395@@ -57,70 +52,6 @@ extern int inplace;
91cf5188
WD
396 extern struct exclude_list_struct server_exclude_list;
397
398
91cf5188
WD
399-static int is_backup_file(char *fn)
400-{
401- int k = strlen(fn) - backup_suffix_len;
402- return k > 0 && strcmp(fn+k, backup_suffix) == 0;
403-}
404-
405-
406-/* This deletes any files on the receiving side that are not present
407- * on the sending side. */
408-void delete_files(struct file_list *flist)
409-{
410- struct file_list *local_file_list;
411- int i, j;
412- char *argv[1], fbuf[MAXPATHLEN];
413- static int deletion_count;
414-
415- if (cvs_exclude)
416- add_cvs_excludes();
417-
418- if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
419- rprintf(FINFO,"IO error encountered - skipping file deletion\n");
420- return;
421- }
422-
423- for (j = 0; j < flist->count; j++) {
424- if (!(flist->files[j]->flags & FLAG_TOP_DIR)
425- || !S_ISDIR(flist->files[j]->mode))
426- continue;
427-
428- argv[0] = f_name_to(flist->files[j], fbuf);
429-
430- if (!(local_file_list = send_file_list(-1, 1, argv)))
431- continue;
432-
433- if (verbose > 1)
434- rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
435-
436- for (i = local_file_list->count-1; i >= 0; i--) {
437- if (max_delete && deletion_count >= max_delete)
438- break;
439- if (!local_file_list->files[i]->basename)
440- continue;
441- if (flist_find(flist,local_file_list->files[i]) < 0) {
442- char *f = f_name(local_file_list->files[i]);
443- int mode = local_file_list->files[i]->mode;
444- if (make_backups && (backup_dir || !is_backup_file(f))
445- && !S_ISDIR(mode)) {
446- make_backup(f);
447- if (verbose) {
448- rprintf(FINFO, "deleting %s\n",
449- safe_fname(f));
450- }
65a73542
WD
451- } else {
452- delete_file(f, S_ISDIR(mode)
b5bbf19c 453- ? DEL_DIR | DEL_RECURSE : 0);
65a73542 454- }
91cf5188
WD
455- deletion_count++;
456- }
457- }
458- flist_free(local_file_list);
459- }
460-}
461-
462-
463 /*
464 * get_tmpname() - create a tmp filename for a given filename
465 *
b5bbf19c
WD
466--- orig/rsync.yo 2005-01-20 19:47:08
467+++ rsync.yo 2005-01-19 01:05:05
91cf5188
WD
468@@ -341,14 +341,15 @@ verb(
469 --existing only update files that already exist
470 --ignore-existing ignore files that already exist on receiver
471 --delete delete files that don't exist on sender
472+ --delete-before receiver deletes before xfer, not during
473+ --delete-after receiver deletes after transfer, not during
474 --delete-excluded also delete excluded files on receiver
475- --delete-after receiver deletes after transfer, not before
476 --ignore-errors delete even if there are I/O errors
477+ --force force deletion of dirs even if not empty
478 --max-delete=NUM don't delete more than NUM files
479 --max-size=SIZE don't transfer any file larger than SIZE
480 --partial keep partially transferred files
481 --partial-dir=DIR put a partially transferred file into DIR
482- --force force deletion of dirs even if not empty
483 --numeric-ids don't map uid/gid values by user/group name
484 --timeout=TIME set I/O timeout in seconds
485 -I, --ignore-times turn off mod time & file size quick check
486@@ -669,7 +670,7 @@ by the shell and rsync thus gets a reque
487 the files' parent directory. Files that are excluded from transfer are
488 excluded from being deleted unless you use --delete-excluded.
489
490-This option has no effect if directory recursion is not selected.
491+This option has no effect unless directory recursion is selected.
492
493 This option can be dangerous if used incorrectly! It is a very good idea
494 to run first using the --dry-run option (-n) to see what files would be
495@@ -681,20 +682,29 @@ prevent temporary filesystem failures (s
496 sending side causing a massive deletion of files on the
497 destination. You can override this with the --ignore-errors option.
498
499+By default rsync does file deletions on the receiving side during the
500+transfer of files to try make it as efficient as possible. For other
501+options, see --delete-before and --delte-after.
502+
503+dit(bf(--delete-before)) Request that the file-deletions on the receving
504+side be done prior to starting the transfer, not incrementally as the
505+transfer happens. Implies --delete.
506+
507+One reason to use --delete-before is if the filesystem is tight for space
508+and removing extraneous files would help to make the transfer possible.
509+However, it does introduce a delay before the start of the transfer (while
510+the receiving side is being scanned for deletions) and this delay might
511+cause the transfer to timeout.
512+
513+dit(bf(--delete-after)) Request that the file-deletions on the receving
514+side be done after the transfer has completed, not incrementally as the
515+transfer happens. Implies --delete.
516+
517 dit(bf(--delete-excluded)) In addition to deleting the files on the
518 receiving side that are not on the sending side, this tells rsync to also
519 delete any files on the receiving side that are excluded (see --exclude).
520 Implies --delete.
521
522-dit(bf(--delete-after)) By default rsync does file deletions on the
523-receiving side before transferring files to try to ensure that there is
524-sufficient space on the receiving filesystem. If you want to delete
525-after transferring, use the --delete-after switch. Implies --delete.
526-
527-One reason to use --delete-after is to avoid a delay before the start of
528-the transfer (while the receiving side is scanned for deletions) as this
529-delay might cause the transfer to timeout.
530-
531 dit(bf(--ignore-errors)) Tells --delete to go ahead and delete files
532 even when there are I/O errors.
533