2 * Main routine for finding files on a file system.
3 * The heart of the work to find the files on the
4 * system is done in find_one.c. Here we have the
5 * higher level control as well as the matching
6 * routines for the new syntax Options resource.
13 Copyright (C) 2000-2006 Kern Sibbald
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License
17 version 2 as amended with additional clauses defined in the
18 file LICENSE in the main source directory.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 the file LICENSE for additional details.
31 int32_t name_max; /* filename max length */
32 int32_t path_max; /* path name max length */
36 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
38 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level);
39 static bool accept_file(FF_PKT *ff);
41 static const int fnmode = 0;
44 * Initialize the find files "global" variables
46 FF_PKT *init_find_files()
50 ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
51 memset(ff, 0, sizeof(FF_PKT));
53 ff->sys_fname = get_pool_memory(PM_FNAME);
55 /* Get system path and filename maximum lengths */
56 path_max = pathconf(".", _PC_PATH_MAX);
57 if (path_max < 1024) {
61 name_max = pathconf(".", _PC_NAME_MAX);
62 if (name_max < 1024) {
65 path_max++; /* add for EOS */
66 name_max++; /* add for EOS */
68 Dmsg1(100, "init_find_files ff=%p\n", ff);
73 * Set find_files options. For the moment, we only
74 * provide for full/incremental saves, and setting
75 * of save_time. For additional options, see above
78 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
80 Dmsg0(100, "Enter set_find_options()\n");
81 ff->incremental = incremental;
82 ff->save_time = save_time;
83 Dmsg0(100, "Leave set_find_options()\n");
87 * For VSS we need to know which windows drives
88 * are used, because we create a snapshot of all used
89 * drives before operation
91 * the function returns the number of used drives and
92 * fills "drives" with up to 26 (A..Z) drive names
96 get_win32_driveletters(FF_PKT *ff, char* szDrives)
98 /* szDrives must be at least 27 bytes long */
100 #if !defined(HAVE_WIN32)
104 szDrives[0] = 0; /* make empty */
107 findFILESET *fileset = ff->fileset;
111 for (i=0; i<fileset->include_list.size(); i++) {
112 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
114 /* look through all files and check */
115 for (j=0; j<incexe->name_list.size(); j++) {
116 char *fname = (char *)incexe->name_list.get(j);
117 /* fname should match x:/ */
118 if (strlen(fname) >= 2 && B_ISALPHA(fname[0])
119 && fname[1] == ':') {
121 /* always add in uppercase */
122 char ch = toupper(fname[0]);
123 /* if not found in string, add drive letter */
124 if (!strchr(szDrives,ch)) {
125 szDrives[nCount] = ch;
126 szDrives[nCount+1] = 0;
137 * Find all specified files (determined by calls to name_add()
138 * This routine calls the (handle_file) subroutine with all
139 * sorts of good information for the final disposition of
142 * Call this subroutine with a callback subroutine as the first
143 * argument and a packet as the second argument, this packet
144 * will be passed back to the callback subroutine as the last
147 * The callback subroutine gets called with:
148 * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
149 * arg2 -- the user supplied packet
153 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level),
156 ff->callback = callback;
158 /* This is the new way */
159 findFILESET *fileset = ff->fileset;
163 ff->VerifyOpts[0] = 'V';
164 ff->VerifyOpts[1] = 0;
165 for (i=0; i<fileset->include_list.size(); i++) {
166 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
167 fileset->incexe = incexe;
169 * By setting all options, we in effect or the global options
170 * which is what we want.
172 for (j=0; j<incexe->opts_list.size(); j++) {
173 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
174 ff->flags |= fo->flags;
175 ff->GZIP_level = fo->GZIP_level;
176 ff->fstypes = fo->fstype;
177 ff->drivetypes = fo->drivetype;
178 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
180 for (j=0; j<incexe->name_list.size(); j++) {
181 Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
182 ff->top_fname = (char *)incexe->name_list.get(j);
183 if (find_one_file(jcr, ff, our_callback, his_pkt, ff->top_fname, (dev_t)-1, true) == 0) {
184 return 0; /* error return */
192 static bool accept_file(FF_PKT *ff)
196 findFILESET *fileset = ff->fileset;
197 findINCEXE *incexe = fileset->incexe;
198 const char *basename;
199 int (*match_func)(const char *pattern, const char *string, int flags);
201 if (ff->flags & FO_ENHANCEDWILD) {
202 match_func = enh_fnmatch;
203 if ((basename = last_path_separator(ff->fname)) != NULL)
206 basename = ff->fname;
208 match_func = fnmatch;
209 basename = ff->fname;
212 for (j = 0; j < incexe->opts_list.size(); j++) {
213 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
214 ff->flags = fo->flags;
215 ff->GZIP_level = fo->GZIP_level;
216 ff->reader = fo->reader;
217 ff->writer = fo->writer;
218 ff->fstypes = fo->fstype;
219 ff->drivetypes = fo->drivetype;
221 fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
222 fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
224 if (S_ISDIR(ff->statp.st_mode)) {
225 for (k=0; k<fo->wilddir.size(); k++) {
226 if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
227 if (ff->flags & FO_EXCLUDE) {
228 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
230 return false; /* reject dir */
232 return true; /* accept dir */
236 for (k=0; k<fo->wildfile.size(); k++) {
237 if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
238 if (ff->flags & FO_EXCLUDE) {
239 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
241 return false; /* reject file */
243 return true; /* accept file */
247 for (k=0; k<fo->wildbase.size(); k++) {
248 if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
249 if (ff->flags & FO_EXCLUDE) {
250 Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
252 return false; /* reject file */
254 return true; /* accept file */
258 for (k=0; k<fo->wild.size(); k++) {
259 if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
260 if (ff->flags & FO_EXCLUDE) {
261 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
263 return false; /* reject file */
265 return true; /* accept file */
268 if (S_ISDIR(ff->statp.st_mode)) {
269 for (k=0; k<fo->regexdir.size(); k++) {
270 const int nmatch = 30;
271 regmatch_t pmatch[nmatch];
272 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
273 if (ff->flags & FO_EXCLUDE) {
274 return false; /* reject file */
276 return true; /* accept file */
280 for (k=0; k<fo->regexfile.size(); k++) {
281 const int nmatch = 30;
282 regmatch_t pmatch[nmatch];
283 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
284 if (ff->flags & FO_EXCLUDE) {
285 return false; /* reject file */
287 return true; /* accept file */
291 for (k=0; k<fo->regex.size(); k++) {
292 const int nmatch = 30;
293 regmatch_t pmatch[nmatch];
294 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
295 if (ff->flags & FO_EXCLUDE) {
296 return false; /* reject file */
298 return true; /* accept file */
302 * If we have an empty Options clause with exclude, then
305 if (ff->flags & FO_EXCLUDE &&
306 fo->regex.size() == 0 && fo->wild.size() == 0 &&
307 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
308 fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
309 fo->wildbase.size() == 0) {
310 return false; /* reject file */
314 /* Now apply the Exclude { } directive */
315 for (i=0; i<fileset->exclude_list.size(); i++) {
316 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
317 for (j=0; j<incexe->opts_list.size(); j++) {
318 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
319 fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
320 for (k=0; k<fo->wild.size(); k++) {
321 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
322 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
323 return false; /* reject file */
327 fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
329 for (j=0; j<incexe->name_list.size(); j++) {
330 if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|fnm_flags) == 0) {
331 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
332 return false; /* reject file */
340 * The code comes here for each file examined.
341 * We filter the files, then call the user's callback if
342 * the file is included.
344 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
347 return ff->callback(ff, hpkt, top_level); /* accept file */
360 // return ff->callback(ff, hpkt, top_level);
362 /* These items can be filtered */
373 if (accept_file(ff)) {
374 // Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
375 return ff->callback(ff, hpkt, top_level);
377 Dmsg1(100, "Skip file %s\n", ff->fname);
378 return -1; /* ignore this file */
382 Dmsg1(000, "Unknown FT code %d\n", ff->type);
389 * Terminate find_files() and release
390 * all allocated memory
393 term_find_files(FF_PKT *ff)
397 free_pool_memory(ff->sys_fname);
398 hard_links = term_find_one(ff);