]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find.c
Start FileSet filtering
[bacula/bacula] / bacula / src / findlib / find.c
1 /*
2  * Main routine for finding files on a file system.
3  *  The heart of the work is done in find_one.c
4  *
5  *  Kern E. Sibbald, MM
6  */
7 /*
8    Copyright (C) 2000-2004 Kern Sibbald and John Walker
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of
13    the License, or (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public
21    License along with this program; if not, write to the Free
22    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23    MA 02111-1307, USA.
24
25  */
26
27
28 #include "bacula.h"
29 #include "find.h"
30
31
32 int32_t name_max;              /* filename max length */
33 int32_t path_max;              /* path name max length */
34
35
36 /* ****FIXME**** debug until stable */
37 #undef bmalloc
38 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
39 static void set_options(FF_PKT *ff, const char *opts);
40 static int our_callback(FF_PKT *ff, void *hpkt);
41 static bool accept_file(FF_PKT *ff);
42
43
44 /* 
45  * Initialize the find files "global" variables
46  */
47 FF_PKT *init_find_files()
48 {
49   FF_PKT *ff;    
50
51   ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
52   memset(ff, 0, sizeof(FF_PKT));
53
54   ff->sys_fname = get_pool_memory(PM_FNAME);
55
56   init_include_exclude_files(ff);           /* init lists */
57
58    /* Get system path and filename maximum lengths */
59    path_max = pathconf(".", _PC_PATH_MAX);
60    if (path_max < 1024) {
61       path_max = 1024;
62    }
63
64    name_max = pathconf(".", _PC_NAME_MAX);
65    if (name_max < 1024) {
66       name_max = 1024;
67    }
68    path_max++;                        /* add for EOS */
69    name_max++;                        /* add for EOS */
70
71   Dmsg1(100, "init_find_files ff=%p\n", ff);
72   return ff;
73 }
74
75 /* 
76  * Set find_files options. For the moment, we only
77  * provide for full/incremental saves, and setting
78  * of save_time. For additional options, see above
79  */
80 void
81 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
82 {
83   Dmsg0(100, "Enter set_find_options()\n");
84   ff->incremental = incremental;
85   ff->save_time = save_time;
86   Dmsg0(100, "Leave set_find_options()\n");
87 }
88
89
90 /* 
91  * Find all specified files (determined by calls to name_add()
92  * This routine calls the (handle_file) subroutine with all
93  * sorts of good information for the final disposition of
94  * the file.
95  * 
96  * Call this subroutine with a callback subroutine as the first
97  * argument and a packet as the second argument, this packet
98  * will be passed back to the callback subroutine as the last
99  * argument.
100  *
101  * The callback subroutine gets called with:
102  *  arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
103  *  arg2 -- the user supplied packet
104  *
105  */
106 int
107 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void *his_pkt) 
108 {
109    ff->callback = callback;
110
111    /* This is the new way */
112    findFILESET *fileset = ff->fileset;
113    if (fileset) {
114       int i, j;
115       for (i=0; i<fileset->include_list.size(); i++) {
116          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
117          fileset->incexe = incexe;
118          /*
119           * By setting all options, we in effect or the global options
120           *   which is what we want.
121           */
122          for (j=0; j<incexe->opts_list.size(); j++) {
123             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
124             Dmsg1(400, "Find global options O %s\n", fo->opts);
125             set_options(ff, fo->opts);
126          }
127          for (j=0; j<incexe->name_list.size(); j++) {
128             Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
129             char *fname = (char *)incexe->name_list.get(j);
130             if (!find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, 1)) {
131                return 0;                  /* error return */
132             }
133          }
134       }
135    } else {
136       struct s_included_file *inc = NULL;
137
138       /* This is the old deprecated way */
139       while (!job_canceled(jcr) && (inc = get_next_included_file(ff, inc))) {
140          /* Copy options for this file */
141          bstrncpy(ff->VerifyOpts, inc->VerifyOpts, sizeof(ff->VerifyOpts)); 
142          Dmsg1(50, "find_files: file=%s\n", inc->fname);
143          if (!file_is_excluded(ff, inc->fname)) {
144             if (!find_one_file(jcr, ff, callback, his_pkt, inc->fname, (dev_t)-1, 1)) {
145                return 0;                  /* error return */
146             }
147          }
148       }
149    }
150    return 1;
151 }
152
153 static bool accept_file(FF_PKT *ff)
154 {
155    int i, j, k;
156    findFILESET *fileset = ff->fileset;
157    findINCEXE *incexe = fileset->incexe;
158
159    for (j=0; j<incexe->opts_list.size(); j++) {
160       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
161       for (k=0; k<fo->wild.size(); k++) {
162          
163       }
164    }
165
166    for (i=0; i<fileset->exclude_list.size(); i++) {
167       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
168       for (j=0; j<incexe->opts_list.size(); j++) {
169          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
170          for (k=0; k<fo->wild.size(); k++) {
171             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
172             if (fnmatch((char *)fo->wild.get(k), ff->fname, FNM_PATHNAME) == 0) {
173                Dmsg1(000, "Reject wild: %s\n", ff->fname);
174                return false;          /* reject file */
175             }
176          }
177       }
178       for (j=0; j<incexe->name_list.size(); j++) {
179          Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
180          if (fnmatch((char *)incexe->name_list.get(j), ff->fname, FNM_PATHNAME) == 0) {
181             Dmsg1(000, "Reject: %s\n", ff->fname);
182             return false;          /* reject file */
183          }
184       }
185    }
186    Dmsg1(000, "Accept: %s\n", ff->fname);
187    return true;
188 }
189
190 /*
191  * The code comes here for each file examined.
192  * We filter the files, then call the user's callback if
193  *    the file is included. 
194  */
195 static int our_callback(FF_PKT *ff, void *hpkt)
196 {
197    switch (ff->type) {
198    case FT_NOACCESS:
199    case FT_NOFOLLOW:
200    case FT_NOSTAT:
201    case FT_NOCHG:
202    case FT_ISARCH:
203    case FT_NORECURSE:
204    case FT_NOFSCHG:
205    case FT_NOOPEN:
206       Dmsg1(000, "File=%s\n", ff->fname);
207       return ff->callback(ff, hpkt);
208
209    /* These items can be filtered */
210    case FT_LNKSAVED:
211    case FT_REGE:
212    case FT_REG:
213    case FT_LNK:
214    case FT_DIRBEGIN:
215    case FT_DIREND:
216    case FT_SPEC:
217       if (accept_file(ff)) {
218          return ff->callback(ff, hpkt);
219       } else {
220          return 0;
221       }
222    }    
223    return 0;
224 }
225
226
227 /*
228  * As an optimization, we should do this during
229  *  "compile" time in filed/job.c, and keep only a bit mask
230  *  and the Verify options.
231  */
232 static void set_options(FF_PKT *ff, const char *opts)
233 {
234    int j;
235    const char *p;
236
237    for (p=opts; *p; p++) {
238       switch (*p) {
239       case 'a':                 /* alway replace */
240       case '0':                 /* no option */
241          break;
242       case 'e':
243          ff->flags |= FO_EXCLUDE;
244          break;
245       case 'f':
246          ff->flags |= FO_MULTIFS;
247          break;
248       case 'h':                 /* no recursion */
249          ff->flags |= FO_NO_RECURSION;
250          break;
251       case 'M':                 /* MD5 */
252          ff->flags |= FO_MD5;
253          break;
254       case 'n':
255          ff->flags |= FO_NOREPLACE;
256          break;
257       case 'p':                 /* use portable data format */
258          ff->flags |= FO_PORTABLE;
259          break;
260       case 'r':                 /* read fifo */
261          ff->flags |= FO_READFIFO;
262          break;
263       case 'S':
264          ff->flags |= FO_SHA1;
265          break;
266       case 's':
267          ff->flags |= FO_SPARSE;
268          break;
269       case 'm':
270          ff->flags |= FO_MTIMEONLY;
271          break;
272       case 'k':
273          ff->flags |= FO_KEEPATIME;
274          break;
275       case 'V':                  /* verify options */
276          /* Copy Verify Options */
277          for (j=0; *p && *p != ':'; p++) {
278             ff->VerifyOpts[j] = *p;
279             if (j < (int)sizeof(ff->VerifyOpts) - 1) {
280                j++;
281             }
282          }
283          ff->VerifyOpts[j] = 0;
284          break;
285       case 'w':
286          ff->flags |= FO_IF_NEWER;
287          break;
288       case 'Z':                 /* gzip compression */
289          ff->flags |= FO_GZIP;
290          ff->GZIP_level = *++p - '0';
291          Dmsg1(200, "Compression level=%d\n", ff->GZIP_level);
292          break;
293       default:
294          Emsg1(M_ERROR, 0, "Unknown include/exclude option: %c\n", *p);
295          break;
296       }
297    }
298 }
299
300
301 /*
302  * Terminate find_files() and release
303  * all allocated memory   
304  */
305 int
306 term_find_files(FF_PKT *ff)
307 {
308   int hard_links;
309
310   term_include_exclude_files(ff);
311   free_pool_memory(ff->sys_fname);
312   hard_links = term_find_one(ff);
313   free(ff);
314   return hard_links;
315 }