[patch] add "--ignore" option
Kirkwood, Matthew
Matthew.Kirkwood at gs.com
Mon Jan 31 17:19:34 GMT 2005
Hi,
The patch below adds a "--ignore" option to rsync, which means
"--exclude-but-dont-delete-even-if-we-specified--delete-excluded".
I need this for a few tasks, the simplest of which is to have rsync resist
trying to delete NetApp filers' ".snapshot" directories.
The change is fairly simple (the boolean filter returns become tri-state),
and works for me both locally and across rsh, but it may not be "right".
I'm not wedded to the implementation, but I do need the functionality,
and I'm happy to be guided in the right direction.
I am subscribed to this list from my personal email account (copied),
but I'd be grateful to remain cc:ed at this address on any follow-up.
Cheers,
Matthew.
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/exclude.c ./exclude.c
--- ../rsync-HEAD-20050125-1221GMT.orig/exclude.c Tue Jan 25 12:21:14
2005
+++ ./exclude.c Thu Jan 27 16:52:33 2005
@@ -117,7 +117,8 @@
rprintf(FINFO, "[%s] make_filter(%.*s, %s%s)\n",
who_am_i(), (int)pat_len, pat,
mflags & MATCHFLG_PERDIR_MERGE ? "per-dir-merge"
- : mflags & MATCHFLG_INCLUDE ? "include" : "exclude",
+ : mflags & MATCHFLG_INCLUDE ? "include"
+ : mflags & MATCHFLG_IGNORE ? "ignore" : "exclude",
listp->debug_type);
}
@@ -563,9 +564,10 @@
* case we add it back in here. */
if (verbose >= 2) {
- rprintf(FINFO, "[%s] %scluding %s %s because of pattern
%s%s%s\n",
+ rprintf(FINFO, "[%s] %sing %s %s because of pattern
%s%s%s\n",
who_am_i(),
- ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex",
+ ent->match_flags & MATCHFLG_INCLUDE ? "includ"
+ : ent->match_flags & MATCHFLG_IGNORE ?
"ignor" : "exclud",
name_is_dir ? "directory" : "file", name,
ent->pattern,
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "",
type);
}
@@ -573,29 +575,34 @@
/*
- * Return -1 if file "name" is defined to be excluded by the specified
- * exclude list, 1 if it is included, and 0 if it was not matched.
+ * Return M_EXCLUDE if file "name" is defined to be excluded by the
specified
+ * exclude list, M_INCLUDE if it is included, M_IGNORE if it is flagged to
be
+ * ignored, and M_NOMATCH (aka 0) if it was not matched.
*/
-int check_filter(struct filter_list_struct *listp, char *name, int
name_is_dir)
+enum matchtype check_filter(struct filter_list_struct *listp, char *name,
int name_is_dir)
{
struct filter_struct *ent;
for (ent = listp->head; ent; ent = ent->next) {
if (ent->match_flags & MATCHFLG_PERDIR_MERGE) {
- int rc = check_filter(ent->u.mergelist, name,
- name_is_dir);
- if (rc)
+ enum matchtype rc = check_filter(ent->u.mergelist,
name,
+ name_is_dir);
+ if (rc != M_NOMATCH)
return rc;
continue;
}
if (rule_matches(name, ent, name_is_dir)) {
report_filter_result(name, ent, name_is_dir,
listp->debug_type);
- return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
+ if (ent->match_flags & MATCHFLG_INCLUDE)
+ return M_INCLUDE;
+ if (ent->match_flags & MATCHFLG_IGNORE)
+ return M_IGNORE;
+ return M_EXCLUDE;
}
}
- return 0;
+ return M_NOMATCH;
}
@@ -625,7 +632,7 @@
return NULL;
/* Figure out what kind of a filter rule "s" is pointing at. */
- if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE))) {
+ if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE |
XFLG_DEF_IGNORE))) {
char *mods = "";
switch (*s) {
case ':':
@@ -695,6 +702,8 @@
} else {
if (xflags & XFLG_DEF_INCLUDE)
mflags |= MATCHFLG_INCLUDE;
+ else if (xflags & XFLG_DEF_IGNORE)
+ mflags |= MATCHFLG_IGNORE;
if (*s == '!')
mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */
}
@@ -712,7 +721,7 @@
len = strlen(s);
if (mflags & MATCHFLG_CLEAR_LIST) {
- if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE)) &&
len) {
+ if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE |
XFLG_DEF_IGNORE)) && len) {
rprintf(FERROR,
"'!' rule has trailing characters: %s\n",
p);
exit_cleanup(RERR_SYNTAX);
@@ -794,6 +803,8 @@
continue;
if (mflags & MATCHFLG_INCLUDE)
flgs |= XFLG_DEF_INCLUDE;
+ else if (mflags & MATCHFLG_IGNORE)
+ flgs |= XFLG_DEF_IGNORE;
else if (mflags & MATCHFLG_NO_PREFIXES)
flgs |= XFLG_DEF_EXCLUDE;
add_filter_file(listp, p, flgs);
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/flist.c ./flist.c
--- ../rsync-HEAD-20050125-1221GMT.orig/flist.c Tue Jan 25 12:21:14 2005
+++ ./flist.c Thu Jan 27 17:12:25 2005
@@ -223,8 +223,9 @@
/* This function is used to check if a file should be included/excluded
* from the list of files based on its name and type etc. The value of
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
-static int is_excluded(char *fname, int is_dir, int filter_level)
+static enum matchtype is_excluded(char *fname, int is_dir, int
filter_level)
{
+ enum matchtype r;
#if 0 /* This currently never happens, so avoid a useless compare. */
if (filter_level == NO_FILTERS)
return 0;
@@ -241,14 +242,19 @@
}
}
if (server_filter_list.head
- && check_filter(&server_filter_list, fname, is_dir) < 0)
- return 1;
- if (filter_level != ALL_FILTERS)
- return 0;
+ && (r = check_filter(&server_filter_list, fname, is_dir)) !=
M_NOMATCH)
+ return r;
+// if (filter_level != ALL_FILTERS)
+// return M_NOMATCH;
if (filter_list.head
- && check_filter(&filter_list, fname, is_dir) < 0)
- return 1;
- return 0;
+ && (r = check_filter(&filter_list, fname, is_dir)) != M_NOMATCH)
{
+ if (filter_level != ALL_FILTERS) {
+ if (r == M_IGNORE)
+ return r;
+ } else
+ return r;
+ }
+ return M_NOMATCH;
}
/* used by the one_file_system code */
@@ -786,9 +792,10 @@
if (readlink_stat(thisname, &st, linkname) != 0) {
int save_errno = errno;
/* See if file is excluded before reporting an error. */
- if (filter_level != NO_FILTERS
- && is_excluded(thisname, 0, filter_level))
- return NULL;
+ if (filter_level != NO_FILTERS) {
+ if (is_excluded(thisname, 0, filter_level) ==
M_EXCLUDE)
+ return NULL;
+ }
if (save_errno == ENOENT) {
#if SUPPORT_LINKS
/* Avoid "vanished" error if symlink points nowhere.
*/
@@ -830,8 +837,12 @@
&& S_ISDIR(st.st_mode))
flags |= FLAG_MOUNT_POINT;
- if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level))
- return NULL;
+ {
+ enum matchtype m = is_excluded(thisname, S_ISDIR(st.st_mode) !=
0, filter_level);
+ if ((m == M_EXCLUDE) || (m == M_IGNORE)) {
+ return NULL;
+ }
+ }
if (lp_ignore_nonreadable(module_id)) {
#if SUPPORT_LINKS
@@ -981,7 +992,8 @@
/* f is set to -1 when calculating deletion file list */
file = make_file(fname, flist,
- f == -1 && delete_excluded? SERVER_FILTERS : ALL_FILTERS);
+ f == -1 && delete_excluded? SERVER_FILTERS : ALL_FILTERS);
+
if (!file)
return;
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/generator.c ./generator.c
--- ../rsync-HEAD-20050125-1221GMT.orig/generator.c Tue Jan 25 12:21:14
2005
+++ ./generator.c Thu Jan 27 16:54:18 2005
@@ -256,7 +256,7 @@
if (server_filter_list.head
&& check_filter(&server_filter_list, fname,
- S_ISDIR(file->mode)) < 0) {
+ S_ISDIR(file->mode)) == M_EXCLUDE) {
if (verbose) {
rprintf(FINFO, "skipping server-excluded file
\"%s\"\n",
safe_fname(fname));
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/options.c ./options.c
--- ../rsync-HEAD-20050125-1221GMT.orig/options.c Tue Jan 25 12:21:14
2005
+++ ./options.c Mon Jan 31 14:28:25 2005
@@ -307,6 +307,8 @@
rprintf(F," --exclude-from=FILE exclude patterns listed in
FILE\n");
rprintf(F," --include=PATTERN don't exclude files matching
PATTERN\n");
rprintf(F," --include-from=FILE don't exclude patterns listed in
FILE\n");
+ rprintf(F," --ignore=PATTERN don't do anything with files
matching PATTERN\n");
+ rprintf(F," --ignore-from=FILE don't do anything with patterns
listed in FILE\n");
rprintf(F," --files-from=FILE read FILE for list of source-file
names\n");
rprintf(F," -0, --from0 all *-from file lists are
delimited by nulls\n");
rprintf(F," --version print version number\n");
@@ -336,6 +338,7 @@
OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
+ OPT_IGNORE, OPT_IGNORE_FROM,
OPT_REFUSED_BASE = 9000};
static struct poptOption long_options[] = {
@@ -359,8 +362,10 @@
{"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
{"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
{"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 },
+ {"ignore" , 0, POPT_ARG_STRING, 0, OPT_IGNORE, 0, 0 },
{"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 },
{"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 },
+ {"ignore-from", 0, POPT_ARG_STRING, 0, OPT_IGNORE_FROM, 0, 0 },
{"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 },
{"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
{"backup", 'b', POPT_ARG_NONE, &make_backups, 0, 0, 0 },
@@ -656,20 +661,26 @@
XFLG_DEF_INCLUDE);
break;
+ case OPT_IGNORE:
+ add_filter(&filter_list, poptGetOptArg(pc),
+ XFLG_DEF_IGNORE);
+ break;
+
case OPT_EXCLUDE_FROM:
case OPT_INCLUDE_FROM:
+ case OPT_IGNORE_FROM:
arg = poptGetOptArg(pc);
if (sanitize_paths)
arg = sanitize_path(NULL, arg, NULL, 0);
if (server_filter_list.head) {
char *cp = (char *)arg;
clean_fname(cp, 1);
- if (check_filter(&server_filter_list, cp, 0)
< 0)
+ if (check_filter(&server_filter_list, cp, 0)
== M_EXCLUDE)
goto options_rejected;
}
add_filter_file(&filter_list, arg, XFLG_FATAL_ERRORS
- | (opt == OPT_INCLUDE_FROM ?
XFLG_DEF_INCLUDE
- :
XFLG_DEF_EXCLUDE));
+ | (opt == OPT_INCLUDE_FROM ?
XFLG_DEF_INCLUDE :
+ opt == OPT_EXCLUDE_FROM ?
XFLG_DEF_EXCLUDE : XFLG_DEF_IGNORE));
break;
case 'h':
@@ -926,28 +937,28 @@
int i;
if (tmpdir) {
clean_fname(tmpdir, 1);
- if (check_filter(elp, tmpdir, 1) < 0)
+ if (check_filter(elp, tmpdir, 1) == M_EXCLUDE)
goto options_rejected;
}
if (partial_dir) {
clean_fname(partial_dir, 1);
- if (check_filter(elp, partial_dir, 1) < 0)
+ if (check_filter(elp, partial_dir, 1) == M_EXCLUDE)
goto options_rejected;
}
for (i = 0; i < basis_dir_cnt; i++) {
clean_fname(basis_dir[i], 1);
- if (check_filter(elp, basis_dir[i], 1) < 0)
+ if (check_filter(elp, basis_dir[i], 1) == M_EXCLUDE)
goto options_rejected;
}
if (backup_dir) {
clean_fname(backup_dir, 1);
- if (check_filter(elp, backup_dir, 1) < 0)
+ if (check_filter(elp, backup_dir, 1) == M_EXCLUDE)
goto options_rejected;
}
}
if (server_filter_list.head && files_from) {
clean_fname(files_from, 1);
- if (check_filter(&server_filter_list, files_from, 0) < 0) {
+ if (check_filter(&server_filter_list, files_from, 0) ==
M_EXCLUDE) {
options_rejected:
snprintf(err_buf, sizeof err_buf,
"Your options have been rejected by the
server.\n");
@@ -1218,6 +1229,24 @@
args[ac++] = "--force";
}
+ {
+ struct filter_struct *lp;
+ for(lp = filter_list.head; lp; lp = lp->next) {
+ if(lp->match_flags & MATCHFLG_IGNORE) {
+ if (asprintf(&arg, "--ignore='%s'",
lp->pattern) < 0)
+ goto oom;
+ args[ac++] = arg;
+ }
+ }
+ for(lp = server_filter_list.head; lp; lp = lp->next) {
+ if(lp->match_flags & MATCHFLG_IGNORE) {
+ if (asprintf(&arg, "--ignore='%s'",
lp->pattern) < 0)
+ goto oom;
+ args[ac++] = arg;
+ }
+ }
+ }
+
if (size_only)
args[ac++] = "--size-only";
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/proto.h ./proto.h
--- ../rsync-HEAD-20050125-1221GMT.orig/proto.h Tue Jan 25 12:21:14 2005
+++ ./proto.h Thu Jan 27 16:54:02 2005
@@ -47,7 +47,8 @@
void set_filter_dir(const char *dir, unsigned int dirlen);
void *push_local_filters(const char *dir, unsigned int dirlen);
void pop_local_filters(void *mem);
-int check_filter(struct filter_list_struct *listp, char *name, int
name_is_dir);
+enum matchtype { M_NOMATCH=0, M_INCLUDE, M_EXCLUDE, M_IGNORE };
+enum matchtype check_filter(struct filter_list_struct *listp, char *name,
int name_is_dir);
void add_filter(struct filter_list_struct *listp, const char *pattern,
int xflags);
void add_filter_file(struct filter_list_struct *listp, const char *fname,
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/receiver.c ./receiver.c
--- ../rsync-HEAD-20050125-1221GMT.orig/receiver.c Tue Jan 25 12:21:14
2005
+++ ./receiver.c Thu Jan 27 16:24:26 2005
@@ -362,7 +362,7 @@
if (server_filter_list.head
&& check_filter(&server_filter_list, fname,
- S_ISDIR(file->mode)) < 0) {
+ S_ISDIR(file->mode)) == M_EXCLUDE) {
rprintf(FERROR, "attempt to hack rsync failed.\n");
exit_cleanup(RERR_PROTOCOL);
}
@@ -556,3 +556,4 @@
return 0;
}
+
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/rsync.h ./rsync.h
--- ../rsync-HEAD-20050125-1221GMT.orig/rsync.h Tue Jan 25 12:21:14 2005
+++ ./rsync.h Thu Jan 27 14:47:03 2005
@@ -114,6 +114,7 @@
#define XFLG_DIRECTORY (1<<4)
#define XFLG_NO_PREFIXES (1<<5)
#define XFLG_ABS_PATH (1<<6)
+#define XFLG_DEF_IGNORE (1<<7)
#define PERMS_REPORT (1<<0)
#define PERMS_SKIP_MTIME (1<<1)
@@ -517,6 +518,7 @@
#define MATCHFLG_PERDIR_MERGE (1<<11)/* merge-file is searched per-dir */
#define MATCHFLG_EXCLUDE_SELF (1<<12)/* merge-file name should be excluded
*/
#define MATCHFLG_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */
+#define MATCHFLG_IGNORE (1<<14)/* pretend that we didn't
even see this */
struct filter_struct {
struct filter_struct *next;
char *pattern;
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/rsync.yo ./rsync.yo
--- ../rsync-HEAD-20050125-1221GMT.orig/rsync.yo Tue Jan 25 03:17:00
2005
+++ ./rsync.yo Fri Jan 28 11:14:37 2005
@@ -372,6 +372,8 @@
--exclude-from=FILE exclude patterns listed in FILE
--include=PATTERN don't exclude files matching PATTERN
--include-from=FILE don't exclude patterns listed in FILE
+ --ignore=PATTERN don't do anything with files matching PATTERN
+ --ignore-from=FILE don't do anything with patterns listed in FILE
--files-from=FILE read FILE for list of source-file names
-0 --from0 all file lists are delimited by nulls
--version print version number
@@ -838,6 +840,16 @@
from a file.
If em(FILE) is "-" the list will be read from standard input.
+dit(bf(--ignore=PATTERN)) This option is a simplified form of the
+--filter option that defaults to an ignore rule and does not allow
+the full rule-parsing syntax of normal filter rules.
+
+See the FILTER RULES section for detailed information on this option.
+
+dit(bf(--ignore-from=FILE)) This specifies a list of ignore patterns
+from a file.
+If em(FILE) is "-" the list will be read from standard input.
+
dit(bf(--files-from=FILE)) Using this option allows you to specify the
exact list of files to transfer (as read from the specified FILE or "-"
for standard input). It also tweaks the default behavior of rsync to make
@@ -877,8 +889,8 @@
dit(bf(-0, --from0)) This tells rsync that the filenames it reads from a
file are terminated by a null ('\0') character, not a NL, CR, or CR+LF.
-This affects --exclude-from, --include-from, --files-from, and any
-merged files specified in a --filter rule.
+This affects --exclude-from, --include-from, --ignore-from, --files-from,
+and any merged files specified in a --filter rule.
It does not affect --cvs-exclude (since all names read from a .cvsignore
file are split on whitespace).
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/t_stub.c ./t_stub.c
--- ../rsync-HEAD-20050125-1221GMT.orig/t_stub.c Tue Jan 25 12:21:14
2005
+++ ./t_stub.c Thu Jan 27 13:52:08 2005
@@ -56,12 +56,12 @@
exit(code);
}
- int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(char
*name),
+ enum matchtype check_filter(UNUSED(struct filter_list_struct *listp),
UNUSED(char *name),
UNUSED(int name_is_dir))
{
/* This function doesn't really get called in this test context, so
- * just return 0. */
- return 0;
+ * just return M_NOMATCH. */
+ return M_NOMATCH;
}
char *lp_name(UNUSED(int mod))
diff -ur ../rsync-HEAD-20050125-1221GMT.orig/util.c ./util.c
--- ../rsync-HEAD-20050125-1221GMT.orig/util.c Tue Jan 25 12:21:14 2005
+++ ./util.c Thu Jan 27 13:51:19 2005
@@ -486,7 +486,7 @@
if (server_filter_list.head) {
for (s = arg; (s = strchr(s, '/')) != NULL; ) {
*s = '\0';
- if (check_filter(&server_filter_list, arg, 1) < 0) {
+ if (check_filter(&server_filter_list, arg, 1) ==
M_EXCLUDE) {
/* We must leave arg truncated! */
return 1;
}
@@ -967,7 +967,7 @@
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
return NULL;
if (server_filter_list.head
- && check_filter(&server_filter_list, partial_fname, 0) < 0)
+ && check_filter(&server_filter_list, partial_fname, 0) ==
M_EXCLUDE)
return NULL;
return partial_fname;
More information about the rsync
mailing list