2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main routine for finding files on a file system.
30 * The heart of the work to find the files on the
31 * system is done in find_one.c. Here we have the
32 * higher level control as well as the matching
33 * routines for the new syntax Options resource.
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->strip_path = fo->strip_path;
191 ff->fstypes = fo->fstype;
192 ff->drivetypes = fo->drivetype;
193 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
196 foreach_dlist(node, &incexe->name_list) {
197 char *fname = node->c_str();
198 Dmsg1(100, "F %s\n", fname);
199 ff->top_fname = fname;
200 if (find_one_file(jcr, ff, our_callback, his_pkt, ff->top_fname, (dev_t)-1, true) == 0) {
201 return 0; /* error return */
204 foreach_dlist(node, &incexe->plugin_list) {
205 char *fname = node->c_str();
206 Dmsg1(100, "P %s\n", fname);
207 ff->top_fname = fname;
208 generate_plugin_event(jcr, bEventPluginCommand, (void *)fname);
215 static bool accept_file(FF_PKT *ff)
219 findFILESET *fileset = ff->fileset;
220 findINCEXE *incexe = fileset->incexe;
221 const char *basename;
222 int (*match_func)(const char *pattern, const char *string, int flags);
224 if (ff->flags & FO_ENHANCEDWILD) {
225 // match_func = enh_fnmatch;
226 match_func = fnmatch;
227 if ((basename = last_path_separator(ff->fname)) != NULL)
230 basename = ff->fname;
232 match_func = fnmatch;
233 basename = ff->fname;
236 for (j = 0; j < incexe->opts_list.size(); j++) {
237 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
238 ff->flags = fo->flags;
239 ff->GZIP_level = fo->GZIP_level;
240 ff->reader = fo->reader;
241 ff->writer = fo->writer;
242 ff->fstypes = fo->fstype;
243 ff->drivetypes = fo->drivetype;
245 fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
246 fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
248 if (S_ISDIR(ff->statp.st_mode)) {
249 for (k=0; k<fo->wilddir.size(); k++) {
250 if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
251 if (ff->flags & FO_EXCLUDE) {
252 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
254 return false; /* reject dir */
256 return true; /* accept dir */
260 for (k=0; k<fo->wildfile.size(); k++) {
261 if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
262 if (ff->flags & FO_EXCLUDE) {
263 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
265 return false; /* reject file */
267 return true; /* accept file */
271 for (k=0; k<fo->wildbase.size(); k++) {
272 if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
273 if (ff->flags & FO_EXCLUDE) {
274 Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
276 return false; /* reject file */
278 return true; /* accept file */
282 for (k=0; k<fo->wild.size(); k++) {
283 if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
284 if (ff->flags & FO_EXCLUDE) {
285 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
287 return false; /* reject file */
289 return true; /* accept file */
292 if (S_ISDIR(ff->statp.st_mode)) {
293 for (k=0; k<fo->regexdir.size(); k++) {
294 const int nmatch = 30;
295 regmatch_t pmatch[nmatch];
296 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
297 if (ff->flags & FO_EXCLUDE) {
298 return false; /* reject file */
300 return true; /* accept file */
304 for (k=0; k<fo->regexfile.size(); k++) {
305 const int nmatch = 30;
306 regmatch_t pmatch[nmatch];
307 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
308 if (ff->flags & FO_EXCLUDE) {
309 return false; /* reject file */
311 return true; /* accept file */
315 for (k=0; k<fo->regex.size(); k++) {
316 const int nmatch = 30;
317 regmatch_t pmatch[nmatch];
318 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
319 if (ff->flags & FO_EXCLUDE) {
320 return false; /* reject file */
322 return true; /* accept file */
326 * If we have an empty Options clause with exclude, then
329 if (ff->flags & FO_EXCLUDE &&
330 fo->regex.size() == 0 && fo->wild.size() == 0 &&
331 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
332 fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
333 fo->wildbase.size() == 0) {
334 return false; /* reject file */
338 /* Now apply the Exclude { } directive */
339 for (i=0; i<fileset->exclude_list.size(); i++) {
340 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
341 for (j=0; j<incexe->opts_list.size(); j++) {
342 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
343 fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
344 for (k=0; k<fo->wild.size(); k++) {
345 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
346 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
347 return false; /* reject file */
351 fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
354 foreach_dlist(node, &incexe->name_list) {
355 char *fname = node->c_str();
356 if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
357 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
358 return false; /* reject file */
366 * The code comes here for each file examined.
367 * We filter the files, then call the user's callback if
368 * the file is included.
370 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
373 return ff->callback(ff, hpkt, top_level); /* accept file */
387 // return ff->callback(ff, hpkt, top_level);
389 /* These items can be filtered */
400 if (accept_file(ff)) {
401 // Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
402 return ff->callback(ff, hpkt, top_level);
404 Dmsg1(100, "Skip file %s\n", ff->fname);
405 return -1; /* ignore this file */
409 Dmsg1(000, "Unknown FT code %d\n", ff->type);
416 * Terminate find_files() and release
417 * all allocated memory
420 term_find_files(FF_PKT *ff)
424 free_pool_memory(ff->sys_fname);
425 if (ff->fname_save) {
426 free_pool_memory(ff->fname_save);
429 free_pool_memory(ff->link_save);
431 hard_links = term_find_one(ff);