]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
c7d789340ac6db44680d4bd260004e096356c6a9
[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(FF_PKT *ff, void *hpkt, 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  * The callback subroutine gets called with:
157  *  arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
158  *  arg2 -- the user supplied packet
159  *
160  */
161 int
162 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level), 
163            void *his_pkt)
164 {
165    ff->callback = callback;
166
167    /* This is the new way */
168    findFILESET *fileset = ff->fileset;
169    if (fileset) {
170       int i, j;
171       ff->flags = 0;
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;
177          /*
178           * By setting all options, we in effect or the global options
179           *   which is what we want.
180           */
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));
189          }
190          dlistString *node;
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 */
197             }
198          }
199          foreach_dlist(node, &incexe->plugin_list) {
200             char *fname = node->c_str();
201             Dmsg1(000, "PluginCommand: %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;
206          }
207       }
208    }
209    return 1;
210 }
211
212 static bool accept_file(FF_PKT *ff)
213 {
214    int i, j, k;
215    int fnm_flags;
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);
220
221    if (ff->flags & FO_ENHANCEDWILD) {
222 //    match_func = enh_fnmatch;
223       match_func = fnmatch;
224       if ((basename = last_path_separator(ff->fname)) != NULL)
225          basename++;
226       else
227          basename = ff->fname;
228    } else {
229       match_func = fnmatch;
230       basename = ff->fname;
231    }
232
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;
239
240       fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
241       fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
242
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),
248                      ff->fname);
249                   return false;       /* reject dir */
250                }
251                return true;           /* accept dir */
252             }
253          }
254       } else {
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),
259                      ff->fname);
260                   return false;       /* reject file */
261                }
262                return true;           /* accept file */
263             }
264          }
265
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),
270                      basename);
271                   return false;       /* reject file */
272                }
273                return true;           /* accept file */
274             }
275          }
276       }
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),
281                   ff->fname);
282                return false;          /* reject file */
283             }
284             return true;              /* accept file */
285          }
286       }
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 */
294                }
295                return true;           /* accept file */
296             }
297          }
298       } else {
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 */
305                }
306                return true;           /* accept file */
307             }
308          }
309       }
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 */
316             }
317             return true;              /* accept file */
318          }
319       }
320       /*
321        * If we have an empty Options clause with exclude, then
322        *  exclude the file
323        */
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 */
330       }
331    }
332
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 */
343             }
344          }
345       }
346       fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
347              ? FNM_CASEFOLD : 0;
348       dlistString *node;
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 */
354          }
355       }
356    }
357    return true;
358 }
359
360 /*
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.
364  */
365 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
366 {
367    if (top_level) {
368       return ff->callback(ff, hpkt, top_level);   /* accept file */
369    }
370    switch (ff->type) {
371    case FT_NOACCESS:
372    case FT_NOFOLLOW:
373    case FT_NOSTAT:
374    case FT_NOCHG:
375    case FT_ISARCH:
376    case FT_NORECURSE:
377    case FT_NOFSCHG:
378    case FT_INVALIDFS:
379    case FT_INVALIDDT:
380    case FT_NOOPEN:
381    case FT_REPARSE:
382 //    return ff->callback(ff, hpkt, top_level);
383
384    /* These items can be filtered */
385    case FT_LNKSAVED:
386    case FT_REGE:
387    case FT_REG:
388    case FT_LNK:
389    case FT_DIRBEGIN:
390    case FT_DIREND:
391    case FT_RAW:
392    case FT_FIFO:
393    case FT_SPEC:
394    case FT_DIRNOCHG:
395       if (accept_file(ff)) {
396          return ff->callback(ff, hpkt, top_level);
397       } else {
398          Dmsg1(100, "Skip file %s\n", ff->fname);
399          return -1;                   /* ignore this file */
400       }
401
402    default:
403       Dmsg1(000, "Unknown FT code %d\n", ff->type);
404       return 0;
405    }
406 }
407
408
409 /*
410  * Terminate find_files() and release
411  * all allocated memory
412  */
413 int
414 term_find_files(FF_PKT *ff)
415 {
416    int hard_links;
417
418    free_pool_memory(ff->sys_fname);
419    if (ff->fname_save) {
420       free_pool_memory(ff->fname_save);
421    }
422    if (ff->link_save) {
423       free_pool_memory(ff->link_save);
424    }
425    hard_links = term_find_one(ff);
426    free(ff);
427    return hard_links;
428 }