X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/ac1cb9380d274602d8f7aae476d8ddd05e32d630..61e16468f0c7a2186b1ef8ca3393e292ba1b1a97:/exclude.c diff --git a/exclude.c b/exclude.c index a606b1bc..8d748641 100644 --- a/exclude.c +++ b/exclude.c @@ -46,8 +46,8 @@ extern unsigned int curr_dir_len; extern unsigned int module_dirlen; struct filter_list_struct filter_list = { 0, 0, "" }; -struct filter_list_struct cvs_filter_list = { 0, 0, " [cvsignore]" }; -struct filter_list_struct server_filter_list = { 0, 0, " [server]" }; +struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" }; +struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" }; /* Need room enough for ":MODS " prefix plus some room to grow. */ #define MAX_RULE_PREFIX (16) @@ -133,9 +133,9 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, listp->debug_type); } - /* This flag also indicates that we're reading a list that + /* These flags also indicate that we're reading a list that * needs to be filtered now, not post-filtered later. */ - if (xflags & XFLG_ANCHORED2ABS) { + if (xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH)) { uint32 mf = mflags & (MATCHFLG_RECEIVER_SIDE|MATCHFLG_SENDER_SIDE); if (am_sender) { if (mf == MATCHFLG_RECEIVER_SIDE) @@ -150,10 +150,14 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, out_of_memory("add_rule"); memset(ret, 0, sizeof ret[0]); - if (xflags & XFLG_ANCHORED2ABS && *pat == '/' - && !(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))) { + if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE)) + && ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/') + || (xflags & XFLG_ABS_IF_SLASH && strchr(pat, '/') != NULL))) { mflags |= MATCHFLG_ABS_PATH; - ex_len = dirbuf_len - module_dirlen - 1; + if (*pat == '/') + ex_len = dirbuf_len - module_dirlen - 1; + else + ex_len = 0; } else ex_len = 0; if (!(ret->pattern = new_array(char, ex_len + pat_len + 1))) @@ -170,6 +174,12 @@ static void add_rule(struct filter_list_struct *listp, const char *pat, /* If the pattern starts with **, note that. */ if (cp == ret->pattern) mflags |= MATCHFLG_WILD2_PREFIX; + /* If the pattern ends with ***, note that. */ + if (pat_len >= 3 + && ret->pattern[pat_len-3] == '*' + && ret->pattern[pat_len-2] == '*' + && ret->pattern[pat_len-1] == '*') + mflags |= MATCHFLG_WILD3_SUFFIX; } } @@ -488,70 +498,68 @@ void pop_local_filters(void *mem) static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir) { - char *p, full_name[MAXPATHLEN]; - int match_start = 0; + int slash_handling, str_cnt = 0, anchored_match = 0; int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1; - char *pattern = ex->pattern; + char *p, *pattern = ex->pattern; + const char *strings[16]; /* more than enough */ if (!*name) return 0; - /* If the pattern does not have any slashes AND it does not have - * a "**" (which could match a slash), then we just match the - * name portion of the path. */ if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) { + /* If the pattern does not have any slashes AND it does + * not have a "**" (which could match a slash), then we + * just match the name portion of the path. */ if ((p = strrchr(name,'/')) != NULL) name = p+1; - } - else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/' + } else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/' && curr_dir_len > module_dirlen + 1) { - pathjoin(full_name, sizeof full_name, - curr_dir + module_dirlen + 1, name); - name = full_name; + /* If we're matching against an absolute-path pattern, + * we need to prepend our full path info. */ + strings[str_cnt++] = curr_dir + module_dirlen + 1; + strings[str_cnt++] = "/"; + } else if (ex->match_flags & MATCHFLG_WILD2_PREFIX && *name != '/') { + /* Allow "**"+"/" to match at the start of the string. */ + strings[str_cnt++] = "/"; } - - if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir) + strings[str_cnt++] = name; + if (name_is_dir) { + /* Allow a trailing "/"+"***" to match the directory. */ + if (ex->match_flags & MATCHFLG_WILD3_SUFFIX) + strings[str_cnt++] = "/"; + } else if (ex->match_flags & MATCHFLG_DIRECTORY) return !ret_match; + strings[str_cnt] = NULL; if (*pattern == '/') { - match_start = 1; + anchored_match = 1; pattern++; - if (*name == '/') - name++; + if (strings[0][0] == '/') + strings[0]++; } - if (ex->match_flags & MATCHFLG_WILD) { + if (!anchored_match && ex->u.slash_cnt + && !(ex->match_flags & MATCHFLG_WILD2)) { /* A non-anchored match with an infix slash and no "**" * needs to match the last slash_cnt+1 name elements. */ - if (!match_start && ex->u.slash_cnt - && !(ex->match_flags & MATCHFLG_WILD2)) { - int cnt = ex->u.slash_cnt + 1; - for (p = name + strlen(name) - 1; p >= name; p--) { - if (*p == '/' && !--cnt) - break; - } - name = p+1; - } - if (wildmatch(pattern, name)) + slash_handling = ex->u.slash_cnt + 1; + } else if (!anchored_match && !(ex->match_flags & MATCHFLG_WILD2_PREFIX) + && ex->match_flags & MATCHFLG_WILD2) { + /* A non-anchored match with an infix or trailing "**" (but not + * a prefixed "**") needs to try matching after every slash. */ + slash_handling = -1; + } else { + /* The pattern matches only at the start of the path or name. */ + slash_handling = 0; + } + + if (ex->match_flags & MATCHFLG_WILD) { + if (wildmatch_array(pattern, strings, slash_handling)) return ret_match; - if (ex->match_flags & MATCHFLG_WILD2_PREFIX) { - /* If the **-prefixed pattern has a '/' as the next - * character, then try to match the rest of the - * pattern at the root. */ - if (pattern[2] == '/' && wildmatch(pattern+3, name)) - return ret_match; - } - else if (!match_start && ex->match_flags & MATCHFLG_WILD2) { - /* A non-anchored match with an infix or trailing "**" - * (but not a prefixed "**") needs to try matching - * after every slash. */ - while ((name = strchr(name, '/')) != NULL) { - name++; - if (wildmatch(pattern, name)) - return ret_match; - } - } - } else if (match_start) { + } else if (str_cnt > 1) { + if (litmatch_array(pattern, strings, slash_handling)) + return ret_match; + } else if (anchored_match) { if (strcmp(name,pattern) == 0) return ret_match; } else { @@ -674,8 +682,7 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags, } else if (*s == '+' && s[1] == ' ') { new_mflags |= MATCHFLG_INCLUDE; s += 2; - } - if (*s == '!') + } else if (*s == '!') new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */ } else { char ch = 0, *mods = ""; @@ -716,7 +723,6 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags, if ((s = RULE_STRCMP(s, "show")) != NULL) ch = 'S'; break; - default: ch = *s; if (s[1] == ',') @@ -829,7 +835,8 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags, len = strlen((char*)s); if (new_mflags & MATCHFLG_CLEAR_LIST) { - if (!(xflags & XFLG_OLD_PREFIXES) && len) { + if (!(mflags & MATCHFLG_NO_PREFIXES) + && !(xflags & XFLG_OLD_PREFIXES) && len) { rprintf(FERROR, "'!' rule has trailing characters: %s\n", p); exit_cleanup(RERR_SYNTAX); @@ -956,7 +963,7 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname, uint32 mflags, int xflags) { FILE *fp; - char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */ + char line[BIGPATHBUFLEN]; char *eob = line + sizeof line - 1; int word_split = mflags & MATCHFLG_WORD_SPLIT; @@ -999,8 +1006,10 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname, int ch, overflow = 0; while (1) { if ((ch = getc(fp)) == EOF) { - if (ferror(fp) && errno == EINTR) + if (ferror(fp) && errno == EINTR) { + clearerr(fp); continue; + } break; } if (word_split && isspace(ch)) @@ -1107,9 +1116,9 @@ static void send_rules(int f_out, struct filter_list_struct *flp) continue; if (ent->match_flags & MATCHFLG_CVS_IGNORE && !(ent->match_flags & MATCHFLG_MERGE_FILE)) { - int f = am_sender || protocol_version < 29 ? f_out : -1; + int f = am_sender || protocol_version < 29 ? f_out : -2; send_rules(f, &cvs_filter_list); - if (f >= 0) + if (f == f_out) continue; } p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen); @@ -1169,7 +1178,7 @@ void send_filter_list(int f_out) /* This is only called by the server. */ void recv_filter_list(int f_in) { - char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */ + char line[BIGPATHBUFLEN]; int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES; int receiver_wants_list = delete_mode && (!delete_excluded || protocol_version >= 29); @@ -1178,7 +1187,7 @@ void recv_filter_list(int f_in) if (!local_server && (am_sender || receiver_wants_list)) { while ((len = read_int(f_in)) != 0) { if (len >= sizeof line) - overflow("recv_rules"); + overflow_exit("recv_rules"); read_sbuf(f_in, line, len); parse_rule(&filter_list, line, 0, xflags); }