X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/48ecccce2d7d893bc5d66a36c6d4baf6d47d8dfb..30e50494bbb057d4191e4636b963c6b7b0770ece:/exclude.c diff --git a/exclude.c b/exclude.c index 5d3ee403..11b187c6 100644 --- a/exclude.c +++ b/exclude.c @@ -32,6 +32,7 @@ extern int recurse; extern int io_error; extern int local_server; extern int prune_empty_dirs; +extern int ignore_perishable; extern int delete_mode; extern int delete_excluded; extern int cvs_exclude; @@ -51,8 +52,8 @@ struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" }; #define MAX_RULE_PREFIX (16) #define MODIFIERS_MERGE_FILE "-+Cenw" -#define MODIFIERS_INCL_EXCL "/!Crs" -#define MODIFIERS_HIDE_PROTECT "/!" +#define MODIFIERS_INCL_EXCL "/!Crsp" +#define MODIFIERS_HIDE_PROTECT "/!p" /* 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 @@ -303,24 +304,23 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr, merge_file); return NULL; } + fn_len = strlen(fn); } else { strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN); - clean_fname(fn, 1); + fn_len = clean_fname(fn, 1); } - fn_len = strlen(fn); - if (fn == buf) - goto done; - - if (dirbuf_len + fn_len >= MAXPATHLEN) { - rprintf(FERROR, "merge-file name overflows: %s\n", fn); - return NULL; + /* If the name isn't in buf yet, it's wasn't absolute. */ + if (fn != buf) { + if (dirbuf_len + fn_len >= MAXPATHLEN) { + rprintf(FERROR, "merge-file name overflows: %s\n", fn); + return NULL; + } + memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip); + memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1); + fn_len = clean_fname(buf, 1); } - memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip); - memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1); - fn_len = clean_fname(buf, 1); - done: if (len_ptr) *len_ptr = fn_len; return buf; @@ -602,6 +602,8 @@ int 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 (ignore_perishable && ent->match_flags & MATCHFLG_PERISHABLE) + continue; if (ent->match_flags & MATCHFLG_PERDIR_MERGE) { int rc = check_filter(ent->u.mergelist, name, name_is_dir); @@ -809,6 +811,9 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags, case 'n': new_mflags |= MATCHFLG_NO_INHERIT; break; + case 'p': + new_mflags |= MATCHFLG_PERISHABLE; + break; case 'r': new_mflags |= MATCHFLG_RECEIVER_SIDE; break; @@ -881,7 +886,7 @@ static void get_cvs_excludes(uint32 mflags) return; initialized = 1; - parse_rule(&cvs_filter_list, default_cvsignore, mflags, 0); + parse_rule(&cvs_filter_list, default_cvsignore, mflags | MATCHFLG_PERISHABLE, 0); p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME"); if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN) @@ -907,12 +912,14 @@ void parse_rule(struct filter_list_struct *listp, const char *pattern, &pat_len, &new_mflags); if (!cp) break; + + pattern = cp + pat_len; + if (pat_len >= MAXPATHLEN) { - rprintf(FERROR, "discarding over-long filter: %s\n", - cp); + rprintf(FERROR, "discarding over-long filter: %.*s\n", + (int)pat_len, cp); continue; } - pattern = cp + pat_len; if (new_mflags & MATCHFLG_CLEAR_LIST) { if (verbose > 2) { @@ -932,11 +939,9 @@ void parse_rule(struct filter_list_struct *listp, const char *pattern, } len = pat_len; if (new_mflags & MATCHFLG_EXCLUDE_SELF) { - const char *name = strrchr(cp, '/'); - if (name) - len -= ++name - cp; - else - name = cp; + const char *name = cp + len; + while (name > cp && name[-1] != '/') name--; + len -= name - cp; add_rule(listp, name, len, 0, 0); new_mflags &= ~MATCHFLG_EXCLUDE_SELF; len = pat_len; @@ -1065,6 +1070,8 @@ char *get_rule_prefix(int match_flags, const char *pat, int for_xfer, else legal_len = 0; + if (match_flags & MATCHFLG_NEGATE) + *op++ = '!'; if (match_flags & MATCHFLG_CVS_IGNORE) *op++ = 'C'; else { @@ -1088,6 +1095,12 @@ char *get_rule_prefix(int match_flags, const char *pat, int for_xfer, && (!for_xfer || protocol_version >= 29 || (delete_excluded && am_sender))) *op++ = 'r'; + if (match_flags & MATCHFLG_PERISHABLE) { + if (!for_xfer || protocol_version >= 30) + *op++ = 'p'; + else if (am_sender) + return NULL; + } if (op - buf > legal_len) return NULL; if (legal_len) @@ -1142,7 +1155,7 @@ static void send_rules(int f_out, struct filter_list_struct *flp) if (!p) { rprintf(FERROR, "filter rules are too modern for remote rsync.\n"); - exit_cleanup(RERR_SYNTAX); + exit_cleanup(RERR_PROTOCOL); } if (f_out < 0) continue;