1*543adbedSBen Gras /*-
2*543adbedSBen Gras * Copyright (c) 2003-2007 Tim Kientzle
3*543adbedSBen Gras * All rights reserved.
4*543adbedSBen Gras *
5*543adbedSBen Gras * Redistribution and use in source and binary forms, with or without
6*543adbedSBen Gras * modification, are permitted provided that the following conditions
7*543adbedSBen Gras * are met:
8*543adbedSBen Gras * 1. Redistributions of source code must retain the above copyright
9*543adbedSBen Gras * notice, this list of conditions and the following disclaimer.
10*543adbedSBen Gras * 2. Redistributions in binary form must reproduce the above copyright
11*543adbedSBen Gras * notice, this list of conditions and the following disclaimer in the
12*543adbedSBen Gras * documentation and/or other materials provided with the distribution.
13*543adbedSBen Gras *
14*543adbedSBen Gras * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15*543adbedSBen Gras * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*543adbedSBen Gras * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*543adbedSBen Gras * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18*543adbedSBen Gras * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*543adbedSBen Gras * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*543adbedSBen Gras * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*543adbedSBen Gras * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*543adbedSBen Gras * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*543adbedSBen Gras * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*543adbedSBen Gras */
25*543adbedSBen Gras
26*543adbedSBen Gras #include "lafe_platform.h"
27*543adbedSBen Gras __FBSDID("$FreeBSD: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientzle Exp $");
28*543adbedSBen Gras
29*543adbedSBen Gras #ifdef HAVE_ERRNO_H
30*543adbedSBen Gras #include <errno.h>
31*543adbedSBen Gras #endif
32*543adbedSBen Gras #ifdef HAVE_STDLIB_H
33*543adbedSBen Gras #include <stdlib.h>
34*543adbedSBen Gras #endif
35*543adbedSBen Gras #ifdef HAVE_STRING_H
36*543adbedSBen Gras #include <string.h>
37*543adbedSBen Gras #endif
38*543adbedSBen Gras
39*543adbedSBen Gras #include "err.h"
40*543adbedSBen Gras #include "line_reader.h"
41*543adbedSBen Gras #include "matching.h"
42*543adbedSBen Gras #include "pathmatch.h"
43*543adbedSBen Gras
44*543adbedSBen Gras struct match {
45*543adbedSBen Gras struct match *next;
46*543adbedSBen Gras int matches;
47*543adbedSBen Gras char pattern[1];
48*543adbedSBen Gras };
49*543adbedSBen Gras
50*543adbedSBen Gras struct lafe_matching {
51*543adbedSBen Gras struct match *exclusions;
52*543adbedSBen Gras int exclusions_count;
53*543adbedSBen Gras struct match *inclusions;
54*543adbedSBen Gras int inclusions_count;
55*543adbedSBen Gras int inclusions_unmatched_count;
56*543adbedSBen Gras };
57*543adbedSBen Gras
58*543adbedSBen Gras static void add_pattern(struct match **list, const char *pattern);
59*543adbedSBen Gras static void initialize_matching(struct lafe_matching **);
60*543adbedSBen Gras static int match_exclusion(struct match *, const char *pathname);
61*543adbedSBen Gras static int match_inclusion(struct match *, const char *pathname);
62*543adbedSBen Gras
63*543adbedSBen Gras /*
64*543adbedSBen Gras * The matching logic here needs to be re-thought. I started out to
65*543adbedSBen Gras * try to mimic gtar's matching logic, but it's not entirely
66*543adbedSBen Gras * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
67*543adbedSBen Gras * on the command line as anchored, but --exclude doesn't.
68*543adbedSBen Gras */
69*543adbedSBen Gras
70*543adbedSBen Gras /*
71*543adbedSBen Gras * Utility functions to manage exclusion/inclusion patterns
72*543adbedSBen Gras */
73*543adbedSBen Gras
74*543adbedSBen Gras int
lafe_exclude(struct lafe_matching ** matching,const char * pattern)75*543adbedSBen Gras lafe_exclude(struct lafe_matching **matching, const char *pattern)
76*543adbedSBen Gras {
77*543adbedSBen Gras
78*543adbedSBen Gras if (*matching == NULL)
79*543adbedSBen Gras initialize_matching(matching);
80*543adbedSBen Gras add_pattern(&((*matching)->exclusions), pattern);
81*543adbedSBen Gras (*matching)->exclusions_count++;
82*543adbedSBen Gras return (0);
83*543adbedSBen Gras }
84*543adbedSBen Gras
85*543adbedSBen Gras int
lafe_exclude_from_file(struct lafe_matching ** matching,const char * pathname)86*543adbedSBen Gras lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname)
87*543adbedSBen Gras {
88*543adbedSBen Gras struct lafe_line_reader *lr;
89*543adbedSBen Gras const char *p;
90*543adbedSBen Gras int ret = 0;
91*543adbedSBen Gras
92*543adbedSBen Gras lr = lafe_line_reader(pathname, 0);
93*543adbedSBen Gras while ((p = lafe_line_reader_next(lr)) != NULL) {
94*543adbedSBen Gras if (lafe_exclude(matching, p) != 0)
95*543adbedSBen Gras ret = -1;
96*543adbedSBen Gras }
97*543adbedSBen Gras lafe_line_reader_free(lr);
98*543adbedSBen Gras return (ret);
99*543adbedSBen Gras }
100*543adbedSBen Gras
101*543adbedSBen Gras int
lafe_include(struct lafe_matching ** matching,const char * pattern)102*543adbedSBen Gras lafe_include(struct lafe_matching **matching, const char *pattern)
103*543adbedSBen Gras {
104*543adbedSBen Gras
105*543adbedSBen Gras if (*matching == NULL)
106*543adbedSBen Gras initialize_matching(matching);
107*543adbedSBen Gras add_pattern(&((*matching)->inclusions), pattern);
108*543adbedSBen Gras (*matching)->inclusions_count++;
109*543adbedSBen Gras (*matching)->inclusions_unmatched_count++;
110*543adbedSBen Gras return (0);
111*543adbedSBen Gras }
112*543adbedSBen Gras
113*543adbedSBen Gras int
lafe_include_from_file(struct lafe_matching ** matching,const char * pathname,int nullSeparator)114*543adbedSBen Gras lafe_include_from_file(struct lafe_matching **matching, const char *pathname,
115*543adbedSBen Gras int nullSeparator)
116*543adbedSBen Gras {
117*543adbedSBen Gras struct lafe_line_reader *lr;
118*543adbedSBen Gras const char *p;
119*543adbedSBen Gras int ret = 0;
120*543adbedSBen Gras
121*543adbedSBen Gras lr = lafe_line_reader(pathname, nullSeparator);
122*543adbedSBen Gras while ((p = lafe_line_reader_next(lr)) != NULL) {
123*543adbedSBen Gras if (lafe_include(matching, p) != 0)
124*543adbedSBen Gras ret = -1;
125*543adbedSBen Gras }
126*543adbedSBen Gras lafe_line_reader_free(lr);
127*543adbedSBen Gras return (ret);
128*543adbedSBen Gras }
129*543adbedSBen Gras
130*543adbedSBen Gras static void
add_pattern(struct match ** list,const char * pattern)131*543adbedSBen Gras add_pattern(struct match **list, const char *pattern)
132*543adbedSBen Gras {
133*543adbedSBen Gras struct match *match;
134*543adbedSBen Gras size_t len;
135*543adbedSBen Gras
136*543adbedSBen Gras len = strlen(pattern);
137*543adbedSBen Gras match = malloc(sizeof(*match) + len + 1);
138*543adbedSBen Gras if (match == NULL)
139*543adbedSBen Gras lafe_errc(1, errno, "Out of memory");
140*543adbedSBen Gras strcpy(match->pattern, pattern);
141*543adbedSBen Gras /* Both "foo/" and "foo" should match "foo/bar". */
142*543adbedSBen Gras if (len && match->pattern[len - 1] == '/')
143*543adbedSBen Gras match->pattern[strlen(match->pattern)-1] = '\0';
144*543adbedSBen Gras match->next = *list;
145*543adbedSBen Gras *list = match;
146*543adbedSBen Gras match->matches = 0;
147*543adbedSBen Gras }
148*543adbedSBen Gras
149*543adbedSBen Gras
150*543adbedSBen Gras int
lafe_excluded(struct lafe_matching * matching,const char * pathname)151*543adbedSBen Gras lafe_excluded(struct lafe_matching *matching, const char *pathname)
152*543adbedSBen Gras {
153*543adbedSBen Gras struct match *match;
154*543adbedSBen Gras struct match *matched;
155*543adbedSBen Gras
156*543adbedSBen Gras if (matching == NULL)
157*543adbedSBen Gras return (0);
158*543adbedSBen Gras
159*543adbedSBen Gras /* Exclusions take priority */
160*543adbedSBen Gras for (match = matching->exclusions; match != NULL; match = match->next){
161*543adbedSBen Gras if (match_exclusion(match, pathname))
162*543adbedSBen Gras return (1);
163*543adbedSBen Gras }
164*543adbedSBen Gras
165*543adbedSBen Gras /* Then check for inclusions */
166*543adbedSBen Gras matched = NULL;
167*543adbedSBen Gras for (match = matching->inclusions; match != NULL; match = match->next){
168*543adbedSBen Gras if (match_inclusion(match, pathname)) {
169*543adbedSBen Gras /*
170*543adbedSBen Gras * If this pattern has never been matched,
171*543adbedSBen Gras * then we're done.
172*543adbedSBen Gras */
173*543adbedSBen Gras if (match->matches == 0) {
174*543adbedSBen Gras match->matches++;
175*543adbedSBen Gras matching->inclusions_unmatched_count--;
176*543adbedSBen Gras return (0);
177*543adbedSBen Gras }
178*543adbedSBen Gras /*
179*543adbedSBen Gras * Otherwise, remember the match but keep checking
180*543adbedSBen Gras * in case we can tick off an unmatched pattern.
181*543adbedSBen Gras */
182*543adbedSBen Gras matched = match;
183*543adbedSBen Gras }
184*543adbedSBen Gras }
185*543adbedSBen Gras /*
186*543adbedSBen Gras * We didn't find a pattern that had never been matched, but
187*543adbedSBen Gras * we did find a match, so count it and exit.
188*543adbedSBen Gras */
189*543adbedSBen Gras if (matched != NULL) {
190*543adbedSBen Gras matched->matches++;
191*543adbedSBen Gras return (0);
192*543adbedSBen Gras }
193*543adbedSBen Gras
194*543adbedSBen Gras /* If there were inclusions, default is to exclude. */
195*543adbedSBen Gras if (matching->inclusions != NULL)
196*543adbedSBen Gras return (1);
197*543adbedSBen Gras
198*543adbedSBen Gras /* No explicit inclusions, default is to match. */
199*543adbedSBen Gras return (0);
200*543adbedSBen Gras }
201*543adbedSBen Gras
202*543adbedSBen Gras /*
203*543adbedSBen Gras * This is a little odd, but it matches the default behavior of
204*543adbedSBen Gras * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
205*543adbedSBen Gras *
206*543adbedSBen Gras */
207*543adbedSBen Gras static int
match_exclusion(struct match * match,const char * pathname)208*543adbedSBen Gras match_exclusion(struct match *match, const char *pathname)
209*543adbedSBen Gras {
210*543adbedSBen Gras return (lafe_pathmatch(match->pattern,
211*543adbedSBen Gras pathname,
212*543adbedSBen Gras PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END));
213*543adbedSBen Gras }
214*543adbedSBen Gras
215*543adbedSBen Gras /*
216*543adbedSBen Gras * Again, mimic gtar: inclusions are always anchored (have to match
217*543adbedSBen Gras * the beginning of the path) even though exclusions are not anchored.
218*543adbedSBen Gras */
219*543adbedSBen Gras static int
match_inclusion(struct match * match,const char * pathname)220*543adbedSBen Gras match_inclusion(struct match *match, const char *pathname)
221*543adbedSBen Gras {
222*543adbedSBen Gras #if 0
223*543adbedSBen Gras return (lafe_pathmatch(match->pattern, pathname, 0));
224*543adbedSBen Gras #else
225*543adbedSBen Gras return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END));
226*543adbedSBen Gras #endif
227*543adbedSBen Gras }
228*543adbedSBen Gras
229*543adbedSBen Gras void
lafe_cleanup_exclusions(struct lafe_matching ** matching)230*543adbedSBen Gras lafe_cleanup_exclusions(struct lafe_matching **matching)
231*543adbedSBen Gras {
232*543adbedSBen Gras struct match *p, *q;
233*543adbedSBen Gras
234*543adbedSBen Gras if (*matching == NULL)
235*543adbedSBen Gras return;
236*543adbedSBen Gras
237*543adbedSBen Gras for (p = (*matching)->inclusions; p != NULL; ) {
238*543adbedSBen Gras q = p;
239*543adbedSBen Gras p = p->next;
240*543adbedSBen Gras free(q);
241*543adbedSBen Gras }
242*543adbedSBen Gras
243*543adbedSBen Gras for (p = (*matching)->exclusions; p != NULL; ) {
244*543adbedSBen Gras q = p;
245*543adbedSBen Gras p = p->next;
246*543adbedSBen Gras free(q);
247*543adbedSBen Gras }
248*543adbedSBen Gras
249*543adbedSBen Gras free(*matching);
250*543adbedSBen Gras *matching = NULL;
251*543adbedSBen Gras }
252*543adbedSBen Gras
253*543adbedSBen Gras static void
initialize_matching(struct lafe_matching ** matching)254*543adbedSBen Gras initialize_matching(struct lafe_matching **matching)
255*543adbedSBen Gras {
256*543adbedSBen Gras *matching = calloc(sizeof(**matching), 1);
257*543adbedSBen Gras if (*matching == NULL)
258*543adbedSBen Gras lafe_errc(1, errno, "No memory");
259*543adbedSBen Gras }
260*543adbedSBen Gras
261*543adbedSBen Gras int
lafe_unmatched_inclusions(struct lafe_matching * matching)262*543adbedSBen Gras lafe_unmatched_inclusions(struct lafe_matching *matching)
263*543adbedSBen Gras {
264*543adbedSBen Gras
265*543adbedSBen Gras if (matching == NULL)
266*543adbedSBen Gras return (0);
267*543adbedSBen Gras return (matching->inclusions_unmatched_count);
268*543adbedSBen Gras }
269*543adbedSBen Gras
270*543adbedSBen Gras int
lafe_unmatched_inclusions_warn(struct lafe_matching * matching,const char * msg)271*543adbedSBen Gras lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg)
272*543adbedSBen Gras {
273*543adbedSBen Gras struct match *p;
274*543adbedSBen Gras
275*543adbedSBen Gras if (matching == NULL)
276*543adbedSBen Gras return (0);
277*543adbedSBen Gras
278*543adbedSBen Gras for (p = matching->inclusions; p != NULL; p = p->next) {
279*543adbedSBen Gras if (p->matches == 0)
280*543adbedSBen Gras lafe_warnc(0, "%s: %s", p->pattern, msg);
281*543adbedSBen Gras }
282*543adbedSBen Gras
283*543adbedSBen Gras return (matching->inclusions_unmatched_count);
284*543adbedSBen Gras }
285