]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
ebl Commit accurate patch project.
[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 void
100 set_find_changed_function(FF_PKT *ff, bool check_fct(JCR *jcr, FF_PKT *ff))
101 {
102    Dmsg0(1, "Enter set_find_changed_function()\n");
103    ff->check_fct = check_fct;
104 }
105
106 /*
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
110  *
111  * the function returns the number of used drives and
112  * fills "drives" with up to 26 (A..Z) drive names
113  *
114  */
115 int
116 get_win32_driveletters(FF_PKT *ff, char* szDrives)
117 {
118    /* szDrives must be at least 27 bytes long */
119
120 #if !defined(HAVE_WIN32)
121    return 0;
122 #endif
123
124    szDrives[0] = 0; /* make empty */
125    int nCount = 0;
126     
127    findFILESET *fileset = ff->fileset;
128    if (fileset) {
129       int i;
130       dlistString *node;
131       
132       for (i=0; i<fileset->include_list.size(); i++) {
133          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
134          
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] == ':') {
141                
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;
148                   nCount++;
149                }                                
150             }            
151          }
152       }
153    }
154    return nCount;
155 }
156
157 /*
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
161  * argument.
162  *
163  */
164 int
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)) 
167 {
168    ff->file_save = file_save;
169    ff->plugin_save = plugin_save;
170
171    /* This is the new way */
172    findFILESET *fileset = ff->fileset;
173    if (fileset) {
174       int i, j;
175       ff->flags = 0;
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;
181          /*
182           * By setting all options, we in effect or the global options
183           *   which is what we want.
184           */
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));
193          }
194          dlistString *node;
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 */
201             }
202          }
203          if (plugin_save) {
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;
211             }
212          }
213       }
214    }
215    return 1;
216 }
217
218 static bool accept_file(FF_PKT *ff)
219 {
220    int i, j, k;
221    int fnm_flags;
222    findFILESET *fileset = ff->fileset;
223    findINCEXE *incexe = fileset->incexe;
224    const char *basename;
225    int (*match_func)(const char *pattern, const char *string, int flags);
226
227    if (ff->flags & FO_ENHANCEDWILD) {
228 //    match_func = enh_fnmatch;
229       match_func = fnmatch;
230       if ((basename = last_path_separator(ff->fname)) != NULL)
231          basename++;
232       else
233          basename = ff->fname;
234    } else {
235       match_func = fnmatch;
236       basename = ff->fname;
237    }
238
239    for (j = 0; j < incexe->opts_list.size(); j++) {
240       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
241       ff->flags = fo->flags;
242       ff->GZIP_level = fo->GZIP_level;
243       ff->fstypes = fo->fstype;
244       ff->drivetypes = fo->drivetype;
245
246       fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
247       fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
248
249       if (S_ISDIR(ff->statp.st_mode)) {
250          for (k=0; k<fo->wilddir.size(); k++) {
251             if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
252                if (ff->flags & FO_EXCLUDE) {
253                   Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
254                      ff->fname);
255                   return false;       /* reject dir */
256                }
257                return true;           /* accept dir */
258             }
259          }
260       } else {
261          for (k=0; k<fo->wildfile.size(); k++) {
262             if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
263                if (ff->flags & FO_EXCLUDE) {
264                   Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
265                      ff->fname);
266                   return false;       /* reject file */
267                }
268                return true;           /* accept file */
269             }
270          }
271
272          for (k=0; k<fo->wildbase.size(); k++) {
273             if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
274                if (ff->flags & FO_EXCLUDE) {
275                   Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
276                      basename);
277                   return false;       /* reject file */
278                }
279                return true;           /* accept file */
280             }
281          }
282       }
283       for (k=0; k<fo->wild.size(); k++) {
284          if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
285             if (ff->flags & FO_EXCLUDE) {
286                Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
287                   ff->fname);
288                return false;          /* reject file */
289             }
290             return true;              /* accept file */
291          }
292       }
293       if (S_ISDIR(ff->statp.st_mode)) {
294          for (k=0; k<fo->regexdir.size(); k++) {
295             const int nmatch = 30;
296             regmatch_t pmatch[nmatch];
297             if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
298                if (ff->flags & FO_EXCLUDE) {
299                   return false;       /* reject file */
300                }
301                return true;           /* accept file */
302             }
303          }
304       } else {
305          for (k=0; k<fo->regexfile.size(); k++) {
306             const int nmatch = 30;
307             regmatch_t pmatch[nmatch];
308             if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
309                if (ff->flags & FO_EXCLUDE) {
310                   return false;       /* reject file */
311                }
312                return true;           /* accept file */
313             }
314          }
315       }
316       for (k=0; k<fo->regex.size(); k++) {
317          const int nmatch = 30;
318          regmatch_t pmatch[nmatch];
319          if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
320             if (ff->flags & FO_EXCLUDE) {
321                return false;          /* reject file */
322             }
323             return true;              /* accept file */
324          }
325       }
326       /*
327        * If we have an empty Options clause with exclude, then
328        *  exclude the file
329        */
330       if (ff->flags & FO_EXCLUDE &&
331           fo->regex.size() == 0     && fo->wild.size() == 0 &&
332           fo->regexdir.size() == 0  && fo->wilddir.size() == 0 &&
333           fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
334           fo->wildbase.size() == 0) {
335          return false;              /* reject file */
336       }
337    }
338
339    /* Now apply the Exclude { } directive */
340    for (i=0; i<fileset->exclude_list.size(); i++) {
341       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
342       for (j=0; j<incexe->opts_list.size(); j++) {
343          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
344          fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
345          for (k=0; k<fo->wild.size(); k++) {
346             if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
347                Dmsg1(100, "Reject wild1: %s\n", ff->fname);
348                return false;          /* reject file */
349             }
350          }
351       }
352       fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
353              ? FNM_CASEFOLD : 0;
354       dlistString *node;
355       foreach_dlist(node, &incexe->name_list) {
356          char *fname = node->c_str();
357          if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
358             Dmsg1(100, "Reject wild2: %s\n", ff->fname);
359             return false;          /* reject file */
360          }
361       }
362    }
363    return true;
364 }
365
366 /*
367  * The code comes here for each file examined.
368  * We filter the files, then call the user's callback if
369  *    the file is included.
370  */
371 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
372 {
373    if (top_level) {
374       return ff->file_save(jcr, ff, top_level);   /* accept file */
375    }
376    switch (ff->type) {
377    case FT_NOACCESS:
378    case FT_NOFOLLOW:
379    case FT_NOSTAT:
380    case FT_NOCHG:
381    case FT_ISARCH:
382    case FT_NORECURSE:
383    case FT_NOFSCHG:
384    case FT_INVALIDFS:
385    case FT_INVALIDDT:
386    case FT_NOOPEN:
387    case FT_REPARSE:
388 //    return ff->file_save(jcr, ff, top_level);
389
390    /* These items can be filtered */
391    case FT_LNKSAVED:
392    case FT_REGE:
393    case FT_REG:
394    case FT_LNK:
395    case FT_DIRBEGIN:
396    case FT_DIREND:
397    case FT_RAW:
398    case FT_FIFO:
399    case FT_SPEC:
400    case FT_DIRNOCHG:
401       if (accept_file(ff)) {
402          return ff->file_save(jcr, ff, top_level);
403       } else {
404          Dmsg1(100, "Skip file %s\n", ff->fname);
405          return -1;                   /* ignore this file */
406       }
407
408    default:
409       Dmsg1(000, "Unknown FT code %d\n", ff->type);
410       return 0;
411    }
412 }
413
414
415 /*
416  * Terminate find_files() and release
417  * all allocated memory
418  */
419 int
420 term_find_files(FF_PKT *ff)
421 {
422    int hard_links;
423
424    free_pool_memory(ff->sys_fname);
425    if (ff->fname_save) {
426       free_pool_memory(ff->fname_save);
427    }
428    if (ff->link_save) {
429       free_pool_memory(ff->link_save);
430    }
431    hard_links = term_find_one(ff);
432    free(ff);
433    return hard_links;
434 }