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 Bacula® - The Network Backup Solution
15 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
17 The main author of Bacula is Kern Sibbald, with contributions from
18 many others, a complete list can be found in the file AUTHORS.
19 This program is Free Software; you can redistribute it and/or
20 modify it under the terms of version two of the GNU General Public
21 License as published by the Free Software Foundation plus additions
22 that are listed in the file LICENSE.
24 This program is distributed in the hope that it will be useful, but
25 WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
34 Bacula® is a registered trademark of John Walker.
35 The licensor of Bacula is the Free Software Foundation Europe
36 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
37 Switzerland, email:ftf@fsfeurope.org.
44 int32_t name_max; /* filename max length */
45 int32_t path_max; /* path name max length */
49 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
51 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level);
52 static bool accept_file(FF_PKT *ff);
54 static const int fnmode = 0;
57 * Initialize the find files "global" variables
59 FF_PKT *init_find_files()
63 ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
64 memset(ff, 0, sizeof(FF_PKT));
66 ff->sys_fname = get_pool_memory(PM_FNAME);
68 /* Get system path and filename maximum lengths */
69 path_max = pathconf(".", _PC_PATH_MAX);
70 if (path_max < 1024) {
74 name_max = pathconf(".", _PC_NAME_MAX);
75 if (name_max < 1024) {
78 path_max++; /* add for EOS */
79 name_max++; /* add for EOS */
81 Dmsg1(100, "init_find_files ff=%p\n", ff);
86 * Set find_files options. For the moment, we only
87 * provide for full/incremental saves, and setting
88 * of save_time. For additional options, see above
91 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
93 Dmsg0(100, "Enter set_find_options()\n");
94 ff->incremental = incremental;
95 ff->save_time = save_time;
96 Dmsg0(100, "Leave set_find_options()\n");
100 * For VSS we need to know which windows drives
101 * are used, because we create a snapshot of all used
102 * drives before operation
104 * the function returns the number of used drives and
105 * fills "drives" with up to 26 (A..Z) drive names
109 get_win32_driveletters(FF_PKT *ff, char* szDrives)
111 /* szDrives must be at least 27 bytes long */
113 #if !defined(HAVE_WIN32)
117 szDrives[0] = 0; /* make empty */
120 findFILESET *fileset = ff->fileset;
125 for (i=0; i<fileset->include_list.size(); i++) {
126 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
128 /* look through all files and check */
129 foreach_dlist(node, &incexe->name_list) {
130 char *fname = node->c_str();
131 /* fname should match x:/ */
132 if (strlen(fname) >= 2 && B_ISALPHA(fname[0])
133 && fname[1] == ':') {
135 /* always add in uppercase */
136 char ch = toupper(fname[0]);
137 /* if not found in string, add drive letter */
138 if (!strchr(szDrives,ch)) {
139 szDrives[nCount] = ch;
140 szDrives[nCount+1] = 0;
151 * Find all specified files (determined by calls to name_add()
152 * This routine calls the (handle_file) subroutine with all
153 * sorts of good information for the final disposition of
156 * Call this subroutine with a callback subroutine as the first
157 * argument and a packet as the second argument, this packet
158 * will be passed back to the callback subroutine as the last
161 * The callback subroutine gets called with:
162 * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
163 * arg2 -- the user supplied packet
167 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level),
170 ff->callback = callback;
172 /* This is the new way */
173 findFILESET *fileset = ff->fileset;
177 ff->VerifyOpts[0] = 'V';
178 ff->VerifyOpts[1] = 0;
179 for (i=0; i<fileset->include_list.size(); i++) {
180 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
181 fileset->incexe = incexe;
183 * By setting all options, we in effect or the global options
184 * which is what we want.
186 for (j=0; j<incexe->opts_list.size(); j++) {
187 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
188 ff->flags |= fo->flags;
189 ff->GZIP_level = fo->GZIP_level;
190 ff->fstypes = fo->fstype;
191 ff->drivetypes = fo->drivetype;
192 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
195 foreach_dlist(node, &incexe->name_list) {
196 char *fname = node->c_str();
197 Dmsg1(100, "F %s\n", fname);
198 ff->top_fname = fname;
199 if (find_one_file(jcr, ff, our_callback, his_pkt, ff->top_fname, (dev_t)-1, true) == 0) {
200 return 0; /* error return */
208 static bool accept_file(FF_PKT *ff)
212 findFILESET *fileset = ff->fileset;
213 findINCEXE *incexe = fileset->incexe;
214 const char *basename;
215 int (*match_func)(const char *pattern, const char *string, int flags);
217 if (ff->flags & FO_ENHANCEDWILD) {
218 match_func = enh_fnmatch;
219 if ((basename = last_path_separator(ff->fname)) != NULL)
222 basename = ff->fname;
224 match_func = fnmatch;
225 basename = ff->fname;
228 for (j = 0; j < incexe->opts_list.size(); j++) {
229 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
230 ff->flags = fo->flags;
231 ff->GZIP_level = fo->GZIP_level;
232 ff->reader = fo->reader;
233 ff->writer = fo->writer;
234 ff->fstypes = fo->fstype;
235 ff->drivetypes = fo->drivetype;
237 fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
238 fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
240 if (S_ISDIR(ff->statp.st_mode)) {
241 for (k=0; k<fo->wilddir.size(); k++) {
242 if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
243 if (ff->flags & FO_EXCLUDE) {
244 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
246 return false; /* reject dir */
248 return true; /* accept dir */
252 for (k=0; k<fo->wildfile.size(); k++) {
253 if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
254 if (ff->flags & FO_EXCLUDE) {
255 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
257 return false; /* reject file */
259 return true; /* accept file */
263 for (k=0; k<fo->wildbase.size(); k++) {
264 if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
265 if (ff->flags & FO_EXCLUDE) {
266 Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
268 return false; /* reject file */
270 return true; /* accept file */
274 for (k=0; k<fo->wild.size(); k++) {
275 if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
276 if (ff->flags & FO_EXCLUDE) {
277 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
279 return false; /* reject file */
281 return true; /* accept file */
284 if (S_ISDIR(ff->statp.st_mode)) {
285 for (k=0; k<fo->regexdir.size(); k++) {
286 const int nmatch = 30;
287 regmatch_t pmatch[nmatch];
288 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
289 if (ff->flags & FO_EXCLUDE) {
290 return false; /* reject file */
292 return true; /* accept file */
296 for (k=0; k<fo->regexfile.size(); k++) {
297 const int nmatch = 30;
298 regmatch_t pmatch[nmatch];
299 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
300 if (ff->flags & FO_EXCLUDE) {
301 return false; /* reject file */
303 return true; /* accept file */
307 for (k=0; k<fo->regex.size(); k++) {
308 const int nmatch = 30;
309 regmatch_t pmatch[nmatch];
310 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
311 if (ff->flags & FO_EXCLUDE) {
312 return false; /* reject file */
314 return true; /* accept file */
318 * If we have an empty Options clause with exclude, then
321 if (ff->flags & FO_EXCLUDE &&
322 fo->regex.size() == 0 && fo->wild.size() == 0 &&
323 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
324 fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
325 fo->wildbase.size() == 0) {
326 return false; /* reject file */
330 /* Now apply the Exclude { } directive */
331 for (i=0; i<fileset->exclude_list.size(); i++) {
332 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
333 for (j=0; j<incexe->opts_list.size(); j++) {
334 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
335 fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
336 for (k=0; k<fo->wild.size(); k++) {
337 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
338 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
339 return false; /* reject file */
343 fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
346 foreach_dlist(node, &incexe->name_list) {
347 char *fname = node->c_str();
348 if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
349 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
350 return false; /* reject file */
358 * The code comes here for each file examined.
359 * We filter the files, then call the user's callback if
360 * the file is included.
362 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
365 return ff->callback(ff, hpkt, top_level); /* accept file */
378 // return ff->callback(ff, hpkt, top_level);
380 /* These items can be filtered */
391 if (accept_file(ff)) {
392 // Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
393 return ff->callback(ff, hpkt, top_level);
395 Dmsg1(100, "Skip file %s\n", ff->fname);
396 return -1; /* ignore this file */
400 Dmsg1(000, "Unknown FT code %d\n", ff->type);
407 * Terminate find_files() and release
408 * all allocated memory
411 term_find_files(FF_PKT *ff)
415 free_pool_memory(ff->sys_fname);
416 hard_links = term_find_one(ff);