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