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;
#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
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;
char *p, *pattern = ex->pattern;
const char *strings[16]; /* more than enough */
+ if (*name == '/')
+ name++;
if (!*name)
return 0;
if (*pattern == '/') {
anchored_match = 1;
pattern++;
- if (strings[0][0] == '/')
- strings[0]++;
}
if (!anchored_match && ex->u.slash_cnt
if (litmatch_array(pattern, strings, slash_handling))
return ret_match;
} else if (anchored_match) {
- if (strcmp(strings[0], pattern) == 0)
+ if (strcmp(name, pattern) == 0)
return ret_match;
} else {
int l1 = strlen(name);
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);
case 'n':
new_mflags |= MATCHFLG_NO_INHERIT;
break;
+ case 'p':
+ new_mflags |= MATCHFLG_PERISHABLE;
+ break;
case 'r':
new_mflags |= MATCHFLG_RECEIVER_SIDE;
break;
exit_cleanup(RERR_SYNTAX);
}
+ /* --delete-excluded turns an un-modified include/exclude into a
+ * sender-side rule. We also affect per-dir merge files that take
+ * no prefixes as a simple optimization. */
+ if (delete_excluded
+ && !(new_mflags & (MATCHFLG_RECEIVER_SIDE|MATCHFLG_SENDER_SIDE))
+ && (!(new_mflags & MATCHFLG_PERDIR_MERGE)
+ || new_mflags & MATCHFLG_NO_PREFIXES))
+ new_mflags |= MATCHFLG_SENDER_SIDE;
+
*len_ptr = len;
*mflags_ptr = new_mflags;
return (const char *)s;
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)
&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) {
}
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;
&& (!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)
int elide = 0;
char *p;
+ /* Note we need to check delete_excluded here in addition to
+ * the code in parse_rule_tok() because some rules may have
+ * been added before we found the --delete-excluded option.
+ * We must also elide any CVS merge-file rules to avoid a
+ * backward compatibility problem, and we elide any no-prefix
+ * merge files as an optimization (since they can only have
+ * include/exclude rules). */
if (ent->match_flags & MATCHFLG_SENDER_SIDE)
elide = am_sender ? 1 : -1;
if (ent->match_flags & MATCHFLG_RECEIVER_SIDE)
elide = elide ? 0 : am_sender ? -1 : 1;
- else if (delete_excluded && !elide)
+ else if (delete_excluded && !elide
+ && (!(ent->match_flags & MATCHFLG_PERDIR_MERGE)
+ || ent->match_flags & MATCHFLG_NO_PREFIXES))
elide = am_sender ? 1 : -1;
if (elide < 0) {
if (prev)
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;