+ static int initialized = 0;
+ char *p, fname[MAXPATHLEN];
+
+ if (initialized)
+ return;
+ initialized = 1;
+
+ parse_rule(&cvs_filter_list, default_cvsignore,
+ mflags | (protocol_version >= 30 ? MATCHFLG_PERISHABLE : 0),
+ 0);
+
+ p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME");
+ if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN)
+ parse_filter_file(&cvs_filter_list, fname, mflags, 0);
+
+ parse_rule(&cvs_filter_list, getenv("CVSIGNORE"), mflags, 0);
+}
+
+
+void parse_rule(struct filter_list_struct *listp, const char *pattern,
+ uint32 mflags, int xflags)
+{
+ unsigned int pat_len;
+ uint32 new_mflags;
+ const char *cp, *p;
+
+ if (!pattern)
+ return;
+
+ while (1) {
+ /* Remember that the returned string is NOT '\0' terminated! */
+ cp = parse_rule_tok(pattern, mflags, xflags,
+ &pat_len, &new_mflags);
+ if (!cp)
+ break;
+
+ pattern = cp + pat_len;
+
+ if (pat_len >= MAXPATHLEN) {
+ rprintf(FERROR, "discarding over-long filter: %.*s\n",
+ (int)pat_len, cp);
+ continue;
+ }
+
+ if (new_mflags & MATCHFLG_CLEAR_LIST) {
+ if (DEBUG_GTE(FILTER, 2)) {
+ rprintf(FINFO,
+ "[%s] clearing filter list%s\n",
+ who_am_i(), listp->debug_type);
+ }
+ clear_filter_list(listp);
+ continue;
+ }
+
+ if (new_mflags & MATCHFLG_MERGE_FILE) {
+ unsigned int len;
+ if (!pat_len) {
+ cp = ".cvsignore";
+ pat_len = 10;
+ }
+ len = pat_len;
+ if (new_mflags & MATCHFLG_EXCLUDE_SELF) {
+ const char *name = cp + len;
+ while (name > cp && name[-1] != '/') name--;
+ len -= name - cp;
+ add_rule(listp, name, len, 0, 0);
+ new_mflags &= ~MATCHFLG_EXCLUDE_SELF;
+ len = pat_len;
+ }
+ if (new_mflags & MATCHFLG_PERDIR_MERGE) {
+ if (parent_dirscan) {
+ if (!(p = parse_merge_name(cp, &len,
+ module_dirlen)))
+ continue;
+ add_rule(listp, p, len, new_mflags, 0);
+ continue;
+ }
+ } else {
+ if (!(p = parse_merge_name(cp, &len, 0)))
+ continue;
+ parse_filter_file(listp, p, new_mflags,
+ XFLG_FATAL_ERRORS);
+ continue;
+ }
+ }
+
+ add_rule(listp, cp, pat_len, new_mflags, xflags);
+
+ if (new_mflags & MATCHFLG_CVS_IGNORE
+ && !(new_mflags & MATCHFLG_MERGE_FILE))
+ get_cvs_excludes(new_mflags);
+ }
+}
+
+
+void parse_filter_file(struct filter_list_struct *listp, const char *fname,
+ uint32 mflags, int xflags)
+{
+ FILE *fp;
+ char line[BIGPATHBUFLEN];
+ char *eob = line + sizeof line - 1;
+ int word_split = mflags & MATCHFLG_WORD_SPLIT;
+
+ if (!fname || !*fname)
+ return;
+
+ if (*fname != '-' || fname[1] || am_server) {
+ if (daemon_filter_list.head) {
+ strlcpy(line, fname, sizeof line);
+ clean_fname(line, CFN_COLLAPSE_DOT_DOT_DIRS);
+ if (check_filter(&daemon_filter_list, FLOG, line, 0) < 0)
+ fp = NULL;
+ else
+ fp = fopen(line, "rb");
+ } else
+ fp = fopen(fname, "rb");
+ } else
+ fp = stdin;
+
+ if (DEBUG_GTE(FILTER, 2)) {
+ rprintf(FINFO, "[%s] parse_filter_file(%s,%x,%x)%s\n",
+ who_am_i(), fname, mflags, xflags,
+ fp ? "" : " [not found]");
+ }
+
+ if (!fp) {
+ if (xflags & XFLG_FATAL_ERRORS) {
+ rsyserr(FERROR, errno,
+ "failed to open %sclude file %s",
+ mflags & MATCHFLG_INCLUDE ? "in" : "ex",
+ fname);
+ exit_cleanup(RERR_FILEIO);
+ }
+ return;
+ }
+ dirbuf[dirbuf_len] = '\0';
+
+ while (1) {
+ char *s = line;
+ int ch, overflow = 0;
+ while (1) {
+ if ((ch = getc(fp)) == EOF) {
+ if (ferror(fp) && errno == EINTR) {
+ clearerr(fp);
+ continue;
+ }
+ break;
+ }
+ if (word_split && isspace(ch))
+ break;
+ if (eol_nulls? !ch : (ch == '\n' || ch == '\r'))
+ break;
+ if (s < eob)
+ *s++ = ch;
+ else
+ overflow = 1;
+ }
+ if (overflow) {
+ rprintf(FERROR, "discarding over-long filter: %s...\n", line);
+ s = line;
+ }
+ *s = '\0';
+ /* Skip an empty token and (when line parsing) comments. */
+ if (*line && (word_split || (*line != ';' && *line != '#')))
+ parse_rule(listp, line, mflags, xflags);
+ if (ch == EOF)
+ break;
+ }
+ fclose(fp);