]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
remove old functions
[bacula/bacula] / bacula / src / findlib / find.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2010 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 three of the GNU Affero 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 Affero 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  */
38
39
40 #include "bacula.h"
41 #include "find.h"
42
43 static const int dbglvl = 450;
44
45 int32_t name_max;              /* filename max length */
46 int32_t path_max;              /* path name max length */
47
48 #ifdef DEBUG
49 #undef bmalloc
50 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
51 #endif
52 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level);
53 static bool accept_file(FF_PKT *ff);
54
55 static const int fnmode = 0;
56
57 /*
58  * Initialize the find files "global" variables
59  */
60 FF_PKT *init_find_files()
61 {
62   FF_PKT *ff;
63
64   ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
65   memset(ff, 0, sizeof(FF_PKT));
66
67   ff->sys_fname = get_pool_memory(PM_FNAME);
68
69    /* Get system path and filename maximum lengths */
70    path_max = pathconf(".", _PC_PATH_MAX);
71    if (path_max < 2048) {
72       path_max = 2048;
73    }
74
75    name_max = pathconf(".", _PC_NAME_MAX);
76    if (name_max < 2048) {
77       name_max = 2048;
78    }
79    path_max++;                        /* add for EOS */
80    name_max++;                        /* add for EOS */
81
82   Dmsg1(dbglvl, "init_find_files ff=%p\n", ff);
83   return ff;
84 }
85
86 /*
87  * Set find_files options. For the moment, we only
88  * provide for full/incremental saves, and setting
89  * of save_time. For additional options, see above
90  */
91 void
92 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
93 {
94   Dmsg0(dbglvl, "Enter set_find_options()\n");
95   ff->incremental = incremental;
96   ff->save_time = save_time;
97   Dmsg0(dbglvl, "Leave set_find_options()\n");
98 }
99
100 void
101 set_find_changed_function(FF_PKT *ff, bool check_fct(JCR *jcr, FF_PKT *ff))
102 {
103    Dmsg0(dbglvl, "Enter set_find_changed_function()\n");
104    ff->check_fct = check_fct;
105 }
106
107 /*
108  * For VSS we need to know which windows drives
109  * are used, because we create a snapshot of all used
110  * drives before operation
111  *
112  * the function returns the number of used drives and
113  * fills "drives" with up to 26 (A..Z) drive names
114  *
115  */
116 int
117 get_win32_driveletters(FF_PKT *ff, char* szDrives)
118 {
119    /* szDrives must be at least 27 bytes long */
120
121 #if !defined(HAVE_WIN32)
122    return 0;
123 #endif
124    int nCount;
125    /* Can be already filled by plugin, so check that everything
126     * is on upper case. TODO: can check for dupplicate?
127     */
128    for (nCount = 0; nCount < 27 && szDrives[nCount] ; nCount++) {
129       szDrives[nCount] = toupper(szDrives[nCount]);
130    }
131
132    findFILESET *fileset = ff->fileset;
133    if (fileset) {
134       int i;
135       dlistString *node;
136       
137       for (i=0; i<fileset->include_list.size(); i++) {
138          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
139          
140          /* look through all files and check */
141          foreach_dlist(node, &incexe->name_list) {
142             char *fname = node->c_str();
143             /* fname should match x:/ */
144             if (strlen(fname) >= 2 && B_ISALPHA(fname[0]) 
145                && fname[1] == ':') {
146                
147                /* always add in uppercase */
148                char ch = toupper(fname[0]);
149                /* if not found in string, add drive letter */
150                if (!strchr(szDrives,ch)) {
151                   szDrives[nCount] = ch;
152                   szDrives[nCount+1] = 0;
153                   nCount++;
154                }                                
155             }            
156          }
157       }
158    }
159    return nCount;
160 }
161
162 /*
163  * Call this subroutine with a callback subroutine as the first
164  * argument and a packet as the second argument, this packet
165  * will be passed back to the callback subroutine as the last
166  * argument.
167  *
168  */
169 int
170 find_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level),
171            int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)) 
172 {
173    ff->file_save = file_save;
174    ff->plugin_save = plugin_save;
175
176    /* This is the new way */
177    findFILESET *fileset = ff->fileset;
178    if (fileset) {
179       int i, j;
180       ff->flags = 0;
181       ff->VerifyOpts[0] = 'V';
182       ff->VerifyOpts[1] = 0;
183       strcpy(ff->AccurateOpts, "Cmcs");  /* mtime+ctime+size by default */
184       strcpy(ff->BaseJobOpts, "Jspug5"); /* size+perm+user+group+chk  */
185       for (i=0; i<fileset->include_list.size(); i++) {
186          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
187          fileset->incexe = incexe;
188          /*
189           * By setting all options, we in effect OR the global options
190           *   which is what we want.
191           */
192          for (j=0; j<incexe->opts_list.size(); j++) {
193             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
194             ff->flags |= fo->flags;
195             ff->Compress_algo = fo->Compress_algo;
196             ff->Compress_level = fo->Compress_level;
197             ff->strip_path = fo->strip_path;
198             ff->fstypes = fo->fstype;
199             ff->drivetypes = fo->drivetype;
200             bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
201             if (fo->AccurateOpts[0]) {
202                bstrncpy(ff->AccurateOpts, fo->AccurateOpts, sizeof(ff->AccurateOpts));
203             }
204             if (fo->BaseJobOpts[0]) {
205                bstrncpy(ff->BaseJobOpts, fo->BaseJobOpts, sizeof(ff->BaseJobOpts));
206             }
207          }
208          Dmsg3(50, "Verify=<%s> Accurate=<%s> BaseJob=<%s>\n", ff->VerifyOpts, ff->AccurateOpts, ff->BaseJobOpts);
209          dlistString *node;
210          foreach_dlist(node, &incexe->name_list) {
211             char *fname = node->c_str();
212             Dmsg1(dbglvl, "F %s\n", fname);
213             ff->top_fname = fname;
214             if (find_one_file(jcr, ff, our_callback, ff->top_fname, (dev_t)-1, true) == 0) {
215                return 0;                  /* error return */
216             }
217             if (job_canceled(jcr)) {
218                return 0;
219             }
220          }
221          foreach_dlist(node, &incexe->plugin_list) {
222             char *fname = node->c_str();
223             if (!plugin_save) {
224                Jmsg(jcr, M_FATAL, 0, _("Plugin: \"%s\" not found.\n"), fname);
225                return 0;
226             }
227             Dmsg1(dbglvl, "PluginCommand: %s\n", fname);
228             ff->top_fname = fname;
229             ff->cmd_plugin = true;
230             plugin_save(jcr, ff, true);
231             ff->cmd_plugin = false;
232             if (job_canceled(jcr)) {
233                return 0;
234             }
235          }
236       }
237    }
238    return 1;
239 }
240
241 /*
242  * Test if the currently selected directory (in ff->fname) is
243  *  explicitly in the Include list or explicitly in the Exclude 
244  *  list.
245  */
246 bool is_in_fileset(FF_PKT *ff)
247 {
248    dlistString *node;
249    char *fname;
250    int i;
251    findINCEXE *incexe;
252    findFILESET *fileset = ff->fileset;
253    if (fileset) {
254       for (i=0; i<fileset->include_list.size(); i++) {
255          incexe = (findINCEXE *)fileset->include_list.get(i);
256          foreach_dlist(node, &incexe->name_list) {
257             fname = node->c_str();
258             Dmsg2(dbglvl, "Inc fname=%s ff->fname=%s\n", fname, ff->fname);
259             if (strcmp(fname, ff->fname) == 0) {
260                return true;
261             }
262          }
263       }
264       for (i=0; i<fileset->exclude_list.size(); i++) {
265          incexe = (findINCEXE *)fileset->exclude_list.get(i);
266          foreach_dlist(node, &incexe->name_list) {
267             fname = node->c_str();
268             Dmsg2(dbglvl, "Exc fname=%s ff->fname=%s\n", fname, ff->fname);
269             if (strcmp(fname, ff->fname) == 0) {
270                return true;
271             }
272          }
273       }
274    }
275    return false;
276 }
277
278
279 static bool accept_file(FF_PKT *ff)
280 {
281    int i, j, k;
282    int fnm_flags;
283    findFILESET *fileset = ff->fileset;
284    findINCEXE *incexe = fileset->incexe;
285    const char *basename;
286    int (*match_func)(const char *pattern, const char *string, int flags);
287
288    Dmsg1(dbglvl, "enter accept_file: fname=%s\n", ff->fname);
289    if (ff->flags & FO_ENHANCEDWILD) {
290 //    match_func = enh_fnmatch;
291       match_func = fnmatch;
292       if ((basename = last_path_separator(ff->fname)) != NULL)
293          basename++;
294       else
295          basename = ff->fname;
296    } else {
297       match_func = fnmatch;
298       basename = ff->fname;
299    }
300
301    for (j = 0; j < incexe->opts_list.size(); j++) {
302       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
303       ff->flags = fo->flags;
304       ff->Compress_algo = fo->Compress_algo;
305       ff->Compress_level = fo->Compress_level;
306       ff->fstypes = fo->fstype;
307       ff->drivetypes = fo->drivetype;
308
309       fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
310       fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0;
311
312       if (S_ISDIR(ff->statp.st_mode)) {
313          for (k=0; k<fo->wilddir.size(); k++) {
314             if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) {
315                if (ff->flags & FO_EXCLUDE) {
316                   Dmsg2(dbglvl, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
317                      ff->fname);
318                   return false;       /* reject dir */
319                }
320                return true;           /* accept dir */
321             }
322          }
323       } else {
324          for (k=0; k<fo->wildfile.size(); k++) {
325             if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) {
326                if (ff->flags & FO_EXCLUDE) {
327                   Dmsg2(dbglvl, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
328                      ff->fname);
329                   return false;       /* reject file */
330                }
331                return true;           /* accept file */
332             }
333          }
334
335          for (k=0; k<fo->wildbase.size(); k++) {
336             if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) {
337                if (ff->flags & FO_EXCLUDE) {
338                   Dmsg2(dbglvl, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k),
339                      basename);
340                   return false;       /* reject file */
341                }
342                return true;           /* accept file */
343             }
344          }
345       }
346       for (k=0; k<fo->wild.size(); k++) {
347          if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
348             if (ff->flags & FO_EXCLUDE) {
349                Dmsg2(dbglvl, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
350                   ff->fname);
351                return false;          /* reject file */
352             }
353             return true;              /* accept file */
354          }
355       }
356       if (S_ISDIR(ff->statp.st_mode)) {
357          for (k=0; k<fo->regexdir.size(); k++) {
358             const int nmatch = 30;
359             regmatch_t pmatch[nmatch];
360             if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
361                if (ff->flags & FO_EXCLUDE) {
362                   return false;       /* reject file */
363                }
364                return true;           /* accept file */
365             }
366          }
367       } else {
368          for (k=0; k<fo->regexfile.size(); k++) {
369             const int nmatch = 30;
370             regmatch_t pmatch[nmatch];
371             if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
372                if (ff->flags & FO_EXCLUDE) {
373                   return false;       /* reject file */
374                }
375                return true;           /* accept file */
376             }
377          }
378       }
379       for (k=0; k<fo->regex.size(); k++) {
380          const int nmatch = 30;
381          regmatch_t pmatch[nmatch];
382          if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
383             if (ff->flags & FO_EXCLUDE) {
384                return false;          /* reject file */
385             }
386             return true;              /* accept file */
387          }
388       }
389       /*
390        * If we have an empty Options clause with exclude, then
391        *  exclude the file
392        */
393       if (ff->flags & FO_EXCLUDE &&
394           fo->regex.size() == 0     && fo->wild.size() == 0 &&
395           fo->regexdir.size() == 0  && fo->wilddir.size() == 0 &&
396           fo->regexfile.size() == 0 && fo->wildfile.size() == 0 &&
397           fo->wildbase.size() == 0) {
398          return false;              /* reject file */
399       }
400    }
401
402    /* Now apply the Exclude { } directive */
403    for (i=0; i<fileset->exclude_list.size(); i++) {
404       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
405       for (j=0; j<incexe->opts_list.size(); j++) {
406          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
407          fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
408          for (k=0; k<fo->wild.size(); k++) {
409             if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) {
410                Dmsg1(dbglvl, "Reject wild1: %s\n", ff->fname);
411                return false;          /* reject file */
412             }
413          }
414       }
415       fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
416              ? FNM_CASEFOLD : 0;
417       dlistString *node;
418       foreach_dlist(node, &incexe->name_list) {
419          char *fname = node->c_str();
420          if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) {
421             Dmsg1(dbglvl, "Reject wild2: %s\n", ff->fname);
422             return false;          /* reject file */
423          }
424       }
425    }
426    return true;
427 }
428
429 /*
430  * The code comes here for each file examined.
431  * We filter the files, then call the user's callback if
432  *    the file is included.
433  */
434 static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level)
435 {
436    if (top_level) {
437       return ff->file_save(jcr, ff, top_level);   /* accept file */
438    }
439    switch (ff->type) {
440    case FT_NOACCESS:
441    case FT_NOFOLLOW:
442    case FT_NOSTAT:
443    case FT_NOCHG:
444    case FT_ISARCH:
445    case FT_NORECURSE:
446    case FT_NOFSCHG:
447    case FT_INVALIDFS:
448    case FT_INVALIDDT:
449    case FT_NOOPEN:
450 //    return ff->file_save(jcr, ff, top_level);
451
452    /* These items can be filtered */
453    case FT_LNKSAVED:
454    case FT_REGE:
455    case FT_REG:
456    case FT_LNK:
457    case FT_DIRBEGIN:
458    case FT_DIREND:
459    case FT_RAW:
460    case FT_FIFO:
461    case FT_SPEC:
462    case FT_DIRNOCHG:
463    case FT_REPARSE:
464    case FT_JUNCTION:
465       if (accept_file(ff)) {
466          return ff->file_save(jcr, ff, top_level);
467       } else {
468          Dmsg1(dbglvl, "Skip file %s\n", ff->fname);
469          return -1;                   /* ignore this file */
470       }
471
472    default:
473       Dmsg1(000, "Unknown FT code %d\n", ff->type);
474       return 0;
475    }
476 }
477
478
479 /*
480  * Terminate find_files() and release
481  * all allocated memory
482  */
483 int
484 term_find_files(FF_PKT *ff)
485 {
486    int hard_links;
487
488    free_pool_memory(ff->sys_fname);
489    if (ff->fname_save) {
490       free_pool_memory(ff->fname_save);
491    }
492    if (ff->link_save) {
493       free_pool_memory(ff->link_save);
494    }
495    hard_links = term_find_one(ff);
496    free(ff);
497    return hard_links;
498 }