]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
kes Remove a redundant jcr argument to find_files, match_files, and
[bacula/bacula] / bacula / src / findlib / find.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
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.
34  *
35  *  Kern E. Sibbald, MM
36  *
37  *   Version $Id$
38  */
39
40
41 #include "bacula.h"
42 #include "find.h"
43
44 int32_t name_max;              /* filename max length */
45 int32_t path_max;              /* path name max length */
46
47 #ifdef DEBUG
48 #undef bmalloc
49 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
50 #endif
51 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level);
52 static bool accept_file(FF_PKT *ff);
53
54 static const int fnmode = 0;
55
56 /*
57  * Initialize the find files "global" variables
58  */
59 FF_PKT *init_find_files()
60 {
61   FF_PKT *ff;
62
63   ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
64   memset(ff, 0, sizeof(FF_PKT));
65
66   ff->sys_fname = get_pool_memory(PM_FNAME);
67
68    /* Get system path and filename maximum lengths */
69    path_max = pathconf(".", _PC_PATH_MAX);
70    if (path_max < 1024) {
71       path_max = 1024;
72    }
73
74    name_max = pathconf(".", _PC_NAME_MAX);
75    if (name_max < 1024) {
76       name_max = 1024;
77    }
78    path_max++;                        /* add for EOS */
79    name_max++;                        /* add for EOS */
80
81   Dmsg1(100, "init_find_files ff=%p\n", ff);
82   return ff;
83 }
84
85 /*
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
89  */
90 void
91 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
92 {
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");
97 }
98
99 /*
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
103  *
104  * the function returns the number of used drives and
105  * fills "drives" with up to 26 (A..Z) drive names
106  *
107  */
108 int
109 get_win32_driveletters(FF_PKT *ff, char* szDrives)
110 {
111    /* szDrives must be at least 27 bytes long */
112
113 #if !defined(HAVE_WIN32)
114    return 0;
115 #endif
116
117    szDrives[0] = 0; /* make empty */
118    int nCount = 0;
119     
120    findFILESET *fileset = ff->fileset;
121    if (fileset) {
122       int i;
123       dlistString *node;
124       
125       for (i=0; i<fileset->include_list.size(); i++) {
126          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
127          
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] == ':') {
134                
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;
141                   nCount++;
142                }                                
143             }            
144          }
145       }
146    }
147    return nCount;
148 }
149
150 /*
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
154  * argument.
155  *
156  */
157 int
158 find_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level),
159            int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)) 
160 {
161    ff->file_save = file_save;
162    ff->plugin_save = plugin_save;
163
164    /* This is the new way */
165    findFILESET *fileset = ff->fileset;
166    if (fileset) {
167       int i, j;
168       ff->flags = 0;
169       ff->VerifyOpts[0] = 'V';
170       ff->VerifyOpts[1] = 0;
171       for (i=0; i<fileset->include_list.size(); i++) {
172          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
173          fileset->incexe = incexe;
174          /*
175           * By setting all options, we in effect or the global options
176           *   which is what we want.
177           */
178          for (j=0; j<incexe->opts_list.size(); j++) {
179             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
180             ff->flags |= fo->flags;
181             ff->GZIP_level = fo->GZIP_level;
182             ff->strip_path = fo->strip_path;
183             ff->fstypes = fo->fstype;
184             ff->drivetypes = fo->drivetype;
185             bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
186          }
187          dlistString *node;
188          foreach_dlist(node, &incexe->name_list) {
189             char *fname = node->c_str();
190             Dmsg1(100, "F %s\n", fname);
191             ff->top_fname = fname;
192             if (find_one_file(jcr, ff, our_callback, ff->top_fname, (dev_t)-1, true) == 0) {
193                return 0;                  /* error return */
194             }
195          }
196          if (plugin_save) {
197             foreach_dlist(node, &incexe->plugin_list) {
198                char *fname = node->c_str();
199                Dmsg1(100, "PluginCommand: %s\n", fname);
200                ff->top_fname = fname;
201                ff->cmd_plugin = true;
202                plugin_save(jcr, ff, true);
203                ff->cmd_plugin = false;
204             }
205          }
206       }
207    }
208    return 1;
209 }
210
211 static bool accept_file(FF_PKT *ff)
212 {
213    int i, j, k;
214    int fnm_flags;
215    findFILESET *fileset = ff->fileset;
216    findINCEXE *incexe = fileset->incexe;
217    const char *basename;
218    int (*match_func)(const char *pattern, const char *string, int flags);
219
220    if (ff->flags & FO_ENHANCEDWILD) {
221 //    match_func = enh_fnmatch;
222       match_func = fnmatch;
223       if ((basename = last_path_separator(ff->fname)) != NULL)
224          basename++;
225       else
226          basename = ff->fname;
227    } else {
228       match_func = fnmatch;
229       basename = ff->fname;
230    }
231
232    for (j = 0; j < incexe->opts_list.size(); j++) {
233       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
234       ff->flags = fo->flags;
235       ff->GZIP_level = fo->GZIP_level;
236       ff->fstypes = fo->fstype;
237       ff->drivetypes = fo->drivetype;
238
239       fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
240       fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
241
242       if (S_ISDIR(ff->statp.st_mode)) {
243          for (k=0; k<fo->wilddir.size(); k++) {
244             if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
245                if (ff->flags & FO_EXCLUDE) {
246                   Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
247                      ff->fname);
248                   return false;       /* reject dir */
249                }
250                return true;           /* accept dir */
251             }
252          }
253       } else {
254          for (k=0; k<fo->wildfile.size(); k++) {
255             if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
256                if (ff->flags & FO_EXCLUDE) {
257                   Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
258                      ff->fname);
259                   return false;       /* reject file */
260                }
261                return true;           /* accept file */
262             }
263          }
264
265          for (k=0; k<fo->wildbase.size(); k++) {
266             if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
267                if (ff->flags & FO_EXCLUDE) {
268                   Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
269                      basename);
270                   return false;       /* reject file */
271                }
272                return true;           /* accept file */
273             }
274          }
275       }
276       for (k=0; k<fo->wild.size(); k++) {
277          if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
278             if (ff->flags & FO_EXCLUDE) {
279                Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
280                   ff->fname);
281                return false;          /* reject file */
282             }
283             return true;              /* accept file */
284          }
285       }
286       if (S_ISDIR(ff->statp.st_mode)) {
287          for (k=0; k<fo->regexdir.size(); k++) {
288             const int nmatch = 30;
289             regmatch_t pmatch[nmatch];
290             if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
291                if (ff->flags & FO_EXCLUDE) {
292                   return false;       /* reject file */
293                }
294                return true;           /* accept file */
295             }
296          }
297       } else {
298          for (k=0; k<fo->regexfile.size(); k++) {
299             const int nmatch = 30;
300             regmatch_t pmatch[nmatch];
301             if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
302                if (ff->flags & FO_EXCLUDE) {
303                   return false;       /* reject file */
304                }
305                return true;           /* accept file */
306             }
307          }
308       }
309       for (k=0; k<fo->regex.size(); k++) {
310          const int nmatch = 30;
311          regmatch_t pmatch[nmatch];
312          if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
313             if (ff->flags & FO_EXCLUDE) {
314                return false;          /* reject file */
315             }
316             return true;              /* accept file */
317          }
318       }
319       /*
320        * If we have an empty Options clause with exclude, then
321        *  exclude the file
322        */
323       if (ff->flags & FO_EXCLUDE &&
324           fo->regex.size() == 0     && fo->wild.size() == 0 &&
325           fo->regexdir.size() == 0  && fo->wilddir.size() == 0 &&
326           fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
327           fo->wildbase.size() == 0) {
328          return false;              /* reject file */
329       }
330    }
331
332    /* Now apply the Exclude { } directive */
333    for (i=0; i<fileset->exclude_list.size(); i++) {
334       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
335       for (j=0; j<incexe->opts_list.size(); j++) {
336          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
337          fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
338          for (k=0; k<fo->wild.size(); k++) {
339             if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
340                Dmsg1(100, "Reject wild1: %s\n", ff->fname);
341                return false;          /* reject file */
342             }
343          }
344       }
345       fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
346              ? FNM_CASEFOLD : 0;
347       dlistString *node;
348       foreach_dlist(node, &incexe->name_list) {
349          char *fname = node->c_str();
350          if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
351             Dmsg1(100, "Reject wild2: %s\n", ff->fname);
352             return false;          /* reject file */
353          }
354       }
355    }
356    return true;
357 }
358
359 /*
360  * The code comes here for each file examined.
361  * We filter the files, then call the user's callback if
362  *    the file is included.
363  */
364 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
365 {
366    if (top_level) {
367       return ff->file_save(jcr, ff, top_level);   /* accept file */
368    }
369    switch (ff->type) {
370    case FT_NOACCESS:
371    case FT_NOFOLLOW:
372    case FT_NOSTAT:
373    case FT_NOCHG:
374    case FT_ISARCH:
375    case FT_NORECURSE:
376    case FT_NOFSCHG:
377    case FT_INVALIDFS:
378    case FT_INVALIDDT:
379    case FT_NOOPEN:
380    case FT_REPARSE:
381 //    return ff->file_save(jcr, ff, top_level);
382
383    /* These items can be filtered */
384    case FT_LNKSAVED:
385    case FT_REGE:
386    case FT_REG:
387    case FT_LNK:
388    case FT_DIRBEGIN:
389    case FT_DIREND:
390    case FT_RAW:
391    case FT_FIFO:
392    case FT_SPEC:
393    case FT_DIRNOCHG:
394       if (accept_file(ff)) {
395          return ff->file_save(jcr, ff, top_level);
396       } else {
397          Dmsg1(100, "Skip file %s\n", ff->fname);
398          return -1;                   /* ignore this file */
399       }
400
401    default:
402       Dmsg1(000, "Unknown FT code %d\n", ff->type);
403       return 0;
404    }
405 }
406
407
408 /*
409  * Terminate find_files() and release
410  * all allocated memory
411  */
412 int
413 term_find_files(FF_PKT *ff)
414 {
415    int hard_links;
416
417    free_pool_memory(ff->sys_fname);
418    if (ff->fname_save) {
419       free_pool_memory(ff->fname_save);
420    }
421    if (ff->link_save) {
422       free_pool_memory(ff->link_save);
423    }
424    hard_links = term_find_one(ff);
425    free(ff);
426    return hard_links;
427 }