- Define MATCHFLG_SENDER_SIDE and MATCHFLG_RECEIVER_SIDE.
[rsync/rsync.git] / exclude.c
index 9fdae3e..49ce25f 100644 (file)
--- a/exclude.c
+++ b/exclude.c
@@ -33,6 +33,7 @@ extern int eol_nulls;
 extern int list_only;
 extern int recurse;
 extern int io_error;
+extern int local_server;
 extern int delete_mode;
 extern int delete_excluded;
 extern int cvs_exclude;
@@ -277,7 +278,7 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
                }
                if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
                        rprintf(FERROR, "merge-file name overflows: %s\n",
-                               merge_file);
+                               safe_fname(merge_file));
                        return NULL;
                }
        } else {
@@ -290,7 +291,8 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
                goto done;
 
        if (dirbuf_len + fn_len >= MAXPATHLEN) {
-               rprintf(FERROR, "merge-file name overflows: %s\n", fn);
+               rprintf(FERROR, "merge-file name overflows: %s\n",
+                       safe_fname(fn));
                return NULL;
        }
        memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
@@ -603,6 +605,18 @@ int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
        return 0;
 }
 
+#define RULE_STRCMP(s,r) rule_strcmp((s), (r), sizeof (r) - 1)
+
+static const char *rule_strcmp(const char *str, const char *rule, int rule_len)
+{
+       if (strncmp(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.
@@ -637,7 +651,7 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
         * for old include/exclude patterns where just "+ " and "- " are
         * allowed as optional prefixes.  */
        if (mflags & MATCHFLG_NO_PREFIXES) {
-               if (*s == '!')
+               if (*s == '!' && mflags & MATCHFLG_CVS_IGNORE)
                        new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */
        } else if (xflags & XFLG_OLD_PREFIXES) {
                if (*s == '-' && s[1] == ' ') {
@@ -650,8 +664,35 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
                if (*s == '!')
                        new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */
        } else {
-               char *mods = "";
+               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 'i':
+                       if ((s = RULE_STRCMP(s, "include")) != NULL)
+                               ch = '+';
+                       break;
+               case 'm':
+                       if ((s = RULE_STRCMP(s, "merge")) != NULL)
+                               ch = '.';
+                       break;
+               default:
+                       ch = *s;
+                       if (s[1] == ',')
+                               s++;
+                       break;
+               }
+               switch (ch) {
                case ':':
                        new_mflags |= MATCHFLG_PERDIR_MERGE
                                    | MATCHFLG_FINISH_SETUP;
@@ -755,6 +796,35 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
 }
 
 
+static char default_cvsignore[] = 
+       /* These default ignored items come from the CVS manual. */
+       "RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS"
+       " .make.state .nse_depinfo *~ #* .#* ,* _$* *$"
+       " *.old *.bak *.BAK *.orig *.rej .del-*"
+       " *.a *.olb *.o *.obj *.so *.exe"
+       " *.Z *.elc *.ln core"
+       /* The rest we added to suit ourself. */
+       " .svn/";
+
+static void get_cvs_excludes(uint32 mflags)
+{
+       char *p, fname[MAXPATHLEN];
+       static int initialized = 0;
+
+       if (initialized)
+               return;
+       initialized = 1;
+
+       parse_rule(&cvs_filter_list, default_cvsignore, mflags, 0);
+
+       p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME");
+       if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN)
+               parse_filter_file(&cvs_filter_list, fname, mflags, 0);
+
+       parse_rule(&cvs_filter_list, getenv("CVSIGNORE"), mflags, 0);
+}
+
+
 void parse_rule(struct filter_list_struct *listp, const char *pattern,
                uint32 mflags, int xflags)
 {
@@ -826,7 +896,7 @@ void parse_rule(struct filter_list_struct *listp, const char *pattern,
 
                if (new_mflags & MATCHFLG_CVS_IGNORE
                    && !(new_mflags & MATCHFLG_MERGE_FILE))
-                       get_cvs_excludes();
+                       get_cvs_excludes(new_mflags);
        }
 }
 
@@ -905,15 +975,15 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
        fclose(fp);
 }
 
-/* If the "sending" flag is > 0, the prefix is made compatible with the
+/* If the "for_xfer" flag is set, the prefix is made compatible with the
  * current protocol_version (if possible) or a NULL is returned (if not
  * possible). */
-char *get_rule_prefix(int match_flags, const char *pat, int sending,
+char *get_rule_prefix(int match_flags, const char *pat, int for_xfer,
                      unsigned int *plen_ptr)
 {
        static char buf[MAX_RULE_PREFIX+1];
        char *op = buf;
-       int legal_len = sending && protocol_version < 29 ? 1 : MAX_RULE_PREFIX;
+       int legal_len = for_xfer && protocol_version < 29 ? 1 : MAX_RULE_PREFIX;
 
        if (match_flags & MATCHFLG_PERDIR_MERGE) {
                if (legal_len == 1)
@@ -927,15 +997,13 @@ char *get_rule_prefix(int match_flags, const char *pat, int sending,
        else
                legal_len = 0;
 
-       if (match_flags & MATCHFLG_EXCLUDE_SELF)
-               *op++ = 'e';
        if (match_flags & MATCHFLG_CVS_IGNORE)
                *op++ = 'C';
        else {
-               if (match_flags & MATCHFLG_WORD_SPLIT)
-                       *op++ = 's';
                if (match_flags & MATCHFLG_NO_INHERIT)
                        *op++ = 'n';
+               if (match_flags & MATCHFLG_WORD_SPLIT)
+                       *op++ = 'w';
                if (match_flags & MATCHFLG_NO_PREFIXES) {
                        if (match_flags & MATCHFLG_INCLUDE)
                                *op++ = '+';
@@ -943,15 +1011,15 @@ char *get_rule_prefix(int match_flags, const char *pat, int sending,
                                *op++ = '-';
                }
        }
-       if (op - buf > legal_len)
-               return NULL;
+       if (match_flags & MATCHFLG_EXCLUDE_SELF)
+               *op++ = 'e';
        if (legal_len)
                *op++ = ' ';
+       if (op - buf > legal_len)
+               return NULL;
        *op = '\0';
        if (plen_ptr)
                *plen_ptr = op - buf;
-       if (op - buf > MAX_RULE_PREFIX)
-               overflow("get_rule_prefix");
        return buf;
 }
 
@@ -992,7 +1060,9 @@ static void send_rules(int f_out, struct filter_list_struct *flp)
 /* This is only called by the client. */
 void send_filter_list(int f_out)
 {
-       if (am_sender && (!delete_mode || delete_excluded))
+       int receiver_wants_list = delete_mode && !delete_excluded;
+
+       if (local_server || (am_sender && !receiver_wants_list))
                f_out = -1;
        if (cvs_exclude && am_sender) {
                if (protocol_version >= 29)
@@ -1024,8 +1094,9 @@ void recv_filter_list(int f_in)
        char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */
        int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
        unsigned int len;
+       int receiver_wants_list = delete_mode && !delete_excluded;
 
-       if (am_sender || (delete_mode && !delete_excluded)) {
+       if (!local_server && (am_sender || receiver_wants_list)) {
                while ((len = read_int(f_in)) != 0) {
                        if (len >= sizeof line)
                                overflow("recv_rules");
@@ -1035,39 +1106,9 @@ void recv_filter_list(int f_in)
        }
 
        if (cvs_exclude) {
-               if (am_sender || protocol_version < 29)
+               if (local_server || am_sender || protocol_version < 29)
                        parse_rule(&filter_list, ":C", 0, 0);
-               if (am_sender)
+               if (local_server || am_sender)
                        parse_rule(&filter_list, "-C", 0, 0);
        }
 }
-
-
-static char default_cvsignore[] = 
-       /* These default ignored items come from the CVS manual. */
-       "RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS"
-       " .make.state .nse_depinfo *~ #* .#* ,* _$* *$"
-       " *.old *.bak *.BAK *.orig *.rej .del-*"
-       " *.a *.olb *.o *.obj *.so *.exe"
-       " *.Z *.elc *.ln core"
-       /* The rest we added to suit ourself. */
-       " .svn/";
-
-void get_cvs_excludes(void)
-{
-       static unsigned cvs_mflags = MATCHFLG_WORD_SPLIT|MATCHFLG_NO_PREFIXES;
-       char *p, fname[MAXPATHLEN];
-       static int initialized = 0;
-
-       if (initialized)
-               return;
-       initialized = 1;
-
-       parse_rule(&cvs_filter_list, default_cvsignore, cvs_mflags, 0);
-
-       p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME");
-       if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN)
-               parse_filter_file(&cvs_filter_list, fname, cvs_mflags, 0);
-
-       parse_rule(&cvs_filter_list, getenv("CVSIGNORE"), cvs_mflags, 0);
-}