xref: /openbsd-src/lib/libc/gen/glob.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: glob.c,v 1.28 2009/02/18 15:50:27 millert Exp $ */
2 /*
3  * Copyright (c) 1989, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Guido van Rossum.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * glob(3) -- a superset of the one defined in POSIX 1003.2.
36  *
37  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
38  *
39  * Optional extra services, controlled by flags not defined by POSIX:
40  *
41  * GLOB_QUOTE:
42  *	Escaping convention: \ inhibits any special meaning the following
43  *	character might have (except \ at end of string is retained).
44  * GLOB_MAGCHAR:
45  *	Set in gl_flags if pattern contained a globbing character.
46  * GLOB_NOMAGIC:
47  *	Same as GLOB_NOCHECK, but it will only append pattern if it did
48  *	not contain any magic characters.  [Used in csh style globbing]
49  * GLOB_ALTDIRFUNC:
50  *	Use alternately specified directory access functions.
51  * GLOB_TILDE:
52  *	expand ~user/foo to the /home/dir/of/user/foo
53  * GLOB_BRACE:
54  *	expand {1,2}{a,b} to 1a 1b 2a 2b
55  * gl_matchc:
56  *	Number of matches in the current invocation of glob.
57  */
58 
59 #include <sys/param.h>
60 #include <sys/stat.h>
61 
62 #include <ctype.h>
63 #include <dirent.h>
64 #include <errno.h>
65 #include <glob.h>
66 #include <pwd.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71 
72 #include "charclass.h"
73 
74 #define	DOLLAR		'$'
75 #define	DOT		'.'
76 #define	EOS		'\0'
77 #define	LBRACKET	'['
78 #define	NOT		'!'
79 #define	QUESTION	'?'
80 #define	QUOTE		'\\'
81 #define	RANGE		'-'
82 #define	RBRACKET	']'
83 #define	SEP		'/'
84 #define	STAR		'*'
85 #define	TILDE		'~'
86 #define	UNDERSCORE	'_'
87 #define	LBRACE		'{'
88 #define	RBRACE		'}'
89 #define	SLASH		'/'
90 #define	COMMA		','
91 
92 #ifndef DEBUG
93 
94 #define	M_QUOTE		0x8000
95 #define	M_PROTECT	0x4000
96 #define	M_MASK		0xffff
97 #define	M_ASCII		0x00ff
98 
99 typedef u_short Char;
100 
101 #else
102 
103 #define	M_QUOTE		0x80
104 #define	M_PROTECT	0x40
105 #define	M_MASK		0xff
106 #define	M_ASCII		0x7f
107 
108 typedef char Char;
109 
110 #endif
111 
112 
113 #define	CHAR(c)		((Char)((c)&M_ASCII))
114 #define	META(c)		((Char)((c)|M_QUOTE))
115 #define	M_ALL		META('*')
116 #define	M_END		META(']')
117 #define	M_NOT		META('!')
118 #define	M_ONE		META('?')
119 #define	M_RNG		META('-')
120 #define	M_SET		META('[')
121 #define	M_CLASS		META(':')
122 #define	ismeta(c)	(((c)&M_QUOTE) != 0)
123 
124 
125 static int	 compare(const void *, const void *);
126 static int	 g_Ctoc(const Char *, char *, u_int);
127 static int	 g_lstat(Char *, struct stat *, glob_t *);
128 static DIR	*g_opendir(Char *, glob_t *);
129 static Char	*g_strchr(const Char *, int);
130 static int	 g_strncmp(const Char *, const char *, size_t);
131 static int	 g_stat(Char *, struct stat *, glob_t *);
132 static int	 glob0(const Char *, glob_t *);
133 static int	 glob1(Char *, Char *, glob_t *, size_t *);
134 static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
135 		    glob_t *, size_t *);
136 static int	 glob3(Char *, Char *, Char *, Char *, Char *,
137 		    Char *, Char *, glob_t *, size_t *);
138 static int	 globextend(const Char *, glob_t *, size_t *);
139 static const Char *
140 		 globtilde(const Char *, Char *, size_t, glob_t *);
141 static int	 globexp1(const Char *, glob_t *);
142 static int	 globexp2(const Char *, const Char *, glob_t *, int *);
143 static int	 match(Char *, Char *, Char *);
144 #ifdef DEBUG
145 static void	 qprintf(const char *, Char *);
146 #endif
147 
148 int
149 glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
150     glob_t *pglob)
151 {
152 	const u_char *patnext;
153 	int c;
154 	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
155 
156 	patnext = (u_char *) pattern;
157 	if (!(flags & GLOB_APPEND)) {
158 		pglob->gl_pathc = 0;
159 		pglob->gl_pathv = NULL;
160 		if (!(flags & GLOB_DOOFFS))
161 			pglob->gl_offs = 0;
162 	}
163 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
164 	pglob->gl_errfunc = errfunc;
165 	pglob->gl_matchc = 0;
166 
167 	bufnext = patbuf;
168 	bufend = bufnext + MAXPATHLEN - 1;
169 	if (flags & GLOB_NOESCAPE)
170 		while (bufnext < bufend && (c = *patnext++) != EOS)
171 			*bufnext++ = c;
172 	else {
173 		/* Protect the quoted characters. */
174 		while (bufnext < bufend && (c = *patnext++) != EOS)
175 			if (c == QUOTE) {
176 				if ((c = *patnext++) == EOS) {
177 					c = QUOTE;
178 					--patnext;
179 				}
180 				*bufnext++ = c | M_PROTECT;
181 			} else
182 				*bufnext++ = c;
183 	}
184 	*bufnext = EOS;
185 
186 	if (flags & GLOB_BRACE)
187 		return globexp1(patbuf, pglob);
188 	else
189 		return glob0(patbuf, pglob);
190 }
191 
192 /*
193  * Expand recursively a glob {} pattern. When there is no more expansion
194  * invoke the standard globbing routine to glob the rest of the magic
195  * characters
196  */
197 static int
198 globexp1(const Char *pattern, glob_t *pglob)
199 {
200 	const Char* ptr = pattern;
201 	int rv;
202 
203 	/* Protect a single {}, for find(1), like csh */
204 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
205 		return glob0(pattern, pglob);
206 
207 	while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
208 		if (!globexp2(ptr, pattern, pglob, &rv))
209 			return rv;
210 
211 	return glob0(pattern, pglob);
212 }
213 
214 
215 /*
216  * Recursive brace globbing helper. Tries to expand a single brace.
217  * If it succeeds then it invokes globexp1 with the new pattern.
218  * If it fails then it tries to glob the rest of the pattern and returns.
219  */
220 static int
221 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
222 {
223 	int     i;
224 	Char   *lm, *ls;
225 	const Char *pe, *pm, *pl;
226 	Char    patbuf[MAXPATHLEN];
227 
228 	/* copy part up to the brace */
229 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
230 		;
231 	*lm = EOS;
232 	ls = lm;
233 
234 	/* Find the balanced brace */
235 	for (i = 0, pe = ++ptr; *pe; pe++)
236 		if (*pe == LBRACKET) {
237 			/* Ignore everything between [] */
238 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
239 				;
240 			if (*pe == EOS) {
241 				/*
242 				 * We could not find a matching RBRACKET.
243 				 * Ignore and just look for RBRACE
244 				 */
245 				pe = pm;
246 			}
247 		} else if (*pe == LBRACE)
248 			i++;
249 		else if (*pe == RBRACE) {
250 			if (i == 0)
251 				break;
252 			i--;
253 		}
254 
255 	/* Non matching braces; just glob the pattern */
256 	if (i != 0 || *pe == EOS) {
257 		*rv = glob0(patbuf, pglob);
258 		return 0;
259 	}
260 
261 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
262 		switch (*pm) {
263 		case LBRACKET:
264 			/* Ignore everything between [] */
265 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
266 				;
267 			if (*pm == EOS) {
268 				/*
269 				 * We could not find a matching RBRACKET.
270 				 * Ignore and just look for RBRACE
271 				 */
272 				pm = pl;
273 			}
274 			break;
275 
276 		case LBRACE:
277 			i++;
278 			break;
279 
280 		case RBRACE:
281 			if (i) {
282 				i--;
283 				break;
284 			}
285 			/* FALLTHROUGH */
286 		case COMMA:
287 			if (i && *pm == COMMA)
288 				break;
289 			else {
290 				/* Append the current string */
291 				for (lm = ls; (pl < pm); *lm++ = *pl++)
292 					;
293 
294 				/*
295 				 * Append the rest of the pattern after the
296 				 * closing brace
297 				 */
298 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
299 					;
300 
301 				/* Expand the current pattern */
302 #ifdef DEBUG
303 				qprintf("globexp2:", patbuf);
304 #endif
305 				*rv = globexp1(patbuf, pglob);
306 
307 				/* move after the comma, to the next string */
308 				pl = pm + 1;
309 			}
310 			break;
311 
312 		default:
313 			break;
314 		}
315 	}
316 	*rv = 0;
317 	return 0;
318 }
319 
320 
321 
322 /*
323  * expand tilde from the passwd file.
324  */
325 static const Char *
326 globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
327 {
328 	struct passwd *pwd;
329 	char *h;
330 	const Char *p;
331 	Char *b, *eb;
332 
333 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
334 		return pattern;
335 
336 	/* Copy up to the end of the string or / */
337 	eb = &patbuf[patbuf_len - 1];
338 	for (p = pattern + 1, h = (char *) patbuf;
339 	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
340 		;
341 
342 	*h = EOS;
343 
344 #if 0
345 	if (h == (char *)eb)
346 		return what;
347 #endif
348 
349 	if (((char *) patbuf)[0] == EOS) {
350 		/*
351 		 * handle a plain ~ or ~/ by expanding $HOME
352 		 * first and then trying the password file
353 		 */
354 		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
355 			if ((pwd = getpwuid(getuid())) == NULL)
356 				return pattern;
357 			else
358 				h = pwd->pw_dir;
359 		}
360 	} else {
361 		/*
362 		 * Expand a ~user
363 		 */
364 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
365 			return pattern;
366 		else
367 			h = pwd->pw_dir;
368 	}
369 
370 	/* Copy the home directory */
371 	for (b = patbuf; b < eb && *h; *b++ = *h++)
372 		;
373 
374 	/* Append the rest of the pattern */
375 	while (b < eb && (*b++ = *p++) != EOS)
376 		;
377 	*b = EOS;
378 
379 	return patbuf;
380 }
381 
382 static int
383 g_strncmp(const Char *s1, const char *s2, size_t n)
384 {
385 	int rv = 0;
386 
387 	while (n--) {
388 		rv = *(Char *)s1 - *(const unsigned char *)s2++;
389 		if (rv)
390 			break;
391 		if (*s1++ == '\0')
392 			break;
393 	}
394 	return rv;
395 }
396 
397 static int
398 g_charclass(const Char **patternp, Char **bufnextp)
399 {
400 	const Char *pattern = *patternp + 1;
401 	Char *bufnext = *bufnextp;
402 	const Char *colon;
403 	struct cclass *cc;
404 	size_t len;
405 
406 	if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
407 		return 1;	/* not a character class */
408 
409 	len = (size_t)(colon - pattern);
410 	for (cc = cclasses; cc->name != NULL; cc++) {
411 		if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
412 			break;
413 	}
414 	if (cc->name == NULL)
415 		return -1;	/* invalid character class */
416 	*bufnext++ = M_CLASS;
417 	*bufnext++ = (Char)(cc - &cclasses[0]);
418 	*bufnextp = bufnext;
419 	*patternp += len + 3;
420 
421 	return 0;
422 }
423 
424 /*
425  * The main glob() routine: compiles the pattern (optionally processing
426  * quotes), calls glob1() to do the real pattern matching, and finally
427  * sorts the list (unless unsorted operation is requested).  Returns 0
428  * if things went well, nonzero if errors occurred.  It is not an error
429  * to find no matches.
430  */
431 static int
432 glob0(const Char *pattern, glob_t *pglob)
433 {
434 	const Char *qpatnext;
435 	int c, err, oldpathc;
436 	Char *bufnext, patbuf[MAXPATHLEN];
437 	size_t limit = 0;
438 
439 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
440 	oldpathc = pglob->gl_pathc;
441 	bufnext = patbuf;
442 
443 	/* We don't need to check for buffer overflow any more. */
444 	while ((c = *qpatnext++) != EOS) {
445 		switch (c) {
446 		case LBRACKET:
447 			c = *qpatnext;
448 			if (c == NOT)
449 				++qpatnext;
450 			if (*qpatnext == EOS ||
451 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
452 				*bufnext++ = LBRACKET;
453 				if (c == NOT)
454 					--qpatnext;
455 				break;
456 			}
457 			*bufnext++ = M_SET;
458 			if (c == NOT)
459 				*bufnext++ = M_NOT;
460 			c = *qpatnext++;
461 			do {
462 				if (c == LBRACKET && *qpatnext == ':') {
463 					do {
464 						err = g_charclass(&qpatnext,
465 						    &bufnext);
466 						if (err)
467 							break;
468 						c = *qpatnext++;
469 					} while (c == LBRACKET && *qpatnext == ':');
470 					if (err == -1 &&
471 					    !(pglob->gl_flags & GLOB_NOCHECK))
472 						return GLOB_NOMATCH;
473 					if (c == RBRACKET)
474 						break;
475 				}
476 				*bufnext++ = CHAR(c);
477 				if (*qpatnext == RANGE &&
478 				    (c = qpatnext[1]) != RBRACKET) {
479 					*bufnext++ = M_RNG;
480 					*bufnext++ = CHAR(c);
481 					qpatnext += 2;
482 				}
483 			} while ((c = *qpatnext++) != RBRACKET);
484 			pglob->gl_flags |= GLOB_MAGCHAR;
485 			*bufnext++ = M_END;
486 			break;
487 		case QUESTION:
488 			pglob->gl_flags |= GLOB_MAGCHAR;
489 			*bufnext++ = M_ONE;
490 			break;
491 		case STAR:
492 			pglob->gl_flags |= GLOB_MAGCHAR;
493 			/* collapse adjacent stars to one,
494 			 * to avoid exponential behavior
495 			 */
496 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
497 				*bufnext++ = M_ALL;
498 			break;
499 		default:
500 			*bufnext++ = CHAR(c);
501 			break;
502 		}
503 	}
504 	*bufnext = EOS;
505 #ifdef DEBUG
506 	qprintf("glob0:", patbuf);
507 #endif
508 
509 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
510 		return(err);
511 
512 	/*
513 	 * If there was no match we are going to append the pattern
514 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
515 	 * and the pattern did not contain any magic characters
516 	 * GLOB_NOMAGIC is there just for compatibility with csh.
517 	 */
518 	if (pglob->gl_pathc == oldpathc) {
519 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
520 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
521 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
522 			return(globextend(pattern, pglob, &limit));
523 		else
524 			return(GLOB_NOMATCH);
525 	}
526 	if (!(pglob->gl_flags & GLOB_NOSORT))
527 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
528 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
529 	return(0);
530 }
531 
532 static int
533 compare(const void *p, const void *q)
534 {
535 	return(strcmp(*(char **)p, *(char **)q));
536 }
537 
538 static int
539 glob1(Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
540 {
541 	Char pathbuf[MAXPATHLEN];
542 
543 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
544 	if (*pattern == EOS)
545 		return(0);
546 	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
547 	    pathbuf, pathbuf+MAXPATHLEN-1,
548 	    pattern, pattern_last, pglob, limitp));
549 }
550 
551 /*
552  * The functions glob2 and glob3 are mutually recursive; there is one level
553  * of recursion for each segment in the pattern that contains one or more
554  * meta characters.
555  */
556 static int
557 glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
558     Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
559 {
560 	struct stat sb;
561 	Char *p, *q;
562 	int anymeta;
563 
564 	/*
565 	 * Loop over pattern segments until end of pattern or until
566 	 * segment with meta character found.
567 	 */
568 	for (anymeta = 0;;) {
569 		if (*pattern == EOS) {		/* End of pattern? */
570 			*pathend = EOS;
571 			if (g_lstat(pathbuf, &sb, pglob))
572 				return(0);
573 
574 			if (((pglob->gl_flags & GLOB_MARK) &&
575 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
576 			    (S_ISLNK(sb.st_mode) &&
577 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
578 			    S_ISDIR(sb.st_mode)))) {
579 				if (pathend+1 > pathend_last)
580 					return (1);
581 				*pathend++ = SEP;
582 				*pathend = EOS;
583 			}
584 			++pglob->gl_matchc;
585 			return(globextend(pathbuf, pglob, limitp));
586 		}
587 
588 		/* Find end of next segment, copy tentatively to pathend. */
589 		q = pathend;
590 		p = pattern;
591 		while (*p != EOS && *p != SEP) {
592 			if (ismeta(*p))
593 				anymeta = 1;
594 			if (q+1 > pathend_last)
595 				return (1);
596 			*q++ = *p++;
597 		}
598 
599 		if (!anymeta) {		/* No expansion, do next segment. */
600 			pathend = q;
601 			pattern = p;
602 			while (*pattern == SEP) {
603 				if (pathend+1 > pathend_last)
604 					return (1);
605 				*pathend++ = *pattern++;
606 			}
607 		} else
608 			/* Need expansion, recurse. */
609 			return(glob3(pathbuf, pathbuf_last, pathend,
610 			    pathend_last, pattern, p, pattern_last,
611 			    pglob, limitp));
612 	}
613 	/* NOTREACHED */
614 }
615 
616 static int
617 glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
618     Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
619     size_t *limitp)
620 {
621 	struct dirent *dp;
622 	DIR *dirp;
623 	int err;
624 	char buf[MAXPATHLEN];
625 
626 	/*
627 	 * The readdirfunc declaration can't be prototyped, because it is
628 	 * assigned, below, to two functions which are prototyped in glob.h
629 	 * and dirent.h as taking pointers to differently typed opaque
630 	 * structures.
631 	 */
632 	struct dirent *(*readdirfunc)(void *);
633 
634 	if (pathend > pathend_last)
635 		return (1);
636 	*pathend = EOS;
637 	errno = 0;
638 
639 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
640 		/* TODO: don't call for ENOENT or ENOTDIR? */
641 		if (pglob->gl_errfunc) {
642 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
643 				return(GLOB_ABORTED);
644 			if (pglob->gl_errfunc(buf, errno) ||
645 			    pglob->gl_flags & GLOB_ERR)
646 				return(GLOB_ABORTED);
647 		}
648 		return(0);
649 	}
650 
651 	err = 0;
652 
653 	/* Search directory for matching names. */
654 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
655 		readdirfunc = pglob->gl_readdir;
656 	else
657 		readdirfunc = (struct dirent *(*)(void *))readdir;
658 	while ((dp = (*readdirfunc)(dirp))) {
659 		u_char *sc;
660 		Char *dc;
661 
662 		/* Initial DOT must be matched literally. */
663 		if (dp->d_name[0] == DOT && *pattern != DOT)
664 			continue;
665 		dc = pathend;
666 		sc = (u_char *) dp->d_name;
667 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
668 			;
669 		if (dc >= pathend_last) {
670 			*dc = EOS;
671 			err = 1;
672 			break;
673 		}
674 
675 		if (!match(pathend, pattern, restpattern)) {
676 			*pathend = EOS;
677 			continue;
678 		}
679 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
680 		    restpattern, restpattern_last, pglob, limitp);
681 		if (err)
682 			break;
683 	}
684 
685 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
686 		(*pglob->gl_closedir)(dirp);
687 	else
688 		closedir(dirp);
689 	return(err);
690 }
691 
692 
693 /*
694  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
695  * add the new item, and update gl_pathc.
696  *
697  * This assumes the BSD realloc, which only copies the block when its size
698  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
699  * behavior.
700  *
701  * Return 0 if new item added, error code if memory couldn't be allocated.
702  *
703  * Invariant of the glob_t structure:
704  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
705  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
706  */
707 static int
708 globextend(const Char *path, glob_t *pglob, size_t *limitp)
709 {
710 	char **pathv;
711 	int i;
712 	u_int newsize, len;
713 	char *copy;
714 	const Char *p;
715 
716 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
717 	pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
718 	    malloc(newsize);
719 	if (pathv == NULL) {
720 		if (pglob->gl_pathv) {
721 			free(pglob->gl_pathv);
722 			pglob->gl_pathv = NULL;
723 		}
724 		return(GLOB_NOSPACE);
725 	}
726 
727 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
728 		/* first time around -- clear initial gl_offs items */
729 		pathv += pglob->gl_offs;
730 		for (i = pglob->gl_offs; --i >= 0; )
731 			*--pathv = NULL;
732 	}
733 	pglob->gl_pathv = pathv;
734 
735 	for (p = path; *p++;)
736 		;
737 	len = (size_t)(p - path);
738 	*limitp += len;
739 	if ((copy = malloc(len)) != NULL) {
740 		if (g_Ctoc(path, copy, len)) {
741 			free(copy);
742 			return(GLOB_NOSPACE);
743 		}
744 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
745 	}
746 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
747 
748 	if ((pglob->gl_flags & GLOB_LIMIT) &&
749 	    newsize + *limitp >= ARG_MAX) {
750 		errno = 0;
751 		return(GLOB_NOSPACE);
752 	}
753 
754 	return(copy == NULL ? GLOB_NOSPACE : 0);
755 }
756 
757 
758 /*
759  * pattern matching function for filenames.  Each occurrence of the *
760  * pattern causes a recursion level.
761  */
762 static int
763 match(Char *name, Char *pat, Char *patend)
764 {
765 	int ok, negate_range;
766 	Char c, k;
767 
768 	while (pat < patend) {
769 		c = *pat++;
770 		switch (c & M_MASK) {
771 		case M_ALL:
772 			if (pat == patend)
773 				return(1);
774 			do {
775 			    if (match(name, pat, patend))
776 				    return(1);
777 			} while (*name++ != EOS);
778 			return(0);
779 		case M_ONE:
780 			if (*name++ == EOS)
781 				return(0);
782 			break;
783 		case M_SET:
784 			ok = 0;
785 			if ((k = *name++) == EOS)
786 				return(0);
787 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
788 				++pat;
789 			while (((c = *pat++) & M_MASK) != M_END) {
790 				if ((c & M_MASK) == M_CLASS) {
791 					int idx = *pat & M_MASK;
792 					if (idx < NCCLASSES &&
793 					    cclasses[idx].isctype(k))
794 						ok = 1;
795 					++pat;
796 				}
797 				if ((*pat & M_MASK) == M_RNG) {
798 					if (c <= k && k <= pat[1])
799 						ok = 1;
800 					pat += 2;
801 				} else if (c == k)
802 					ok = 1;
803 			}
804 			if (ok == negate_range)
805 				return(0);
806 			break;
807 		default:
808 			if (*name++ != c)
809 				return(0);
810 			break;
811 		}
812 	}
813 	return(*name == EOS);
814 }
815 
816 /* Free allocated data belonging to a glob_t structure. */
817 void
818 globfree(glob_t *pglob)
819 {
820 	int i;
821 	char **pp;
822 
823 	if (pglob->gl_pathv != NULL) {
824 		pp = pglob->gl_pathv + pglob->gl_offs;
825 		for (i = pglob->gl_pathc; i--; ++pp)
826 			if (*pp)
827 				free(*pp);
828 		free(pglob->gl_pathv);
829 		pglob->gl_pathv = NULL;
830 	}
831 }
832 
833 static DIR *
834 g_opendir(Char *str, glob_t *pglob)
835 {
836 	char buf[MAXPATHLEN];
837 
838 	if (!*str)
839 		strlcpy(buf, ".", sizeof buf);
840 	else {
841 		if (g_Ctoc(str, buf, sizeof(buf)))
842 			return(NULL);
843 	}
844 
845 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
846 		return((*pglob->gl_opendir)(buf));
847 
848 	return(opendir(buf));
849 }
850 
851 static int
852 g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
853 {
854 	char buf[MAXPATHLEN];
855 
856 	if (g_Ctoc(fn, buf, sizeof(buf)))
857 		return(-1);
858 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
859 		return((*pglob->gl_lstat)(buf, sb));
860 	return(lstat(buf, sb));
861 }
862 
863 static int
864 g_stat(Char *fn, struct stat *sb, glob_t *pglob)
865 {
866 	char buf[MAXPATHLEN];
867 
868 	if (g_Ctoc(fn, buf, sizeof(buf)))
869 		return(-1);
870 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
871 		return((*pglob->gl_stat)(buf, sb));
872 	return(stat(buf, sb));
873 }
874 
875 static Char *
876 g_strchr(const Char *str, int ch)
877 {
878 	do {
879 		if (*str == ch)
880 			return ((Char *)str);
881 	} while (*str++);
882 	return (NULL);
883 }
884 
885 static int
886 g_Ctoc(const Char *str, char *buf, u_int len)
887 {
888 
889 	while (len--) {
890 		if ((*buf++ = *str++) == EOS)
891 			return (0);
892 	}
893 	return (1);
894 }
895 
896 #ifdef DEBUG
897 static void
898 qprintf(const char *str, Char *s)
899 {
900 	Char *p;
901 
902 	(void)printf("%s:\n", str);
903 	for (p = s; *p; p++)
904 		(void)printf("%c", CHAR(*p));
905 	(void)printf("\n");
906 	for (p = s; *p; p++)
907 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
908 	(void)printf("\n");
909 	for (p = s; *p; p++)
910 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
911 	(void)printf("\n");
912 }
913 #endif
914