]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
ce6d210a73b804daaabba9aa095b7deddb13b8db
[bacula/bacula] / bacula / src / findlib / find.c
1 /*
2  * Main routine for finding files on a file system.
3  *  The heart of the work to find the files on the
4  *    system is done in find_one.c. Here we have the
5  *    higher level control as well as the matching
6  *    routines for the new syntax Options resource.
7  *
8  *  Kern E. Sibbald, MM
9  *
10  *   Version $Id$
11  */
12 /*
13    Copyright (C) 2000-2005 Kern Sibbald
14
15    This program is free software; you can redistribute it and/or
16    modify it under the terms of the GNU General Public License
17    version 2 as ammended with additional clauses defined in the
18    file LICENSE in the main source directory.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
23    the file LICENSE for additional details.
24
25  */
26
27
28 #include "bacula.h"
29 #include "find.h"
30
31 int32_t name_max;              /* filename max length */
32 int32_t path_max;              /* path name max length */
33
34 #ifdef DEBUG
35 #undef bmalloc
36 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
37 #endif
38 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level);
39 static bool accept_file(FF_PKT *ff);
40
41 /* Fold case in fnmatch() on Win32 */
42 #ifdef WIN32
43 static const int fnmode = FNM_CASEFOLD;
44 #else
45 static const int fnmode = 0;
46 #endif
47
48
49 /*
50  * Initialize the find files "global" variables
51  */
52 FF_PKT *init_find_files()
53 {
54   FF_PKT *ff;
55
56   ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
57   memset(ff, 0, sizeof(FF_PKT));
58
59   ff->sys_fname = get_pool_memory(PM_FNAME);
60
61    /* Get system path and filename maximum lengths */
62    path_max = pathconf(".", _PC_PATH_MAX);
63    if (path_max < 1024) {
64       path_max = 1024;
65    }
66
67    name_max = pathconf(".", _PC_NAME_MAX);
68    if (name_max < 1024) {
69       name_max = 1024;
70    }
71    path_max++;                        /* add for EOS */
72    name_max++;                        /* add for EOS */
73
74   Dmsg1(100, "init_find_files ff=%p\n", ff);
75   return ff;
76 }
77
78 /*
79  * Set find_files options. For the moment, we only
80  * provide for full/incremental saves, and setting
81  * of save_time. For additional options, see above
82  */
83 void
84 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
85 {
86   Dmsg0(100, "Enter set_find_options()\n");
87   ff->incremental = incremental;
88   ff->save_time = save_time;
89   Dmsg0(100, "Leave set_find_options()\n");
90 }
91
92 /*
93  * For VSS we need to know which windows drives
94  * are used, because we create a snapshot of all used
95  * drives before operation
96  *
97  * the function returns the number of used drives and
98  * fills "drives" with up to 26 (A..Z) drive names
99  *
100  */
101 int
102 get_win32_driveletters(FF_PKT *ff, char* szDrives)
103 {
104    /* szDrives must be at least 27 bytes long */
105
106 #ifndef WIN32
107    return 0;
108 #endif
109
110    szDrives[0] = 0; /* make empty */
111    int nCount = 0;
112     
113    findFILESET *fileset = ff->fileset;
114    if (fileset) {
115       int i, j;
116       
117       for (i=0; i<fileset->include_list.size(); i++) {
118          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
119          
120          /* look through all files and check */
121          for (j=0; j<incexe->name_list.size(); j++) {
122             char *fname = (char *)incexe->name_list.get(j);
123             /* fname should match x:/ */
124             if (strlen (fname) > 3 && B_ISALPHA(fname[0]) 
125                && fname[1] == ':' && fname[2] == '/') {
126                
127                /* always add in uppercase */
128                char ch = toupper(fname[0]);
129                /* if not found in string, add drive letter */
130                if (!strchr(szDrives,ch)) {
131                   szDrives[nCount] = ch;
132                   szDrives[nCount+1] = 0;
133                   nCount++;
134                }                                
135             }            
136          }
137       }
138    }
139    return nCount;
140 }
141
142 /*
143  * Find all specified files (determined by calls to name_add()
144  * This routine calls the (handle_file) subroutine with all
145  * sorts of good information for the final disposition of
146  * the file.
147  *
148  * Call this subroutine with a callback subroutine as the first
149  * argument and a packet as the second argument, this packet
150  * will be passed back to the callback subroutine as the last
151  * argument.
152  *
153  * The callback subroutine gets called with:
154  *  arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
155  *  arg2 -- the user supplied packet
156  *
157  */
158 int
159 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level), 
160            void *his_pkt)
161 {
162    ff->callback = callback;
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->fstypes = fo->fstype;
183             bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
184          }
185          for (j=0; j<incexe->name_list.size(); j++) {
186             Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
187             char *fname = (char *)incexe->name_list.get(j);
188             if (find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, true) == 0) {
189                return 0;                  /* error return */
190             }
191          }
192       }
193    }
194    return 1;
195 }
196
197 static bool accept_file(FF_PKT *ff)
198 {
199    int i, j, k;
200    int ic;
201    findFILESET *fileset = ff->fileset;
202    findINCEXE *incexe = fileset->incexe;
203
204    for (j=0; j<incexe->opts_list.size(); j++) {
205       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
206       ff->flags = fo->flags;
207       ff->GZIP_level = fo->GZIP_level;
208       ff->reader = fo->reader;
209       ff->writer = fo->writer;
210       ff->fstypes = fo->fstype;
211       ic = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
212       if (S_ISDIR(ff->statp.st_mode)) {
213          for (k=0; k<fo->wilddir.size(); k++) {
214             if (fnmatch((char *)fo->wilddir.get(k), ff->fname, fnmode|ic) == 0) {
215                if (ff->flags & FO_EXCLUDE) {
216                   Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
217                      ff->fname);
218                   return false;       /* reject file */
219                }
220                return true;           /* accept file */
221             }
222          }
223       } else {
224          for (k=0; k<fo->wildfile.size(); k++) {
225             if (fnmatch((char *)fo->wildfile.get(k), ff->fname, fnmode|ic) == 0) {
226                if (ff->flags & FO_EXCLUDE) {
227                   Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
228                      ff->fname);
229                   return false;       /* reject file */
230                }
231                return true;           /* accept file */
232             }
233          }
234       }
235       for (k=0; k<fo->wild.size(); k++) {
236          if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
237             if (ff->flags & FO_EXCLUDE) {
238                Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
239                   ff->fname);
240                return false;          /* reject file */
241             }
242             return true;              /* accept file */
243          }
244       }
245 #ifndef WIN32
246       if (S_ISDIR(ff->statp.st_mode)) {
247          for (k=0; k<fo->regexdir.size(); k++) {
248             const int nmatch = 30;
249             regmatch_t pmatch[nmatch];
250             if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
251                if (ff->flags & FO_EXCLUDE) {
252                   return false;       /* reject file */
253                }
254                return true;           /* accept file */
255             }
256          }
257       } else {
258          for (k=0; k<fo->regexfile.size(); k++) {
259             const int nmatch = 30;
260             regmatch_t pmatch[nmatch];
261             if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
262                if (ff->flags & FO_EXCLUDE) {
263                   return false;       /* reject file */
264                }
265                return true;           /* accept file */
266             }
267          }
268       }
269       for (k=0; k<fo->regex.size(); k++) {
270          const int nmatch = 30;
271          regmatch_t pmatch[nmatch];
272          if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch,  0) == 0) {
273             if (ff->flags & FO_EXCLUDE) {
274                return false;          /* reject file */
275             }
276             return true;              /* accept file */
277          }
278       }
279 #endif
280       /*
281        * If we have an empty Options clause with exclude, then
282        *  exclude the file
283        */
284       if (ff->flags & FO_EXCLUDE &&
285           fo->regex.size() == 0     && fo->wild.size() == 0 &&
286           fo->regexdir.size() == 0  && fo->wilddir.size() == 0 &&
287           fo->regexfile.size() == 0 && fo->wildfile.size() == 0) {
288          return false;              /* reject file */
289       }
290    }
291
292    /* Now apply the Exclude { } directive */
293    for (i=0; i<fileset->exclude_list.size(); i++) {
294       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
295       for (j=0; j<incexe->opts_list.size(); j++) {
296          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
297          ic = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
298          for (k=0; k<fo->wild.size(); k++) {
299             if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
300                Dmsg1(100, "Reject wild1: %s\n", ff->fname);
301                return false;          /* reject file */
302             }
303          }
304       }
305       ic = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
306              ? FNM_CASEFOLD : 0;
307       for (j=0; j<incexe->name_list.size(); j++) {
308          if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|ic) == 0) {
309             Dmsg1(100, "Reject wild2: %s\n", ff->fname);
310             return false;          /* reject file */
311          }
312       }
313    }
314    return true;
315 }
316
317 /*
318  * The code comes here for each file examined.
319  * We filter the files, then call the user's callback if
320  *    the file is included.
321  */
322 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
323 {
324    if (top_level) {
325       return ff->callback(ff, hpkt, top_level);   /* accept file */
326    }
327    switch (ff->type) {
328    case FT_NOACCESS:
329    case FT_NOFOLLOW:
330    case FT_NOSTAT:
331    case FT_NOCHG:
332    case FT_ISARCH:
333    case FT_NORECURSE:
334    case FT_NOFSCHG:
335    case FT_INVALIDFS:
336    case FT_NOOPEN:
337 //    return ff->callback(ff, hpkt, top_level);
338
339    /* These items can be filtered */
340    case FT_LNKSAVED:
341    case FT_REGE:
342    case FT_REG:
343    case FT_LNK:
344    case FT_DIRBEGIN:
345    case FT_DIREND:
346    case FT_RAW:
347    case FT_FIFO:
348    case FT_SPEC:
349    case FT_DIRNOCHG:
350       if (accept_file(ff)) {
351 //       Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
352          return ff->callback(ff, hpkt, top_level);
353       } else {
354          Dmsg1(100, "Skip file %s\n", ff->fname);
355          return -1;                   /* ignore this file */
356       }
357
358    default:
359       Dmsg1(000, "Unknown FT code %d\n", ff->type);
360       return 0;
361    }
362 }
363
364
365 /*
366  * Terminate find_files() and release
367  * all allocated memory
368  */
369 int
370 term_find_files(FF_PKT *ff)
371 {
372   int hard_links;
373
374   free_pool_memory(ff->sys_fname);
375   hard_links = term_find_one(ff);
376   free(ff);
377   return hard_links;
378 }