]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/match.c
90b9041aea393b5a8b8ec405c9b5d1310677e211
[bacula/bacula] / bacula / src / findlib / match.c
1 /*
2  *     Old style 
3  *
4  *  Routines used to keep and match include and exclude
5  *   filename/pathname patterns.
6  *
7  *  Note, this file is used for the old style include and
8  *   excludes, so is deprecated. The new style code is
9  *   found in find.c.   
10  *  This code is still used for lists in testls and bextract.
11  *
12  *   Kern E. Sibbald, December MMI
13  *
14  */
15 /*
16    Bacula® - The Network Backup Solution
17
18    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
19
20    The main author of Bacula is Kern Sibbald, with contributions from
21    many others, a complete list can be found in the file AUTHORS.
22    This program is Free Software; you can redistribute it and/or
23    modify it under the terms of version two of the GNU General Public
24    License as published by the Free Software Foundation plus additions
25    that are listed in the file LICENSE.
26
27    This program is distributed in the hope that it will be useful, but
28    WITHOUT ANY WARRANTY; without even the implied warranty of
29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30    General Public License for more details.
31
32    You should have received a copy of the GNU General Public License
33    along with this program; if not, write to the Free Software
34    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35    02110-1301, USA.
36
37    Bacula® is a registered trademark of John Walker.
38    The licensor of Bacula is the Free Software Foundation Europe
39    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
40    Switzerland, email:ftf@fsfeurope.org.
41 */
42
43 #include "bacula.h"
44 #include "find.h"
45
46 #include <pwd.h>
47 #include <grp.h>
48 #include <sys/types.h>
49
50 #ifndef FNM_LEADING_DIR
51 #define FNM_LEADING_DIR 0
52 #endif
53
54 /* Fold case in fnmatch() on Win32 */
55 #ifdef HAVE_WIN32
56 static const int fnmode = FNM_CASEFOLD;
57 #else
58 static const int fnmode = 0;
59 #endif
60
61
62 #undef bmalloc
63 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
64
65
66 int
67 match_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool), void *his_pkt)
68 {
69    ff->callback = callback;
70
71    struct s_included_file *inc = NULL;
72
73    /* This is the old deprecated way */
74    while (!job_canceled(jcr) && (inc = get_next_included_file(ff, inc))) {
75       /* Copy options for this file */
76       bstrncat(ff->VerifyOpts, inc->VerifyOpts, sizeof(ff->VerifyOpts));
77       Dmsg1(100, "find_files: file=%s\n", inc->fname);
78       if (!file_is_excluded(ff, inc->fname)) {
79          if (find_one_file(jcr, ff, callback, his_pkt, inc->fname, (dev_t)-1, 1) ==0) {
80             return 0;                  /* error return */
81          }
82       }
83    }
84    return 1;
85 }
86
87
88 /*
89  * Done doing filename matching, release all
90  *  resources used.
91  */
92 void term_include_exclude_files(FF_PKT *ff)
93 {
94    struct s_included_file *inc, *next_inc;
95    struct s_excluded_file *exc, *next_exc;
96
97    for (inc=ff->included_files_list; inc; ) {
98       next_inc = inc->next;
99       free(inc);
100       inc = next_inc;
101    }
102    ff->included_files_list = NULL;
103
104    for (exc=ff->excluded_files_list; exc; ) {
105       next_exc = exc->next;
106       free(exc);
107       exc = next_exc;
108    }
109    ff->excluded_files_list = NULL;
110
111    for (exc=ff->excluded_paths_list; exc; ) {
112       next_exc = exc->next;
113       free(exc);
114       exc = next_exc;
115    }
116    ff->excluded_paths_list = NULL;
117 }
118
119 /*
120  * Add a filename to list of included files
121  */
122 void add_fname_to_include_list(FF_PKT *ff, int prefixed, const char *fname)
123 {
124    int len, j;
125    struct s_included_file *inc;
126    char *p;
127    const char *rp;
128
129    len = strlen(fname);
130
131    inc =(struct s_included_file *)bmalloc(sizeof(struct s_included_file) + len + 1);
132    inc->options = 0;
133    inc->VerifyOpts[0] = 'V';
134    inc->VerifyOpts[1] = ':';
135    inc->VerifyOpts[2] = 0;
136
137    /* prefixed = preceded with options */
138    if (prefixed) {
139       for (rp=fname; *rp && *rp != ' '; rp++) {
140          switch (*rp) {
141          case 'a':                 /* alway replace */
142          case '0':                 /* no option */
143             break;
144          case 'f':
145             inc->options |= FO_MULTIFS;
146             break;
147          case 'h':                 /* no recursion */
148             inc->options |= FO_NO_RECURSION;
149             break;
150          case 'M':                 /* MD5 */
151             inc->options |= FO_MD5;
152             break;
153          case 'n':
154             inc->options |= FO_NOREPLACE;
155             break;
156          case 'p':                 /* use portable data format */
157             inc->options |= FO_PORTABLE;
158             break;
159          case 'r':                 /* read fifo */
160             inc->options |= FO_READFIFO;
161             break;
162          case 'S':
163             inc->options |= FO_SHA1;
164             break;
165          case 's':
166             inc->options |= FO_SPARSE;
167             break;
168          case 'm':
169             inc->options |= FO_MTIMEONLY;
170             break;
171          case 'k':
172             inc->options |= FO_KEEPATIME;
173             break;
174          case 'V':                  /* verify options */
175             /* Copy Verify Options */
176             for (j=0; *rp && *rp != ':'; rp++) {
177                inc->VerifyOpts[j] = *rp;
178                if (j < (int)sizeof(inc->VerifyOpts) - 1) {
179                   j++;
180                }
181             }
182             inc->VerifyOpts[j] = 0;
183             break;
184          case 'w':
185             inc->options |= FO_IF_NEWER;
186             break;
187          case 'A':
188             inc->options |= FO_ACL;
189             break;
190          case 'Z':                 /* gzip compression */
191             inc->options |= FO_GZIP;
192             inc->level = *++rp - '0';
193             Dmsg1(200, "Compression level=%d\n", inc->level);
194             break;
195          case 'K':
196             inc->options |= FO_NOATIME;
197             break;
198          default:
199             Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *rp);
200             break;
201          }
202       }
203       /* Skip past space(s) */
204       for ( ; *rp == ' '; rp++)
205          {}
206    } else {
207       rp = fname;
208    }
209
210    strcpy(inc->fname, rp);
211    p = inc->fname;
212    len = strlen(p);
213    /* Zap trailing slashes.  */
214    p += len - 1;
215    while (p > inc->fname && IsPathSeparator(*p)) {
216       *p-- = 0;
217       len--;
218    }
219    inc->len = len;
220    /* Check for wild cards */
221    inc->pattern = 0;
222    for (p=inc->fname; *p; p++) {
223       if (*p == '*' || *p == '[' || *p == '?') {
224          inc->pattern = 1;
225          break;
226       }
227    }
228 #if defined(HAVE_WIN32)
229    /* Convert any \'s into /'s */
230    for (p=inc->fname; *p; p++) {
231       if (*p == '\\') {
232          *p = '/';
233       }
234    }
235 #endif
236    inc->next = NULL;
237    /* Chain this one on the end of the list */
238    if (!ff->included_files_list) {
239       /* First one, so set head */
240       ff->included_files_list = inc;
241    } else {
242       struct s_included_file *next;
243       /* Walk to end of list */
244       for (next=ff->included_files_list; next->next; next=next->next)
245          { }
246       next->next = inc;
247    }
248    Dmsg1(50, "add_fname_to_include fname=%s\n", inc->fname);
249 }
250
251 /*
252  * We add an exclude name to either the exclude path
253  *  list or the exclude filename list.
254  */
255 void add_fname_to_exclude_list(FF_PKT *ff, const char *fname)
256 {
257    int len;
258    struct s_excluded_file *exc, **list;
259
260    Dmsg1(20, "Add name to exclude: %s\n", fname);
261
262    if (first_path_separator(fname) != NULL) {
263       list = &ff->excluded_paths_list;
264    } else {
265       list = &ff->excluded_files_list;
266    }
267
268    len = strlen(fname);
269
270    exc = (struct s_excluded_file *)bmalloc(sizeof(struct s_excluded_file) + len + 1);
271    exc->next = *list;
272    exc->len = len;
273    strcpy(exc->fname, fname);
274 #if defined(HAVE_WIN32)
275    /* Convert any \'s into /'s */
276    for (char *p=exc->fname; *p; p++) {
277       if (*p == '\\') {
278          *p = '/';
279       }
280    }
281 #endif
282    *list = exc;
283 }
284
285
286 /*
287  * Get next included file
288  */
289 struct s_included_file *get_next_included_file(FF_PKT *ff, struct s_included_file *ainc)
290 {
291    struct s_included_file *inc;
292
293    if (ainc == NULL) {
294       inc = ff->included_files_list;
295    } else {
296       inc = ainc->next;
297    }
298    /*
299     * copy inc_options for this file into the ff packet
300     */
301    if (inc) {
302       ff->flags = inc->options;
303       ff->GZIP_level = inc->level;
304    }
305    return inc;
306 }
307
308 /*
309  * Walk through the included list to see if this
310  *  file is included possibly with wild-cards.
311  */
312
313 int file_is_included(FF_PKT *ff, const char *file)
314 {
315    struct s_included_file *inc = ff->included_files_list;
316    int len;
317
318    for ( ; inc; inc=inc->next ) {
319       if (inc->pattern) {
320          if (fnmatch(inc->fname, file, fnmode|FNM_LEADING_DIR) == 0) {
321             return 1;
322          }
323          continue;
324       }
325       /*
326        * No wild cards. We accept a match to the
327        *  end of any component.
328        */
329       Dmsg2(900, "pat=%s file=%s\n", inc->fname, file);
330       len = strlen(file);
331       if (inc->len == len && strcmp(inc->fname, file) == 0) {
332          return 1;
333       }
334       if (inc->len < len && IsPathSeparator(file[inc->len]) &&
335           strncmp(inc->fname, file, inc->len) == 0) {
336          return 1;
337       }
338       if (inc->len == 1 && IsPathSeparator(inc->fname[0])) {
339          return 1;
340       }
341    }
342    return 0;
343 }
344
345
346 /*
347  * This is the workhorse of excluded_file().
348  * Determine if the file is excluded or not.
349  */
350 static int
351 file_in_excluded_list(struct s_excluded_file *exc, const char *file)
352 {
353    if (exc == NULL) {
354       Dmsg0(900, "exc is NULL\n");
355    }
356    for ( ; exc; exc=exc->next ) {
357       if (fnmatch(exc->fname, file, fnmode|FNM_PATHNAME) == 0) {
358          Dmsg2(900, "Match exc pat=%s: file=%s:\n", exc->fname, file);
359          return 1;
360       }
361       Dmsg2(900, "No match exc pat=%s: file=%s:\n", exc->fname, file);
362    }
363    return 0;
364 }
365
366
367 /*
368  * Walk through the excluded lists to see if this
369  *  file is excluded, or if it matches a component
370  *  of an excluded directory.
371  */
372
373 int file_is_excluded(FF_PKT *ff, const char *file)
374 {
375    const char *p;
376
377 #if defined(HAVE_WIN32)
378    /*
379     *  ***NB*** this removes the drive from the exclude
380     *  rule.  Why?????
381     */
382    if (file[1] == ':') {
383       file += 2;
384    }
385 #endif
386
387    if (file_in_excluded_list(ff->excluded_paths_list, file)) {
388       return 1;
389    }
390
391    /* Try each component */
392    for (p = file; *p; p++) {
393       /* Match from the beginning of a component only */
394       if ((p == file || (!IsPathSeparator(*p) && IsPathSeparator(p[-1])))
395            && file_in_excluded_list(ff->excluded_files_list, p)) {
396          return 1;
397       }
398    }
399    return 0;
400 }