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