00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "rsync.h"
00028
00029 extern int verbose;
00030 extern int am_server;
00031 extern int am_sender;
00032 extern int eol_nulls;
00033 extern int list_only;
00034 extern int recurse;
00035 extern int io_error;
00036 extern int local_server;
00037 extern int prune_empty_dirs;
00038 extern int delete_mode;
00039 extern int delete_excluded;
00040 extern int cvs_exclude;
00041 extern int sanitize_paths;
00042 extern int protocol_version;
00043 extern int module_id;
00044
00045 extern char curr_dir[];
00046 extern unsigned int curr_dir_len;
00047 extern unsigned int module_dirlen;
00048
00049 struct filter_list_struct filter_list = { 0, 0, "" };
00050 struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" };
00051 struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
00052
00053
00054 #define MAX_RULE_PREFIX (16)
00055
00056 #define MODIFIERS_MERGE_FILE "-+Cenw"
00057 #define MODIFIERS_INCL_EXCL "/!Crs"
00058 #define MODIFIERS_HIDE_PROTECT "/!"
00059
00060
00061
00062
00063
00064 static char dirbuf[MAXPATHLEN+1];
00065 static unsigned int dirbuf_len = 0;
00066 static int dirbuf_depth;
00067
00068
00069 static BOOL parent_dirscan = False;
00070
00071
00072
00073
00074 static struct filter_struct **mergelist_parents;
00075 static int mergelist_cnt = 0;
00076 static int mergelist_size = 0;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 static void free_filter(struct filter_struct *ex)
00110 {
00111 if (ex->match_flags & MATCHFLG_PERDIR_MERGE) {
00112 free(ex->u.mergelist->debug_type);
00113 free(ex->u.mergelist);
00114 mergelist_cnt--;
00115 }
00116 free(ex->pattern);
00117 free(ex);
00118 }
00119
00120
00121
00122 static void add_rule(struct filter_list_struct *listp, const char *pat,
00123 unsigned int pat_len, uint32 mflags, int xflags)
00124 {
00125 struct filter_struct *ret;
00126 const char *cp;
00127 unsigned int ex_len;
00128
00129 if (verbose > 2) {
00130 rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n",
00131 who_am_i(), get_rule_prefix(mflags, pat, 0, NULL),
00132 (int)pat_len, pat,
00133 (mflags & MATCHFLG_DIRECTORY) ? "/" : "",
00134 listp->debug_type);
00135 }
00136
00137
00138
00139 if (xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH)) {
00140 uint32 mf = mflags & (MATCHFLG_RECEIVER_SIDE|MATCHFLG_SENDER_SIDE);
00141 if (am_sender) {
00142 if (mf == MATCHFLG_RECEIVER_SIDE)
00143 return;
00144 } else {
00145 if (mf == MATCHFLG_SENDER_SIDE)
00146 return;
00147 }
00148 }
00149
00150 if (!(ret = new(struct filter_struct)))
00151 out_of_memory("add_rule");
00152 memset(ret, 0, sizeof ret[0]);
00153
00154 if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))
00155 && ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/')
00156 || (xflags & XFLG_ABS_IF_SLASH && strchr(pat, '/') != NULL))) {
00157 mflags |= MATCHFLG_ABS_PATH;
00158 if (*pat == '/')
00159 ex_len = dirbuf_len - module_dirlen - 1;
00160 else
00161 ex_len = 0;
00162 } else
00163 ex_len = 0;
00164 if (!(ret->pattern = new_array(char, ex_len + pat_len + 1)))
00165 out_of_memory("add_rule");
00166 if (ex_len)
00167 memcpy(ret->pattern, dirbuf + module_dirlen, ex_len);
00168 strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
00169 pat_len += ex_len;
00170
00171 if (strpbrk(ret->pattern, "*[?")) {
00172 mflags |= MATCHFLG_WILD;
00173 if ((cp = strstr(ret->pattern, "**")) != NULL) {
00174 mflags |= MATCHFLG_WILD2;
00175
00176 if (cp == ret->pattern)
00177 mflags |= MATCHFLG_WILD2_PREFIX;
00178
00179 if (pat_len >= 3
00180 && ret->pattern[pat_len-3] == '*'
00181 && ret->pattern[pat_len-2] == '*'
00182 && ret->pattern[pat_len-1] == '*')
00183 mflags |= MATCHFLG_WILD3_SUFFIX;
00184 }
00185 }
00186
00187 if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
00188 ret->pattern[pat_len-1] = 0;
00189 mflags |= MATCHFLG_DIRECTORY;
00190 }
00191
00192 if (mflags & MATCHFLG_PERDIR_MERGE) {
00193 struct filter_list_struct *lp;
00194 unsigned int len;
00195 int i;
00196
00197 if ((cp = strrchr(ret->pattern, '/')) != NULL)
00198 cp++;
00199 else
00200 cp = ret->pattern;
00201
00202
00203
00204 for (i = 0; i < mergelist_cnt; i++) {
00205 struct filter_struct *ex = mergelist_parents[i];
00206 const char *s = strrchr(ex->pattern, '/');
00207 if (s)
00208 s++;
00209 else
00210 s = ex->pattern;
00211 len = strlen(s);
00212 if (len == pat_len - (cp - ret->pattern)
00213 && memcmp(s, cp, len) == 0) {
00214 free_filter(ret);
00215 return;
00216 }
00217 }
00218
00219 if (!(lp = new_array(struct filter_list_struct, 1)))
00220 out_of_memory("add_rule");
00221 lp->head = lp->tail = NULL;
00222 if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)
00223 out_of_memory("add_rule");
00224 ret->u.mergelist = lp;
00225
00226 if (mergelist_cnt == mergelist_size) {
00227 mergelist_size += 5;
00228 mergelist_parents = realloc_array(mergelist_parents,
00229 struct filter_struct *,
00230 mergelist_size);
00231 if (!mergelist_parents)
00232 out_of_memory("add_rule");
00233 }
00234 mergelist_parents[mergelist_cnt++] = ret;
00235 } else {
00236 for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
00237 ret->u.slash_cnt++;
00238 }
00239
00240 ret->match_flags = mflags;
00241
00242 if (!listp->tail) {
00243 ret->next = listp->head;
00244 listp->head = listp->tail = ret;
00245 } else {
00246 ret->next = listp->tail->next;
00247 listp->tail->next = ret;
00248 listp->tail = ret;
00249 }
00250 }
00251
00252 static void clear_filter_list(struct filter_list_struct *listp)
00253 {
00254 if (listp->tail) {
00255 struct filter_struct *ent, *next;
00256
00257 listp->tail->next = NULL;
00258
00259 for (ent = listp->head; ent; ent = next) {
00260 next = ent->next;
00261 free_filter(ent);
00262 }
00263 }
00264
00265 listp->head = listp->tail = NULL;
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275 static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
00276 unsigned int prefix_skip)
00277 {
00278 static char buf[MAXPATHLEN];
00279 char *fn, tmpbuf[MAXPATHLEN];
00280 unsigned int fn_len;
00281
00282 if (!parent_dirscan && *merge_file != '/') {
00283
00284 if (len_ptr) {
00285 const char *p = merge_file + *len_ptr;
00286 while (--p > merge_file && *p != '/') {}
00287 if (p == merge_file) {
00288 strlcpy(buf, merge_file, *len_ptr + 1);
00289 return buf;
00290 }
00291 } else if (strchr(merge_file, '/') == NULL)
00292 return (char *)merge_file;
00293 }
00294
00295 fn = *merge_file == '/' ? buf : tmpbuf;
00296 if (sanitize_paths) {
00297 const char *r = prefix_skip ? "/" : NULL;
00298
00299 if (len_ptr && merge_file[*len_ptr]) {
00300 char *to = fn == buf ? tmpbuf : buf;
00301 strlcpy(to, merge_file, *len_ptr + 1);
00302 merge_file = to;
00303 }
00304 if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
00305 rprintf(FERROR, "merge-file name overflows: %s\n",
00306 merge_file);
00307 return NULL;
00308 }
00309 } else {
00310 strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN);
00311 clean_fname(fn, 1);
00312 }
00313
00314 fn_len = strlen(fn);
00315 if (fn == buf)
00316 goto done;
00317
00318 if (dirbuf_len + fn_len >= MAXPATHLEN) {
00319 rprintf(FERROR, "merge-file name overflows: %s\n", fn);
00320 return NULL;
00321 }
00322 memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
00323 memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1);
00324 fn_len = clean_fname(buf, 1);
00325
00326 done:
00327 if (len_ptr)
00328 *len_ptr = fn_len;
00329 return buf;
00330 }
00331
00332
00333 void set_filter_dir(const char *dir, unsigned int dirlen)
00334 {
00335 unsigned int len;
00336 if (*dir != '/') {
00337 memcpy(dirbuf, curr_dir, curr_dir_len);
00338 dirbuf[curr_dir_len] = '/';
00339 len = curr_dir_len + 1;
00340 if (len + dirlen >= MAXPATHLEN)
00341 dirlen = 0;
00342 } else
00343 len = 0;
00344 memcpy(dirbuf + len, dir, dirlen);
00345 dirbuf[dirlen + len] = '\0';
00346 dirbuf_len = clean_fname(dirbuf, 1);
00347 if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.'
00348 && dirbuf[dirbuf_len-2] == '/')
00349 dirbuf_len -= 2;
00350 if (dirbuf_len != 1)
00351 dirbuf[dirbuf_len++] = '/';
00352 dirbuf[dirbuf_len] = '\0';
00353 if (sanitize_paths)
00354 dirbuf_depth = count_dir_elements(dirbuf + module_dirlen);
00355 }
00356
00357
00358
00359
00360
00361
00362 static BOOL setup_merge_file(struct filter_struct *ex,
00363 struct filter_list_struct *lp)
00364 {
00365 char buf[MAXPATHLEN];
00366 char *x, *y, *pat = ex->pattern;
00367 unsigned int len;
00368
00369 if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/')
00370 return 0;
00371
00372 y = strrchr(x, '/');
00373 *y = '\0';
00374 ex->pattern = strdup(y+1);
00375 if (!*x)
00376 x = "/";
00377 if (*x == '/')
00378 strlcpy(buf, x, MAXPATHLEN);
00379 else
00380 pathjoin(buf, MAXPATHLEN, dirbuf, x);
00381
00382 len = clean_fname(buf, 1);
00383 if (len != 1 && len < MAXPATHLEN-1) {
00384 buf[len++] = '/';
00385 buf[len] = '\0';
00386 }
00387
00388 for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {}
00389 if (*x)
00390 y += strlen(y);
00391
00392 parent_dirscan = True;
00393 while (*y) {
00394 char save[MAXPATHLEN];
00395 strlcpy(save, y, MAXPATHLEN);
00396 *y = '\0';
00397 dirbuf_len = y - dirbuf;
00398 strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
00399 parse_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS);
00400 if (ex->match_flags & MATCHFLG_NO_INHERIT)
00401 lp->head = NULL;
00402 lp->tail = NULL;
00403 strlcpy(y, save, MAXPATHLEN);
00404 while ((*x++ = *y++) != '/') {}
00405 }
00406 parent_dirscan = False;
00407 free(pat);
00408 return 1;
00409 }
00410
00411
00412
00413
00414
00415 void *push_local_filters(const char *dir, unsigned int dirlen)
00416 {
00417 struct filter_list_struct *ap, *push;
00418 int i;
00419
00420 set_filter_dir(dir, dirlen);
00421
00422 if (!mergelist_cnt)
00423 return NULL;
00424
00425 push = new_array(struct filter_list_struct, mergelist_cnt);
00426 if (!push)
00427 out_of_memory("push_local_filters");
00428
00429 for (i = 0, ap = push; i < mergelist_cnt; i++) {
00430 memcpy(ap++, mergelist_parents[i]->u.mergelist,
00431 sizeof (struct filter_list_struct));
00432 }
00433
00434
00435
00436 for (i = 0; i < mergelist_cnt; i++) {
00437 struct filter_struct *ex = mergelist_parents[i];
00438 struct filter_list_struct *lp = ex->u.mergelist;
00439
00440 if (verbose > 2) {
00441 rprintf(FINFO, "[%s] pushing filter list%s\n",
00442 who_am_i(), lp->debug_type);
00443 }
00444
00445 lp->tail = NULL;
00446 if (ex->match_flags & MATCHFLG_NO_INHERIT)
00447 lp->head = NULL;
00448
00449 if (ex->match_flags & MATCHFLG_FINISH_SETUP) {
00450 ex->match_flags &= ~MATCHFLG_FINISH_SETUP;
00451 if (setup_merge_file(ex, lp))
00452 set_filter_dir(dir, dirlen);
00453 }
00454
00455 if (strlcpy(dirbuf + dirbuf_len, ex->pattern,
00456 MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) {
00457 parse_filter_file(lp, dirbuf, ex->match_flags,
00458 XFLG_ANCHORED2ABS);
00459 } else {
00460 io_error |= IOERR_GENERAL;
00461 rprintf(FINFO,
00462 "cannot add local filter rules in long-named directory: %s\n",
00463 full_fname(dirbuf));
00464 }
00465 dirbuf[dirbuf_len] = '\0';
00466 }
00467
00468 return (void*)push;
00469 }
00470
00471 void pop_local_filters(void *mem)
00472 {
00473 struct filter_list_struct *ap, *pop = (struct filter_list_struct*)mem;
00474 int i;
00475
00476 for (i = mergelist_cnt; i-- > 0; ) {
00477 struct filter_struct *ex = mergelist_parents[i];
00478 struct filter_list_struct *lp = ex->u.mergelist;
00479
00480 if (verbose > 2) {
00481 rprintf(FINFO, "[%s] popping filter list%s\n",
00482 who_am_i(), lp->debug_type);
00483 }
00484
00485 clear_filter_list(lp);
00486 }
00487
00488 if (!pop)
00489 return;
00490
00491 for (i = 0, ap = pop; i < mergelist_cnt; i++) {
00492 memcpy(mergelist_parents[i]->u.mergelist, ap++,
00493 sizeof (struct filter_list_struct));
00494 }
00495
00496 free(pop);
00497 }
00498
00499 static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir)
00500 {
00501 int slash_handling, str_cnt = 0, anchored_match = 0;
00502 int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1;
00503 char *p, *pattern = ex->pattern;
00504 const char *strings[16];
00505
00506 if (!*name)
00507 return 0;
00508
00509 if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
00510
00511
00512
00513 if ((p = strrchr(name,'/')) != NULL)
00514 name = p+1;
00515 } else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
00516 && curr_dir_len > module_dirlen + 1) {
00517
00518
00519 strings[str_cnt++] = curr_dir + module_dirlen + 1;
00520 strings[str_cnt++] = "/";
00521 } else if (ex->match_flags & MATCHFLG_WILD2_PREFIX && *name != '/') {
00522
00523 strings[str_cnt++] = "/";
00524 }
00525 strings[str_cnt++] = name;
00526 if (name_is_dir) {
00527
00528 if (ex->match_flags & MATCHFLG_WILD3_SUFFIX)
00529 strings[str_cnt++] = "/";
00530 } else if (ex->match_flags & MATCHFLG_DIRECTORY)
00531 return !ret_match;
00532 strings[str_cnt] = NULL;
00533
00534 if (*pattern == '/') {
00535 anchored_match = 1;
00536 pattern++;
00537 if (strings[0][0] == '/')
00538 strings[0]++;
00539 }
00540
00541 if (!anchored_match && ex->u.slash_cnt
00542 && !(ex->match_flags & MATCHFLG_WILD2)) {
00543
00544
00545 slash_handling = ex->u.slash_cnt + 1;
00546 } else if (!anchored_match && !(ex->match_flags & MATCHFLG_WILD2_PREFIX)
00547 && ex->match_flags & MATCHFLG_WILD2) {
00548
00549
00550 slash_handling = -1;
00551 } else {
00552
00553 slash_handling = 0;
00554 }
00555
00556 if (ex->match_flags & MATCHFLG_WILD) {
00557 if (wildmatch_array(pattern, strings, slash_handling))
00558 return ret_match;
00559 } else if (str_cnt > 1) {
00560 if (litmatch_array(pattern, strings, slash_handling))
00561 return ret_match;
00562 } else if (anchored_match) {
00563 if (strcmp(strings[0], pattern) == 0)
00564 return ret_match;
00565 } else {
00566 int l1 = strlen(name);
00567 int l2 = strlen(pattern);
00568 if (l2 <= l1 &&
00569 strcmp(name+(l1-l2),pattern) == 0 &&
00570 (l1==l2 || name[l1-(l2+1)] == '/')) {
00571 return ret_match;
00572 }
00573 }
00574
00575 return !ret_match;
00576 }
00577
00578
00579 static void report_filter_result(char const *name,
00580 struct filter_struct const *ent,
00581 int name_is_dir, const char *type)
00582 {
00583
00584
00585
00586
00587 if (verbose >= 2) {
00588 static char *actions[2][2]
00589 = { {"show", "hid"}, {"risk", "protect"} };
00590 const char *w = who_am_i();
00591 rprintf(FINFO, "[%s] %sing %s %s because of pattern %s%s%s\n",
00592 w, actions[*w!='s'][!(ent->match_flags&MATCHFLG_INCLUDE)],
00593 name_is_dir ? "directory" : "file", name, ent->pattern,
00594 ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type);
00595 }
00596 }
00597
00598
00599
00600
00601
00602
00603 int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
00604 {
00605 struct filter_struct *ent;
00606
00607 for (ent = listp->head; ent; ent = ent->next) {
00608 if (ent->match_flags & MATCHFLG_PERDIR_MERGE) {
00609 int rc = check_filter(ent->u.mergelist, name,
00610 name_is_dir);
00611 if (rc)
00612 return rc;
00613 continue;
00614 }
00615 if (ent->match_flags & MATCHFLG_CVS_IGNORE) {
00616 int rc = check_filter(&cvs_filter_list, name,
00617 name_is_dir);
00618 if (rc)
00619 return rc;
00620 continue;
00621 }
00622 if (rule_matches(name, ent, name_is_dir)) {
00623 report_filter_result(name, ent, name_is_dir,
00624 listp->debug_type);
00625 return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
00626 }
00627 }
00628
00629 return 0;
00630 }
00631
00632 #define RULE_STRCMP(s,r) rule_strcmp((s), (r), sizeof (r) - 1)
00633
00634 static const uchar *rule_strcmp(const uchar *str, const char *rule, int rule_len)
00635 {
00636 if (strncmp((char*)str, rule, rule_len) != 0)
00637 return NULL;
00638 if (isspace(str[rule_len]) || str[rule_len] == '_' || !str[rule_len])
00639 return str + rule_len - 1;
00640 if (str[rule_len] == ',')
00641 return str + rule_len;
00642 return NULL;
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652 static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
00653 unsigned int *len_ptr, uint32 *mflags_ptr)
00654 {
00655 const uchar *s = (const uchar *)p;
00656 uint32 new_mflags;
00657 unsigned int len;
00658
00659 if (mflags & MATCHFLG_WORD_SPLIT) {
00660
00661 while (isspace(*s))
00662 s++;
00663
00664 p = (const char *)s;
00665 }
00666 if (!*s)
00667 return NULL;
00668
00669 new_mflags = mflags & MATCHFLGS_FROM_CONTAINER;
00670
00671
00672
00673
00674
00675
00676
00677 if (mflags & MATCHFLG_NO_PREFIXES) {
00678 if (*s == '!' && mflags & MATCHFLG_CVS_IGNORE)
00679 new_mflags |= MATCHFLG_CLEAR_LIST;
00680 } else if (xflags & XFLG_OLD_PREFIXES) {
00681 if (*s == '-' && s[1] == ' ') {
00682 new_mflags &= ~MATCHFLG_INCLUDE;
00683 s += 2;
00684 } else if (*s == '+' && s[1] == ' ') {
00685 new_mflags |= MATCHFLG_INCLUDE;
00686 s += 2;
00687 } else if (*s == '!')
00688 new_mflags |= MATCHFLG_CLEAR_LIST;
00689 } else {
00690 char ch = 0, *mods = "";
00691 switch (*s) {
00692 case 'c':
00693 if ((s = RULE_STRCMP(s, "clear")) != NULL)
00694 ch = '!';
00695 break;
00696 case 'd':
00697 if ((s = RULE_STRCMP(s, "dir-merge")) != NULL)
00698 ch = ':';
00699 break;
00700 case 'e':
00701 if ((s = RULE_STRCMP(s, "exclude")) != NULL)
00702 ch = '-';
00703 break;
00704 case 'h':
00705 if ((s = RULE_STRCMP(s, "hide")) != NULL)
00706 ch = 'H';
00707 break;
00708 case 'i':
00709 if ((s = RULE_STRCMP(s, "include")) != NULL)
00710 ch = '+';
00711 break;
00712 case 'm':
00713 if ((s = RULE_STRCMP(s, "merge")) != NULL)
00714 ch = '.';
00715 break;
00716 case 'p':
00717 if ((s = RULE_STRCMP(s, "protect")) != NULL)
00718 ch = 'P';
00719 break;
00720 case 'r':
00721 if ((s = RULE_STRCMP(s, "risk")) != NULL)
00722 ch = 'R';
00723 break;
00724 case 's':
00725 if ((s = RULE_STRCMP(s, "show")) != NULL)
00726 ch = 'S';
00727 break;
00728 default:
00729 ch = *s;
00730 if (s[1] == ',')
00731 s++;
00732 break;
00733 }
00734 switch (ch) {
00735 case ':':
00736 new_mflags |= MATCHFLG_PERDIR_MERGE
00737 | MATCHFLG_FINISH_SETUP;
00738
00739 case '.':
00740 new_mflags |= MATCHFLG_MERGE_FILE;
00741 mods = MODIFIERS_INCL_EXCL MODIFIERS_MERGE_FILE;
00742 break;
00743 case '+':
00744 new_mflags |= MATCHFLG_INCLUDE;
00745
00746 case '-':
00747 mods = MODIFIERS_INCL_EXCL;
00748 break;
00749 case 'S':
00750 new_mflags |= MATCHFLG_INCLUDE;
00751
00752 case 'H':
00753 new_mflags |= MATCHFLG_SENDER_SIDE;
00754 mods = MODIFIERS_HIDE_PROTECT;
00755 break;
00756 case 'R':
00757 new_mflags |= MATCHFLG_INCLUDE;
00758
00759 case 'P':
00760 new_mflags |= MATCHFLG_RECEIVER_SIDE;
00761 mods = MODIFIERS_HIDE_PROTECT;
00762 break;
00763 case '!':
00764 new_mflags |= MATCHFLG_CLEAR_LIST;
00765 mods = NULL;
00766 break;
00767 default:
00768 rprintf(FERROR, "Unknown filter rule: `%s'\n", p);
00769 exit_cleanup(RERR_SYNTAX);
00770 }
00771 while (mods && *++s && *s != ' ' && *s != '_') {
00772 if (strchr(mods, *s) == NULL) {
00773 if (mflags & MATCHFLG_WORD_SPLIT && isspace(*s)) {
00774 s--;
00775 break;
00776 }
00777 invalid:
00778 rprintf(FERROR,
00779 "invalid modifier sequence at '%c' in filter rule: %s\n",
00780 *s, p);
00781 exit_cleanup(RERR_SYNTAX);
00782 }
00783 switch (*s) {
00784 case '-':
00785 if (new_mflags & MATCHFLG_NO_PREFIXES)
00786 goto invalid;
00787 new_mflags |= MATCHFLG_NO_PREFIXES;
00788 break;
00789 case '+':
00790 if (new_mflags & MATCHFLG_NO_PREFIXES)
00791 goto invalid;
00792 new_mflags |= MATCHFLG_NO_PREFIXES
00793 | MATCHFLG_INCLUDE;
00794 break;
00795 case '/':
00796 new_mflags |= MATCHFLG_ABS_PATH;
00797 break;
00798 case '!':
00799 new_mflags |= MATCHFLG_NEGATE;
00800 break;
00801 case 'C':
00802 if (new_mflags & MATCHFLG_NO_PREFIXES)
00803 goto invalid;
00804 new_mflags |= MATCHFLG_NO_PREFIXES
00805 | MATCHFLG_WORD_SPLIT
00806 | MATCHFLG_NO_INHERIT
00807 | MATCHFLG_CVS_IGNORE;
00808 break;
00809 case 'e':
00810 new_mflags |= MATCHFLG_EXCLUDE_SELF;
00811 break;
00812 case 'n':
00813 new_mflags |= MATCHFLG_NO_INHERIT;
00814 break;
00815 case 'r':
00816 new_mflags |= MATCHFLG_RECEIVER_SIDE;
00817 break;
00818 case 's':
00819 new_mflags |= MATCHFLG_SENDER_SIDE;
00820 break;
00821 case 'w':
00822 new_mflags |= MATCHFLG_WORD_SPLIT;
00823 break;
00824 }
00825 }
00826 if (*s)
00827 s++;
00828 }
00829
00830 if (mflags & MATCHFLG_WORD_SPLIT) {
00831 const uchar *cp = s;
00832
00833 while (!isspace(*cp) && *cp != '\0')
00834 cp++;
00835 len = cp - s;
00836 } else
00837 len = strlen((char*)s);
00838
00839 if (new_mflags & MATCHFLG_CLEAR_LIST) {
00840 if (!(mflags & MATCHFLG_NO_PREFIXES)
00841 && !(xflags & XFLG_OLD_PREFIXES) && len) {
00842 rprintf(FERROR,
00843 "'!' rule has trailing characters: %s\n", p);
00844 exit_cleanup(RERR_SYNTAX);
00845 }
00846 if (len > 1)
00847 new_mflags &= ~MATCHFLG_CLEAR_LIST;
00848 } else if (!len && !(new_mflags & MATCHFLG_CVS_IGNORE)) {
00849 rprintf(FERROR, "unexpected end of filter rule: %s\n", p);
00850 exit_cleanup(RERR_SYNTAX);
00851 }
00852
00853 *len_ptr = len;
00854 *mflags_ptr = new_mflags;
00855 return (const char *)s;
00856 }
00857
00858
00859 static char default_cvsignore[] =
00860
00861 "RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS"
00862 " .make.state .nse_depinfo *~ #* .#* ,* _$* *$"
00863 " *.old *.bak *.BAK *.orig *.rej .del-*"
00864 " *.a *.olb *.o *.obj *.so *.exe"
00865 " *.Z *.elc *.ln core"
00866
00867 " .svn/";
00868
00869 static void get_cvs_excludes(uint32 mflags)
00870 {
00871 char *p, fname[MAXPATHLEN];
00872 static int initialized = 0;
00873
00874 if (initialized)
00875 return;
00876 initialized = 1;
00877
00878 parse_rule(&cvs_filter_list, default_cvsignore, mflags, 0);
00879
00880 p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME");
00881 if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN)
00882 parse_filter_file(&cvs_filter_list, fname, mflags, 0);
00883
00884 parse_rule(&cvs_filter_list, getenv("CVSIGNORE"), mflags, 0);
00885 }
00886
00887
00888 void parse_rule(struct filter_list_struct *listp, const char *pattern,
00889 uint32 mflags, int xflags)
00890 {
00891 unsigned int pat_len;
00892 uint32 new_mflags;
00893 const char *cp, *p;
00894
00895 if (!pattern)
00896 return;
00897
00898 while (1) {
00899
00900 cp = parse_rule_tok(pattern, mflags, xflags,
00901 &pat_len, &new_mflags);
00902 if (!cp)
00903 break;
00904 if (pat_len >= MAXPATHLEN) {
00905 rprintf(FERROR, "discarding over-long filter: %s\n",
00906 cp);
00907 continue;
00908 }
00909 pattern = cp + pat_len;
00910
00911 if (new_mflags & MATCHFLG_CLEAR_LIST) {
00912 if (verbose > 2) {
00913 rprintf(FINFO,
00914 "[%s] clearing filter list%s\n",
00915 who_am_i(), listp->debug_type);
00916 }
00917 clear_filter_list(listp);
00918 continue;
00919 }
00920
00921 if (new_mflags & MATCHFLG_MERGE_FILE) {
00922 unsigned int len;
00923 if (!pat_len) {
00924 cp = ".cvsignore";
00925 pat_len = 10;
00926 }
00927 len = pat_len;
00928 if (new_mflags & MATCHFLG_EXCLUDE_SELF) {
00929 const char *name = strrchr(cp, '/');
00930 if (name)
00931 len -= ++name - cp;
00932 else
00933 name = cp;
00934 add_rule(listp, name, len, 0, 0);
00935 new_mflags &= ~MATCHFLG_EXCLUDE_SELF;
00936 len = pat_len;
00937 }
00938 if (new_mflags & MATCHFLG_PERDIR_MERGE) {
00939 if (parent_dirscan) {
00940 if (!(p = parse_merge_name(cp, &len,
00941 module_dirlen)))
00942 continue;
00943 add_rule(listp, p, len, new_mflags, 0);
00944 continue;
00945 }
00946 } else {
00947 if (!(p = parse_merge_name(cp, &len, 0)))
00948 continue;
00949 parse_filter_file(listp, p, new_mflags,
00950 XFLG_FATAL_ERRORS);
00951 continue;
00952 }
00953 }
00954
00955 add_rule(listp, cp, pat_len, new_mflags, xflags);
00956
00957 if (new_mflags & MATCHFLG_CVS_IGNORE
00958 && !(new_mflags & MATCHFLG_MERGE_FILE))
00959 get_cvs_excludes(new_mflags);
00960 }
00961 }
00962
00963
00964 void parse_filter_file(struct filter_list_struct *listp, const char *fname,
00965 uint32 mflags, int xflags)
00966 {
00967 FILE *fp;
00968 char line[BIGPATHBUFLEN];
00969 char *eob = line + sizeof line - 1;
00970 int word_split = mflags & MATCHFLG_WORD_SPLIT;
00971
00972 if (!fname || !*fname)
00973 return;
00974
00975 if (*fname != '-' || fname[1] || am_server) {
00976 if (server_filter_list.head) {
00977 strlcpy(line, fname, sizeof line);
00978 clean_fname(line, 1);
00979 if (check_filter(&server_filter_list, line, 0) < 0)
00980 fp = NULL;
00981 else
00982 fp = fopen(line, "rb");
00983 } else
00984 fp = fopen(fname, "rb");
00985 } else
00986 fp = stdin;
00987
00988 if (verbose > 2) {
00989 rprintf(FINFO, "[%s] parse_filter_file(%s,%x,%x)%s\n",
00990 who_am_i(), fname, mflags, xflags,
00991 fp ? "" : " [not found]");
00992 }
00993
00994 if (!fp) {
00995 if (xflags & XFLG_FATAL_ERRORS) {
00996 rsyserr(FERROR, errno,
00997 "failed to open %sclude file %s",
00998 mflags & MATCHFLG_INCLUDE ? "in" : "ex",
00999 fname);
01000 exit_cleanup(RERR_FILEIO);
01001 }
01002 return;
01003 }
01004 dirbuf[dirbuf_len] = '\0';
01005
01006 while (1) {
01007 char *s = line;
01008 int ch, overflow = 0;
01009 while (1) {
01010 if ((ch = getc(fp)) == EOF) {
01011 if (ferror(fp) && errno == EINTR) {
01012 clearerr(fp);
01013 continue;
01014 }
01015 break;
01016 }
01017 if (word_split && isspace(ch))
01018 break;
01019 if (eol_nulls? !ch : (ch == '\n' || ch == '\r'))
01020 break;
01021 if (s < eob)
01022 *s++ = ch;
01023 else
01024 overflow = 1;
01025 }
01026 if (overflow) {
01027 rprintf(FERROR, "discarding over-long filter: %s...\n", line);
01028 s = line;
01029 }
01030 *s = '\0';
01031
01032 if (*line && (word_split || (*line != ';' && *line != '#')))
01033 parse_rule(listp, line, mflags, xflags);
01034 if (ch == EOF)
01035 break;
01036 }
01037 fclose(fp);
01038 }
01039
01040
01041
01042
01043 char *get_rule_prefix(int match_flags, const char *pat, int for_xfer,
01044 unsigned int *plen_ptr)
01045 {
01046 static char buf[MAX_RULE_PREFIX+1];
01047 char *op = buf;
01048 int legal_len = for_xfer && protocol_version < 29 ? 1 : MAX_RULE_PREFIX-1;
01049
01050 if (match_flags & MATCHFLG_PERDIR_MERGE) {
01051 if (legal_len == 1)
01052 return NULL;
01053 *op++ = ':';
01054 } else if (match_flags & MATCHFLG_INCLUDE)
01055 *op++ = '+';
01056 else if (legal_len != 1
01057 || ((*pat == '-' || *pat == '+') && pat[1] == ' '))
01058 *op++ = '-';
01059 else
01060 legal_len = 0;
01061
01062 if (match_flags & MATCHFLG_CVS_IGNORE)
01063 *op++ = 'C';
01064 else {
01065 if (match_flags & MATCHFLG_NO_INHERIT)
01066 *op++ = 'n';
01067 if (match_flags & MATCHFLG_WORD_SPLIT)
01068 *op++ = 'w';
01069 if (match_flags & MATCHFLG_NO_PREFIXES) {
01070 if (match_flags & MATCHFLG_INCLUDE)
01071 *op++ = '+';
01072 else
01073 *op++ = '-';
01074 }
01075 }
01076 if (match_flags & MATCHFLG_EXCLUDE_SELF)
01077 *op++ = 'e';
01078 if (match_flags & MATCHFLG_SENDER_SIDE
01079 && (!for_xfer || protocol_version >= 29))
01080 *op++ = 's';
01081 if (match_flags & MATCHFLG_RECEIVER_SIDE
01082 && (!for_xfer || protocol_version >= 29
01083 || (delete_excluded && am_sender)))
01084 *op++ = 'r';
01085 if (op - buf > legal_len)
01086 return NULL;
01087 if (legal_len)
01088 *op++ = ' ';
01089 *op = '\0';
01090 if (plen_ptr)
01091 *plen_ptr = op - buf;
01092 return buf;
01093 }
01094
01095 static void send_rules(int f_out, struct filter_list_struct *flp)
01096 {
01097 struct filter_struct *ent, *prev = NULL;
01098
01099 for (ent = flp->head; ent; ent = ent->next) {
01100 unsigned int len, plen, dlen;
01101 int elide = 0;
01102 char *p;
01103
01104 if (ent->match_flags & MATCHFLG_SENDER_SIDE)
01105 elide = am_sender ? 1 : -1;
01106 if (ent->match_flags & MATCHFLG_RECEIVER_SIDE)
01107 elide = elide ? 0 : am_sender ? -1 : 1;
01108 else if (delete_excluded && !elide)
01109 elide = am_sender ? 1 : -1;
01110 if (elide < 0) {
01111 if (prev)
01112 prev->next = ent->next;
01113 else
01114 flp->head = ent->next;
01115 } else
01116 prev = ent;
01117 if (elide > 0)
01118 continue;
01119 if (ent->match_flags & MATCHFLG_CVS_IGNORE
01120 && !(ent->match_flags & MATCHFLG_MERGE_FILE)) {
01121 int f = am_sender || protocol_version < 29 ? f_out : -2;
01122 send_rules(f, &cvs_filter_list);
01123 if (f == f_out)
01124 continue;
01125 }
01126 p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen);
01127 if (!p) {
01128 rprintf(FERROR,
01129 "filter rules are too modern for remote rsync.\n");
01130 exit_cleanup(RERR_SYNTAX);
01131 }
01132 if (f_out < 0)
01133 continue;
01134 len = strlen(ent->pattern);
01135 dlen = ent->match_flags & MATCHFLG_DIRECTORY ? 1 : 0;
01136 if (!(plen + len + dlen))
01137 continue;
01138 write_int(f_out, plen + len + dlen);
01139 if (plen)
01140 write_buf(f_out, p, plen);
01141 write_buf(f_out, ent->pattern, len);
01142 if (dlen)
01143 write_byte(f_out, '/');
01144 }
01145 flp->tail = prev;
01146 }
01147
01148
01149 void send_filter_list(int f_out)
01150 {
01151 int receiver_wants_list = prune_empty_dirs
01152 || (delete_mode && (!delete_excluded || protocol_version >= 29));
01153
01154 if (local_server || (am_sender && !receiver_wants_list))
01155 f_out = -1;
01156 if (cvs_exclude && am_sender) {
01157 if (protocol_version >= 29)
01158 parse_rule(&filter_list, ":C", 0, 0);
01159 parse_rule(&filter_list, "-C", 0, 0);
01160 }
01161
01162
01163
01164 if (list_only == 1 && !recurse)
01165 parse_rule(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0);
01166
01167 send_rules(f_out, &filter_list);
01168
01169 if (f_out >= 0)
01170 write_int(f_out, 0);
01171
01172 if (cvs_exclude) {
01173 if (!am_sender || protocol_version < 29)
01174 parse_rule(&filter_list, ":C", 0, 0);
01175 if (!am_sender)
01176 parse_rule(&filter_list, "-C", 0, 0);
01177 }
01178 }
01179
01180
01181 void recv_filter_list(int f_in)
01182 {
01183 char line[BIGPATHBUFLEN];
01184 int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
01185 int receiver_wants_list = prune_empty_dirs
01186 || (delete_mode
01187 && (!delete_excluded || protocol_version >= 29));
01188 unsigned int len;
01189
01190 if (!local_server && (am_sender || receiver_wants_list)) {
01191 while ((len = read_int(f_in)) != 0) {
01192 if (len >= sizeof line)
01193 overflow_exit("recv_rules");
01194 read_sbuf(f_in, line, len);
01195 parse_rule(&filter_list, line, 0, xflags);
01196 }
01197 }
01198
01199 if (cvs_exclude) {
01200 if (local_server || am_sender || protocol_version < 29)
01201 parse_rule(&filter_list, ":C", 0, 0);
01202 if (local_server || am_sender)
01203 parse_rule(&filter_list, "-C", 0, 0);
01204 }
01205
01206 if (local_server)
01207 send_rules(-1, &filter_list);
01208 }