📄 exclude.c
字号:
/* Each time rsync changes to a new directory it call this function to * handle all the per-dir merge-files. The "dir" value is the current path * relative to curr_dir (which might not be null-terminated). We copy it * into dirbuf so that we can easily append a file name on the end. */void *push_local_filters(const char *dir, unsigned int dirlen){ struct filter_list_struct *ap, *push; int i; set_filter_dir(dir, dirlen); if (!mergelist_cnt) return NULL; push = new_array(struct filter_list_struct, mergelist_cnt); if (!push) out_of_memory("push_local_filters"); for (i = 0, ap = push; i < mergelist_cnt; i++) { memcpy(ap++, mergelist_parents[i]->u.mergelist, sizeof (struct filter_list_struct)); } /* Note: parse_filter_file() might increase mergelist_cnt, so keep * this loop separate from the above loop. */ for (i = 0; i < mergelist_cnt; i++) { struct filter_struct *ex = mergelist_parents[i]; struct filter_list_struct *lp = ex->u.mergelist; if (verbose > 2) { rprintf(FINFO, "[%s] pushing filter list%s\n", who_am_i(), lp->debug_type); } lp->tail = NULL; /* Switch any local rules to inherited. */ if (ex->match_flags & MATCHFLG_NO_INHERIT) lp->head = NULL; if (ex->match_flags & MATCHFLG_FINISH_SETUP) { ex->match_flags &= ~MATCHFLG_FINISH_SETUP; if (setup_merge_file(ex, lp)) set_filter_dir(dir, dirlen); } if (strlcpy(dirbuf + dirbuf_len, ex->pattern, MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) { parse_filter_file(lp, dirbuf, ex->match_flags, XFLG_ANCHORED2ABS); } else { io_error |= IOERR_GENERAL; rprintf(FERROR, "cannot add local filter rules in long-named directory: %s\n", full_fname(dirbuf)); } dirbuf[dirbuf_len] = '\0'; } return (void*)push;}void pop_local_filters(void *mem){ struct filter_list_struct *ap, *pop = (struct filter_list_struct*)mem; int i; for (i = mergelist_cnt; i-- > 0; ) { struct filter_struct *ex = mergelist_parents[i]; struct filter_list_struct *lp = ex->u.mergelist; if (verbose > 2) { rprintf(FINFO, "[%s] popping filter list%s\n", who_am_i(), lp->debug_type); } clear_filter_list(lp); } if (!pop) return; for (i = 0, ap = pop; i < mergelist_cnt; i++) { memcpy(mergelist_parents[i]->u.mergelist, ap++, sizeof (struct filter_list_struct)); } free(pop);}void change_local_filter_dir(const char *dname, int dlen, int dir_depth){ static int cur_depth = -1; static void *filt_array[MAXPATHLEN/2+1]; if (!dname) { for ( ; cur_depth >= 0; cur_depth--) { if (filt_array[cur_depth]) { pop_local_filters(filt_array[cur_depth]); filt_array[cur_depth] = NULL; } } return; } assert(dir_depth < MAXPATHLEN/2+1); for ( ; cur_depth >= dir_depth; cur_depth--) { if (filt_array[cur_depth]) { pop_local_filters(filt_array[cur_depth]); filt_array[cur_depth] = NULL; } } cur_depth = dir_depth; filt_array[cur_depth] = push_local_filters(dname, dlen);}static int rule_matches(const char *fname, struct filter_struct *ex, int name_is_dir){ int slash_handling, str_cnt = 0, anchored_match = 0; int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1; char *p, *pattern = ex->pattern; const char *strings[16]; /* more than enough */ const char *name = fname + (*fname == '/'); if (!*name) return 0; 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 && *fname != '/' && curr_dir_len > module_dirlen + 1) { /* 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 && *fname != '/') { /* Allow "**"+"/" to match at the start of the string. */ strings[str_cnt++] = "/"; } 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 == '/') { anchored_match = 1; pattern++; } 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. */ 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; } 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 { int l1 = strlen(name); int l2 = strlen(pattern); if (l2 <= l1 && strcmp(name+(l1-l2),pattern) == 0 && (l1==l2 || name[l1-(l2+1)] == '/')) { return ret_match; } } return !ret_match;}static void report_filter_result(enum logcode code, char const *name, struct filter_struct const *ent, int name_is_dir, const char *type){ /* If a trailing slash is present to match only directories, * then it is stripped out by add_rule(). So as a special * case we add it back in here. */ if (verbose >= 2) { static char *actions[2][2] = { {"show", "hid"}, {"risk", "protect"} }; const char *w = who_am_i(); rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n", w, actions[*w!='s'][!(ent->match_flags&MATCHFLG_INCLUDE)], name_is_dir ? "directory" : "file", name, ent->pattern, ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type); }}/* * 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. */int check_filter(struct filter_list_struct *listp, enum logcode code, const char *name, int name_is_dir){ struct filter_struct *ent; for (ent = listp->head; ent; ent = ent->next) { if (ignore_perishable && ent->match_flags & MATCHFLG_PERISHABLE) continue; if (ent->match_flags & MATCHFLG_PERDIR_MERGE) { int rc = check_filter(ent->u.mergelist, code, name, name_is_dir); if (rc) return rc; continue; } if (ent->match_flags & MATCHFLG_CVS_IGNORE) { int rc = check_filter(&cvs_filter_list, code, name, name_is_dir); if (rc) return rc; continue; } if (rule_matches(name, ent, name_is_dir)) { report_filter_result(code, name, ent, name_is_dir, listp->debug_type); return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1; } } return 0;}#define RULE_STRCMP(s,r) rule_strcmp((s), (r), sizeof (r) - 1)static const uchar *rule_strcmp(const uchar *str, const char *rule, int rule_len){ if (strncmp((char*)str, rule, rule_len) != 0) return NULL; if (isspace(str[rule_len]) || str[rule_len] == '_' || !str[rule_len]) return str + rule_len - 1; if (str[rule_len] == ',') return str + rule_len; return NULL;}/* Get the next include/exclude arg from the string. The token will not * 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 (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 *parse_rule_tok(const char *p, uint32 mflags, int xflags, unsigned int *len_ptr, uint32 *mflags_ptr){ const uchar *s = (const uchar *)p; uint32 new_mflags; unsigned int len; if (mflags & MATCHFLG_WORD_SPLIT) { /* Skip over any initial whitespace. */ while (isspace(*s)) s++; /* Update to point to real start of rule. */ p = (const char *)s; } if (!*s) return NULL; 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 == '!' && mflags & MATCHFLG_CVS_IGNORE) 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; } else if (*s == '!') new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */ } else { char ch = 0, *mods = ""; switch (*s) { case 'c': if ((s = RULE_STRCMP(s, "clear")) != NULL) ch = '!'; break; case 'd': if ((s = RULE_STRCMP(s, "dir-merge")) != NULL) ch = ':'; break; case 'e': if ((s = RULE_STRCMP(s, "exclude")) != NULL) ch = '-'; break; case 'h': if ((s = RULE_STRCMP(s, "hide")) != NULL) ch = 'H'; break; case 'i': if ((s = RULE_STRCMP(s, "include")) != NULL) ch = '+'; break; case 'm': if ((s = RULE_STRCMP(s, "merge")) != NULL) ch = '.'; break; case 'p': if ((s = RULE_STRCMP(s, "protect")) != NULL) ch = 'P'; break; case 'r': if ((s = RULE_STRCMP(s, "risk")) != NULL) ch = 'R'; break; case 's': if ((s = RULE_STRCMP(s, "show")) != NULL) ch = 'S'; break; default: ch = *s; if (s[1] == ',') s++; break; } switch (ch) { case ':': new_mflags |= MATCHFLG_PERDIR_MERGE | MATCHFLG_FINISH_SETUP; /* FALL THROUGH */ case '.': new_mflags |= MATCHFLG_MERGE_FILE; mods = MODIFIERS_INCL_EXCL MODIFIERS_MERGE_FILE; break; case '+': new_mflags |= MATCHFLG_INCLUDE; /* FALL THROUGH */ case '-': mods = MODIFIERS_INCL_EXCL; break; case 'S': new_mflags |= MATCHFLG_INCLUDE; /* FALL THROUGH */ case 'H': new_mflags |= MATCHFLG_SENDER_SIDE; mods = MODIFIERS_HIDE_PROTECT; break; case 'R': new_mflags |= MATCHFLG_INCLUDE; /* FALL THROUGH */ case 'P': new_mflags |= MATCHFLG_RECEIVER_SIDE; mods = MODIFIERS_HIDE_PROTECT; break; case '!': new_mflags |= MATCHFLG_CLEAR_LIST; mods = NULL; break; default: rprintf(FERROR, "Unknown filter rule: `%s'\n", p); exit_cleanup(RERR_SYNTAX); } while (mods && *++s && *s != ' ' && *s != '_') { if (strchr(mods, *s) == NULL) { if (mflags & MATCHFLG_WORD_SPLIT && isspace(*s)) { s--; break; } invalid: rprintf(FERROR, "invalid modifier sequence at '%c' in filter rule: %s\n", *s, p); exit_cleanup(RERR_SYNTAX); } switch (*s) { case '-': if (new_mflags & MATCHFLG_NO_PREFIXES) goto invalid; new_mflags |= MATCHFLG_NO_PREFIXES; break; case '+': if (new_mflags & MATCHFLG_NO_PREFIXES) goto invalid; new_mflags |= MATCHFLG_NO_PREFIXES | MATCHFLG_INCLUDE; break; case '/': new_mflags |= MATCHFLG_ABS_PATH; break; case '!': new_mflags |= MATCHFLG_NEGATE; break; case 'C': if (new_mflags & MATCHFLG_NO_PREFIXES) goto invalid; new_mflags |= MATCHFLG_NO_PREFIXES | MATCHFLG_WORD_SPLIT | MATCHFLG_NO_INHERIT | MATCHFLG_CVS_IGNORE; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -