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 * Call this subroutine with a callback subroutine as the first
152 * argument and a packet as the second argument, this packet
153 * will be passed back to the callback subroutine as the last
156 * The callback subroutine gets called with:
157 * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
158 * arg2 -- the user supplied packet
162 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level),
165 ff->callback = callback;
167 /* This is the new way */
168 findFILESET *fileset = ff->fileset;
172 ff->VerifyOpts[0] = 'V';
173 ff->VerifyOpts[1] = 0;
174 for (i=0; i<fileset->include_list.size(); i++) {
175 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
176 fileset->incexe = incexe;
178 * By setting all options, we in effect or the global options
179 * which is what we want.
181 for (j=0; j<incexe->opts_list.size(); j++) {
182 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
183 ff->flags |= fo->flags;
184 ff->GZIP_level = fo->GZIP_level;
185 ff->strip_path = fo->strip_path;
186 ff->fstypes = fo->fstype;
187 ff->drivetypes = fo->drivetype;
188 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
191 foreach_dlist(node, &incexe->name_list) {
192 char *fname = node->c_str();
193 Dmsg1(100, "F %s\n", fname);
194 ff->top_fname = fname;
195 if (find_one_file(jcr, ff, our_callback, his_pkt, ff->top_fname, (dev_t)-1, true) == 0) {
196 return 0; /* error return */
199 foreach_dlist(node, &incexe->plugin_list) {
200 char *fname = node->c_str();
201 Dmsg1(100, "P %s\n", fname);
202 ff->top_fname = fname;
203 ff->cmd_plugin = true;
204 generate_plugin_event(jcr, bEventPluginCommand, (void *)fname);
205 ff->cmd_plugin = false;
212 static bool accept_file(FF_PKT *ff)
216 findFILESET *fileset = ff->fileset;
217 findINCEXE *incexe = fileset->incexe;
218 const char *basename;
219 int (*match_func)(const char *pattern, const char *string, int flags);
221 if (ff->flags & FO_ENHANCEDWILD) {
222 // match_func = enh_fnmatch;
223 match_func = fnmatch;
224 if ((basename = last_path_separator(ff->fname)) != NULL)
227 basename = ff->fname;
229 match_func = fnmatch;
230 basename = ff->fname;
233 for (j = 0; j < incexe->opts_list.size(); j++) {
234 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
235 ff->flags = fo->flags;
236 ff->GZIP_level = fo->GZIP_level;
237 ff->fstypes = fo->fstype;
238 ff->drivetypes = fo->drivetype;
240 fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
241 fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
243 if (S_ISDIR(ff->statp.st_mode)) {
244 for (k=0; k<fo->wilddir.size(); k++) {
245 if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
246 if (ff->flags & FO_EXCLUDE) {
247 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
249 return false; /* reject dir */
251 return true; /* accept dir */
255 for (k=0; k<fo->wildfile.size(); k++) {
256 if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
257 if (ff->flags & FO_EXCLUDE) {
258 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
260 return false; /* reject file */
262 return true; /* accept file */
266 for (k=0; k<fo->wildbase.size(); k++) {
267 if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
268 if (ff->flags & FO_EXCLUDE) {
269 Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
271 return false; /* reject file */
273 return true; /* accept file */
277 for (k=0; k<fo->wild.size(); k++) {
278 if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
279 if (ff->flags & FO_EXCLUDE) {
280 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
282 return false; /* reject file */
284 return true; /* accept file */
287 if (S_ISDIR(ff->statp.st_mode)) {
288 for (k=0; k<fo->regexdir.size(); k++) {
289 const int nmatch = 30;
290 regmatch_t pmatch[nmatch];
291 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
292 if (ff->flags & FO_EXCLUDE) {
293 return false; /* reject file */
295 return true; /* accept file */
299 for (k=0; k<fo->regexfile.size(); k++) {
300 const int nmatch = 30;
301 regmatch_t pmatch[nmatch];
302 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
303 if (ff->flags & FO_EXCLUDE) {
304 return false; /* reject file */
306 return true; /* accept file */
310 for (k=0; k<fo->regex.size(); k++) {
311 const int nmatch = 30;
312 regmatch_t pmatch[nmatch];
313 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
314 if (ff->flags & FO_EXCLUDE) {
315 return false; /* reject file */
317 return true; /* accept file */
321 * If we have an empty Options clause with exclude, then
324 if (ff->flags & FO_EXCLUDE &&
325 fo->regex.size() == 0 && fo->wild.size() == 0 &&
326 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
327 fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
328 fo->wildbase.size() == 0) {
329 return false; /* reject file */
333 /* Now apply the Exclude { } directive */
334 for (i=0; i<fileset->exclude_list.size(); i++) {
335 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
336 for (j=0; j<incexe->opts_list.size(); j++) {
337 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
338 fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
339 for (k=0; k<fo->wild.size(); k++) {
340 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
341 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
342 return false; /* reject file */
346 fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
349 foreach_dlist(node, &incexe->name_list) {
350 char *fname = node->c_str();
351 if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
352 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
353 return false; /* reject file */
361 * The code comes here for each file examined.
362 * We filter the files, then call the user's callback if
363 * the file is included.
365 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
368 return ff->callback(ff, hpkt, top_level); /* accept file */
382 // return ff->callback(ff, hpkt, top_level);
384 /* These items can be filtered */
395 if (accept_file(ff)) {
396 return ff->callback(ff, hpkt, top_level);
398 Dmsg1(100, "Skip file %s\n", ff->fname);
399 return -1; /* ignore this file */
403 Dmsg1(000, "Unknown FT code %d\n", ff->type);
410 * Terminate find_files() and release
411 * all allocated memory
414 term_find_files(FF_PKT *ff)
418 free_pool_memory(ff->sys_fname);
419 if (ff->fname_save) {
420 free_pool_memory(ff->fname_save);
423 free_pool_memory(ff->link_save);
425 hard_links = term_find_one(ff);