From ce66f41791ab9e3c684a2089da28f23943d720b8 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. --- NEWS | 4 ++++ flist.c | 27 ++++++++++++++++++++------- generator.c | 7 +++++++ options.c | 8 +++++++- rsync.yo | 8 ++++++++ 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index bc44c5ec..ee0661ba 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,10 @@ Changes since 3.0.4: control over what is output. Added an extra type of --progress output using --info=progress2. + - 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). + - Added a "T" (terabyte) category to the --human-readable size suffixes. - Enhanced the --stats output: 1) to mention how many files were created diff --git a/flist.c b/flist.c index 90c0ce50..7d01c9c5 100644 --- a/flist.c +++ b/flist.c @@ -51,6 +51,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; @@ -431,7 +432,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, stats.num_symlinks++; else if (IS_DEVICE(file->mode)) stats.num_devices++; - else + else if (IS_SPECIAL(file->mode)) stats.num_specials++; xflags = 0; } @@ -1124,8 +1125,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; @@ -1166,6 +1169,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) @@ -2169,10 +2177,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 cd67f0fc..a9f3374d 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; @@ -1172,6 +1173,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 5f8018fe..51697adf 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; @@ -718,6 +719,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"); @@ -908,6 +910,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 }, @@ -1922,7 +1925,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; } @@ -2479,6 +2482,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 afa5061c..2ff224f4 100644 --- a/rsync.yo +++ b/rsync.yo @@ -375,6 +375,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 @@ -1263,6 +1264,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