1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This code is MKS code ported to Solaris originally with minimum
29 * modifications so that upgrades from MKS would readily integrate.
30 * The MKS basis for this modification was:
31 *
32 * $Id: glob.c 1.31 1994/04/07 22:50:43 mark
33 *
34 * Additional modifications have been made to this code to make it
35 * 64-bit clean.
36 */
37
38 /*
39 * glob, globfree -- POSIX.2 compatible file name expansion routines.
40 *
41 * Copyright 1985, 1991 by Mortice Kern Systems Inc. All rights reserved.
42 *
43 * Written by Eric Gisin.
44 */
45
46 #pragma ident "%Z%%M% %I% %E% SMI"
47
48 #pragma weak _glob = glob
49 #pragma weak _globfree = globfree
50
51 #include "lint.h"
52 #include <stdio.h>
53 #include <unistd.h>
54 #include <limits.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <dirent.h>
58 #include <sys/stat.h>
59 #include <glob.h>
60 #include <errno.h>
61 #include <fnmatch.h>
62
63 #define GLOB__CHECK 0x80 /* stat generated paths */
64
65 #define INITIAL 8 /* initial pathv allocation */
66 #define NULLCPP ((char **)0) /* Null char ** */
67 #define NAME_MAX 1024 /* something large */
68
69 static int globit(size_t, const char *, glob_t *, int,
70 int (*)(const char *, int), char **);
71 static int pstrcmp(const void *, const void *);
72 static int append(glob_t *, const char *);
73
74 /*
75 * Free all space consumed by glob.
76 */
77 void
78 globfree(glob_t *gp)
79 {
80 size_t i;
81
82 if (gp->gl_pathv == 0)
83 return;
84
85 for (i = gp->gl_offs; i < gp->gl_offs + gp->gl_pathc; ++i)
86 free(gp->gl_pathv[i]);
87 free((void *)gp->gl_pathv);
88
89 gp->gl_pathc = 0;
90 gp->gl_pathv = NULLCPP;
91 }
92
93 /*
94 * Do filename expansion.
95 */
96 int
97 glob(const char *pattern, int flags,
98 int (*errfn)(const char *, int), glob_t *gp)
99 {
100 int rv;
101 size_t i;
102 size_t ipathc;
103 char *path;
104
105 if ((flags & GLOB_DOOFFS) == 0)
106 gp->gl_offs = 0;
107
108 if (!(flags & GLOB_APPEND)) {
109 gp->gl_pathc = 0;
110 gp->gl_pathn = gp->gl_offs + INITIAL;
111 gp->gl_pathv = (char **)malloc(sizeof (char *) * gp->gl_pathn);
112
113 if (gp->gl_pathv == NULLCPP)
114 return (GLOB_NOSPACE);
115 gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
116
117 for (i = 0; i < gp->gl_offs; ++i)
118 gp->gl_pathv[i] = NULL;
119 }
120
121 if ((path = malloc(strlen(pattern)+1)) == NULL)
122 return (GLOB_NOSPACE);
123
124 ipathc = gp->gl_pathc;
125 rv = globit(0, pattern, gp, flags, errfn, &path);
126
127 if (rv == GLOB_ABORTED) {
128 /*
129 * User's error function returned non-zero, or GLOB_ERR was
130 * set, and we encountered a directory we couldn't search.
131 */
132 free(path);
133 return (GLOB_ABORTED);
134 }
135
136 i = gp->gl_pathc - ipathc;
137 if (i >= 1 && !(flags & GLOB_NOSORT)) {
138 qsort((char *)(gp->gl_pathp+ipathc), i, sizeof (char *),
139 pstrcmp);
140 }
141 if (i == 0) {
142 if (flags & GLOB_NOCHECK)
143 (void) append(gp, pattern);
144 else
145 rv = GLOB_NOMATCH;
146 }
147 gp->gl_pathp[gp->gl_pathc] = NULL;
148 free(path);
149
150 return (rv);
151 }
152
153
154 /*
155 * Recursive routine to match glob pattern, and walk directories.
156 */
157 int
158 globit(size_t dend, const char *sp, glob_t *gp, int flags,
159 int (*errfn)(const char *, int), char **path)
160 {
161 size_t n;
162 size_t m;
163 ssize_t end = 0; /* end of expanded directory */
164 char *pat = (char *)sp; /* pattern component */
165 char *dp = (*path) + dend;
166 int expand = 0; /* path has pattern */
167 char *cp;
168 struct stat64 sb;
169 DIR *dirp;
170 struct dirent64 *d;
171 int err;
172
173 for (;;)
174 switch (*dp++ = *(unsigned char *)sp++) {
175 case '\0': /* end of source path */
176 if (expand)
177 goto Expand;
178 else {
179 if (!(flags & GLOB_NOCHECK) ||
180 flags & (GLOB__CHECK|GLOB_MARK))
181 if (stat64(*path, &sb) < 0) {
182 return (0);
183 }
184 if (flags & GLOB_MARK && S_ISDIR(sb.st_mode)) {
185 *dp = '\0';
186 *--dp = '/';
187 }
188 if (append(gp, *path) < 0) {
189 return (GLOB_NOSPACE);
190 }
191 return (0);
192 }
193 /*NOTREACHED*/
194
195 case '*':
196 case '?':
197 case '[':
198 case '\\':
199 ++expand;
200 break;
201
202 case '/':
203 if (expand)
204 goto Expand;
205 end = dp - *path;
206 pat = (char *)sp;
207 break;
208
209 Expand:
210 /* determine directory and open it */
211 (*path)[end] = '\0';
212 dirp = opendir(**path == '\0' ? "." : *path);
213 if (dirp == NULL) {
214 if (errfn != 0 && errfn(*path, errno) != 0 ||
215 flags&GLOB_ERR) {
216 return (GLOB_ABORTED);
217 }
218 return (0);
219 }
220
221 /* extract pattern component */
222 n = sp - pat;
223 if ((cp = malloc(n)) == NULL) {
224 (void) closedir(dirp);
225 return (GLOB_NOSPACE);
226 }
227 pat = memcpy(cp, pat, n);
228 pat[n-1] = '\0';
229 if (*--sp != '\0')
230 flags |= GLOB__CHECK;
231
232 /* expand path to max. expansion */
233 n = dp - *path;
234 *path = realloc(*path,
235 strlen(*path) + NAME_MAX + strlen(sp) + 1);
236 if (*path == NULL) {
237 (void) closedir(dirp);
238 free(pat);
239 return (GLOB_NOSPACE);
240 }
241 dp = (*path) + n;
242
243 /* read directory and match entries */
244 err = 0;
245 while ((d = readdir64(dirp)) != NULL) {
246 cp = d->d_name;
247 if ((flags&GLOB_NOESCAPE)
248 ? fnmatch(pat, cp, FNM_PERIOD|FNM_NOESCAPE)
249 : fnmatch(pat, cp, FNM_PERIOD))
250 continue;
251
252 n = strlen(cp);
253 (void) memcpy((*path) + end, cp, n);
254 m = dp - *path;
255 err = globit(end+n, sp, gp, flags, errfn, path);
256 dp = (*path) + m; /* globit can move path */
257 if (err != 0)
258 break;
259 }
260
261 (void) closedir(dirp);
262 free(pat);
263 return (err);
264 }
265 /* NOTREACHED */
266 }
267
268 /*
269 * Comparison routine for two name arguments, called by qsort.
270 */
271 int
272 pstrcmp(const void *npp1, const void *npp2)
273 {
274 return (strcoll(*(char **)npp1, *(char **)npp2));
275 }
276
277 /*
278 * Add a new matched filename to the glob_t structure, increasing the
279 * size of that array, as required.
280 */
281 int
282 append(glob_t *gp, const char *str)
283 {
284 char *cp;
285
286 if ((cp = malloc(strlen(str)+1)) == NULL)
287 return (GLOB_NOSPACE);
288 gp->gl_pathp[gp->gl_pathc++] = strcpy(cp, str);
289
290 if ((gp->gl_pathc + gp->gl_offs) >= gp->gl_pathn) {
291 gp->gl_pathn *= 2;
292 gp->gl_pathv = (char **)realloc((void *)gp->gl_pathv,
293 gp->gl_pathn * sizeof (char *));
294 if (gp->gl_pathv == NULLCPP)
295 return (GLOB_NOSPACE);
296 gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
297 }
298 return (0);
299 }
|
1 /*
2 * Copyright (c) 2013 Gary Mills
3 */
4 /* $OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
5 /*
6 * Copyright (c) 1989, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Guido van Rossum.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 /*
38 * glob(3) -- a superset of the one defined in POSIX 1003.2.
39 *
40 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
41 *
42 * Optional extra services, controlled by flags not defined by POSIX:
43 *
44 * GLOB_QUOTE:
45 * Escaping convention: \ inhibits any special meaning the following
46 * character might have (except \ at end of string is retained).
47 * GLOB_MAGCHAR:
48 * Set in gl_flags if pattern contained a globbing character.
49 * GLOB_NOMAGIC:
50 * Same as GLOB_NOCHECK, but it will only append pattern if it did
51 * not contain any magic characters. [Used in csh style globbing]
52 * GLOB_ALTDIRFUNC:
53 * Use alternately specified directory access functions.
54 * GLOB_TILDE:
55 * expand ~user/foo to the /home/dir/of/user/foo
56 * GLOB_BRACE:
57 * expand {1,2}{a,b} to 1a 1b 2a 2b
58 * gl_matchc:
59 * Number of matches in the current invocation of glob.
60 */
61
62 #pragma weak _glob = glob
63 #pragma weak __glob_ext = _glob_ext
64 #pragma weak _globfree = globfree
65 #pragma weak __globfree_ext = _globfree_ext
66
67 #include "lint.h"
68
69 #include <sys/param.h>
70 #include <sys/stat.h>
71
72 #include <ctype.h>
73 #include <dirent.h>
74 #include <errno.h>
75 #define _GLOB_LIBC
76 #include <glob.h>
77 #undef _GLOB_LIBC
78 #include <limits.h>
79 #include <pwd.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <wchar.h>
85 #include <wctype.h>
86
87 #define DOLLAR '$'
88 #define DOT '.'
89 #define EOS '\0'
90 #define LBRACKET '['
91 #define NOT '!'
92 #define QUESTION '?'
93 #define QUOTE '\\'
94 #define RANGE '-'
95 #define RBRACKET ']'
96 #define SEP '/'
97 #define STAR '*'
98 #define TILDE '~'
99 #define UNDERSCORE '_'
100 #define LBRACE '{'
101 #define RBRACE '}'
102 #define SLASH '/'
103 #define COMMA ','
104 #define COLON ':'
105
106 #define M_QUOTE 0x800000
107 #define M_PROTECT 0x400000
108
109 typedef struct wcat {
110 wchar_t w_wc;
111 uint_t w_at;
112 } wcat_t;
113
114 #define M_ALL '*' /* Plus M_QUOTE */
115 #define M_END ']' /* Plus M_QUOTE */
116 #define M_NOT '!' /* Plus M_QUOTE */
117 #define M_ONE '?' /* Plus M_QUOTE */
118 #define M_RNG '-' /* Plus M_QUOTE */
119 #define M_SET '[' /* Plus M_QUOTE */
120 #define M_CLASS ':' /* Plus M_QUOTE */
121 #define ismeta(c) (((c).w_at&M_QUOTE) != 0)
122
123 #define GLOB_LIMIT_MALLOC 65536
124 #define GLOB_LIMIT_STAT 2048
125 #define GLOB_LIMIT_READDIR 16384
126
127 /* Limit of recursion during matching attempts. */
128 #define GLOB_LIMIT_RECUR 64
129
130 struct glob_lim {
131 size_t glim_malloc;
132 size_t glim_stat;
133 size_t glim_readdir;
134 };
135
136 struct glob_path_stat {
137 char *gps_path;
138 struct stat *gps_stat;
139 };
140
141 static int compare(const void *, const void *);
142 static int compare_gps(const void *, const void *);
143 static int g_Ctoc(const wcat_t *, char *, uint_t);
144 static int g_lstat(wcat_t *, struct stat *, glob_t *);
145 static DIR *g_opendir(wcat_t *, glob_t *);
146 static wcat_t *g_strchr(const wcat_t *, wchar_t);
147 static int g_stat(wcat_t *, struct stat *, glob_t *);
148 static int glob_com(const char *, int, int (*)(const char *, int),
149 glob_t *);
150 static int glob0(const wcat_t *, glob_t *, struct glob_lim *,
151 int (*)(const char *, int));
152 static int glob1(wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
153 int (*)(const char *, int));
154 static int glob2(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
155 wcat_t *, glob_t *, struct glob_lim *,
156 int (*)(const char *, int));
157 static int glob3(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
158 wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
159 int (*)(const char *, int));
160 static int globextend(const wcat_t *, glob_t *, struct glob_lim *,
161 struct stat *);
162 static
163 const wcat_t *globtilde(const wcat_t *, wcat_t *, size_t, glob_t *);
164 static int globexp1(const wcat_t *, glob_t *, struct glob_lim *,
165 int (*)(const char *, int));
166 static int globexp2(const wcat_t *, const wcat_t *, glob_t *,
167 struct glob_lim *, int (*)(const char *, int));
168 static int match(wcat_t *, wcat_t *, wcat_t *, int);
169 static void globfree_com(glob_t *);
170 #ifdef DEBUG
171 static void qprintf(const char *, wcat_t *);
172 #endif
173
174 /* glob() function with legacy glob structure */
175 int
176 glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
177 glob_t *pglob)
178 {
179 /* Only POSIX flags allowed */
180 if ((flags & ~GLOB_POSIX) != 0)
181 return (GLOB_NOMATCH);
182
183 return (glob_com(pattern, flags, errfunc, pglob));
184 }
185
186 /* Extended glob() function, selected by #pragma redefine_extname in glob.h */
187 int
188 _glob_ext(const char *pattern, int flags, int (*errfunc)(const char *, int),
189 glob_t *pglob)
190 {
191 return (glob_com(pattern, flags, errfunc, pglob));
192 }
193
194 static int
195 glob_com(const char *pattern, int flags, int (*errfunc)(const char *, int),
196 glob_t *pglob)
197 {
198 const char *patnext;
199 int n;
200 size_t patlen;
201 wchar_t c;
202 wcat_t *bufnext, *bufend, patbuf[MAXPATHLEN];
203 struct glob_lim limit = { 0, 0, 0 };
204
205 if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX)
206 return (GLOB_NOMATCH);
207
208 patnext = pattern;
209 if (!(flags & GLOB_APPEND)) {
210 pglob->gl_pathc = 0;
211 pglob->gl_pathv = NULL;
212 if ((flags & GLOB_KEEPSTAT) != 0)
213 pglob->gl_statv = NULL;
214 if (!(flags & GLOB_DOOFFS))
215 pglob->gl_offs = 0;
216 }
217 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
218 pglob->gl_matchc = 0;
219
220 if (pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
221 pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
222 return (GLOB_NOSPACE);
223
224 bufnext = patbuf;
225 bufend = bufnext + MAXPATHLEN - 1;
226 patlen += 1;
227 if (flags & GLOB_NOESCAPE) {
228 while (bufnext < bufend) {
229 if ((n = mbtowc(&c, patnext, patlen)) > 0) {
230 patnext += n;
231 patlen -= n;
232 bufnext->w_at = 0;
233 (bufnext++)->w_wc = c;
234 } else if (n == 0) {
235 break;
236 } else {
237 return (GLOB_NOMATCH);
238 }
239 }
240 } else {
241 /* Protect the quoted characters. */
242 while (bufnext < bufend) {
243 if ((n = mbtowc(&c, patnext, patlen)) > 0) {
244 patnext += n;
245 patlen -= n;
246 if (c == QUOTE) {
247 n = mbtowc(&c, patnext, patlen);
248 if (n < 0)
249 return (GLOB_NOMATCH);
250 if (n > 0) {
251 patnext += n;
252 patlen -= n;
253 }
254 if (n == 0)
255 c = QUOTE;
256 bufnext->w_at = M_PROTECT;
257 (bufnext++)->w_wc = c;
258 } else {
259 bufnext->w_at = 0;
260 (bufnext++)->w_wc = c;
261 }
262 } else if (n == 0) {
263 break;
264 } else {
265 return (GLOB_NOMATCH);
266 }
267 }
268 }
269 bufnext->w_at = 0;
270 bufnext->w_wc = EOS;
271
272 if (flags & GLOB_BRACE)
273 return (globexp1(patbuf, pglob, &limit, errfunc));
274 else
275 return (glob0(patbuf, pglob, &limit, errfunc));
276 }
277
278 /*
279 * Expand recursively a glob {} pattern. When there is no more expansion
280 * invoke the standard globbing routine to glob the rest of the magic
281 * characters
282 */
283 static int
284 globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
285 int (*errfunc)(const char *, int))
286 {
287 const wcat_t *ptr = pattern;
288
289 /* Protect a single {}, for find(1), like csh */
290 if (pattern[0].w_wc == LBRACE && pattern[1].w_wc == RBRACE &&
291 pattern[2].w_wc == EOS)
292 return (glob0(pattern, pglob, limitp, errfunc));
293
294 if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL)
295 return (globexp2(ptr, pattern, pglob, limitp, errfunc));
296
297 return (glob0(pattern, pglob, limitp, errfunc));
298 }
299
300
301 /*
302 * Recursive brace globbing helper. Tries to expand a single brace.
303 * If it succeeds then it invokes globexp1 with the new pattern.
304 * If it fails then it tries to glob the rest of the pattern and returns.
305 */
306 static int
307 globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob,
308 struct glob_lim *limitp, int (*errfunc)(const char *, int))
309 {
310 int i, rv;
311 wcat_t *lm, *ls;
312 const wcat_t *pe, *pm, *pl;
313 wcat_t patbuf[MAXPATHLEN];
314
315 /* copy part up to the brace */
316 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
317 ;
318 lm->w_at = 0;
319 lm->w_wc = EOS;
320 ls = lm;
321
322 /* Find the balanced brace */
323 for (i = 0, pe = ++ptr; pe->w_wc != EOS; pe++)
324 if (pe->w_wc == LBRACKET) {
325 /* Ignore everything between [] */
326 for (pm = pe++; pe->w_wc != RBRACKET &&
327 pe->w_wc != EOS; pe++)
328 ;
329 if (pe->w_wc == EOS) {
330 /*
331 * We could not find a matching RBRACKET.
332 * Ignore and just look for RBRACE
333 */
334 pe = pm;
335 }
336 } else if (pe->w_wc == LBRACE) {
337 i++;
338 } else if (pe->w_wc == RBRACE) {
339 if (i == 0)
340 break;
341 i--;
342 }
343
344 /* Non matching braces; just glob the pattern */
345 if (i != 0 || pe->w_wc == EOS)
346 return (glob0(patbuf, pglob, limitp, errfunc));
347
348 for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
349 switch (pm->w_wc) {
350 case LBRACKET:
351 /* Ignore everything between [] */
352 for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS;
353 pm++)
354 ;
355 if (pm->w_wc == EOS) {
356 /*
357 * We could not find a matching RBRACKET.
358 * Ignore and just look for RBRACE
359 */
360 pm = pl;
361 }
362 break;
363
364 case LBRACE:
365 i++;
366 break;
367
368 case RBRACE:
369 if (i) {
370 i--;
371 break;
372 }
373 /* FALLTHROUGH */
374 case COMMA:
375 if (i && pm->w_wc == COMMA)
376 break;
377 else {
378 /* Append the current string */
379 for (lm = ls; (pl < pm); *lm++ = *pl++)
380 ;
381
382 /*
383 * Append the rest of the pattern after the
384 * closing brace
385 */
386 for (pl = pe + 1;
387 (*lm++ = *pl++).w_wc != EOS; /* */)
388 ;
389
390 /* Expand the current pattern */
391 rv = globexp1(patbuf, pglob, limitp, errfunc);
392 if (rv && rv != GLOB_NOMATCH)
393 return (rv);
394
395 /* move after the comma, to the next string */
396 pl = pm + 1;
397 }
398 break;
399
400 default:
401 break;
402 }
403 }
404 return (0);
405 }
406
407
408
409 /*
410 * expand tilde from the passwd file.
411 */
412 static const wcat_t *
413 globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len,
414 glob_t *pglob)
415 {
416 struct passwd *pwd;
417 char *h;
418 const wcat_t *p;
419 wcat_t *b, *eb, *q;
420 int n;
421 size_t lenh;
422 wchar_t c;
423
424 if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
425 return (pattern);
426
427 /* Copy up to the end of the string or / */
428 eb = &patbuf[patbuf_len - 1];
429 for (p = pattern + 1, q = patbuf;
430 q < eb && p->w_wc != EOS && p->w_wc != SLASH; *q++ = *p++)
431 ;
432
433 q->w_at = 0;
434 q->w_wc = EOS;
435
436 /* What to do if patbuf is full? */
437
438 if (patbuf[0].w_wc == EOS) {
439 /*
440 * handle a plain ~ or ~/ by expanding $HOME
441 * first and then trying the password file
442 */
443 if (issetugid() != 0)
444 return (pattern);
445 if ((h = getenv("HOME")) == NULL) {
446 if ((pwd = getpwuid(getuid())) == NULL)
447 return (pattern);
448 else
449 h = pwd->pw_dir;
450 }
451 } else {
452 /*
453 * Expand a ~user
454 */
455 if ((pwd = getpwnam((char *)patbuf)) == NULL)
456 return (pattern);
457 else
458 h = pwd->pw_dir;
459 }
460
461 /* Copy the home directory */
462 lenh = strlen(h) + 1;
463 for (b = patbuf; b < eb && *h != EOS; b++) {
464 if ((n = mbtowc(&c, h, lenh)) > 0) {
465 h += n;
466 lenh -= n;
467 b->w_at = 0;
468 b->w_wc = c;
469 } else if (n < 0) {
470 return (pattern);
471 } else {
472 break;
473 }
474 }
475
476 /* Append the rest of the pattern */
477 while (b < eb && (*b++ = *p++).w_wc != EOS)
478 ;
479 b->w_at = 0;
480 b->w_wc = EOS;
481
482 return (patbuf);
483 }
484
485 static int
486 g_charclass(const wcat_t **patternp, wcat_t **bufnextp)
487 {
488 const wcat_t *pattern = *patternp + 1;
489 wcat_t *bufnext = *bufnextp;
490 const wcat_t *colon;
491 char cbuf[MB_LEN_MAX + 32];
492 wctype_t cc;
493 size_t len;
494
495 if ((colon = g_strchr(pattern, COLON)) == NULL ||
496 colon[1].w_wc != RBRACKET)
497 return (1); /* not a character class */
498
499 len = (size_t)(colon - pattern);
500 if (len + MB_LEN_MAX + 1 > sizeof (cbuf))
501 return (-1); /* invalid character class */
502 {
503 wchar_t w;
504 const wcat_t *s1 = pattern;
505 char *s2 = cbuf;
506 size_t n = len;
507
508 /* Copy the string. */
509 while (n > 0) {
510 w = (s1++)->w_wc;
511 /* Character class names must be ASCII. */
512 if (iswascii(w)) {
513 n--;
514 *s2++ = w;
515 } else {
516 return (-1); /* invalid character class */
517 }
518 }
519 *s2 = EOS;
520 }
521 if ((cc = wctype(cbuf)) == 0)
522 return (-1); /* invalid character class */
523 bufnext->w_at = M_QUOTE;
524 (bufnext++)->w_wc = M_CLASS;
525 bufnext->w_at = 0;
526 (bufnext++)->w_wc = cc;
527 *bufnextp = bufnext;
528 *patternp += len + 3;
529
530 return (0);
531 }
532
533 /*
534 * The main glob() routine: compiles the pattern (optionally processing
535 * quotes), calls glob1() to do the real pattern matching, and finally
536 * sorts the list (unless unsorted operation is requested). Returns 0
537 * if things went well, nonzero if errors occurred. It is not an error
538 * to find no matches.
539 */
540 static int
541 glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
542 int (*errfunc)(const char *, int))
543 {
544 const wcat_t *qpatnext;
545 int err, oldpathc;
546 wchar_t c;
547 int a;
548 wcat_t *bufnext, patbuf[MAXPATHLEN];
549
550 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
551 oldpathc = pglob->gl_pathc;
552 bufnext = patbuf;
553
554 /*
555 * We don't need to check for buffer overflow any more.
556 * The pattern has already been copied to an internal buffer.
557 */
558 while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) {
559 switch (c) {
560 case LBRACKET:
561 if (a != 0) {
562 bufnext->w_at = a;
563 (bufnext++)->w_wc = c;
564 break;
565 }
566 a = qpatnext->w_at;
567 c = qpatnext->w_wc;
568 if (a == 0 && c == NOT)
569 ++qpatnext;
570 if (qpatnext->w_wc == EOS ||
571 g_strchr(qpatnext+1, RBRACKET) == NULL) {
572 bufnext->w_at = 0;
573 (bufnext++)->w_wc = LBRACKET;
574 if (a == 0 && c == NOT)
575 --qpatnext;
576 break;
577 }
578 bufnext->w_at = M_QUOTE;
579 (bufnext++)->w_wc = M_SET;
580 if (a == 0 && c == NOT) {
581 bufnext->w_at = M_QUOTE;
582 (bufnext++)->w_wc = M_NOT;
583 }
584 a = qpatnext->w_at;
585 c = (qpatnext++)->w_wc;
586 do {
587 if (a == 0 && c == LBRACKET &&
588 qpatnext->w_wc == COLON) {
589 do {
590 err = g_charclass(&qpatnext,
591 &bufnext);
592 if (err)
593 break;
594 a = qpatnext->w_at;
595 c = (qpatnext++)->w_wc;
596 } while (a == 0 && c == LBRACKET &&
597 qpatnext->w_wc == COLON);
598 if (err == -1 &&
599 !(pglob->gl_flags & GLOB_NOCHECK))
600 return (GLOB_NOMATCH);
601 if (a == 0 && c == RBRACKET)
602 break;
603 }
604 bufnext->w_at = a;
605 (bufnext++)->w_wc = c;
606 if (qpatnext->w_at == 0 &&
607 qpatnext->w_wc == RANGE) {
608 a = qpatnext[1].w_at;
609 c = qpatnext[1].w_wc;
610 if (qpatnext[1].w_at != 0 ||
611 qpatnext[1].w_wc != RBRACKET) {
612 bufnext->w_at = M_QUOTE;
613 (bufnext++)->w_wc = M_RNG;
614 bufnext->w_at = a;
615 (bufnext++)->w_wc = c;
616 qpatnext += 2;
617 }
618 }
619 a = qpatnext->w_at;
620 c = (qpatnext++)->w_wc;
621 } while (a != 0 || c != RBRACKET);
622 pglob->gl_flags |= GLOB_MAGCHAR;
623 bufnext->w_at = M_QUOTE;
624 (bufnext++)->w_wc = M_END;
625 break;
626 case QUESTION:
627 if (a != 0) {
628 bufnext->w_at = a;
629 (bufnext++)->w_wc = c;
630 break;
631 }
632 pglob->gl_flags |= GLOB_MAGCHAR;
633 bufnext->w_at = M_QUOTE;
634 (bufnext++)->w_wc = M_ONE;
635 break;
636 case STAR:
637 if (a != 0) {
638 bufnext->w_at = a;
639 (bufnext++)->w_wc = c;
640 break;
641 }
642 pglob->gl_flags |= GLOB_MAGCHAR;
643 /*
644 * collapse adjacent stars to one,
645 * to avoid exponential behavior
646 */
647 if (bufnext == patbuf ||
648 bufnext[-1].w_at != M_QUOTE ||
649 bufnext[-1].w_wc != M_ALL) {
650 bufnext->w_at = M_QUOTE;
651 (bufnext++)->w_wc = M_ALL;
652 }
653 break;
654 default:
655 bufnext->w_at = a;
656 (bufnext++)->w_wc = c;
657 break;
658 }
659 }
660 bufnext->w_at = 0;
661 bufnext->w_wc = EOS;
662 #ifdef DEBUG
663 qprintf("glob0:glob1:patbuf", patbuf);
664 #endif
665
666 if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp, errfunc))
667 != 0)
668 return (err);
669
670 /*
671 * If there was no match we are going to append the pattern
672 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
673 * and the pattern did not contain any magic characters
674 * GLOB_NOMAGIC is there just for compatibility with csh.
675 */
676 if (pglob->gl_pathc == oldpathc) {
677 if ((pglob->gl_flags & GLOB_NOCHECK) ||
678 ((pglob->gl_flags & GLOB_NOMAGIC) &&
679 !(pglob->gl_flags & GLOB_MAGCHAR)))
680 return (globextend(pattern, pglob, limitp, NULL));
681 else
682 return (GLOB_NOMATCH);
683 }
684 if (!(pglob->gl_flags & GLOB_NOSORT)) {
685 if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
686 /* Keep the paths and stat info synced during sort */
687 struct glob_path_stat *path_stat;
688 int i;
689 int n = pglob->gl_pathc - oldpathc;
690 int o = pglob->gl_offs + oldpathc;
691
692 if ((path_stat = calloc(n, sizeof (*path_stat))) ==
693 NULL)
694 return (GLOB_NOSPACE);
695 for (i = 0; i < n; i++) {
696 path_stat[i].gps_path = pglob->gl_pathv[o + i];
697 path_stat[i].gps_stat = pglob->gl_statv[o + i];
698 }
699 qsort(path_stat, n, sizeof (*path_stat), compare_gps);
700 for (i = 0; i < n; i++) {
701 pglob->gl_pathv[o + i] = path_stat[i].gps_path;
702 pglob->gl_statv[o + i] = path_stat[i].gps_stat;
703 }
704 free(path_stat);
705 } else {
706 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
707 pglob->gl_pathc - oldpathc, sizeof (char *),
708 compare);
709 }
710 }
711 return (0);
712 }
713
714 static int
715 compare(const void *p, const void *q)
716 {
717 return (strcmp(*(char **)p, *(char **)q));
718 }
719
720 static int
721 compare_gps(const void *_p, const void *_q)
722 {
723 const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
724 const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
725
726 return (strcmp(p->gps_path, q->gps_path));
727 }
728
729 static int
730 glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob,
731 struct glob_lim *limitp, int (*errfunc)(const char *, int))
732 {
733 wcat_t pathbuf[MAXPATHLEN];
734
735 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
736 if (pattern->w_wc == EOS)
737 return (0);
738 return (glob2(pathbuf, pathbuf+MAXPATHLEN-1,
739 pathbuf, pathbuf+MAXPATHLEN-1,
740 pattern, pattern_last, pglob, limitp, errfunc));
741 }
742
743 /*
744 * The functions glob2 and glob3 are mutually recursive; there is one level
745 * of recursion for each segment in the pattern that contains one or more
746 * meta characters.
747 */
748 static int
749 glob2(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
750 wcat_t *pathend_last, wcat_t *pattern, wcat_t *pattern_last,
751 glob_t *pglob, struct glob_lim *limitp, int (*errfunc)(const char *, int))
752 {
753 struct stat sb;
754 wcat_t *p, *q;
755 int anymeta;
756
757 /*
758 * Loop over pattern segments until end of pattern or until
759 * segment with meta character found.
760 */
761 for (anymeta = 0; ; ) {
762 if (pattern->w_wc == EOS) { /* End of pattern? */
763 pathend->w_at = 0;
764 pathend->w_wc = EOS;
765
766 if ((pglob->gl_flags & GLOB_LIMIT) &&
767 limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
768 errno = 0;
769 pathend->w_at = 0;
770 (pathend++)->w_wc = SEP;
771 pathend->w_at = 0;
772 pathend->w_wc = EOS;
773 return (GLOB_NOSPACE);
774 }
775 if (g_lstat(pathbuf, &sb, pglob))
776 return (0);
777
778 if (((pglob->gl_flags & GLOB_MARK) &&
779 (pathend[-1].w_at != 0 ||
780 pathend[-1].w_wc != SEP)) &&
781 (S_ISDIR(sb.st_mode) ||
782 (S_ISLNK(sb.st_mode) &&
783 (g_stat(pathbuf, &sb, pglob) == 0) &&
784 S_ISDIR(sb.st_mode)))) {
785 if (pathend+1 > pathend_last)
786 return (GLOB_NOSPACE);
787 pathend->w_at = 0;
788 (pathend++)->w_wc = SEP;
789 pathend->w_at = 0;
790 pathend->w_wc = EOS;
791 }
792 ++pglob->gl_matchc;
793 return (globextend(pathbuf, pglob, limitp, &sb));
794 }
795
796 /* Find end of next segment, copy tentatively to pathend. */
797 q = pathend;
798 p = pattern;
799 while (p->w_wc != EOS && p->w_wc != SEP) {
800 if (ismeta(*p))
801 anymeta = 1;
802 if (q+1 > pathend_last)
803 return (GLOB_NOSPACE);
804 *q++ = *p++;
805 }
806
807 if (!anymeta) { /* No expansion, do next segment. */
808 pathend = q;
809 pattern = p;
810 while (pattern->w_wc == SEP) {
811 if (pathend+1 > pathend_last)
812 return (GLOB_NOSPACE);
813 *pathend++ = *pattern++;
814 }
815 } else {
816 /* Need expansion, recurse. */
817 return (glob3(pathbuf, pathbuf_last, pathend,
818 pathend_last, pattern, p, pattern_last,
819 pglob, limitp, errfunc));
820 }
821 }
822 /* NOTREACHED */
823 }
824
825 static int
826 glob3(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
827 wcat_t *pathend_last, wcat_t *pattern, wcat_t *restpattern,
828 wcat_t *restpattern_last, glob_t *pglob, struct glob_lim *limitp,
829 int (*errfunc)(const char *, int))
830 {
831 struct dirent *dp;
832 DIR *dirp;
833 int err;
834 char buf[MAXPATHLEN];
835
836 /*
837 * The readdirfunc declaration can't be prototyped, because it is
838 * assigned, below, to two functions which are prototyped in glob.h
839 * and dirent.h as taking pointers to differently typed opaque
840 * structures.
841 */
842 struct dirent *(*readdirfunc)(void *);
843
844 if (pathend > pathend_last)
845 return (GLOB_NOSPACE);
846 pathend->w_at = 0;
847 pathend->w_wc = EOS;
848 errno = 0;
849
850 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
851 /* TODO: don't call for ENOENT or ENOTDIR? */
852 if (errfunc) {
853 if (g_Ctoc(pathbuf, buf, sizeof (buf)))
854 return (GLOB_ABORTED);
855 if (errfunc(buf, errno) ||
856 pglob->gl_flags & GLOB_ERR)
857 return (GLOB_ABORTED);
858 }
859 return (0);
860 }
861
862 err = 0;
863
864 /* Search directory for matching names. */
865 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
866 readdirfunc = pglob->gl_readdir;
867 else
868 readdirfunc = (struct dirent *(*)(void *))readdir;
869 while ((dp = (*readdirfunc)(dirp))) {
870 char *sc;
871 wcat_t *dc;
872 int n;
873 int lensc;
874 wchar_t w;
875
876 if ((pglob->gl_flags & GLOB_LIMIT) &&
877 limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
878 errno = 0;
879 pathend->w_at = 0;
880 (pathend++)->w_wc = SEP;
881 pathend->w_at = 0;
882 pathend->w_wc = EOS;
883 err = GLOB_NOSPACE;
884 break;
885 }
886
887 /* Initial DOT must be matched literally. */
888 if (dp->d_name[0] == DOT && pattern->w_wc != DOT)
889 continue;
890 dc = pathend;
891 sc = dp->d_name;
892 lensc = strlen(sc) + 1;
893 while (dc < pathend_last) {
894 if ((n = mbtowc(&w, sc, lensc)) <= 0) {
895 sc += 1;
896 lensc -= 1;
897 dc->w_at = 0;
898 dc->w_wc = EOS;
899 } else {
900 sc += n;
901 lensc -= n;
902 dc->w_at = 0;
903 dc->w_wc = w;
904 }
905 dc++;
906 if (n <= 0)
907 break;
908 }
909 if (dc >= pathend_last) {
910 dc->w_at = 0;
911 dc->w_wc = EOS;
912 err = GLOB_NOSPACE;
913 break;
914 }
915 if (n < 0) {
916 err = GLOB_NOMATCH;
917 break;
918 }
919
920 if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
921 pathend->w_at = 0;
922 pathend->w_wc = EOS;
923 continue;
924 }
925 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
926 restpattern, restpattern_last, pglob, limitp,
927 errfunc);
928 if (err)
929 break;
930 }
931
932 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
933 (*pglob->gl_closedir)(dirp);
934 else
935 (void) closedir(dirp);
936 return (err);
937 }
938
939
940 /*
941 * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
942 * add the new item, and update gl_pathc.
943 *
944 * This assumes the BSD realloc, which only copies the block when its size
945 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
946 * behavior.
947 *
948 * Return 0 if new item added, error code if memory couldn't be allocated.
949 *
950 * Invariant of the glob_t structure:
951 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
952 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
953 */
954 static int
955 globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp,
956 struct stat *sb)
957 {
958 char **pathv;
959 ssize_t i;
960 size_t newn, len;
961 char *copy = NULL;
962 const wcat_t *p;
963 struct stat **statv;
964 char junk[MB_LEN_MAX];
965 int n;
966
967 newn = 2 + pglob->gl_pathc + pglob->gl_offs;
968 if (pglob->gl_offs >= INT_MAX ||
969 pglob->gl_pathc >= INT_MAX ||
970 newn >= INT_MAX ||
971 SIZE_MAX / sizeof (*pathv) <= newn ||
972 SIZE_MAX / sizeof (*statv) <= newn) {
973 nospace:
974 for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); i++) {
975 if (pglob->gl_pathv && pglob->gl_pathv[i])
976 free(pglob->gl_pathv[i]);
977 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
978 pglob->gl_statv && pglob->gl_statv[i])
979 free(pglob->gl_statv[i]);
980 }
981 if (pglob->gl_pathv) {
982 free(pglob->gl_pathv);
983 pglob->gl_pathv = NULL;
984 }
985 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
986 pglob->gl_statv) {
987 free(pglob->gl_statv);
988 pglob->gl_statv = NULL;
989 }
990 return (GLOB_NOSPACE);
991 }
992
993 pathv = realloc(pglob->gl_pathv, newn * sizeof (*pathv));
994 if (pathv == NULL)
995 goto nospace;
996 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
997 /* first time around -- clear initial gl_offs items */
998 pathv += pglob->gl_offs;
999 for (i = pglob->gl_offs; --i >= 0; )
1000 *--pathv = NULL;
1001 }
1002 pglob->gl_pathv = pathv;
1003
1004 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
1005 statv = realloc(pglob->gl_statv, newn * sizeof (*statv));
1006 if (statv == NULL)
1007 goto nospace;
1008 if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
1009 /* first time around -- clear initial gl_offs items */
1010 statv += pglob->gl_offs;
1011 for (i = pglob->gl_offs; --i >= 0; )
1012 *--statv = NULL;
1013 }
1014 pglob->gl_statv = statv;
1015 if (sb == NULL)
1016 statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1017 else {
1018 limitp->glim_malloc += sizeof (**statv);
1019 if ((pglob->gl_flags & GLOB_LIMIT) &&
1020 limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
1021 errno = 0;
1022 return (GLOB_NOSPACE);
1023 }
1024 if ((statv[pglob->gl_offs + pglob->gl_pathc] =
1025 malloc(sizeof (**statv))) == NULL)
1026 goto copy_error;
1027 (void) memcpy(statv[pglob->gl_offs + pglob->gl_pathc],
1028 sb, sizeof (*sb));
1029 }
1030 statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
1031 }
1032
1033 len = MB_LEN_MAX;
1034 p = path;
1035 while ((n = wctomb(junk, p->w_wc)) > 0) {
1036 len += n;
1037 if ((p++)->w_wc == EOS)
1038 break;
1039 }
1040 if (n < 0)
1041 return (GLOB_NOMATCH);
1042
1043 limitp->glim_malloc += len;
1044 if ((copy = malloc(len)) != NULL) {
1045 if (g_Ctoc(path, copy, len)) {
1046 free(copy);
1047 return (GLOB_NOSPACE);
1048 }
1049 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1050 }
1051 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1052
1053 if ((pglob->gl_flags & GLOB_LIMIT) &&
1054 (newn * sizeof (*pathv)) + limitp->glim_malloc >
1055 GLOB_LIMIT_MALLOC) {
1056 errno = 0;
1057 return (GLOB_NOSPACE);
1058 }
1059 copy_error:
1060 return (copy == NULL ? GLOB_NOSPACE : 0);
1061 }
1062
1063
1064 /*
1065 * pattern matching function for filenames. Each occurrence of the *
1066 * pattern causes a recursion level.
1067 */
1068 static int
1069 match(wcat_t *name, wcat_t *pat, wcat_t *patend, int recur)
1070 {
1071 int ok, negate_range;
1072 wcat_t c, k;
1073
1074 if (recur-- == 0)
1075 return (1);
1076
1077 while (pat < patend) {
1078 c = *pat++;
1079 switch (c.w_wc) {
1080 case M_ALL:
1081 if (c.w_at != M_QUOTE) {
1082 k = *name++;
1083 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1084 return (0);
1085 break;
1086 }
1087 while (pat < patend && pat->w_at == M_QUOTE &&
1088 pat->w_wc == M_ALL)
1089 pat++; /* eat consecutive '*' */
1090 if (pat == patend)
1091 return (1);
1092 do {
1093 if (match(name, pat, patend, recur))
1094 return (1);
1095 } while ((name++)->w_wc != EOS);
1096 return (0);
1097 case M_ONE:
1098 if (c.w_at != M_QUOTE) {
1099 k = *name++;
1100 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1101 return (0);
1102 break;
1103 }
1104 if ((name++)->w_wc == EOS)
1105 return (0);
1106 break;
1107 case M_SET:
1108 if (c.w_at != M_QUOTE) {
1109 k = *name++;
1110 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1111 return (0);
1112 break;
1113 }
1114 ok = 0;
1115 if ((k = *name++).w_wc == EOS)
1116 return (0);
1117 if ((negate_range = (pat->w_at == M_QUOTE &&
1118 pat->w_wc == M_NOT)) != 0)
1119 ++pat;
1120 while (((c = *pat++).w_at != M_QUOTE) ||
1121 c.w_wc != M_END) {
1122 if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) {
1123 wcat_t cc;
1124
1125 cc.w_at = pat->w_at;
1126 cc.w_wc = pat->w_wc;
1127 if (iswctype(k.w_wc, cc.w_wc))
1128 ok = 1;
1129 ++pat;
1130 }
1131 if (pat->w_at == M_QUOTE &&
1132 pat->w_wc == M_RNG) {
1133 if (c.w_wc <= k.w_wc &&
1134 k.w_wc <= pat[1].w_wc)
1135 ok = 1;
1136 pat += 2;
1137 } else if (c.w_wc == k.w_wc)
1138 ok = 1;
1139 }
1140 if (ok == negate_range)
1141 return (0);
1142 break;
1143 default:
1144 k = *name++;
1145 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1146 return (0);
1147 break;
1148 }
1149 }
1150 return (name->w_wc == EOS);
1151 }
1152
1153 /* globfree() function with legacy glob structure */
1154 void
1155 globfree(glob_t *pglob)
1156 {
1157 /* Only POSIX flags allowed */
1158 pglob->gl_flags &= GLOB_POSIX;
1159
1160 globfree_com(pglob);
1161 }
1162
1163 /*
1164 * Extended globfree() function, selected by #pragma redefine_extname
1165 * in glob.h
1166 */
1167 void
1168 _globfree_ext(glob_t *pglob)
1169 {
1170 globfree_com(pglob);
1171 }
1172
1173 /* Free allocated data belonging to a glob_t structure. */
1174 void
1175 globfree_com(glob_t *pglob)
1176 {
1177 int i;
1178 char **pp;
1179
1180 if (pglob->gl_pathv != NULL) {
1181 pp = pglob->gl_pathv + pglob->gl_offs;
1182 for (i = pglob->gl_pathc; i--; ++pp)
1183 if (*pp)
1184 free(*pp);
1185 free(pglob->gl_pathv);
1186 pglob->gl_pathv = NULL;
1187 }
1188 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1189 pglob->gl_statv != NULL) {
1190 for (i = 0; i < pglob->gl_pathc; i++) {
1191 if (pglob->gl_statv[i] != NULL)
1192 free(pglob->gl_statv[i]);
1193 }
1194 free(pglob->gl_statv);
1195 pglob->gl_statv = NULL;
1196 }
1197 }
1198
1199 static DIR *
1200 g_opendir(wcat_t *str, glob_t *pglob)
1201 {
1202 char buf[MAXPATHLEN];
1203
1204 if (str->w_wc == EOS)
1205 (void) strlcpy(buf, ".", sizeof (buf));
1206 else {
1207 if (g_Ctoc(str, buf, sizeof (buf)))
1208 return (NULL);
1209 }
1210
1211 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1212 return ((*pglob->gl_opendir)(buf));
1213
1214 return (opendir(buf));
1215 }
1216
1217 static int
1218 g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1219 {
1220 char buf[MAXPATHLEN];
1221
1222 if (g_Ctoc(fn, buf, sizeof (buf)))
1223 return (-1);
1224 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1225 return ((*pglob->gl_lstat)(buf, sb));
1226 return (lstat(buf, sb));
1227 }
1228
1229 static int
1230 g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1231 {
1232 char buf[MAXPATHLEN];
1233
1234 if (g_Ctoc(fn, buf, sizeof (buf)))
1235 return (-1);
1236 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1237 return ((*pglob->gl_stat)(buf, sb));
1238 return (stat(buf, sb));
1239 }
1240
1241 static wcat_t *
1242 g_strchr(const wcat_t *str, wchar_t ch)
1243 {
1244 do {
1245 if (str->w_at == 0 && str->w_wc == ch)
1246 return ((wcat_t *)str);
1247 } while ((str++)->w_wc != EOS);
1248 return (NULL);
1249 }
1250
1251 static int
1252 g_Ctoc(const wcat_t *str, char *buf, uint_t len)
1253 {
1254 int n;
1255 wchar_t w;
1256
1257 while (len >= MB_LEN_MAX) {
1258 w = (str++)->w_wc;
1259 if ((n = wctomb(buf, w)) > 0) {
1260 len -= n;
1261 buf += n;
1262 }
1263 if (n < 0)
1264 break;
1265 if (w == EOS)
1266 return (0);
1267 }
1268 return (1);
1269 }
1270
1271 #ifdef DEBUG
1272 static void
1273 qprintf(const char *str, wcat_t *s)
1274 {
1275 wcat_t *p;
1276
1277 (void) printf("%s:\n", str);
1278 for (p = s; p->w_wc != EOS; p++)
1279 (void) printf("%wc", p->w_wc);
1280 (void) printf("\n");
1281 for (p = s; p->w_wc != EOS; p++)
1282 (void) printf("%c", p->w_at & M_PROTECT ? '"' : ' ');
1283 (void) printf("\n");
1284 for (p = s; p->w_wc != EOS; p++)
1285 (void) printf("%c", ismeta(*p) ? '_' : ' ');
1286 (void) printf("\n");
1287 }
1288 #endif
|