Diff for /embedaddon/rsync/exclude.c between versions 1.1.1.2 and 1.1.1.4

version 1.1.1.2, 2013/10/14 07:51:14 version 1.1.1.4, 2021/03/17 00:32:36
Line 4 Line 4
  * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>   * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
  * Copyright (C) 1996 Paul Mackerras   * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool   * Copyright (C) 2002 Martin Pool
 * Copyright (C) 2003-2013 Wayne Davison * Copyright (C) 2003-2020 Wayne Davison
  *   *
  * This program is free software; you can redistribute it and/or modify   * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
Line 21 Line 21
  */   */
   
 #include "rsync.h"  #include "rsync.h"
   #include "ifuncs.h"
   
 extern int am_server;  extern int am_server;
 extern int am_sender;  extern int am_sender;
Line 44  filter_rule_list filter_list = { .debug_type = "" }; Line 45  filter_rule_list filter_list = { .debug_type = "" };
 filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };  filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };
 filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };  filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
   
/* Need room enough for ":MODS " prefix plus some room to grow. */filter_rule *last_hit_filter_rule;
#define MAX_RULE_PREFIX (16) 
   
   int saw_xattr_filter = 0;
   
   /* Need room enough for ":MODS " prefix, which can now include
    * chmod/user/group values. */
   #define MAX_RULE_PREFIX (256)
   
 #define SLASH_WILD3_SUFFIX "/***"  #define SLASH_WILD3_SUFFIX "/***"
   
 /* The dirbuf is set by push_local_filters() to the current subdirectory  /* The dirbuf is set by push_local_filters() to the current subdirectory
Line 100  static int mergelist_size = 0; Line 106  static int mergelist_size = 0;
   
 static void teardown_mergelist(filter_rule *ex)  static void teardown_mergelist(filter_rule *ex)
 {  {
           int j;
   
           if (!ex->u.mergelist)
                   return;
   
         if (DEBUG_GTE(FILTER, 2)) {          if (DEBUG_GTE(FILTER, 2)) {
                 rprintf(FINFO, "[%s] deactivating mergelist #%d%s\n",                  rprintf(FINFO, "[%s] deactivating mergelist #%d%s\n",
                         who_am_i(), mergelist_cnt - 1,                          who_am_i(), mergelist_cnt - 1,
                         ex->u.mergelist->debug_type);                          ex->u.mergelist->debug_type);
         }          }
   
         /* We should deactivate mergelists in LIFO order. */  
         assert(mergelist_cnt > 0);  
         assert(ex == mergelist_parents[mergelist_cnt - 1]);  
   
         /* The parent_dirscan filters should have been freed. */  
         assert(ex->u.mergelist->parent_dirscan_head == NULL);  
   
         free(ex->u.mergelist->debug_type);          free(ex->u.mergelist->debug_type);
         free(ex->u.mergelist);          free(ex->u.mergelist);
        mergelist_cnt--;
         for (j = 0; j < mergelist_cnt; j++) {
                 if (mergelist_parents[j] == ex) {
                         mergelist_parents[j] = NULL;
                         break;
                 }
         }
         while (mergelist_cnt && mergelist_parents[mergelist_cnt-1] == NULL)
                 mergelist_cnt--;
 }  }
   
   static struct filter_chmod_struct *ref_filter_chmod(struct filter_chmod_struct *chmod)
   {
           chmod->ref_cnt++;
           assert(chmod->ref_cnt != 0); /* Catch overflow. */
           return chmod;
   }
   
   static void unref_filter_chmod(struct filter_chmod_struct *chmod)
   {
           chmod->ref_cnt--;
           if (chmod->ref_cnt == 0) {
                   free(chmod->modestr);
                   free_chmod_mode(chmod->modes);
                   free(chmod);
           }
   }
   
 static void free_filter(filter_rule *ex)  static void free_filter(filter_rule *ex)
 {  {
           if (ex->rflags & FILTRULE_CHMOD)
                   unref_filter_chmod(ex->chmod);
           if (ex->rflags & FILTRULE_PERDIR_MERGE)
                   teardown_mergelist(ex);
         free(ex->pattern);          free(ex->pattern);
         free(ex);          free(ex);
 }  }
   
