2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 Kern Sibbald.
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(JCR *jcr, FF_PKT *ff, 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 < 2048) {
74 name_max = pathconf(".", _PC_NAME_MAX);
75 if (name_max < 2048) {
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 set_find_changed_function(FF_PKT *ff, bool check_fct(JCR *jcr, FF_PKT *ff))
102 Dmsg0(100, "Enter set_find_changed_function()\n");
103 ff->check_fct = check_fct;
107 * For VSS we need to know which windows drives
108 * are used, because we create a snapshot of all used
109 * drives before operation
111 * the function returns the number of used drives and
112 * fills "drives" with up to 26 (A..Z) drive names
116 get_win32_driveletters(FF_PKT *ff, char* szDrives)
118 /* szDrives must be at least 27 bytes long */
120 #if !defined(HAVE_WIN32)
124 szDrives[0] = 0; /* make empty */
127 findFILESET *fileset = ff->fileset;
132 for (i=0; i<fileset->include_list.size(); i++) {
133 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
135 /* look through all files and check */
136 foreach_dlist(node, &incexe->name_list) {
137 char *fname = node->c_str();
138 /* fname should match x:/ */
139 if (strlen(fname) >= 2 && B_ISALPHA(fname[0])
140 && fname[1] == ':') {
142 /* always add in uppercase */
143 char ch = toupper(fname[0]);
144 /* if not found in string, add drive letter */
145 if (!strchr(szDrives,ch)) {
146 szDrives[nCount] = ch;
147 szDrives[nCount+1] = 0;
158 * Call this subroutine with a callback subroutine as the first
159 * argument and a packet as the second argument, this packet
160 * will be passed back to the callback subroutine as the last
165 find_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level),
166 int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level))
168 ff->file_save = file_save;
169 ff->plugin_save = plugin_save;
171 /* This is the new way */
172 findFILESET *fileset = ff->fileset;
176 ff->VerifyOpts[0] = 'V';
177 ff->VerifyOpts[1] = 0;
178 for (i=0; i<fileset->include_list.size(); i++) {
179 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
180 fileset->incexe = incexe;
182 * By setting all options, we in effect or the global options
183 * which is what we want.
185 for (j=0; j<incexe->opts_list.size(); j++) {
186 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
187 ff->flags |= fo->flags;
188 ff->GZIP_level = fo->GZIP_level;
189 ff->strip_path = fo->strip_path;
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, ff->top_fname, (dev_t)-1, true) == 0) {
200 return 0; /* error return */
204 foreach_dlist(node, &incexe->plugin_list) {
205 char *fname = node->c_str();
206 Dmsg1(100, "PluginCommand: %s\n", fname);
207 ff->top_fname = fname;
208 ff->cmd_plugin = true;
209 plugin_save(jcr, ff, true);
210 ff->cmd_plugin = false;
219 * Test if the currently selected directory (in ff->fname) is
220 * explicitly in the Include list or explicitly in the Exclude
223 bool is_in_fileset(FF_PKT *ff)
229 findFILESET *fileset = ff->fileset;
231 for (i=0; i<fileset->include_list.size(); i++) {
232 incexe = (findINCEXE *)fileset->include_list.get(i);
233 foreach_dlist(node, &incexe->name_list) {
234 fname = node->c_str();
235 Dmsg2(100, "Inc fname=%s ff->fname=%s\n", fname, ff->fname);
236 if (strcmp(fname, ff->fname) == 0) {
241 for (i=0; i<fileset->exclude_list.size(); i++) {
242 incexe = (findINCEXE *)fileset->exclude_list.get(i);
243 foreach_dlist(node, &incexe->name_list) {
244 fname = node->c_str();
245 Dmsg2(100, "Exc fname=%s ff->fname=%s\n", fname, ff->fname);
246 if (strcmp(fname, ff->fname) == 0) {
256 static bool accept_file(FF_PKT *ff)
260 findFILESET *fileset = ff->fileset;
261 findINCEXE *incexe = fileset->incexe;
262 const char *basename;
263 int (*match_func)(const char *pattern, const char *string, int flags);
265 if (ff->flags & FO_ENHANCEDWILD) {
266 // match_func = enh_fnmatch;
267 match_func = fnmatch;
268 if ((basename = last_path_separator(ff->fname)) != NULL)
271 basename = ff->fname;
273 match_func = fnmatch;
274 basename = ff->fname;
277 ff->ignoredir = incexe->ignoredir;
279 for (j = 0; j < incexe->opts_list.size(); j++) {
280 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
281 ff->flags = fo->flags;
282 ff->GZIP_level = fo->GZIP_level;
283 ff->fstypes = fo->fstype;
284 ff->drivetypes = fo->drivetype;
286 fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
287 fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
289 if (S_ISDIR(ff->statp.st_mode)) {
290 for (k=0; k<fo->wilddir.size(); k++) {
291 if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
292 if (ff->flags & FO_EXCLUDE) {
293 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
295 return false; /* reject dir */
297 return true; /* accept dir */
301 for (k=0; k<fo->wildfile.size(); k++) {
302 if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
303 if (ff->flags & FO_EXCLUDE) {
304 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
306 return false; /* reject file */
308 return true; /* accept file */
312 for (k=0; k<fo->wildbase.size(); k++) {
313 if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
314 if (ff->flags & FO_EXCLUDE) {
315 Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
317 return false; /* reject file */
319 return true; /* accept file */
323 for (k=0; k<fo->wild.size(); k++) {
324 if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
325 if (ff->flags & FO_EXCLUDE) {
326 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
328 return false; /* reject file */
330 return true; /* accept file */
333 if (S_ISDIR(ff->statp.st_mode)) {
334 for (k=0; k<fo->regexdir.size(); k++) {
335 const int nmatch = 30;
336 regmatch_t pmatch[nmatch];
337 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
338 if (ff->flags & FO_EXCLUDE) {
339 return false; /* reject file */
341 return true; /* accept file */
345 for (k=0; k<fo->regexfile.size(); k++) {
346 const int nmatch = 30;
347 regmatch_t pmatch[nmatch];
348 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
349 if (ff->flags & FO_EXCLUDE) {
350 return false; /* reject file */
352 return true; /* accept file */
356 for (k=0; k<fo->regex.size(); k++) {
357 const int nmatch = 30;
358 regmatch_t pmatch[nmatch];
359 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
360 if (ff->flags & FO_EXCLUDE) {
361 return false; /* reject file */
363 return true; /* accept file */
367 * If we have an empty Options clause with exclude, then
370 if (ff->flags & FO_EXCLUDE &&
371 fo->regex.size() == 0 && fo->wild.size() == 0 &&
372 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
373 fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
374 fo->wildbase.size() == 0) {
375 return false; /* reject file */
379 /* Now apply the Exclude { } directive */
380 for (i=0; i<fileset->exclude_list.size(); i++) {
381 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
382 for (j=0; j<incexe->opts_list.size(); j++) {
383 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
384 fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
385 for (k=0; k<fo->wild.size(); k++) {
386 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
387 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
388 return false; /* reject file */
392 fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
395 foreach_dlist(node, &incexe->name_list) {
396 char *fname = node->c_str();
397 if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
398 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
399 return false; /* reject file */
407 * The code comes here for each file examined.
408 * We filter the files, then call the user's callback if
409 * the file is included.
411 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
414 return ff->file_save(jcr, ff, top_level); /* accept file */
428 // return ff->file_save(jcr, ff, top_level);
430 /* These items can be filtered */
441 if (accept_file(ff)) {
442 return ff->file_save(jcr, ff, top_level);
444 Dmsg1(100, "Skip file %s\n", ff->fname);
445 return -1; /* ignore this file */
449 Dmsg1(000, "Unknown FT code %d\n", ff->type);
456 * Terminate find_files() and release
457 * all allocated memory
460 term_find_files(FF_PKT *ff)
464 free_pool_memory(ff->sys_fname);
465 if (ff->fname_save) {
466 free_pool_memory(ff->fname_save);
469 free_pool_memory(ff->link_save);
471 hard_links = term_find_one(ff);