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