1 /*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Guido van Rossum.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32 /* check-sources:disable-copyright-check */
33
34 /* OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert */
35
36 /*
37 * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
38 * Compares a filename or pathname to a pattern.
39 */
40
41 /* Define SYS to use the system fnmatch() rather than ours */
42 /* #define SYS 1 */
43
44 #include "include/bareos.h"
45 #ifdef SYS
46 # include <fnmatch.h>
47 #else
48 # include "fnmatch.h"
49 #endif
50
51 #undef EOS
52 #define EOS '\0'
53
54 #define RANGE_MATCH 1
55 #define RANGE_NOMATCH 0
56 #define RANGE_ERROR (-1)
57
58 /* Limit of recursion during matching attempts. */
59 #define FNM_MAX_RECUR 64
60
61 #define ISSET(x, y) ((x) & (y))
62 #define FOLD(c) ((flags & FNM_CASEFOLD) && B_ISUPPER(c) ? tolower(c) : (c))
63
64 static int Rangematch(const char*, char, int, char**);
65 static int r_fnmatch(const char*, const char*, int, int);
66
67 #ifdef SYS
xfnmatch(const char * pattern,const char * string,int flags)68 int xfnmatch(const char* pattern, const char* string, int flags)
69 #else
70 int fnmatch(const char* pattern, const char* string, int flags)
71 #endif
72 {
73 int e;
74
75 e = r_fnmatch(pattern, string, flags, FNM_MAX_RECUR);
76 if (e == -1) { /* Too much recursion */
77 e = FNM_NOMATCH;
78 }
79 return (e);
80 }
81
r_fnmatch(const char * pattern,const char * string,int flags,int recur)82 static int r_fnmatch(const char* pattern,
83 const char* string,
84 int flags,
85 int recur)
86 {
87 const char* stringstart;
88 char* newp;
89 char c, test;
90 int e;
91
92 if (recur-- <= 0) { return (-1); }
93
94 stringstart = string;
95 for (;;) {
96 switch (c = *pattern++) {
97 case EOS:
98 if (ISSET(flags, FNM_LEADING_DIR) && IsPathSeparator(*string))
99 return (0);
100 return (*string == EOS ? 0 : FNM_NOMATCH);
101 case '?':
102 if (*string == EOS) return (FNM_NOMATCH);
103 if (IsPathSeparator(*string) && ISSET(flags, FNM_PATHNAME))
104 return (FNM_NOMATCH);
105 if (*string == '.' && ISSET(flags, FNM_PERIOD)
106 && (string == stringstart
107 || (ISSET(flags, FNM_PATHNAME)
108 && IsPathSeparator(*(string - 1)))))
109 return (FNM_NOMATCH);
110 ++string;
111 break;
112 case '*':
113 c = *pattern;
114 /* Collapse multiple stars. */
115 while (c == '*') { c = *++pattern; }
116
117 if (*string == '.' && ISSET(flags, FNM_PERIOD)
118 && (string == stringstart
119 || (ISSET(flags, FNM_PATHNAME)
120 && IsPathSeparator(*(string - 1))))) {
121 return (FNM_NOMATCH);
122 }
123
124 /* Optimize for pattern with * at end or before /. */
125 if (c == EOS) {
126 if (ISSET(flags, FNM_PATHNAME)) {
127 return (ISSET(flags, FNM_LEADING_DIR) || strchr(string, '/') == NULL
128 ? 0
129 : FNM_NOMATCH);
130 } else {
131 return (0);
132 }
133 } else if (IsPathSeparator(c) && ISSET(flags, FNM_PATHNAME)) {
134 if ((string = strchr(string, '/')) == NULL) return (FNM_NOMATCH);
135 break;
136 }
137
138 /* General case, use recursion. */
139 while ((test = *string) != EOS) {
140 e = r_fnmatch(pattern, string, flags & ~FNM_PERIOD, recur);
141 if (e != FNM_NOMATCH) { /* can be NOMATCH, -1 or MATCH */
142 return (e);
143 }
144 if (test == '/' && ISSET(flags, FNM_PATHNAME)) { break; }
145 ++string;
146 }
147 return (FNM_NOMATCH);
148 case '[':
149 if (*string == EOS) return (FNM_NOMATCH);
150 if (IsPathSeparator(*string) && ISSET(flags, FNM_PATHNAME))
151 return (FNM_NOMATCH);
152 if (*string == '.' && ISSET(flags, FNM_PERIOD)
153 && (string == stringstart
154 || (ISSET(flags, FNM_PATHNAME)
155 && IsPathSeparator(*(string - 1)))))
156 return (FNM_NOMATCH);
157
158 switch (Rangematch(pattern, *string, flags, &newp)) {
159 case RANGE_ERROR:
160 /* not a good range, treat as normal text */
161 goto normal;
162 case RANGE_MATCH:
163 pattern = newp;
164 break;
165 case RANGE_NOMATCH:
166 return (FNM_NOMATCH);
167 }
168 ++string;
169 break;
170
171 case '\\':
172 if (!ISSET(flags, FNM_NOESCAPE)) {
173 if ((c = *pattern++) == EOS) {
174 c = '\\';
175 --pattern;
176 }
177 }
178 /* FALLTHROUGH */
179 default:
180 normal:
181 if (FOLD(c) != FOLD(*string)) { return (FNM_NOMATCH); }
182 ++string;
183 break;
184 }
185 }
186 /* NOTREACHED */
187 }
188
Rangematch(const char * pattern,char test,int flags,char ** newp)189 static int Rangematch(const char* pattern, char test, int flags, char** newp)
190 {
191 int negate, ok;
192 char c, c2;
193
194 /*
195 * A bracket expression starting with an unquoted circumflex
196 * character produces unspecified results (IEEE 1003.2-1992,
197 * 3.13.2). This implementation treats it like '!', for
198 * consistency with the regular expression syntax.
199 * J.T. Conklin (conklin@ngai.kaleida.com)
200 */
201 if ((negate = (*pattern == '!' || *pattern == '^'))) ++pattern;
202
203 test = FOLD(test);
204
205 /*
206 * A right bracket shall lose its special meaning and represent
207 * itself in a bracket expression if it occurs first in the list.
208 * -- POSIX.2 2.8.3.2
209 */
210 ok = 0;
211 c = *pattern++;
212 do {
213 if (c == '\\' && !ISSET(flags, FNM_NOESCAPE)) c = *pattern++;
214 if (c == EOS) return (RANGE_ERROR);
215 if (c == '/' && ISSET(flags, FNM_PATHNAME)) return (RANGE_NOMATCH);
216 c = FOLD(c);
217 if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
218 pattern += 2;
219 if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE)) c2 = *pattern++;
220 if (c2 == EOS) return (RANGE_ERROR);
221 c2 = FOLD(c2);
222 if (c <= test && test <= c2) ok = 1;
223 } else if (c == test)
224 ok = 1;
225 } while ((c = *pattern++) != ']');
226
227 *newp = (char*)pattern;
228 return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
229 }
230