Added an mflags arg to get_filter_tok(), add_filter_file(), and

add_filter().  This made for less flag conversion between various
MATCHFLG_* and XFLG_* values.  It also made it easy to fix a bug
in the handling of no-prefix per-directory include/exclude files.
We also use the new XFLG_OLD_PREFIXES and MATCHFLGS_FROM_CONTAINER
defines.
This commit is contained in:
Wayne Davison
2005-02-03 19:00:20 +00:00
parent 0a68f869d7
commit b6f06b8e8b

201
exclude.c
View File

@@ -46,6 +46,9 @@ struct filter_list_struct server_filter_list = { 0, 0, "server " };
/* Need room enough for ":MODS " prefix plus some room to grow. */
#define MAX_RULE_PREFIX (16)
#define MODIFIERS_MERGE_FILE "-+Cens"
#define MODIFIERS_INCL_EXCL "/!"
/* The dirbuf is set by push_local_filters() to the current subdirectory
* relative to curr_dir that is being processed. The path always has a
* trailing slash appended, and the variable dirbuf_len contains the length
@@ -109,7 +112,7 @@ static void free_filter(struct filter_struct *ex)
/* Build a filter structure given a filter pattern. The value in "pat"
* is not null-terminated. */
static void filter_rule(struct filter_list_struct *listp, const char *pat,
unsigned int pat_len, unsigned int mflags, int xflags)
unsigned int pat_len, unsigned mflags, int xflags)
{
struct filter_struct *ret;
const char *cp;
@@ -328,7 +331,7 @@ void set_filter_dir(const char *dir, unsigned int dirlen)
* dirs from that point through the parent dir of the transfer dir looking
* for the per-dir merge-file in each one. */
static BOOL setup_merge_file(struct filter_struct *ex,
struct filter_list_struct *lp, int flags)
struct filter_list_struct *lp)
{
char buf[MAXPATHLEN];
char *x, *y, *pat = ex->pattern;
@@ -364,7 +367,7 @@ static BOOL setup_merge_file(struct filter_struct *ex,
*y = '\0';
dirbuf_len = y - dirbuf;
strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
add_filter_file(lp, buf, flags | XFLG_ANCHORED2ABS);
add_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS);
if (ex->match_flags & MATCHFLG_NO_INHERIT)
lp->head = NULL;
lp->tail = NULL;
@@ -404,7 +407,6 @@ void *push_local_filters(const char *dir, unsigned int dirlen)
for (i = 0; i < mergelist_cnt; i++) {
struct filter_struct *ex = mergelist_parents[i];
struct filter_list_struct *lp = ex->u.mergelist;
int flags = 0;
if (verbose > 2) {
rprintf(FINFO, "[%s] pushing filter list%s\n",
@@ -414,25 +416,18 @@ void *push_local_filters(const char *dir, unsigned int dirlen)
lp->tail = NULL; /* Switch any local rules to inherited. */
if (ex->match_flags & MATCHFLG_NO_INHERIT)
lp->head = NULL;
if (ex->match_flags & MATCHFLG_WORD_SPLIT)
flags |= XFLG_WORD_SPLIT;
if (ex->match_flags & MATCHFLG_NO_PREFIXES)
flags |= XFLG_NO_PREFIXES;
if (ex->match_flags & MATCHFLG_INCLUDE)
flags |= XFLG_DEF_INCLUDE;
else if (ex->match_flags & MATCHFLG_NO_PREFIXES)
flags |= XFLG_DEF_EXCLUDE;
if (ex->match_flags & MATCHFLG_FINISH_SETUP) {
ex->match_flags &= ~MATCHFLG_FINISH_SETUP;
if (setup_merge_file(ex, lp, flags))
if (setup_merge_file(ex, lp))
set_filter_dir(dir, dirlen);
}
if (strlcpy(dirbuf + dirbuf_len, ex->pattern,
MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len)
add_filter_file(lp, dirbuf, flags | XFLG_ANCHORED2ABS);
else {
MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) {
add_filter_file(lp, dirbuf, ex->match_flags,
XFLG_ANCHORED2ABS);
} else {
io_error |= IOERR_GENERAL;
rprintf(FINFO,
"cannot add local filter rules in long-named directory: %s\n",
@@ -603,18 +598,17 @@ int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
* be '\0' terminated, so use the returned length to limit the string.
* Also, be sure to add this length to the returned pointer before passing
* it back to ask for the next token. This routine parses the "!" (list-
* clearing) token and (if xflags does NOT contain XFLG_NO_PREFIXES) the
* +/- prefixes for overriding the include/exclude mode. The *flag_ptr
* value will also be set to the MATCHFLG_* bits for the current token.
*/
static const char *get_filter_tok(const char *p, int xflags,
unsigned int *len_ptr, unsigned int *flag_ptr)
* clearing) token and (depending on the mflags) the various prefixes.
* The *mflags_ptr value will be set on exit to the new MATCHFLG_* bits
* for the current token. */
static const char *get_filter_tok(const char *p, unsigned mflags, int xflags,
unsigned int *len_ptr, unsigned int *mflags_ptr)
{
const unsigned char *s = (const unsigned char *)p;
unsigned int len, mflags = 0;
unsigned int len, new_mflags;
int empty_pat_is_OK = 0;
if (xflags & XFLG_WORD_SPLIT) {
if (mflags & MATCHFLG_WORD_SPLIT) {
/* Skip over any initial whitespace. */
while (isspace(*s))
s++;
@@ -624,26 +618,46 @@ static const char *get_filter_tok(const char *p, int xflags,
if (!*s)
return NULL;
/* Figure out what kind of a filter rule "s" is pointing at. */
if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE))) {
new_mflags = mflags & MATCHFLGS_FROM_CONTAINER;
/* Figure out what kind of a filter rule "s" is pointing at. Note
* that if MATCHFLG_NO_PREFIXES is set, the rule is either an include
* or an exclude based on the inheritance of the MATCHFLG_INCLUDE
* flag (above). XFLG_OLD_PREFIXES indicates a compatibility mode
* for old include/exclude patterns where just "+ " and "- " are
* allowed as optional prefixes. */
if (mflags & MATCHFLG_NO_PREFIXES) {
if (*s == '!')
new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */
} else if (xflags & XFLG_OLD_PREFIXES) {
if (*s == '-' && s[1] == ' ') {
new_mflags &= ~MATCHFLG_INCLUDE;
s += 2;
} else if (*s == '+' && s[1] == ' ') {
new_mflags |= MATCHFLG_INCLUDE;
s += 2;
}
if (*s == '!')
new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */
} else {
char *mods = "";
switch (*s) {
case ':':
mflags |= MATCHFLG_PERDIR_MERGE
| MATCHFLG_FINISH_SETUP;
new_mflags |= MATCHFLG_PERDIR_MERGE
| MATCHFLG_FINISH_SETUP;
/* FALL THROUGH */
case '.':
mflags |= MATCHFLG_MERGE_FILE;
mods = "-+Cens";
new_mflags |= MATCHFLG_MERGE_FILE;
mods = MODIFIERS_INCL_EXCL MODIFIERS_MERGE_FILE;
break;
case '+':
mflags |= MATCHFLG_INCLUDE;
new_mflags |= MATCHFLG_INCLUDE;
/* FALL THROUGH */
case '-':
mods = "!/";
mods = MODIFIERS_INCL_EXCL;
break;
case '!':
mflags |= MATCHFLG_CLEAR_LIST;
new_mflags |= MATCHFLG_CLEAR_LIST;
mods = NULL;
break;
default:
@@ -652,64 +666,58 @@ static const char *get_filter_tok(const char *p, int xflags,
}
while (mods && *++s && *s != ' ' && *s != '_') {
if (strchr(mods, *s) == NULL) {
if (xflags & XFLG_WORD_SPLIT && isspace(*s)) {
if (mflags & MATCHFLG_WORD_SPLIT && isspace(*s)) {
s--;
break;
}
invalid:
rprintf(FERROR,
"unknown modifier '%c' in filter rule: %s\n",
"invalid modifier sequence at '%c' in filter rule: %s\n",
*s, p);
exit_cleanup(RERR_SYNTAX);
}
switch (*s) {
case '-':
mflags |= MATCHFLG_NO_PREFIXES;
if (new_mflags & MATCHFLG_NO_PREFIXES)
goto invalid;
new_mflags |= MATCHFLG_NO_PREFIXES;
break;
case '+':
mflags |= MATCHFLG_NO_PREFIXES
| MATCHFLG_INCLUDE;
if (new_mflags & MATCHFLG_NO_PREFIXES)
goto invalid;
new_mflags |= MATCHFLG_NO_PREFIXES
| MATCHFLG_INCLUDE;
break;
case '/':
mflags |= MATCHFLG_ABS_PATH;
new_mflags |= MATCHFLG_ABS_PATH;
break;
case '!':
mflags |= MATCHFLG_NEGATE;
new_mflags |= MATCHFLG_NEGATE;
break;
case 'C':
if (new_mflags & MATCHFLG_NO_PREFIXES)
goto invalid;
empty_pat_is_OK = 1;
mflags |= MATCHFLG_NO_PREFIXES
| MATCHFLG_WORD_SPLIT
| MATCHFLG_NO_INHERIT;
new_mflags |= MATCHFLG_NO_PREFIXES
| MATCHFLG_WORD_SPLIT
| MATCHFLG_NO_INHERIT;
break;
case 'e':
mflags |= MATCHFLG_EXCLUDE_SELF;
new_mflags |= MATCHFLG_EXCLUDE_SELF;
break;
case 'n':
mflags |= MATCHFLG_NO_INHERIT;
new_mflags |= MATCHFLG_NO_INHERIT;
break;
case 'w':
mflags |= MATCHFLG_WORD_SPLIT;
new_mflags |= MATCHFLG_WORD_SPLIT;
break;
}
}
if (*s)
s++;
} else if (!(xflags & XFLG_NO_PREFIXES)
&& (*s == '-' || *s == '+') && s[1] == ' ') {
if (*s == '+')
mflags |= MATCHFLG_INCLUDE;
s += 2;
} else {
if (xflags & XFLG_DEF_INCLUDE)
mflags |= MATCHFLG_INCLUDE;
if (*s == '!')
mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */
}
if (xflags & XFLG_DIRECTORY)
mflags |= MATCHFLG_DIRECTORY;
if (xflags & XFLG_WORD_SPLIT) {
if (mflags & MATCHFLG_WORD_SPLIT) {
const unsigned char *cp = s;
/* Token ends at whitespace or the end of the string. */
while (!isspace(*cp) && *cp != '\0')
@@ -718,29 +726,29 @@ static const char *get_filter_tok(const char *p, int xflags,
} else
len = strlen((char*)s);
if (mflags & MATCHFLG_CLEAR_LIST) {
if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE)) && len) {
if (new_mflags & MATCHFLG_CLEAR_LIST) {
if (!(xflags & XFLG_OLD_PREFIXES) && len) {
rprintf(FERROR,
"'!' rule has trailing characters: %s\n", p);
exit_cleanup(RERR_SYNTAX);
}
if (len > 1)
mflags &= ~MATCHFLG_CLEAR_LIST;
new_mflags &= ~MATCHFLG_CLEAR_LIST;
} else if (!len && !empty_pat_is_OK) {
rprintf(FERROR, "unexpected end of filter rule: %s\n", p);
exit_cleanup(RERR_SYNTAX);
}
*len_ptr = len;
*flag_ptr = mflags;
*mflags_ptr = new_mflags;
return (const char *)s;
}
void add_filter(struct filter_list_struct *listp, const char *pattern,
int xflags)
unsigned mflags, int xflags)
{
unsigned int pat_len, mflags;
unsigned int pat_len, new_mflags;
const char *cp, *p;
if (!pattern)
@@ -748,7 +756,8 @@ void add_filter(struct filter_list_struct *listp, const char *pattern,
while (1) {
/* Remember that the returned string is NOT '\0' terminated! */
cp = get_filter_tok(pattern, xflags, &pat_len, &mflags);
cp = get_filter_tok(pattern, mflags, xflags,
&pat_len, &new_mflags);
if (!cp)
break;
if (pat_len >= MAXPATHLEN) {
@@ -758,7 +767,7 @@ void add_filter(struct filter_list_struct *listp, const char *pattern,
}
pattern = cp + pat_len;
if (mflags & MATCHFLG_CLEAR_LIST) {
if (new_mflags & MATCHFLG_CLEAR_LIST) {
if (verbose > 2) {
rprintf(FINFO,
"[%s] clearing filter list%s\n",
@@ -773,50 +782,48 @@ void add_filter(struct filter_list_struct *listp, const char *pattern,
pat_len = 10;
}
if (mflags & MATCHFLG_MERGE_FILE) {
if (new_mflags & MATCHFLG_MERGE_FILE) {
unsigned int len = pat_len;
if (mflags & MATCHFLG_EXCLUDE_SELF) {
if (new_mflags & MATCHFLG_EXCLUDE_SELF) {
const char *name = strrchr(cp, '/');
if (name)
len -= ++name - cp;
else
name = cp;
filter_rule(listp, name, len, 0, 0);
mflags &= ~MATCHFLG_EXCLUDE_SELF;
new_mflags &= ~MATCHFLG_EXCLUDE_SELF;
len = pat_len;
}
if (mflags & MATCHFLG_PERDIR_MERGE) {
if (new_mflags & MATCHFLG_PERDIR_MERGE) {
if (parent_dirscan) {
if (!(p = parse_merge_name(cp, &len, module_dirlen)))
if (!(p = parse_merge_name(cp, &len,
module_dirlen)))
continue;
filter_rule(listp, p, len, mflags, 0);
filter_rule(listp, p, len,
new_mflags, 0);
continue;
}
} else {
int flgs = XFLG_FATAL_ERRORS;
if (!(p = parse_merge_name(cp, &len, 0)))
continue;
if (mflags & MATCHFLG_INCLUDE)
flgs |= XFLG_DEF_INCLUDE;
else if (mflags & MATCHFLG_NO_PREFIXES)
flgs |= XFLG_DEF_EXCLUDE;
add_filter_file(listp, p, flgs);
add_filter_file(listp, p, new_mflags,
XFLG_FATAL_ERRORS);
continue;
}
}
filter_rule(listp, cp, pat_len, mflags, xflags);
filter_rule(listp, cp, pat_len, new_mflags, xflags);
}
}
void add_filter_file(struct filter_list_struct *listp, const char *fname,
int xflags)
unsigned mflags, int xflags)
{
FILE *fp;
char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */
char *eob = line + sizeof line - 1;
int word_split = xflags & XFLG_WORD_SPLIT;
int word_split = mflags & MATCHFLG_WORD_SPLIT;
if (!fname || !*fname)
return;
@@ -835,8 +842,8 @@ void add_filter_file(struct filter_list_struct *listp, const char *fname,
fp = stdin;
if (verbose > 2) {
rprintf(FINFO, "[%s] add_filter_file(%s,%d)%s\n",
who_am_i(), safe_fname(fname), xflags,
rprintf(FINFO, "[%s] add_filter_file(%s,%x,%x)%s\n",
who_am_i(), safe_fname(fname), mflags, xflags,
fp ? "" : " [not found]");
}
@@ -844,7 +851,7 @@ void add_filter_file(struct filter_list_struct *listp, const char *fname,
if (xflags & XFLG_FATAL_ERRORS) {
rsyserr(FERROR, errno,
"failed to open %sclude file %s",
xflags & XFLG_DEF_INCLUDE ? "in" : "ex",
mflags & MATCHFLG_INCLUDE ? "in" : "ex",
safe_fname(fname));
exit_cleanup(RERR_FILEIO);
}
@@ -877,7 +884,7 @@ void add_filter_file(struct filter_list_struct *listp, const char *fname,
*s = '\0';
/* Skip an empty token and (when line parsing) comments. */
if (*line && (word_split || (*line != ';' && *line != '#')))
add_filter(listp, line, xflags);
add_filter(listp, line, mflags, xflags);
if (ch == EOF)
break;
}
@@ -927,7 +934,7 @@ void send_filter_list(int f)
/* This is a complete hack - blame Rusty. FIXME!
* Remove this hack when older rsyncs (below 2.6.4) are gone. */
if (list_only == 1 && !recurse)
add_filter(&filter_list, "/*/*", XFLG_DEF_EXCLUDE);
add_filter(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0);
for (ent = filter_list.head; ent; ent = ent->next) {
unsigned int len, plen, dlen;
@@ -961,14 +968,14 @@ void send_filter_list(int f)
void recv_filter_list(int f)
{
char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */
unsigned int xflags = protocol_version >= 29 ? 0 : XFLG_DEF_EXCLUDE;
unsigned int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
unsigned int l;
while ((l = read_int(f)) != 0) {
if (l >= sizeof line)
overflow("recv_filter_list");
read_sbuf(f, line, l);
add_filter(&filter_list, line, xflags);
add_filter(&filter_list, line, 0, xflags);
}
}
@@ -985,18 +992,16 @@ static char default_cvsignore[] =
void add_cvs_excludes(void)
{
static unsigned int cvs_flags = XFLG_WORD_SPLIT | XFLG_NO_PREFIXES
| XFLG_DEF_EXCLUDE;
static unsigned cvs_mflags = MATCHFLG_WORD_SPLIT|MATCHFLG_NO_PREFIXES;
char fname[MAXPATHLEN];
char *p = module_id >= 0 && lp_use_chroot(module_id)
? "/" : getenv("HOME");
add_filter(&filter_list, ":C", 0);
add_filter(&filter_list, default_cvsignore, cvs_flags);
add_filter(&filter_list, ":C", 0, 0);
add_filter(&filter_list, default_cvsignore, cvs_mflags, 0);
if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN) {
add_filter_file(&filter_list, fname, cvs_flags);
}
if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN)
add_filter_file(&filter_list, fname, cvs_mflags, 0);
add_filter(&filter_list, getenv("CVSIGNORE"), cvs_flags);
add_filter(&filter_list, getenv("CVSIGNORE"), cvs_mflags, 0);
}