version 1.1.1.3, 2016/11/01 09:54:32
|
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-2015 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 124 static void teardown_mergelist(filter_rule *ex)
|
Line 130 static void teardown_mergelist(filter_rule *ex)
|
mergelist_cnt--; |
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) |
if (ex->rflags & FILTRULE_PERDIR_MERGE) |
teardown_mergelist(ex); |
teardown_mergelist(ex); |
free(ex->pattern); |
free(ex->pattern); |
Line 197 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 259 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_array0(filter_rule_list, 1))) | lp = new_array0(filter_rule_list, 1); |
out_of_memory("add_rule"); | |
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 495 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++) { |
Line 622 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 633 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 650 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 685 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 702 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 712 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 730 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 766 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 783 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 796 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 947 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 970 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 1022 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 1041 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 1105 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 1257 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 1270 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 1375 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)) { |