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