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