source: trunk/essentials/app-arch/tar/lib/exclude.c

Last change on this file was 3342, checked in by bird, 18 years ago

tar 1.16.1

File size: 6.0 KB
Line 
1/* exclude.c -- exclude file names
2
3 Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2006 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING.
18 If not, write to the Free Software Foundation,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20
21/* Written by Paul Eggert <eggert@twinsun.com> */
22
23#include <config.h>
24
25#include <stdbool.h>
26
27#include <ctype.h>
28#include <errno.h>
29#include <stddef.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include "exclude.h"
35#include "fnmatch.h"
36#include "strcase.h"
37#include "xalloc.h"
38#include "verify.h"
39
40#if USE_UNLOCKED_IO
41# include "unlocked-io.h"
42#endif
43
44/* Non-GNU systems lack these options, so we don't need to check them. */
45#ifndef FNM_CASEFOLD
46# define FNM_CASEFOLD 0
47#endif
48#ifndef FNM_LEADING_DIR
49# define FNM_LEADING_DIR 0
50#endif
51
52verify (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
53 & (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
54 | FNM_CASEFOLD))
55 == 0);
56
57/* An exclude pattern-options pair. The options are fnmatch options
58 ORed with EXCLUDE_* options. */
59
60struct patopts
61 {
62 char const *pattern;
63 int options;
64 };
65
66/* An exclude list, of pattern-options pairs. */
67
68struct exclude
69 {
70 struct patopts *exclude;
71 size_t exclude_alloc;
72 size_t exclude_count;
73 };
74
75/* Return a newly allocated and empty exclude list. */
76
77struct exclude *
78new_exclude (void)
79{
80 return xzalloc (sizeof *new_exclude ());
81}
82
83/* Free the storage associated with an exclude list. */
84
85void
86free_exclude (struct exclude *ex)
87{
88 free (ex->exclude);
89 free (ex);
90}
91
92/* Return zero if PATTERN matches F, obeying OPTIONS, except that
93 (unlike fnmatch) wildcards are disabled in PATTERN. */
94
95static int
96fnmatch_no_wildcards (char const *pattern, char const *f, int options)
97{
98 if (! (options & FNM_LEADING_DIR))
99 return ((options & FNM_CASEFOLD)
100 ? strcasecmp (pattern, f)
101 : strcmp (pattern, f));
102 else
103 {
104 size_t patlen = strlen (pattern);
105 int r = ((options & FNM_CASEFOLD)
106 ? strncasecmp (pattern, f, patlen)
107 : strncmp (pattern, f, patlen));
108 if (! r)
109 {
110 r = f[patlen];
111 if (r == '/')
112 r = 0;
113 }
114 return r;
115 }
116}
117
118bool
119exclude_fnmatch (char const *pattern, char const *f, int options)
120{
121 int (*matcher) (char const *, char const *, int) =
122 (options & EXCLUDE_WILDCARDS
123 ? fnmatch
124 : fnmatch_no_wildcards);
125 bool matched = ((*matcher) (pattern, f, options) == 0);
126 char const *p;
127
128 if (! (options & EXCLUDE_ANCHORED))
129 for (p = f; *p && ! matched; p++)
130 if (*p == '/' && p[1] != '/')
131 matched = ((*matcher) (pattern, p + 1, options) == 0);
132
133 return matched;
134}
135
136/* Return true if EX excludes F. */
137
138bool
139excluded_file_name (struct exclude const *ex, char const *f)
140{
141 size_t exclude_count = ex->exclude_count;
142
143 /* If no options are given, the default is to include. */
144 if (exclude_count == 0)
145 return false;
146 else
147 {
148 struct patopts const *exclude = ex->exclude;
149 size_t i;
150
151 /* Otherwise, the default is the opposite of the first option. */
152 bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
153
154 /* Scan through the options, seeing whether they change F from
155 excluded to included or vice versa. */
156 for (i = 0; i < exclude_count; i++)
157 {
158 char const *pattern = exclude[i].pattern;
159 int options = exclude[i].options;
160 if (excluded == !! (options & EXCLUDE_INCLUDE))
161 excluded ^= exclude_fnmatch (pattern, f, options);
162 }
163
164 return excluded;
165 }
166}
167
168/* Append to EX the exclusion PATTERN with OPTIONS. */
169
170void
171add_exclude (struct exclude *ex, char const *pattern, int options)
172{
173 struct patopts *patopts;
174
175 if (ex->exclude_count == ex->exclude_alloc)
176 ex->exclude = x2nrealloc (ex->exclude, &ex->exclude_alloc,
177 sizeof *ex->exclude);
178
179 patopts = &ex->exclude[ex->exclude_count++];
180 patopts->pattern = pattern;
181 patopts->options = options;
182}
183
184/* Use ADD_FUNC to append to EX the patterns in FILE_NAME, each with
185 OPTIONS. LINE_END terminates each pattern in the file. If
186 LINE_END is a space character, ignore trailing spaces and empty
187 lines in FILE. Return -1 on failure, 0 on success. */
188
189int
190add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
191 struct exclude *ex, char const *file_name, int options,
192 char line_end)
193{
194 bool use_stdin = file_name[0] == '-' && !file_name[1];
195 FILE *in;
196 char *buf = NULL;
197 char *p;
198 char const *pattern;
199 char const *lim;
200 size_t buf_alloc = 0;
201 size_t buf_count = 0;
202 int c;
203 int e = 0;
204
205 if (use_stdin)
206 in = stdin;
207 else if (! (in = fopen (file_name, "r")))
208 return -1;
209
210 while ((c = getc (in)) != EOF)
211 {
212 if (buf_count == buf_alloc)
213 buf = x2realloc (buf, &buf_alloc);
214 buf[buf_count++] = c;
215 }
216
217 if (ferror (in))
218 e = errno;
219
220 if (!use_stdin && fclose (in) != 0)
221 e = errno;
222
223 buf = xrealloc (buf, buf_count + 1);
224 buf[buf_count] = line_end;
225 lim = buf + buf_count + ! (buf_count == 0 || buf[buf_count - 1] == line_end);
226 pattern = buf;
227
228 for (p = buf; p < lim; p++)
229 if (*p == line_end)
230 {
231 char *pattern_end = p;
232
233 if (isspace ((unsigned char) line_end))
234 {
235 for (; ; pattern_end--)
236 if (pattern_end == pattern)
237 goto next_pattern;
238 else if (! isspace ((unsigned char) pattern_end[-1]))
239 break;
240 }
241
242 *pattern_end = '\0';
243 (*add_func) (ex, pattern, options);
244
245 next_pattern:
246 pattern = p + 1;
247 }
248
249 errno = e;
250 return e ? -1 : 0;
251}
Note: See TracBrowser for help on using the repository browser.