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-2006 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;
124 for (i=0; i<fileset->include_list.size(); i++) {
125 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
127 /* look through all files and check */
128 for (j=0; j<incexe->name_list.size(); j++) {
129 char *fname = (char *)incexe->name_list.get(j);
130 /* fname should match x:/ */
131 if (strlen(fname) >= 2 && B_ISALPHA(fname[0])
132 && fname[1] == ':') {
134 /* always add in uppercase */
135 char ch = toupper(fname[0]);
136 /* if not found in string, add drive letter */
137 if (!strchr(szDrives,ch)) {
138 szDrives[nCount] = ch;
139 szDrives[nCount+1] = 0;
150 * Find all specified files (determined by calls to name_add()
151 * This routine calls the (handle_file) subroutine with all
152 * sorts of good information for the final disposition of
155 * Call this subroutine with a callback subroutine as the first
156 * argument and a packet as the second argument, this packet
157 * will be passed back to the callback subroutine as the last
160 * The callback subroutine gets called with:
161 * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
162 * arg2 -- the user supplied packet
166 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level),
169 ff->callback = callback;
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->fstypes = fo->fstype;
190 ff->drivetypes = fo->drivetype;
191 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
193 for (j=0; j<incexe->name_list.size(); j++) {
194 Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
195 ff->top_fname = (char *)incexe->name_list.get(j);
196 if (find_one_file(jcr, ff, our_callback, his_pkt, ff->top_fname, (dev_t)-1, true) == 0) {
197 return 0; /* error return */
205 static bool accept_file(FF_PKT *ff)
209 findFILESET *fileset = ff->fileset;
210 findINCEXE *incexe = fileset->incexe;
211 const char *basename;
212 int (*match_func)(const char *pattern, const char *string, int flags);
214 if (ff->flags & FO_ENHANCEDWILD) {
215 match_func = enh_fnmatch;
216 if ((basename = last_path_separator(ff->fname)) != NULL)
219 basename = ff->fname;
221 match_func = fnmatch;
222 basename = ff->fname;
225 for (j = 0; j < incexe->opts_list.size(); j++) {
226 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
227 ff->flags = fo->flags;
228 ff->GZIP_level = fo->GZIP_level;
229 ff->reader = fo->reader;
230 ff->writer = fo->writer;
231 ff->fstypes = fo->fstype;
232 ff->drivetypes = fo->drivetype;
234 fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
235 fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
237 if (S_ISDIR(ff->statp.st_mode)) {
238 for (k=0; k<fo->wilddir.size(); k++) {
239 if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
240 if (ff->flags & FO_EXCLUDE) {
241 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
243 return false; /* reject dir */
245 return true; /* accept dir */
249 for (k=0; k<fo->wildfile.size(); k++) {
250 if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
251 if (ff->flags & FO_EXCLUDE) {
252 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
254 return false; /* reject file */
256 return true; /* accept file */
260 for (k=0; k<fo->wildbase.size(); k++) {
261 if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
262 if (ff->flags & FO_EXCLUDE) {
263 Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
265 return false; /* reject file */
267 return true; /* accept file */
271 for (k=0; k<fo->wild.size(); k++) {
272 if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
273 if (ff->flags & FO_EXCLUDE) {
274 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
276 return false; /* reject file */
278 return true; /* accept file */
281 if (S_ISDIR(ff->statp.st_mode)) {
282 for (k=0; k<fo->regexdir.size(); k++) {
283 const int nmatch = 30;
284 regmatch_t pmatch[nmatch];
285 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
286 if (ff->flags & FO_EXCLUDE) {
287 return false; /* reject file */
289 return true; /* accept file */
293 for (k=0; k<fo->regexfile.size(); k++) {
294 const int nmatch = 30;
295 regmatch_t pmatch[nmatch];
296 if (regexec((regex_t *)fo->regexfile.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->regex.size(); k++) {
305 const int nmatch = 30;
306 regmatch_t pmatch[nmatch];
307 if (regexec((regex_t *)fo->regex.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 * If we have an empty Options clause with exclude, then
318 if (ff->flags & FO_EXCLUDE &&
319 fo->regex.size() == 0 && fo->wild.size() == 0 &&
320 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
321 fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
322 fo->wildbase.size() == 0) {
323 return false; /* reject file */
327 /* Now apply the Exclude { } directive */
328 for (i=0; i<fileset->exclude_list.size(); i++) {
329 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
330 for (j=0; j<incexe->opts_list.size(); j++) {
331 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
332 fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
333 for (k=0; k<fo->wild.size(); k++) {
334 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
335 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
336 return false; /* reject file */
340 fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
342 for (j=0; j<incexe->name_list.size(); j++) {
343 if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|fnm_flags) == 0) {
344 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
345 return false; /* reject file */
353 * The code comes here for each file examined.
354 * We filter the files, then call the user's callback if
355 * the file is included.
357 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
360 return ff->callback(ff, hpkt, top_level); /* accept file */
373 // return ff->callback(ff, hpkt, top_level);
375 /* These items can be filtered */
386 if (accept_file(ff)) {
387 // Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
388 return ff->callback(ff, hpkt, top_level);
390 Dmsg1(100, "Skip file %s\n", ff->fname);
391 return -1; /* ignore this file */
395 Dmsg1(000, "Unknown FT code %d\n", ff->type);
402 * Terminate find_files() and release
403 * all allocated memory
406 term_find_files(FF_PKT *ff)
410 free_pool_memory(ff->sys_fname);
411 hard_links = term_find_one(ff);