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