From f6d530b3fc8d95427a93d51b49ef20f9e3ee5054 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 28 Feb 2009 09:22:51 -0800 Subject: [PATCH] Added the --delete-missing-args option to delete specified files on the receiver that don't exist on the sender. Backported to rsync v3.0.6 by Matt McCutchen, 2009-11-12. --- NEWS | 4 ++++ flist.c | 25 +++++++++++++++++++------ generator.c | 7 +++++++ options.c | 8 +++++++- rsync.yo | 8 ++++++++ 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 5740b109..1ad15b7e 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ Changes since 3.0.5: - The sender now skips a (bogus) symlink that has a 0-length value, which avoids a transfer error in the receiver. + - Added the --delete-missing option to delete user-specified files on the + receiver that are missing on the sender (normally the absence of user- + specified files generates an error). + - Fixed a case where the sender could die with a tag-0 error if there was an I/O during the sending of the file list. diff --git a/flist.c b/flist.c index 83effc08..c0550ecb 100644 --- a/flist.c +++ b/flist.c @@ -52,6 +52,7 @@ extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_specials; +extern int delete_missing_args; extern int uid_ndx; extern int gid_ndx; extern int eol_nulls; @@ -1097,8 +1098,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (sanitize_paths) sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); - if (stp && S_ISDIR(stp->st_mode)) { - st = *stp; /* Needed for "symlink/." with --relative. */ + if (stp && (S_ISDIR(stp->st_mode) || stp->st_mode == 0)) { + /* This is needed to handle a "symlink/." with a --relative + * dir, or a request to delete a specific file. */ + st = *stp; *linkname = '\0'; /* make IBM code checker happy */ } else if (readlink_stat(thisname, &st, linkname) != 0) { int save_errno = errno; @@ -1139,6 +1142,11 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, full_fname(thisname)); } return NULL; + } else if (st.st_mode == 0) { + io_error |= IOERR_GENERAL; + rprintf(FINFO, "skipping file with bogus (zero) st_mode: %s\n", + full_fname(thisname)); + return NULL; } if (filter_level == NO_FILTERS) @@ -2133,10 +2141,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0 || (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode))) || (relative_paths && path_is_daemon_excluded(fbuf, 1))) { - io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, errno, "link_stat %s failed", - full_fname(fbuf)); - continue; + if (errno == ENOENT && delete_missing_args) { + /* Rsync will treat a mode of 0 as deleted. */ + memset(&st, 0, sizeof st); + } else { + io_error |= IOERR_GENERAL; + rsyserr(FERROR_XFER, errno, "link_stat %s failed", + full_fname(fbuf)); + continue; + } } /* A dot-dir should not be excluded! */ diff --git a/generator.c b/generator.c index fb832af2..2ffd88a4 100644 --- a/generator.c +++ b/generator.c @@ -50,6 +50,7 @@ extern int delete_mode; extern int delete_before; extern int delete_during; extern int delete_after; +extern int delete_missing_args; extern int msgdone_cnt; extern int ignore_errors; extern int remove_source_files; @@ -1369,6 +1370,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, stat_errno = errno; } + if (delete_missing_args && file->mode == 0) { + if (statret == 0) + delete_item(fname, sx.st.st_mode, del_opts); + return; + } + if (ignore_non_existing > 0 && statret == -1 && stat_errno == ENOENT) { if (is_dir) { if (is_dir < 0) diff --git a/options.c b/options.c index b6f7bae4..34741a60 100644 --- a/options.c +++ b/options.c @@ -69,6 +69,7 @@ int delete_during = 0; int delete_before = 0; int delete_after = 0; int delete_excluded = 0; +int delete_missing_args = 0; int remove_source_files = 0; int one_file_system = 0; int protocol_version = PROTOCOL_VERSION; @@ -375,6 +376,7 @@ void usage(enum logcode F) rprintf(F," --delete-delay find deletions during, delete after\n"); rprintf(F," --delete-after receiver deletes after transfer, not during\n"); rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); + rprintf(F," --delete-missing-args receiver deletes each missing source arg\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); rprintf(F," --force force deletion of directories even if not empty\n"); rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); @@ -555,6 +557,7 @@ static struct poptOption long_options[] = { {"delete-delay", 0, POPT_ARG_VAL, &delete_during, 2, 0, 0 }, {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 }, {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 }, + {"delete-missing-args",0,POPT_ARG_NONE, &delete_missing_args, 0, 0, 0 }, {"remove-sent-files",0, POPT_ARG_VAL, &remove_source_files, 2, 0, 0 }, /* deprecated */ {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 }, {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, @@ -1436,7 +1439,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; } - if (delete_mode && refused_delete) { + if (refused_delete && (delete_mode || delete_missing_args)) { create_refuse_error(refused_delete); return 0; } @@ -1975,6 +1978,9 @@ void server_options(char **args, int *argc_p) } } + if (delete_missing_args) + args[ac++] = "--delete-missing-args"; + if (modify_window_set) { if (asprintf(&arg, "--modify-window=%d", modify_window) < 0) goto oom; diff --git a/rsync.yo b/rsync.yo index b4a6df86..6d3d3c9d 100644 --- a/rsync.yo +++ b/rsync.yo @@ -372,6 +372,7 @@ to the detailed description below for a complete description. verb( --delete-delay find deletions during, delete after --delete-after receiver deletes after transfer, not before --delete-excluded also delete excluded files from dest dirs + --delete-missing-args receiver deletes each missing source arg --ignore-errors delete even if there are I/O errors --force force deletion of dirs even if not empty --max-delete=NUM don't delete more than NUM files @@ -1213,6 +1214,13 @@ this way on the receiver, and for a way to protect files from bf(--delete-excluded). See bf(--delete) (which is implied) for more details on file-deletion. +dit(bf(--delete-missing-args)) Any source arg that is found to me missing is +treated as a request to delete the file by the receiver rather than the sender +generating a missing-file error. Does not affect vanished files discovered +through recursive scanning of directories, just the args mentioned on the +command-line or in the bf(--files-from) list. Can be used with or without any +other type of delete processing. + dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files even when there are I/O errors. -- 2.34.1