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