]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
Fix bug #1368. Increase default path/file length to 2048
[bacula/bacula] / bacula / src / findlib / find.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 Kern Sibbald.
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 < 2048) {
71       path_max = 2048;
72    }
73
74    name_max = pathconf(".", _PC_NAME_MAX);
75    if (name_max < 2048) {
76       name_max = 2048;
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(100, "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 /*
219  * Test if the currently selected directory (in ff->fname) is
220  *  explicitly in the Include list or explicitly in the Exclude 
221  *  list.
222  */
223 bool is_in_fileset(FF_PKT *ff)
224 {
225    dlistString *node;
226    char *fname;
227    int i;
228    findINCEXE *incexe;
229    findFILESET *fileset = ff->fileset;
230    if (fileset) {
231       for (i=0; i<fileset->include_list.size(); i++) {
232          incexe = (findINCEXE *)fileset->include_list.get(i);
233          foreach_dlist(node, &incexe->name_list) {
234             fname = node->c_str();
235             Dmsg2(100, "Inc fname=%s ff->fname=%s\n", fname, ff->fname);
236             if (strcmp(fname, ff->fname) == 0) {
237                return true;
238             }
239          }
240       }
241       for (i=0; i<fileset->exclude_list.size(); i++) {
242          incexe = (findINCEXE *)fileset->exclude_list.get(i);
243          foreach_dlist(node, &incexe->name_list) {
244             fname = node->c_str();
245             Dmsg2(100, "Exc fname=%s ff->fname=%s\n", fname, ff->fname);
246             if (strcmp(fname, ff->fname) == 0) {
247                return true;
248             }
249          }
250       }
251    }
252    return false;
253 }
254
255
256 static bool accept_file(FF_PKT *ff)
257 {
258    int i, j, k;
259    int fnm_flags;
260    findFILESET *fileset = ff->fileset;
261    findINCEXE *incexe = fileset->incexe;
262    const char *basename;
263    int (*match_func)(const char *pattern, const char *string, int flags);
264
265    if (ff->flags & FO_ENHANCEDWILD) {
266 //    match_func = enh_fnmatch;
267       match_func = fnmatch;
268       if ((basename = last_path_separator(ff->fname)) != NULL)
269          basename++;
270       else
271          basename = ff->fname;
272    } else {
273       match_func = fnmatch;
274       basename = ff->fname;
275    }
276
277    for (j = 0; j < incexe->opts_list.size(); j++) {
278       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
279       ff->flags = fo->flags;
280       ff->GZIP_level = fo->GZIP_level;
281       ff->ignoredir = fo->ignoredir;
282       ff->fstypes = fo->fstype;
283       ff->drivetypes = fo->drivetype;
284
285       fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
286       fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
287
288       if (S_ISDIR(ff->statp.st_mode)) {
289          for (k=0; k<fo->wilddir.size(); k++) {
290             if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
291                if (ff->flags & FO_EXCLUDE) {
292                   Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
293                      ff->fname);
294                   return false;       /* reject dir */
295                }
296                return true;           /* accept dir */
297             }
298          }
299       } else {
300          for (k=0; k<fo->wildfile.size(); k++) {
301             if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
302                if (ff->flags & FO_EXCLUDE) {
303                   Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
304                      ff->fname);
305                   return false;       /* reject file */
306                }
307                return true;           /* accept file */
308             }
309          }
310
311          for (k=0; k<fo->wildbase.size(); k++) {
312             if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
313                if (ff->flags & FO_EXCLUDE) {
314                   Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
315                      basename);
316                   return false;       /* reject file */
317                }
318                return true;           /* accept file */
319             }
320          }
321       }
322       for (k=0; k<fo->wild.size(); k++) {
323          if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
324             if (ff->flags & FO_EXCLUDE) {
325                Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
326                   ff->fname);
327                return false;          /* reject file */
328             }
329             return true;              /* accept file */
330          }
331       }
332       if (S_ISDIR(ff->statp.st_mode)) {
333          for (k=0; k<fo->regexdir.size(); k++) {
334             const int nmatch = 30;
335             regmatch_t pmatch[nmatch];
336             if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
337                if (ff->flags & FO_EXCLUDE) {
338                   return false;       /* reject file */
339                }
340                return true;           /* accept file */
341             }
342          }
343       } else {
344          for (k=0; k<fo->regexfile.size(); k++) {
345             const int nmatch = 30;
346             regmatch_t pmatch[nmatch];
347             if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
348                if (ff->flags & FO_EXCLUDE) {
349                   return false;       /* reject file */
350                }
351                return true;           /* accept file */
352             }
353          }
354       }
355       for (k=0; k<fo->regex.size(); k++) {
356          const int nmatch = 30;
357          regmatch_t pmatch[nmatch];
358          if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
359             if (ff->flags & FO_EXCLUDE) {
360                return false;          /* reject file */
361             }
362             return true;              /* accept file */
363          }
364       }
365       /*
366        * If we have an empty Options clause with exclude, then
367        *  exclude the file
368        */
369       if (ff->flags & FO_EXCLUDE &&
370           fo->regex.size() == 0     && fo->wild.size() == 0 &&
371           fo->regexdir.size() == 0  && fo->wilddir.size() == 0 &&
372           fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
373           fo->wildbase.size() == 0) {
374          return false;              /* reject file */
375       }
376    }
377
378    /* Now apply the Exclude { } directive */
379    for (i=0; i<fileset->exclude_list.size(); i++) {
380       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
381       for (j=0; j<incexe->opts_list.size(); j++) {
382          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
383          fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
384          for (k=0; k<fo->wild.size(); k++) {
385             if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
386                Dmsg1(100, "Reject wild1: %s\n", ff->fname);
387                return false;          /* reject file */
388             }
389          }
390       }
391       fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
392              ? FNM_CASEFOLD : 0;
393       dlistString *node;
394       foreach_dlist(node, &incexe->name_list) {
395          char *fname = node->c_str();
396          if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
397             Dmsg1(100, "Reject wild2: %s\n", ff->fname);
398             return false;          /* reject file */
399          }
400       }
401    }
402    return true;
403 }
404
405 /*
406  * The code comes here for each file examined.
407  * We filter the files, then call the user's callback if
408  *    the file is included.
409  */
410 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
411 {
412    if (top_level) {
413       return ff->file_save(jcr, ff, top_level);   /* accept file */
414    }
415    switch (ff->type) {
416    case FT_NOACCESS:
417    case FT_NOFOLLOW:
418    case FT_NOSTAT:
419    case FT_NOCHG:
420    case FT_ISARCH:
421    case FT_NORECURSE:
422    case FT_NOFSCHG:
423    case FT_INVALIDFS:
424    case FT_INVALIDDT:
425    case FT_NOOPEN:
426    case FT_REPARSE:
427 //    return ff->file_save(jcr, ff, top_level);
428
429    /* These items can be filtered */
430    case FT_LNKSAVED:
431    case FT_REGE:
432    case FT_REG:
433    case FT_LNK:
434    case FT_DIRBEGIN:
435    case FT_DIREND:
436    case FT_RAW:
437    case FT_FIFO:
438    case FT_SPEC:
439    case FT_DIRNOCHG:
440       if (accept_file(ff)) {
441          return ff->file_save(jcr, ff, top_level);
442       } else {
443          Dmsg1(100, "Skip file %s\n", ff->fname);
444          return -1;                   /* ignore this file */
445       }
446
447    default:
448       Dmsg1(000, "Unknown FT code %d\n", ff->type);
449       return 0;
450    }
451 }
452
453
454 /*
455  * Terminate find_files() and release
456  * all allocated memory
457  */
458 int
459 term_find_files(FF_PKT *ff)
460 {
461    int hard_links;
462
463    free_pool_memory(ff->sys_fname);
464    if (ff->fname_save) {
465       free_pool_memory(ff->fname_save);
466    }
467    if (ff->link_save) {
468       free_pool_memory(ff->link_save);
469    }
470    hard_links = term_find_one(ff);
471    free(ff);
472    return hard_links;
473 }