A helper file for cleanup.c.
[rsync/rsync.git] / exclude.c
index eb2353c..397acf2 100644 (file)
--- a/exclude.c
+++ b/exclude.c
@@ -298,29 +298,28 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
                        strlcpy(to, merge_file, *len_ptr + 1);
                        merge_file = to;
                }
-               if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
+               if (!sanitize_path(fn, merge_file, r, dirbuf_depth, NULL)) {
                        rprintf(FERROR, "merge-file name overflows: %s\n",
                                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;
@@ -500,6 +499,8 @@ static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir)
        char *p, *pattern = ex->pattern;
        const char *strings[16]; /* more than enough */
 
+       if (*name == '/')
+               name++;
        if (!*name)
                return 0;
 
@@ -531,8 +532,6 @@ static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir)
        if (*pattern == '/') {
                anchored_match = 1;
                pattern++;
-               if (strings[0][0] == '/')
-                       strings[0]++;
        }
 
        if (!anchored_match && ex->u.slash_cnt
@@ -557,7 +556,7 @@ static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir)
                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);
@@ -847,6 +846,15 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
                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;
@@ -861,7 +869,7 @@ static char default_cvsignore[] =
        " *.a *.olb *.o *.obj *.so *.exe"
        " *.Z *.elc *.ln core"
        /* The rest we added to suit ourself. */
-       " .svn/";
+       " .svn/ .bzr/";
 
 static void get_cvs_excludes(uint32 mflags)
 {
@@ -898,12 +906,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) {
@@ -923,11 +933,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;
@@ -1098,11 +1106,20 @@ static void send_rules(int f_out, struct filter_list_struct *flp)
                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)