static void free_filters(filter_rule *head)static void free_filters(filter_rule *ent)
 {  {
        filter_rule *rev_head = NULL;        while (ent) {
                filter_rule *next = ent->next;
        /* Reverse the list so we deactivate mergelists in the proper LIFO                free_filter(ent);
         * order. */                ent = next;
        while (head) { 
                filter_rule *next = head->next; 
                head->next = rev_head; 
                rev_head = head; 
                head = next; 
         }          }
   
         while (rev_head) {  
                 filter_rule *prev = rev_head->next;  
                 /* Tear down mergelists here, not in free_filter, so that we  
                  * affect only real filter lists and not temporarily allocated  
                  * filters. */  
                 if (rev_head->rflags & FILTRULE_PERDIR_MERGE)  
                         teardown_mergelist(rev_head);  
                 free_filter(rev_head);  
                 rev_head = prev;  
         }  
 }  }
   
 /* Build a filter structure given a filter pattern.  The value in "pat"  /* Build a filter structure given a filter pattern.  The value in "pat"
Line 205  static void add_rule(filter_rule_list *listp, const ch Line 222  static void add_rule(filter_rule_list *listp, const ch
         } else          } else
                 suf_len = 0;                  suf_len = 0;
   
        if (!(rule->pattern = new_array(char, pre_len + pat_len + suf_len + 1)))        rule->pattern = new_array(char, pre_len + pat_len + suf_len + 1);
                out_of_memory("add_rule"); 
         if (pre_len) {          if (pre_len) {
                 memcpy(rule->pattern, dirbuf + module_dirlen, pre_len);                  memcpy(rule->pattern, dirbuf + module_dirlen, pre_len);
                 for (cp = rule->pattern; cp < rule->pattern + pre_len; cp++) {                  for (cp = rule->pattern; cp < rule->pattern + pre_len; cp++) {
Line 252  static void add_rule(filter_rule_list *listp, const ch Line 268  static void add_rule(filter_rule_list *listp, const ch
                  * add it again. */                   * add it again. */
                 for (i = 0; i < mergelist_cnt; i++) {                  for (i = 0; i < mergelist_cnt; i++) {
                         filter_rule *ex = mergelist_parents[i];                          filter_rule *ex = mergelist_parents[i];
                        const char *s = strrchr(ex->pattern, '/');                        const char *s;
                         if (!ex)
                                 continue;
                         s = strrchr(ex->pattern, '/');
                         if (s)                          if (s)
                                 s++;                                  s++;
                         else                          else
Line 264  static void add_rule(filter_rule_list *listp, const ch Line 283  static void add_rule(filter_rule_list *listp, const ch
                         }                          }
                 }                  }
   
                if (!(lp = new_array(filter_rule_list, 1)))                lp = new_array0(filter_rule_list, 1);
                        out_of_memory("add_rule"); 
                lp->head = lp->tail = lp->parent_dirscan_head = NULL; 
                 if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)                  if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)
                         out_of_memory("add_rule");                          out_of_memory("add_rule");
                 rule->u.mergelist = lp;                  rule->u.mergelist = lp;
   
                 if (mergelist_cnt == mergelist_size) {                  if (mergelist_cnt == mergelist_size) {
                         mergelist_size += 5;                          mergelist_size += 5;
                        mergelist_parents = realloc_array(mergelist_parents,                        mergelist_parents = realloc_array(mergelist_parents, filter_rule *, mergelist_size);
                                                filter_rule *, 
                                                mergelist_size); 
                        if (!mergelist_parents) 
                                out_of_memory("add_rule"); 
                 }                  }
                 if (DEBUG_GTE(FILTER, 2)) {                  if (DEBUG_GTE(FILTER, 2)) {
                         rprintf(FINFO, "[%s] activating mergelist #%d%s\n",                          rprintf(FINFO, "[%s] activating mergelist #%d%s\n",
Line 297  static void add_rule(filter_rule_list *listp, const ch Line 310  static void add_rule(filter_rule_list *listp, const ch
         }          }
 }  }
   
static void clear_filter_list(filter_rule_list *listp)/* This frees any non-inherited items, leaving just inherited items on the list. */
 static void pop_filter_list(filter_rule_list *listp)
 {  {
        if (listp->tail) {        filter_rule *inherited;
                /* Truncate any inherited items from the local list. */ 
                listp->tail->next = NULL; 
                /* Now free everything that is left. */ 
                free_filters(listp->head); 
        } 
   
        listp->head = listp->tail = NULL;        if (!listp->tail)
                 return;
 
         inherited = listp->tail->next;
 
         /* Truncate any inherited items from the local list. */
         listp->tail->next = NULL;
         /* Now free everything that is left. */
         free_filters(listp->head);
 
         listp->head = inherited;
         listp->tail = NULL;
 }  }
   
 /* This returns an expanded (absolute) filename for the merge-file name if  /* This returns an expanded (absolute) filename for the merge-file name if
Line 356  static char *parse_merge_name(const char *merge_file,  Line 376  static char *parse_merge_name(const char *merge_file, 
                 fn_len = clean_fname(fn, CFN_COLLAPSE_DOT_DOT_DIRS);                  fn_len = clean_fname(fn, CFN_COLLAPSE_DOT_DOT_DIRS);
         }          }
   
        /* If the name isn't in buf yet, it's wasn't absolute. */        /* If the name isn't in buf yet, it wasn't absolute. */
         if (fn != buf) {          if (fn != buf) {
                 int d_len = dirbuf_len - prefix_skip;                  int d_len = dirbuf_len - prefix_skip;
                 if (d_len + fn_len >= MAXPATHLEN) {                  if (d_len + fn_len >= MAXPATHLEN) {
Line 457  static BOOL setup_merge_file(int mergelist_num, filter Line 477  static BOOL setup_merge_file(int mergelist_num, filter
                 strlcpy(y, save, MAXPATHLEN);                  strlcpy(y, save, MAXPATHLEN);
                 while ((*x++ = *y++) != '/') {}                  while ((*x++ = *y++) != '/') {}
         }          }
         /* Save current head for freeing when the mergelist becomes inactive. */  
         lp->parent_dirscan_head = lp->head;  
         parent_dirscan = False;          parent_dirscan = False;
         if (DEBUG_GTE(FILTER, 2)) {          if (DEBUG_GTE(FILTER, 2)) {
                 rprintf(FINFO, "[%s] completed parent_dirscan for mergelist #%d%s\n",                  rprintf(FINFO, "[%s] completed parent_dirscan for mergelist #%d%s\n",
Line 496  void *push_local_filters(const char *dir, unsigned int Line 514  void *push_local_filters(const char *dir, unsigned int
         push = (struct local_filter_state *)new_array(char,          push = (struct local_filter_state *)new_array(char,
                           sizeof (struct local_filter_state)                            sizeof (struct local_filter_state)
                         + (mergelist_cnt-1) * sizeof (filter_rule_list));                          + (mergelist_cnt-1) * sizeof (filter_rule_list));
         if (!push)  
                 out_of_memory("push_local_filters");  
   
         push->mergelist_cnt = mergelist_cnt;          push->mergelist_cnt = mergelist_cnt;
         for (i = 0; i < mergelist_cnt; i++) {          for (i = 0; i < mergelist_cnt; i++) {
                memcpy(&push->mergelists[i], mergelist_parents[i]->u.mergelist,                filter_rule *ex = mergelist_parents[i];
                       sizeof (filter_rule_list));                if (!ex)
                         continue;
                 memcpy(&push->mergelists[i], ex->u.mergelist, sizeof (filter_rule_list));
         }          }
   
         /* Note: parse_filter_file() might increase mergelist_cnt, so keep          /* Note: parse_filter_file() might increase mergelist_cnt, so keep
          * this loop separate from the above loop. */           * this loop separate from the above loop. */
         for (i = 0; i < mergelist_cnt; i++) {          for (i = 0; i < mergelist_cnt; i++) {
                 filter_rule *ex = mergelist_parents[i];                  filter_rule *ex = mergelist_parents[i];
                filter_rule_list *lp = ex->u.mergelist;                filter_rule_list *lp;
                 if (!ex)
                         continue;
                 lp = ex->u.mergelist;
   
                 if (DEBUG_GTE(FILTER, 2)) {                  if (DEBUG_GTE(FILTER, 2)) {
                         rprintf(FINFO, "[%s] pushing mergelist #%d%s\n",                          rprintf(FINFO, "[%s] pushing mergelist #%d%s\n",
Line 553  void pop_local_filters(void *mem) Line 574  void pop_local_filters(void *mem)
   
         for (i = mergelist_cnt; i-- > 0; ) {          for (i = mergelist_cnt; i-- > 0; ) {
                 filter_rule *ex = mergelist_parents[i];                  filter_rule *ex = mergelist_parents[i];
                filter_rule_list *lp = ex->u.mergelist;                filter_rule_list *lp;
                 if (!ex)
                         continue;
                 lp = ex->u.mergelist;
   
                 if (DEBUG_GTE(FILTER, 2)) {                  if (DEBUG_GTE(FILTER, 2)) {
                         rprintf(FINFO, "[%s] popping mergelist #%d%s\n",                          rprintf(FINFO, "[%s] popping mergelist #%d%s\n",
                                 who_am_i(), i, lp->debug_type);                                  who_am_i(), i, lp->debug_type);
                 }                  }
   
                clear_filter_list(lp);                pop_filter_list(lp);
                if (i >= old_mergelist_cnt && lp->head) {
                if (i >= old_mergelist_cnt) {                        /* This mergelist does not exist in the state to be restored, but it
                        /* This mergelist does not exist in the state to be                         * still has inherited rules.  This can sometimes happen if a per-dir
                         * restored.  Free its parent_dirscan list to clean up                         * merge file calls setup_merge_file() in push_local_filters() and that
                         * any per-dir mergelists defined there so we don't                         * leaves some inherited rules that aren't in the pushed list state. */
                         * crash trying to restore nonexistent state for them 
                         * below.  (Counterpart to setup_merge_file call in 
                         * push_local_filters.  Must be done here, not in 
                         * free_filter, for LIFO order.) */ 
                         if (DEBUG_GTE(FILTER, 2)) {                          if (DEBUG_GTE(FILTER, 2)) {
                                 rprintf(FINFO, "[%s] freeing parent_dirscan filters of mergelist #%d%s\n",                                  rprintf(FINFO, "[%s] freeing parent_dirscan filters of mergelist #%d%s\n",
                                         who_am_i(), i, ex->u.mergelist->debug_type);                                          who_am_i(), i, ex->u.mergelist->debug_type);
                         }                          }
                        free_filters(lp->parent_dirscan_head);                        pop_filter_list(lp);
                        lp->parent_dirscan_head = NULL; 
                 }                  }
         }          }
   
        /* If we cleaned things up properly, the only still-active mergelists        if (!pop)
         * should be those with a state to be restored. */                return; /* No state to restore. */
        assert(mergelist_cnt == old_mergelist_cnt); 
   
        if (!pop) {        for (i = 0; i < old_mergelist_cnt; i++) {
                /* No state to restore. */                filter_rule *ex = mergelist_parents[i];
                return;                if (!ex)
                         continue;
                 memcpy(ex->u.mergelist, &pop->mergelists[i], sizeof (filter_rule_list));
         }          }
   
         for (i = 0; i < mergelist_cnt; i++) {  
                 memcpy(mergelist_parents[i]->u.mergelist, &pop->mergelists[i],  
                        sizeof (filter_rule_list));  
         }  
   
         free(pop);          free(pop);
 }  }
   
Line 624  void change_local_filter_dir(const char *dname, int dl Line 639  void change_local_filter_dir(const char *dname, int dl
         filt_array[cur_depth] = push_local_filters(dname, dlen);          filt_array[cur_depth] = push_local_filters(dname, dlen);
 }  }
   
static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)static int rule_matches(const char *fname, filter_rule *ex, int name_flags)
 {  {
         int slash_handling, str_cnt = 0, anchored_match = 0;          int slash_handling, str_cnt = 0, anchored_match = 0;
         int ret_match = ex->rflags & FILTRULE_NEGATE ? 0 : 1;          int ret_match = ex->rflags & FILTRULE_NEGATE ? 0 : 1;
Line 635  static int rule_matches(const char *fname, filter_rule Line 650  static int rule_matches(const char *fname, filter_rule
         if (!*name)          if (!*name)
                 return 0;                  return 0;
   
           if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR))
                   return 0;
   
         if (!ex->u.slash_cnt && !(ex->rflags & FILTRULE_WILD2)) {          if (!ex->u.slash_cnt && !(ex->rflags & FILTRULE_WILD2)) {
                 /* If the pattern does not have any slashes AND it does                  /* If the pattern does not have any slashes AND it does
                  * not have a "**" (which could match a slash), then we                   * not have a "**" (which could match a slash), then we
Line 652  static int rule_matches(const char *fname, filter_rule Line 670  static int rule_matches(const char *fname, filter_rule
                 strings[str_cnt++] = "/";                  strings[str_cnt++] = "/";
         }          }
         strings[str_cnt++] = name;          strings[str_cnt++] = name;
        if (name_is_dir) {        if (name_flags & NAME_IS_DIR) {
                 /* Allow a trailing "/"+"***" to match the directory. */                  /* Allow a trailing "/"+"***" to match the directory. */
                 if (ex->rflags & FILTRULE_WILD3_SUFFIX)                  if (ex->rflags & FILTRULE_WILD3_SUFFIX)
                         strings[str_cnt++] = "/";                          strings[str_cnt++] = "/";
Line 687  static int rule_matches(const char *fname, filter_rule Line 705  static int rule_matches(const char *fname, filter_rule
                 if (litmatch_array(pattern, strings, slash_handling))                  if (litmatch_array(pattern, strings, slash_handling))
                         return ret_match;                          return ret_match;
         } else if (anchored_match) {          } else if (anchored_match) {
                if (strcmp(name, pattern) == 0)                if (ic_strEQ(name, pattern))
                         return ret_match;                          return ret_match;
         } else {          } else {
                 int l1 = strlen(name);                  int l1 = strlen(name);
                 int l2 = strlen(pattern);                  int l2 = strlen(pattern);
                if (l2 <= l1 &&                if (l2 <= l1
                    strcmp(name+(l1-l2),pattern) == 0 &&                 && ic_strEQ(name + (l1-l2), pattern)
                    (l1==l2 || name[l1-(l2+1)] == '/')) {                 && (l1 == l2 || name[l1 - (l2+1)] == '/'))
                         return ret_match;                          return ret_match;
                 }  
         }          }
   
         return !ret_match;          return !ret_match;
Line 704  static int rule_matches(const char *fname, filter_rule Line 721  static int rule_matches(const char *fname, filter_rule
   
 static void report_filter_result(enum logcode code, char const *name,  static void report_filter_result(enum logcode code, char const *name,
                                  filter_rule const *ent,                                   filter_rule const *ent,
                                 int name_is_dir, const char *type)                                 int name_flags, const char *type)
 {  {
         /* If a trailing slash is present to match only directories,          /* If a trailing slash is present to match only directories,
          * then it is stripped out by add_rule().  So as a special           * then it is stripped out by add_rule().  So as a special
Line 714  static void report_filter_result(enum logcode code, ch Line 731  static void report_filter_result(enum logcode code, ch
                 static char *actions[2][2]                  static char *actions[2][2]
                     = { {"show", "hid"}, {"risk", "protect"} };                      = { {"show", "hid"}, {"risk", "protect"} };
                 const char *w = who_am_i();                  const char *w = who_am_i();
                   const char *t = name_flags & NAME_IS_XATTR ? "xattr"
                                 : name_flags & NAME_IS_DIR ? "directory"
                                 : "file";
                 rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",                  rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
                     w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],                      w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],
                    name_is_dir ? "directory" : "file", name, ent->pattern,                    t, name, ent->pattern,
                     ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);                      ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);
         }          }
 }  }
   
   /* This function is used to check if a file should be included/excluded
    * from the list of files based on its name and type etc.  The value of
    * filter_level is set to either SERVER_FILTERS or ALL_FILTERS.
    * "last_hit_filter_rule" will be set to the operative filter, or NULL if none. */
   
   int name_is_excluded(const char *fname, int name_flags, int filter_level)
   {
           if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fname, name_flags) < 0) {
                   if (!(name_flags & NAME_IS_XATTR))
                           errno = ENOENT;
                   return 1;
           }
   
           /* Don't leave a daemon include in last_hit_filter_rule. */
           last_hit_filter_rule = NULL;
   
           if (filter_level != ALL_FILTERS)
                   return 0;
   
           if (filter_list.head && check_filter(&filter_list, FINFO, fname, name_flags) < 0)
                   return 1;
   
           return 0;
   }
   
 /* Return -1 if file "name" is defined to be excluded by the specified  /* 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. */ * exclude list, 1 if it is included, and 0 if it was not matched.
  * Sets last_hit_filter_rule to the filter that was hit, or NULL if none. */
 int check_filter(filter_rule_list *listp, enum logcode code,  int check_filter(filter_rule_list *listp, enum logcode code,
                 const char *name, int name_is_dir)                 const char *name, int name_flags)
 {  {
         filter_rule *ent;          filter_rule *ent;
   
Line 732  int check_filter(filter_rule_list *listp, enum logcode Line 778  int check_filter(filter_rule_list *listp, enum logcode
                 if (ignore_perishable && ent->rflags & FILTRULE_PERISHABLE)                  if (ignore_perishable && ent->rflags & FILTRULE_PERISHABLE)
                         continue;                          continue;
                 if (ent->rflags & FILTRULE_PERDIR_MERGE) {                  if (ent->rflags & FILTRULE_PERDIR_MERGE) {
                        int rc = check_filter(ent->u.mergelist, code, name,                        int rc = check_filter(ent->u.mergelist, code, name, name_flags);
                                              name_is_dir); 
                         if (rc)                          if (rc)
                                 return rc;                                  return rc;
                         continue;                          continue;
                 }                  }
                 if (ent->rflags & FILTRULE_CVS_IGNORE) {                  if (ent->rflags & FILTRULE_CVS_IGNORE) {
                        int rc = check_filter(&cvs_filter_list, code, name,                        int rc = check_filter(&cvs_filter_list, code, name, name_flags);
                                              name_is_dir); 
                         if (rc)                          if (rc)
                                 return rc;                                  return rc;
                         continue;                          continue;
                 }                  }
                if (rule_matches(name, ent, name_is_dir)) {                if (rule_matches(name, ent, name_flags)) {
                        report_filter_result(code, name, ent, name_is_dir,                        report_filter_result(code, name, ent, name_flags, listp->debug_type);
                                             listp->debug_type);                        last_hit_filter_rule = ent;
                         return ent->rflags & FILTRULE_INCLUDE ? 1 : -1;                          return ent->rflags & FILTRULE_INCLUDE ? 1 : -1;
                 }                  }
         }          }
   
           last_hit_filter_rule = NULL;
         return 0;          return 0;
 }  }
   
Line 768  static const uchar *rule_strcmp(const uchar *str, cons Line 813  static const uchar *rule_strcmp(const uchar *str, cons
         return NULL;          return NULL;
 }  }
   
   static char *grab_paren_value(const uchar **s_ptr)
   {
           const uchar *start, *end;
           int val_sz;
           char *val;
   
           if ((*s_ptr)[1] != '(')
                   return NULL;
           start = (*s_ptr) + 2;
   
           for (end = start; *end != ')'; end++)
                   if (!*end || *end == ' ' || *end == '_')
                           return NULL;
   
           val_sz = end - start + 1;
           val = new_array(char, val_sz);
           strlcpy(val, (const char *)start, val_sz);
           *s_ptr = end; /* remember ++s in parse_rule_tok */
           return val;
   }
   
   static struct filter_chmod_struct *make_chmod_struct(char *modestr)
   {
           struct filter_chmod_struct *chmod;
           struct chmod_mode_struct *modes = NULL;
   
           if (!parse_chmod(modestr, &modes))
                   return NULL;
   
           chmod = new(struct filter_chmod_struct);
           chmod->ref_cnt = 1;
           chmod->modestr = modestr;
           chmod->modes = modes;
           return chmod;
   }
   
 #define FILTRULES_FROM_CONTAINER (FILTRULE_ABS_PATH | FILTRULE_INCLUDE \  #define FILTRULES_FROM_CONTAINER (FILTRULE_ABS_PATH | FILTRULE_INCLUDE \
                                 | FILTRULE_DIRECTORY | FILTRULE_NEGATE \                                  | FILTRULE_DIRECTORY | FILTRULE_NEGATE \
                                | FILTRULE_PERISHABLE)                                | FILTRULE_PERISHABLE | FILTRULES_ATTRS)
   
 /* Gets the next include/exclude rule from *rulestr_ptr and advances  /* Gets the next include/exclude rule from *rulestr_ptr and advances
  * *rulestr_ptr to point beyond it.  Stores the pattern's start (within   * *rulestr_ptr to point beyond it.  Stores the pattern's start (within
Line 785  static filter_rule *parse_rule_tok(const char **rulest Line 866  static filter_rule *parse_rule_tok(const char **rulest
                                    const char **pat_ptr, unsigned int *pat_len_ptr)                                     const char **pat_ptr, unsigned int *pat_len_ptr)
 {  {
         const uchar *s = (const uchar *)*rulestr_ptr;          const uchar *s = (const uchar *)*rulestr_ptr;
           char *val;
         filter_rule *rule;          filter_rule *rule;
         unsigned int len;          unsigned int len;
   
Line 798  static filter_rule *parse_rule_tok(const char **rulest Line 880  static filter_rule *parse_rule_tok(const char **rulest
         if (!*s)          if (!*s)
                 return NULL;                  return NULL;
   
        if (!(rule = new0(filter_rule)))        rule = new0(filter_rule);
                out_of_memory("parse_rule_tok"); 
   
         /* Inherit from the template.  Don't inherit FILTRULES_SIDES; we check          /* Inherit from the template.  Don't inherit FILTRULES_SIDES; we check
          * that later. */           * that later. */
         rule->rflags = template->rflags & FILTRULES_FROM_CONTAINER;          rule->rflags = template->rflags & FILTRULES_FROM_CONTAINER;
           if (template->rflags & FILTRULE_CHMOD)
                   rule->chmod = ref_filter_chmod(template->chmod);
           if (template->rflags & FILTRULE_FORCE_OWNER)
                   rule->force_uid = template->force_uid;
           if (template->rflags & FILTRULE_FORCE_GROUP)
                   rule->force_gid = template->force_gid;
   
         /* Figure out what kind of a filter rule "s" is pointing at.  Note          /* Figure out what kind of a filter rule "s" is pointing at.  Note
          * that if FILTRULE_NO_PREFIXES is set, the rule is either an include           * that if FILTRULE_NO_PREFIXES is set, the rule is either an include
Line 872  static filter_rule *parse_rule_tok(const char **rulest Line 959  static filter_rule *parse_rule_tok(const char **rulest
                 switch (ch) {                  switch (ch) {
                 case ':':                  case ':':
                         rule->rflags |= FILTRULE_PERDIR_MERGE                          rule->rflags |= FILTRULE_PERDIR_MERGE
                                       | FILTRULE_FINISH_SETUP;                                      | FILTRULE_FINISH_SETUP;
                         /* FALL THROUGH */                          /* FALL THROUGH */
                 case '.':                  case '.':
                         rule->rflags |= FILTRULE_MERGE_FILE;                          rule->rflags |= FILTRULE_MERGE_FILE;
Line 949  static filter_rule *parse_rule_tok(const char **rulest Line 1036  static filter_rule *parse_rule_tok(const char **rulest
                                         goto invalid;                                          goto invalid;
                                 rule->rflags |= FILTRULE_EXCLUDE_SELF;                                  rule->rflags |= FILTRULE_EXCLUDE_SELF;
                                 break;                                  break;
                           case 'g': {
                                   gid_t gid;
   
                                   if (!(val = grab_paren_value(&s)))
                                           goto invalid;
                                   if (group_to_gid(val, &gid, True)) {
                                           rule->rflags |= FILTRULE_FORCE_GROUP;
                                           rule->force_gid = gid;
                                   } else {
                                           rprintf(FERROR,
                                                   "unknown group '%s' in filter rule: %s\n",
                                                   val, *rulestr_ptr);
                                           exit_cleanup(RERR_SYNTAX);
                                   }
                                   free(val);
                                   break;
                           }
                           case 'm': {
                                   struct filter_chmod_struct *chmod;
   
                                   if (!(val = grab_paren_value(&s)))
                                           goto invalid;
                                   if ((chmod = make_chmod_struct(val))) {
                                           if (rule->rflags & FILTRULE_CHMOD)
                                                   unref_filter_chmod(rule->chmod);
                                           rule->rflags |= FILTRULE_CHMOD;
                                           rule->chmod = chmod;
                                   } else {
                                           rprintf(FERROR,
                                                   "unparseable chmod string '%s' in filter rule: %s\n",
                                                   val, *rulestr_ptr);
                                           exit_cleanup(RERR_SYNTAX);
                                   }
                                   break;
                           }
                         case 'n':                          case 'n':
                                 if (!(rule->rflags & FILTRULE_MERGE_FILE))                                  if (!(rule->rflags & FILTRULE_MERGE_FILE))
                                         goto invalid;                                          goto invalid;
                                 rule->rflags |= FILTRULE_NO_INHERIT;                                  rule->rflags |= FILTRULE_NO_INHERIT;
                                 break;                                  break;
                           case 'o': {
                                   uid_t uid;
   
                                   if (!(val = grab_paren_value(&s)))
                                           goto invalid;
                                   if (user_to_uid(val, &uid, True)) {
                                           rule->rflags |= FILTRULE_FORCE_OWNER;
                                           rule->force_uid = uid;
                                   } else {
                                           rprintf(FERROR,
                                                   "unknown user '%s' in filter rule: %s\n",
                                                   val, *rulestr_ptr);
                                           exit_cleanup(RERR_SYNTAX);
                                   }
                                   free(val);
                                   break;
                           }
                         case 'p':                          case 'p':
                                 rule->rflags |= FILTRULE_PERISHABLE;                                  rule->rflags |= FILTRULE_PERISHABLE;
                                 break;                                  break;
Line 972  static filter_rule *parse_rule_tok(const char **rulest Line 1111  static filter_rule *parse_rule_tok(const char **rulest
                                         goto invalid;                                          goto invalid;
                                 rule->rflags |= FILTRULE_WORD_SPLIT;                                  rule->rflags |= FILTRULE_WORD_SPLIT;
                                 break;                                  break;
                           case 'x':
                                   rule->rflags |= FILTRULE_XATTR;
                                   saw_xattr_filter = 1;
                                   break;
                         }                          }
                 }                  }
                 if (*s)                  if (*s)
Line 1024  static filter_rule *parse_rule_tok(const char **rulest Line 1167  static filter_rule *parse_rule_tok(const char **rulest
         return rule;          return rule;
 }  }
   
 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/ .git/ .hg/ .bzr/";  
   
 static void get_cvs_excludes(uint32 rflags)  static void get_cvs_excludes(uint32 rflags)
 {  {
         static int initialized = 0;          static int initialized = 0;
Line 1043  static void get_cvs_excludes(uint32 rflags) Line 1176  static void get_cvs_excludes(uint32 rflags)
                 return;                  return;
         initialized = 1;          initialized = 1;
   
        parse_filter_str(&cvs_filter_list, default_cvsignore,        parse_filter_str(&cvs_filter_list, default_cvsignore(),
                          rule_template(rflags | (protocol_version >= 30 ? FILTRULE_PERISHABLE : 0)),                           rule_template(rflags | (protocol_version >= 30 ? FILTRULE_PERISHABLE : 0)),
                          0);                           0);
   
Line 1093  void parse_filter_str(filter_rule_list *listp, const c Line 1226  void parse_filter_str(filter_rule_list *listp, const c
                                         "[%s] clearing filter list%s\n",                                          "[%s] clearing filter list%s\n",
                                         who_am_i(), listp->debug_type);                                          who_am_i(), listp->debug_type);
                         }                          }
                        clear_filter_list(listp);                        pop_filter_list(listp);
                         listp->head = NULL;
                         goto free_continue;                          goto free_continue;
                 }                  }
   
Line 1106  void parse_filter_str(filter_rule_list *listp, const c Line 1240  void parse_filter_str(filter_rule_list *listp, const c
                                 const char *name;                                  const char *name;
                                 filter_rule *excl_self;                                  filter_rule *excl_self;
   
                                if (!(excl_self = new0(filter_rule)))                                excl_self = new0(filter_rule);
                                        out_of_memory("parse_filter_str"); 
                                 /* Find the beginning of the basename and add an exclude for it. */                                  /* Find the beginning of the basename and add an exclude for it. */
                                 for (name = pat + pat_len; name > pat && name[-1] != '/'; name--) {}                                  for (name = pat + pat_len; name > pat && name[-1] != '/'; name--) {}
                                 add_rule(listp, name, (pat + pat_len) - name, excl_self, 0);                                  add_rule(listp, name, (pat + pat_len) - name, excl_self, 0);
Line 1258  char *get_rule_prefix(filter_rule *rule, const char *p Line 1391  char *get_rule_prefix(filter_rule *rule, const char *p
         }          }
         if (rule->rflags & FILTRULE_EXCLUDE_SELF)          if (rule->rflags & FILTRULE_EXCLUDE_SELF)
                 *op++ = 'e';                  *op++ = 'e';
           if (rule->rflags & FILTRULE_XATTR)
                   *op++ = 'x';
         if (rule->rflags & FILTRULE_SENDER_SIDE          if (rule->rflags & FILTRULE_SENDER_SIDE
             && (!for_xfer || protocol_version >= 29))              && (!for_xfer || protocol_version >= 29))
                 *op++ = 's';                  *op++ = 's';
Line 1271  char *get_rule_prefix(filter_rule *rule, const char *p Line 1406  char *get_rule_prefix(filter_rule *rule, const char *p
                 else if (am_sender)                  else if (am_sender)
                         return NULL;                          return NULL;
         }          }
           if (rule->rflags & FILTRULES_ATTRS) {
                   if (!for_xfer || protocol_version >= 31) {
                           if (rule->rflags & FILTRULE_CHMOD)
                                   if (!snappendf(&op, (buf + sizeof buf) - op,
                                           "m(%s)", rule->chmod->modestr))
                                           return NULL;
                           if (rule->rflags & FILTRULE_FORCE_OWNER)
                                   if (!snappendf(&op, (buf + sizeof buf) - op,
                                           "o(%u)", (unsigned)rule->force_uid))
                                           return NULL;
                           if (rule->rflags & FILTRULE_FORCE_GROUP)
                                   if (!snappendf(&op, (buf + sizeof buf) - op,
                                           "g(%u)", (unsigned)rule->force_gid))
                                           return NULL;
                   } else if (!am_sender)
                           return NULL;
           }
         if (op - buf > legal_len)          if (op - buf > legal_len)
                 return NULL;                  return NULL;
         if (legal_len)          if (legal_len)
Line 1376  void recv_filter_list(int f_in) Line 1528  void recv_filter_list(int f_in)
         char line[BIGPATHBUFLEN];          char line[BIGPATHBUFLEN];
         int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;          int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
         int receiver_wants_list = prune_empty_dirs          int receiver_wants_list = prune_empty_dirs
            || (delete_mode            || (delete_mode && (!delete_excluded || protocol_version >= 29));
             && (!delete_excluded || protocol_version >= 29)); 
         unsigned int len;          unsigned int len;
   
         if (!local_server && (am_sender || receiver_wants_list)) {          if (!local_server && (am_sender || receiver_wants_list)) {

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>