関数 | |
static void | free_filter (struct filter_struct *ex) |
static void | add_rule (struct filter_list_struct *listp, const char *pat, unsigned int pat_len, uint32 mflags, int xflags) |
static void | clear_filter_list (struct filter_list_struct *listp) |
static char * | parse_merge_name (const char *merge_file, unsigned int *len_ptr, unsigned int prefix_skip) |
void | set_filter_dir (const char *dir, unsigned int dirlen) |
static BOOL | setup_merge_file (struct filter_struct *ex, struct filter_list_struct *lp) |
void * | push_local_filters (const char *dir, unsigned int dirlen) |
void | pop_local_filters (void *mem) |
static int | rule_matches (char *name, struct filter_struct *ex, int name_is_dir) |
static void | report_filter_result (char const *name, struct filter_struct const *ent, int name_is_dir, const char *type) |
int | check_filter (struct filter_list_struct *listp, char *name, int name_is_dir) |
static const uchar * | rule_strcmp (const uchar *str, const char *rule, int rule_len) |
static const char * | parse_rule_tok (const char *p, uint32 mflags, int xflags, unsigned int *len_ptr, uint32 *mflags_ptr) |
static void | get_cvs_excludes (uint32 mflags) |
void | parse_rule (struct filter_list_struct *listp, const char *pattern, uint32 mflags, int xflags) |
void | parse_filter_file (struct filter_list_struct *listp, const char *fname, uint32 mflags, int xflags) |
char * | get_rule_prefix (int match_flags, const char *pat, int for_xfer, unsigned int *plen_ptr) |
static void | send_rules (int f_out, struct filter_list_struct *flp) |
void | send_filter_list (int f_out) |
void | recv_filter_list (int f_in) |
変数 | |
int | verbose |
int | am_server |
int | am_sender |
int | eol_nulls |
int | list_only |
int | recurse |
int | io_error |
int | local_server |
int | prune_empty_dirs |
int | delete_mode |
int | delete_excluded |
int | cvs_exclude |
int | sanitize_paths |
int | protocol_version |
int | module_id |
char | curr_dir [] |
unsigned int | curr_dir_len |
unsigned int | module_dirlen |
filter_list_struct | filter_list = { 0, 0, "" } |
filter_list_struct | cvs_filter_list = { 0, 0, " [global CVS]" } |
filter_list_struct | server_filter_list = { 0, 0, " [daemon]" } |
static char | dirbuf [MAXPATHLEN+1] |
static unsigned int | dirbuf_len = 0 |
static int | dirbuf_depth |
static BOOL | parent_dirscan = False |
static struct filter_struct ** | mergelist_parents |
static int | mergelist_cnt = 0 |
static int | mergelist_size = 0 |
static char | default_cvsignore [] |
static void free_filter | ( | struct filter_struct * | ex | ) | [static] |
参照先 filter_list_struct::debug_type・filter_struct::match_flags・filter_struct::mergelist・mergelist_cnt・filter_struct::pattern・filter_struct::u.
参照元 add_rule()・clear_filter_list().
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 }
static void add_rule | ( | struct filter_list_struct * | listp, | |
const char * | pat, | |||
unsigned int | pat_len, | |||
uint32 | mflags, | |||
int | xflags | |||
) | [static] |
参照先 am_sender・asprintf()・filter_list_struct::debug_type・dirbuf・dirbuf_len・FINFO・free_filter()・get_rule_prefix()・filter_list_struct::head・mergelist_cnt・mergelist_parents・mergelist_size・module_dirlen・out_of_memory()・rprintf()・filter_struct::slash_cnt・strlcpy()・strpbrk()・filter_list_struct::tail・filter_struct::u・verbose・who_am_i().
参照元 parse_rule().
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 /* These flags also indicate that we're reading a list that 00138 * needs to be filtered now, not post-filtered later. */ 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 /* If the pattern starts with **, note that. */ 00176 if (cp == ret->pattern) 00177 mflags |= MATCHFLG_WILD2_PREFIX; 00178 /* If the pattern ends with ***, note that. */ 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 /* If the local merge file was already mentioned, don't 00203 * add it again. */ 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 }
static void clear_filter_list | ( | struct filter_list_struct * | listp | ) | [static] |
参照先 free_filter()・filter_list_struct::head・filter_struct::next・filter_list_struct::tail.
参照元 parse_rule()・pop_local_filters().
00253 { 00254 if (listp->tail) { 00255 struct filter_struct *ent, *next; 00256 /* Truncate any inherited items from the local list. */ 00257 listp->tail->next = NULL; 00258 /* Now free everything that is left. */ 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 }
static char* parse_merge_name | ( | const char * | merge_file, | |
unsigned int * | len_ptr, | |||
unsigned int | prefix_skip | |||
) | [static] |
参照先 buf・clean_fname()・dirbuf・dirbuf_depth・dirbuf_len・FERROR・parent_dirscan・rprintf()・sanitize_path()・sanitize_paths・strlcpy().
参照元 parse_rule()・setup_merge_file().
00277 { 00278 static char buf[MAXPATHLEN]; 00279 char *fn, tmpbuf[MAXPATHLEN]; 00280 unsigned int fn_len; 00281 00282 if (!parent_dirscan && *merge_file != '/') { 00283 /* Return the name unchanged it doesn't have any slashes. */ 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 /* null-terminate the name if it isn't already */ 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 }
void set_filter_dir | ( | const char * | dir, | |
unsigned int | dirlen | |||
) |
参照先 clean_fname()・count_dir_elements()・curr_dir・curr_dir_len・dirbuf・dirbuf_depth・dirbuf_len・module_dirlen・sanitize_paths.
参照元 push_local_filters()・rsync_module().
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 }
static BOOL setup_merge_file | ( | struct filter_struct * | ex, | |
struct filter_list_struct * | lp | |||
) | [static] |
参照先 buf・clean_fname()・dirbuf・dirbuf_len・filter_list_struct::head・filter_struct::match_flags・parent_dirscan・parse_filter_file()・parse_merge_name()・pathjoin()・filter_struct::pattern・strdup()・strlcpy()・filter_list_struct::tail.
参照元 push_local_filters().
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 /* This ensures that the specified dir is a parent of the transfer. */ 00388 for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {} 00389 if (*x) 00390 y += strlen(y); /* nope -- skip the scan */ 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 }
void* push_local_filters | ( | const char * | dir, | |
unsigned int | dirlen | |||
) |
参照先 filter_list_struct::debug_type・dirbuf・dirbuf_len・FINFO・filter_list_struct::head・filter_struct::match_flags・filter_struct::mergelist・mergelist_cnt・mergelist_parents・out_of_memory()・parse_filter_file()・filter_struct::pattern・rprintf()・set_filter_dir()・setup_merge_file()・strlcpy()・filter_list_struct::tail・filter_struct::u・verbose・who_am_i().
参照元 delete_in_dir()・delete_item()・send_if_directory().
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 /* Note: parse_filter_file() might increase mergelist_cnt, so keep 00435 * this loop separate from the above loop. */ 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; /* Switch any local rules to inherited. */ 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 }
void pop_local_filters | ( | void * | mem | ) |
参照先 clear_filter_list()・filter_list_struct::debug_type・FINFO・filter_struct::mergelist・mergelist_cnt・mergelist_parents・rprintf()・filter_struct::u・verbose・who_am_i().
参照元 delete_in_dir()・delete_item()・send_if_directory().
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 }
static int rule_matches | ( | char * | name, | |
struct filter_struct * | ex, | |||
int | name_is_dir | |||
) | [static] |
参照先 curr_dir・curr_dir_len・litmatch_array()・filter_struct::match_flags・module_dirlen・filter_struct::pattern・filter_struct::slash_cnt・filter_struct::u・wildmatch_array().
参照元 check_filter().
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]; /* more than enough */ 00505 00506 if (!*name) 00507 return 0; 00508 00509 if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) { 00510 /* If the pattern does not have any slashes AND it does 00511 * not have a "**" (which could match a slash), then we 00512 * just match the name portion of the path. */ 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 /* If we're matching against an absolute-path pattern, 00518 * we need to prepend our full path info. */ 00519 strings[str_cnt++] = curr_dir + module_dirlen + 1; 00520 strings[str_cnt++] = "/"; 00521 } else if (ex->match_flags & MATCHFLG_WILD2_PREFIX && *name != '/') { 00522 /* Allow "**"+"/" to match at the start of the string. */ 00523 strings[str_cnt++] = "/"; 00524 } 00525 strings[str_cnt++] = name; 00526 if (name_is_dir) { 00527 /* Allow a trailing "/"+"***" to match the directory. */ 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 /* A non-anchored match with an infix slash and no "**" 00544 * needs to match the last slash_cnt+1 name elements. */ 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 /* A non-anchored match with an infix or trailing "**" (but not 00549 * a prefixed "**") needs to try matching after every slash. */ 00550 slash_handling = -1; 00551 } else { 00552 /* The pattern matches only at the start of the path or name. */ 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 }
static void report_filter_result | ( | char const * | name, | |
struct filter_struct const * | ent, | |||
int | name_is_dir, | |||
const char * | type | |||
) | [static] |
参照先 FINFO・filter_struct::match_flags・filter_struct::pattern・rprintf()・verbose・who_am_i().
参照元 check_filter().
00582 { 00583 /* If a trailing slash is present to match only directories, 00584 * then it is stripped out by add_rule(). So as a special 00585 * case we add it back in here. */ 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 }
int check_filter | ( | struct filter_list_struct * | listp, | |
char * | name, | |||
int | name_is_dir | |||
) |
参照先 cvs_filter_list・filter_list_struct::debug_type・filter_list_struct::head・filter_struct::match_flags・filter_struct::mergelist・filter_struct::next・report_filter_result()・rule_matches()・filter_struct::u.
参照元 filter_server_path()・is_excluded()・parse_arguments()・parse_filter_file()・partial_dir_fname()・recv_files()・recv_generator().
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 }
static const uchar* rule_strcmp | ( | const uchar * | str, | |
const char * | rule, | |||
int | rule_len | |||
) | [static] |
static const char* parse_rule_tok | ( | const char * | p, | |
uint32 | mflags, | |||
int | xflags, | |||
unsigned int * | len_ptr, | |||
uint32 * | mflags_ptr | |||
) | [static] |
参照元 parse_rule().
00654 { 00655 const uchar *s = (const uchar *)p; 00656 uint32 new_mflags; 00657 unsigned int len; 00658 00659 if (mflags & MATCHFLG_WORD_SPLIT) { 00660 /* Skip over any initial whitespace. */ 00661 while (isspace(*s)) 00662 s++; 00663 /* Update to point to real start of rule. */ 00664 p = (const char *)s; 00665 } 00666 if (!*s) 00667 return NULL; 00668 00669 new_mflags = mflags & MATCHFLGS_FROM_CONTAINER; 00670 00671 /* Figure out what kind of a filter rule "s" is pointing at. Note 00672 * that if MATCHFLG_NO_PREFIXES is set, the rule is either an include 00673 * or an exclude based on the inheritance of the MATCHFLG_INCLUDE 00674 * flag (above). XFLG_OLD_PREFIXES indicates a compatibility mode 00675 * for old include/exclude patterns where just "+ " and "- " are 00676 * allowed as optional prefixes. */ 00677 if (mflags & MATCHFLG_NO_PREFIXES) { 00678 if (*s == '!' && mflags & MATCHFLG_CVS_IGNORE) 00679 new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */ 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; /* Tentative! */ 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 /* FALL THROUGH */ 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 /* FALL THROUGH */ 00746 case '-': 00747 mods = MODIFIERS_INCL_EXCL; 00748 break; 00749 case 'S': 00750 new_mflags |= MATCHFLG_INCLUDE; 00751 /* FALL THROUGH */ 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 /* FALL THROUGH */ 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 /* Token ends at whitespace or the end of the string. */ 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 }
static void get_cvs_excludes | ( | uint32 | mflags | ) | [static] |
参照先 cvs_filter_list・lp_use_chroot()・module_id・parse_filter_file()・parse_rule()・pathjoin().
参照元 parse_rule().
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 }
void parse_rule | ( | struct filter_list_struct * | listp, | |
const char * | pattern, | |||
uint32 | mflags, | |||
int | xflags | |||
) |
参照先 add_rule()・clear_filter_list()・filter_list_struct::debug_type・FERROR・FINFO・get_cvs_excludes()・module_dirlen・name・parent_dirscan・parse_filter_file()・parse_merge_name()・parse_rule_tok()・rprintf()・verbose・who_am_i().
参照元 get_cvs_excludes()・parse_arguments()・parse_filter_file()・recv_filter_list()・rsync_module()・send_filter_list().
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 /* Remember that the returned string is NOT '\0' terminated! */ 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 }
void parse_filter_file | ( | struct filter_list_struct * | listp, | |
const char * | fname, | |||
uint32 | mflags, | |||
int | xflags | |||
) |
参照先 am_server・check_filter()・clean_fname()・dirbuf・dirbuf_len・eol_nulls・errno・FERROR・FINFO・filter_list_struct::head・parse_rule()・rprintf()・rsyserr()・server_filter_list・strlcpy()・verbose・who_am_i().
参照元 get_cvs_excludes()・parse_arguments()・parse_rule()・push_local_filters()・rsync_module()・setup_merge_file().
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 /* Skip an empty token and (when line parsing) comments. */ 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 }
char* get_rule_prefix | ( | int | match_flags, | |
const char * | pat, | |||
int | for_xfer, | |||
unsigned int * | plen_ptr | |||
) |
参照先 am_sender・delete_excluded・protocol_version.
参照元 add_rule()・send_rules()・write_filter_rules().
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 }
static void send_rules | ( | int | f_out, | |
struct filter_list_struct * | flp | |||
) | [static] |
参照先 am_sender・cvs_filter_list・delete_excluded・FERROR・get_rule_prefix()・filter_list_struct::head・filter_struct::match_flags・filter_struct::next・filter_struct::pattern・protocol_version・rprintf()・filter_list_struct::tail・write_buf()・write_byte()・write_int().
参照元 recv_filter_list()・send_filter_list().
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 }
void send_filter_list | ( | int | f_out | ) |
参照先 am_sender・cvs_exclude・delete_excluded・delete_mode・filter_list・list_only・local_server・parse_rule()・protocol_version・prune_empty_dirs・recurse・send_rules()・write_int().
参照元 client_run().
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 /* This is a complete hack - blame Rusty. FIXME! 01163 * Remove this hack when older rsyncs (below 2.6.4) are gone. */ 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 }
void recv_filter_list | ( | int | f_in | ) |
参照先 am_sender・cvs_exclude・delete_excluded・delete_mode・filter_list・local_server・overflow_exit()・parse_rule()・protocol_version・prune_empty_dirs・read_int()・read_sbuf()・send_rules().
参照元 do_server_recv()・start_server().
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) /* filter out any rules that aren't for us. */ 01207 send_rules(-1, &filter_list); 01208 }
int prune_empty_dirs |
int delete_mode |
int delete_excluded |
int cvs_exclude |
int sanitize_paths |
int protocol_version |
int module_id |
clientserver.c の 60 行で定義されています。
char curr_dir[] |
unsigned int curr_dir_len |
unsigned int module_dirlen |
clientserver.c の 64 行で定義されています。
参照元 add_rule()・parse_rule()・rsync_module()・rule_matches()・set_filter_dir().
struct filter_list_struct filter_list = { 0, 0, "" } |
struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" } |
struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" } |
char dirbuf[MAXPATHLEN+1] [static] |
unsigned int dirbuf_len = 0 [static] |
int dirbuf_depth [static] |
BOOL parent_dirscan = False [static] |
struct filter_struct** mergelist_parents [static] |
int mergelist_cnt = 0 [static] |
int mergelist_size = 0 [static] |
char default_cvsignore[] [static] |