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