+/*
+ * Test if the currently selected directory (in ff->fname) is
+ * explicitly in the Include list or explicitly in the Exclude
+ * list.
+ */
+bool is_in_fileset(FF_PKT *ff)
+{
+ dlistString *node;
+ char *fname;
+ int i;
+ findINCEXE *incexe;
+ findFILESET *fileset = ff->fileset;
+ if (fileset) {
+ for (i=0; i<fileset->include_list.size(); i++) {
+ incexe = (findINCEXE *)fileset->include_list.get(i);
+ foreach_dlist(node, &incexe->name_list) {
+ fname = node->c_str();
+ Dmsg2(dbglvl, "Inc fname=%s ff->fname=%s\n", fname, ff->fname);
+ if (strcmp(fname, ff->fname) == 0) {
+ return true;
+ }
+ }
+ }
+ for (i=0; i<fileset->exclude_list.size(); i++) {
+ incexe = (findINCEXE *)fileset->exclude_list.get(i);
+ foreach_dlist(node, &incexe->name_list) {
+ fname = node->c_str();
+ Dmsg2(dbglvl, "Exc fname=%s ff->fname=%s\n", fname, ff->fname);
+ if (strcmp(fname, ff->fname) == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+bool accept_file(FF_PKT *ff)
+{
+ int i, j, k;
+ int fnm_flags;
+ findFILESET *fileset = ff->fileset;
+ findINCEXE *incexe = fileset->incexe;
+ const char *basename;
+ int (*match_func)(const char *pattern, const char *string, int flags);
+
+ Dmsg1(dbglvl, "enter accept_file: fname=%s\n", ff->fname);
+ if (ff->flags & FO_ENHANCEDWILD) {
+// match_func = enh_fnmatch;
+ match_func = fnmatch;
+ if ((basename = last_path_separator(ff->fname)) != NULL)
+ basename++;
+ else
+ basename = ff->fname;
+ } else {
+ match_func = fnmatch;
+ basename = ff->fname;
+ }
+
+ for (j = 0; j < incexe->opts_list.size(); j++) {
+ findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
+ ff->flags = fo->flags;
+ ff->Compress_algo = fo->Compress_algo;
+ ff->Compress_level = fo->Compress_level;
+ ff->fstypes = fo->fstype;
+ ff->drivetypes = fo->drivetype;
+
+ fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
+ fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
+
+ if (S_ISDIR(ff->statp.st_mode)) {
+ for (k=0; k<fo->wilddir.size(); k++) {
+ if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ Dmsg2(dbglvl, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
+ ff->fname);
+ return false; /* reject dir */
+ }
+ return true; /* accept dir */
+ }
+ }
+ } else {
+ for (k=0; k<fo->wildfile.size(); k++) {
+ if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ Dmsg2(dbglvl, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
+ ff->fname);
+ return false; /* reject file */
+ }
+ return true; /* accept file */
+ }
+ }
+
+ for (k=0; k<fo->wildbase.size(); k++) {
+ if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ Dmsg2(dbglvl, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
+ basename);
+ return false; /* reject file */
+ }
+ return true; /* accept file */
+ }
+ }
+ }
+ for (k=0; k<fo->wild.size(); k++) {
+ if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ Dmsg2(dbglvl, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
+ ff->fname);
+ return false; /* reject file */
+ }
+ return true; /* accept file */
+ }
+ }
+ if (S_ISDIR(ff->statp.st_mode)) {
+ for (k=0; k<fo->regexdir.size(); k++) {
+ const int nmatch = 30;
+ regmatch_t pmatch[nmatch];
+ if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ return false; /* reject file */
+ }
+ return true; /* accept file */
+ }
+ }
+ } else {
+ for (k=0; k<fo->regexfile.size(); k++) {
+ const int nmatch = 30;
+ regmatch_t pmatch[nmatch];
+ if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ return false; /* reject file */
+ }
+ return true; /* accept file */
+ }
+ }
+ }
+ for (k=0; k<fo->regex.size(); k++) {
+ const int nmatch = 30;
+ regmatch_t pmatch[nmatch];
+ if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
+ if (ff->flags & FO_EXCLUDE) {
+ return false; /* reject file */
+ }
+ return true; /* accept file */
+ }
+ }
+ /*
+ * If we have an empty Options clause with exclude, then
+ * exclude the file
+ */
+ if (ff->flags & FO_EXCLUDE &&
+ fo->regex.size() == 0 && fo->wild.size() == 0 &&
+ fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
+ fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
+ fo->wildbase.size() == 0) {
+ return false; /* reject file */
+ }
+ }
+
+ /* Now apply the Exclude { } directive */
+ for (i=0; i<fileset->exclude_list.size(); i++) {
+ findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
+ for (j=0; j<incexe->opts_list.size(); j++) {
+ findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
+ fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
+ for (k=0; k<fo->wild.size(); k++) {
+ if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
+ Dmsg1(dbglvl, "Reject wild1: %s\n", ff->fname);
+ return false; /* reject file */
+ }
+ }
+ }
+ fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
+ ? FNM_CASEFOLD : 0;
+ dlistString *node;
+ foreach_dlist(node, &incexe->name_list) {
+ char *fname = node->c_str();
+ if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
+ Dmsg1(dbglvl, "Reject wild2: %s\n", ff->fname);
+ return false; /* reject file */
+ }
+ }
+ }
+ return true;
+}
+
+/*
+ * The code comes here for each file examined.
+ * We filter the files, then call the user's callback if
+ * the file is included.
+ */
+static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
+{
+ if (top_level) {
+ return ff->file_save(jcr, ff, top_level); /* accept file */
+ }
+ switch (ff->type) {
+ case FT_NOACCESS:
+ case FT_NOFOLLOW:
+ case FT_NOSTAT:
+ case FT_NOCHG:
+ case FT_ISARCH:
+ case FT_NORECURSE:
+ case FT_NOFSCHG:
+ case FT_INVALIDFS:
+ case FT_INVALIDDT:
+ case FT_NOOPEN:
+// return ff->file_save(jcr, ff, top_level);
+
+ /* These items can be filtered */
+ case FT_LNKSAVED:
+ case FT_REGE:
+ case FT_REG:
+ case FT_LNK:
+ case FT_DIRBEGIN:
+ case FT_DIREND:
+ case FT_RAW:
+ case FT_FIFO:
+ case FT_SPEC:
+ case FT_DIRNOCHG:
+ case FT_REPARSE:
+ case FT_JUNCTION:
+ if (accept_file(ff)) {
+ return ff->file_save(jcr, ff, top_level);
+ } else {
+ Dmsg1(dbglvl, "Skip file %s\n", ff->fname);
+ return -1; /* ignore this file */
+ }
+
+ default:
+ Dmsg1(000, "Unknown FT code %d\n", ff->type);
+ return 0;
+ }
+}
+
+