2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2018 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
22 * Routines used to keep and match include and exclude
23 * filename/pathname patterns.
25 * Note, this file is used for the old style include and
26 * excludes, so is deprecated. The new style code is
28 * This code is still used for lists in testls and bextract.
30 * Kern E. Sibbald, December MMI
38 #include <sys/types.h>
40 #ifndef FNM_LEADING_DIR
41 #define FNM_LEADING_DIR 0
44 /* Fold case in fnmatch() on Win32 */
46 static const int fnmode = FNM_CASEFOLD;
48 static const int fnmode = 0;
53 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
57 match_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *, FF_PKT *ff_pkt, bool))
59 ff->file_save = file_save;
61 struct s_included_file *inc = NULL;
63 /* This is the old deprecated way */
64 while (!job_canceled(jcr) && (inc = get_next_included_file(ff, inc))) {
65 /* Copy options for this file */
66 bstrncat(ff->VerifyOpts, inc->VerifyOpts, sizeof(ff->VerifyOpts));
67 Dmsg1(100, "find_files: file=%s\n", inc->fname);
68 if (!file_is_excluded(ff, inc->fname)) {
69 if (find_one_file(jcr, ff, file_save, inc->fname, (dev_t)-1, 1) ==0) {
70 return 0; /* error return */
79 * Done doing filename matching, release all
82 void term_include_exclude_files(FF_PKT *ff)
84 struct s_included_file *inc, *next_inc;
85 struct s_excluded_file *exc, *next_exc;
87 for (inc=ff->included_files_list; inc; ) {
92 ff->included_files_list = NULL;
94 for (exc=ff->excluded_files_list; exc; ) {
99 ff->excluded_files_list = NULL;
101 for (exc=ff->excluded_paths_list; exc; ) {
102 next_exc = exc->next;
106 ff->excluded_paths_list = NULL;
110 * Add a filename to list of included files
112 void add_fname_to_include_list(FF_PKT *ff, int prefixed, const char *fname)
115 struct s_included_file *inc;
121 inc =(struct s_included_file *)bmalloc(sizeof(struct s_included_file) + len + 1);
123 inc->VerifyOpts[0] = 'V';
124 inc->VerifyOpts[1] = ':';
125 inc->VerifyOpts[2] = 0;
127 /* prefixed = preceded with options */
129 for (rp=fname; *rp && *rp != ' '; rp++) {
131 case 'a': /* alway replace */
132 case '0': /* no option */
135 inc->options |= FO_MULTIFS;
137 case 'h': /* no recursion */
138 inc->options |= FO_NO_RECURSION;
141 inc->options |= FO_MD5;
144 inc->options |= FO_NOREPLACE;
146 case 'p': /* use portable data format */
147 inc->options |= FO_PORTABLE;
149 case 'r': /* read fifo */
150 inc->options |= FO_READFIFO;
153 inc->options |= FO_SHA1;
156 inc->options |= FO_SPARSE;
159 inc->options |= FO_MTIMEONLY;
162 inc->options |= FO_KEEPATIME;
164 case 'V': /* verify options */
165 /* Copy Verify Options */
166 for (j=0; *rp && *rp != ':'; rp++) {
167 inc->VerifyOpts[j] = *rp;
168 if (j < (int)sizeof(inc->VerifyOpts) - 1) {
172 inc->VerifyOpts[j] = 0;
175 inc->options |= FO_IF_NEWER;
178 inc->options |= FO_ACL;
180 case 'Z': /* compression */
182 if (*rp >= '0' && *rp <= '9') {
183 inc->options |= FO_COMPRESS;
184 inc->algo = COMPRESS_GZIP;
185 inc->Compress_level = *rp - '0';
187 else if (*rp == 'o') {
188 inc->options |= FO_COMPRESS;
189 inc->algo = COMPRESS_LZO1X;
190 inc->Compress_level = 1; /* not used with LZO */
192 Dmsg2(200, "Compression alg=%d level=%d\n", inc->algo, inc->Compress_level);
195 inc->options |= FO_NOATIME;
198 inc->options |= FO_XATTR;
201 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *rp);
205 /* Skip past space(s) */
206 for ( ; *rp == ' '; rp++)
212 strcpy(inc->fname, rp);
215 /* Zap trailing slashes. */
217 while (p > inc->fname && IsPathSeparator(*p)) {
222 /* Check for wild cards */
224 for (p=inc->fname; *p; p++) {
225 if (*p == '*' || *p == '[' || *p == '?') {
230 #if defined(HAVE_WIN32)
231 /* Convert any \'s into /'s */
232 for (p=inc->fname; *p; p++) {
239 /* Chain this one on the end of the list */
240 if (!ff->included_files_list) {
241 /* First one, so set head */
242 ff->included_files_list = inc;
244 struct s_included_file *next;
245 /* Walk to end of list */
246 for (next=ff->included_files_list; next->next; next=next->next)
250 Dmsg4(100, "add_fname_to_include prefix=%d compres=%d alg= %d fname=%s\n",
251 prefixed, !!(inc->options & FO_COMPRESS), inc->algo, inc->fname);
255 * We add an exclude name to either the exclude path
256 * list or the exclude filename list.
258 void add_fname_to_exclude_list(FF_PKT *ff, const char *fname)
261 struct s_excluded_file *exc, **list;
263 Dmsg1(20, "Add name to exclude: %s\n", fname);
265 if (first_path_separator(fname) != NULL) {
266 list = &ff->excluded_paths_list;
268 list = &ff->excluded_files_list;
273 exc = (struct s_excluded_file *)bmalloc(sizeof(struct s_excluded_file) + len + 1);
276 strcpy(exc->fname, fname);
277 #if defined(HAVE_WIN32)
278 /* Convert any \'s into /'s */
279 for (char *p=exc->fname; *p; p++) {
290 * Get next included file
292 struct s_included_file *get_next_included_file(FF_PKT *ff, struct s_included_file *ainc)
294 struct s_included_file *inc;
297 inc = ff->included_files_list;
302 * copy inc_options for this file into the ff packet
305 ff->flags = inc->options;
306 ff->Compress_algo = inc->algo;
307 ff->Compress_level = inc->Compress_level;
313 * Walk through the included list to see if this
314 * file is included possibly with wild-cards.
317 int file_is_included(FF_PKT *ff, const char *file)
319 struct s_included_file *inc = ff->included_files_list;
322 for ( ; inc; inc=inc->next ) {
324 if (fnmatch(inc->fname, file, fnmode|FNM_LEADING_DIR) == 0) {
330 * No wild cards. We accept a match to the
331 * end of any component.
333 Dmsg2(900, "pat=%s file=%s\n", inc->fname, file);
335 if (inc->len == len && strcmp(inc->fname, file) == 0) {
338 if (inc->len < len && IsPathSeparator(file[inc->len]) &&
339 strncmp(inc->fname, file, inc->len) == 0) {
342 if (inc->len == 1 && IsPathSeparator(inc->fname[0])) {
351 * This is the workhorse of excluded_file().
352 * Determine if the file is excluded or not.
355 file_in_excluded_list(struct s_excluded_file *exc, const char *file)
358 Dmsg0(900, "exc is NULL\n");
360 for ( ; exc; exc=exc->next ) {
361 if (fnmatch(exc->fname, file, fnmode|FNM_PATHNAME) == 0) {
362 Dmsg2(900, "Match exc pat=%s: file=%s:\n", exc->fname, file);
365 Dmsg2(900, "No match exc pat=%s: file=%s:\n", exc->fname, file);
372 * Walk through the excluded lists to see if this
373 * file is excluded, or if it matches a component
374 * of an excluded directory.
377 int file_is_excluded(FF_PKT *ff, const char *file)
381 #if defined(HAVE_WIN32)
383 * ***NB*** this removes the drive from the exclude
386 if (file[1] == ':') {
391 if (file_in_excluded_list(ff->excluded_paths_list, file)) {
395 /* Try each component */
396 for (p = file; *p; p++) {
397 /* Match from the beginning of a component only */
398 if ((p == file || (!IsPathSeparator(*p) && IsPathSeparator(p[-1])))
399 && file_in_excluded_list(ff->excluded_files_list, p)) {