xref: /dflybsd-src/lib/libssh/openbsd-compat/glob.c (revision bc9cc67551e02abead3208ce19947fac15901d84)
1*bc9cc675SDaniel Fojt /*	$OpenBSD: glob.c,v 1.49 2020/04/21 08:25:22 dtucker Exp $ */
22c0338ffSzrj /*
32c0338ffSzrj  * Copyright (c) 1989, 1993
42c0338ffSzrj  *	The Regents of the University of California.  All rights reserved.
52c0338ffSzrj  *
62c0338ffSzrj  * This code is derived from software contributed to Berkeley by
72c0338ffSzrj  * Guido van Rossum.
82c0338ffSzrj  *
92c0338ffSzrj  * Redistribution and use in source and binary forms, with or without
102c0338ffSzrj  * modification, are permitted provided that the following conditions
112c0338ffSzrj  * are met:
122c0338ffSzrj  * 1. Redistributions of source code must retain the above copyright
132c0338ffSzrj  *    notice, this list of conditions and the following disclaimer.
142c0338ffSzrj  * 2. Redistributions in binary form must reproduce the above copyright
152c0338ffSzrj  *    notice, this list of conditions and the following disclaimer in the
162c0338ffSzrj  *    documentation and/or other materials provided with the distribution.
172c0338ffSzrj  * 3. Neither the name of the University nor the names of its contributors
182c0338ffSzrj  *    may be used to endorse or promote products derived from this software
192c0338ffSzrj  *    without specific prior written permission.
202c0338ffSzrj  *
212c0338ffSzrj  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
222c0338ffSzrj  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232c0338ffSzrj  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242c0338ffSzrj  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
252c0338ffSzrj  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
262c0338ffSzrj  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
272c0338ffSzrj  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
282c0338ffSzrj  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
292c0338ffSzrj  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
302c0338ffSzrj  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312c0338ffSzrj  * SUCH DAMAGE.
322c0338ffSzrj  */
332c0338ffSzrj 
342c0338ffSzrj /* OPENBSD ORIGINAL: lib/libc/gen/glob.c */
352c0338ffSzrj 
362c0338ffSzrj /*
372c0338ffSzrj  * glob(3) -- a superset of the one defined in POSIX 1003.2.
382c0338ffSzrj  *
392c0338ffSzrj  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
402c0338ffSzrj  *
412c0338ffSzrj  * Optional extra services, controlled by flags not defined by POSIX:
422c0338ffSzrj  *
432c0338ffSzrj  * GLOB_QUOTE:
442c0338ffSzrj  *	Escaping convention: \ inhibits any special meaning the following
452c0338ffSzrj  *	character might have (except \ at end of string is retained).
462c0338ffSzrj  * GLOB_MAGCHAR:
472c0338ffSzrj  *	Set in gl_flags if pattern contained a globbing character.
482c0338ffSzrj  * GLOB_NOMAGIC:
492c0338ffSzrj  *	Same as GLOB_NOCHECK, but it will only append pattern if it did
502c0338ffSzrj  *	not contain any magic characters.  [Used in csh style globbing]
512c0338ffSzrj  * GLOB_ALTDIRFUNC:
522c0338ffSzrj  *	Use alternately specified directory access functions.
532c0338ffSzrj  * GLOB_TILDE:
542c0338ffSzrj  *	expand ~user/foo to the /home/dir/of/user/foo
552c0338ffSzrj  * GLOB_BRACE:
562c0338ffSzrj  *	expand {1,2}{a,b} to 1a 1b 2a 2b
572c0338ffSzrj  * gl_matchc:
582c0338ffSzrj  *	Number of matches in the current invocation of glob.
592c0338ffSzrj  */
602c0338ffSzrj 
612c0338ffSzrj #include "includes.h"
622c0338ffSzrj #include "glob.h"
632c0338ffSzrj 
642c0338ffSzrj #include <sys/types.h>
652c0338ffSzrj #include <sys/stat.h>
662c0338ffSzrj 
672c0338ffSzrj #include <dirent.h>
682c0338ffSzrj #include <ctype.h>
692c0338ffSzrj #include <errno.h>
702c0338ffSzrj #include <limits.h>
712c0338ffSzrj #include <pwd.h>
722c0338ffSzrj #include <stdlib.h>
73*bc9cc675SDaniel Fojt #ifdef HAVE_STDINT_H
74*bc9cc675SDaniel Fojt #include <stdint.h>
75*bc9cc675SDaniel Fojt #endif
762c0338ffSzrj #include <string.h>
772c0338ffSzrj #include <unistd.h>
782c0338ffSzrj 
792c0338ffSzrj #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
802c0338ffSzrj     !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
812c0338ffSzrj     !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
822c0338ffSzrj     defined(BROKEN_GLOB)
832c0338ffSzrj 
842c0338ffSzrj #include "charclass.h"
852c0338ffSzrj 
86*bc9cc675SDaniel Fojt #ifdef TILDE
87*bc9cc675SDaniel Fojt # undef TILDE
88*bc9cc675SDaniel Fojt #endif
89*bc9cc675SDaniel Fojt 
902c0338ffSzrj #define	DOLLAR		'$'
912c0338ffSzrj #define	DOT		'.'
922c0338ffSzrj #define	EOS		'\0'
932c0338ffSzrj #define	LBRACKET	'['
942c0338ffSzrj #define	NOT		'!'
952c0338ffSzrj #define	QUESTION	'?'
962c0338ffSzrj #define	QUOTE		'\\'
972c0338ffSzrj #define	RANGE		'-'
982c0338ffSzrj #define	RBRACKET	']'
992c0338ffSzrj #define	SEP		'/'
1002c0338ffSzrj #define	STAR		'*'
1012c0338ffSzrj #define	TILDE		'~'
1022c0338ffSzrj #define	UNDERSCORE	'_'
1032c0338ffSzrj #define	LBRACE		'{'
1042c0338ffSzrj #define	RBRACE		'}'
1052c0338ffSzrj #define	SLASH		'/'
1062c0338ffSzrj #define	COMMA		','
1072c0338ffSzrj 
1082c0338ffSzrj #ifndef DEBUG
1092c0338ffSzrj 
1102c0338ffSzrj #define	M_QUOTE		0x8000
1112c0338ffSzrj #define	M_PROTECT	0x4000
1122c0338ffSzrj #define	M_MASK		0xffff
1132c0338ffSzrj #define	M_ASCII		0x00ff
1142c0338ffSzrj 
1152c0338ffSzrj typedef u_short Char;
1162c0338ffSzrj 
1172c0338ffSzrj #else
1182c0338ffSzrj 
1192c0338ffSzrj #define	M_QUOTE		0x80
1202c0338ffSzrj #define	M_PROTECT	0x40
1212c0338ffSzrj #define	M_MASK		0xff
1222c0338ffSzrj #define	M_ASCII		0x7f
1232c0338ffSzrj 
1242c0338ffSzrj typedef char Char;
1252c0338ffSzrj 
1262c0338ffSzrj #endif
1272c0338ffSzrj 
1282c0338ffSzrj 
1292c0338ffSzrj #define	CHAR(c)		((Char)((c)&M_ASCII))
1302c0338ffSzrj #define	META(c)		((Char)((c)|M_QUOTE))
1312c0338ffSzrj #define	M_ALL		META('*')
1322c0338ffSzrj #define	M_END		META(']')
1332c0338ffSzrj #define	M_NOT		META('!')
1342c0338ffSzrj #define	M_ONE		META('?')
1352c0338ffSzrj #define	M_RNG		META('-')
1362c0338ffSzrj #define	M_SET		META('[')
1372c0338ffSzrj #define	M_CLASS		META(':')
1382c0338ffSzrj #define	ismeta(c)	(((c)&M_QUOTE) != 0)
1392c0338ffSzrj 
1402c0338ffSzrj #define	GLOB_LIMIT_MALLOC	65536
141*bc9cc675SDaniel Fojt #define	GLOB_LIMIT_STAT		2048
1422c0338ffSzrj #define	GLOB_LIMIT_READDIR	16384
1432c0338ffSzrj 
1442c0338ffSzrj struct glob_lim {
1452c0338ffSzrj 	size_t	glim_malloc;
1462c0338ffSzrj 	size_t	glim_stat;
1472c0338ffSzrj 	size_t	glim_readdir;
1482c0338ffSzrj };
1492c0338ffSzrj 
1502c0338ffSzrj struct glob_path_stat {
1512c0338ffSzrj 	char		*gps_path;
1522c0338ffSzrj 	struct stat	*gps_stat;
1532c0338ffSzrj };
1542c0338ffSzrj 
1552c0338ffSzrj static int	 compare(const void *, const void *);
1562c0338ffSzrj static int	 compare_gps(const void *, const void *);
157*bc9cc675SDaniel Fojt static int	 g_Ctoc(const Char *, char *, size_t);
1582c0338ffSzrj static int	 g_lstat(Char *, struct stat *, glob_t *);
1592c0338ffSzrj static DIR	*g_opendir(Char *, glob_t *);
1602c0338ffSzrj static Char	*g_strchr(const Char *, int);
1612c0338ffSzrj static int	 g_strncmp(const Char *, const char *, size_t);
1622c0338ffSzrj static int	 g_stat(Char *, struct stat *, glob_t *);
1632c0338ffSzrj static int	 glob0(const Char *, glob_t *, struct glob_lim *);
1642c0338ffSzrj static int	 glob1(Char *, Char *, glob_t *, struct glob_lim *);
1652c0338ffSzrj static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
1662c0338ffSzrj 		    glob_t *, struct glob_lim *);
1672c0338ffSzrj static int	 glob3(Char *, Char *, Char *, Char *, Char *,
1682c0338ffSzrj 		    Char *, Char *, glob_t *, struct glob_lim *);
1692c0338ffSzrj static int	 globextend(const Char *, glob_t *, struct glob_lim *,
1702c0338ffSzrj 		    struct stat *);
1712c0338ffSzrj static const Char *
1722c0338ffSzrj 		 globtilde(const Char *, Char *, size_t, glob_t *);
1732c0338ffSzrj static int	 globexp1(const Char *, glob_t *, struct glob_lim *);
1742c0338ffSzrj static int	 globexp2(const Char *, const Char *, glob_t *,
1752c0338ffSzrj 		    struct glob_lim *);
176*bc9cc675SDaniel Fojt static int	 match(Char *, Char *, Char *);
1772c0338ffSzrj #ifdef DEBUG
1782c0338ffSzrj static void	 qprintf(const char *, Char *);
1792c0338ffSzrj #endif
1802c0338ffSzrj 
1812c0338ffSzrj int
glob(const char * pattern,int flags,int (* errfunc)(const char *,int),glob_t * pglob)1822c0338ffSzrj glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
1832c0338ffSzrj     glob_t *pglob)
1842c0338ffSzrj {
1852c0338ffSzrj 	const u_char *patnext;
1862c0338ffSzrj 	int c;
187*bc9cc675SDaniel Fojt 	Char *bufnext, *bufend, patbuf[PATH_MAX];
1882c0338ffSzrj 	struct glob_lim limit = { 0, 0, 0 };
1892c0338ffSzrj 
1902c0338ffSzrj 	patnext = (u_char *) pattern;
1912c0338ffSzrj 	if (!(flags & GLOB_APPEND)) {
1922c0338ffSzrj 		pglob->gl_pathc = 0;
1932c0338ffSzrj 		pglob->gl_pathv = NULL;
1942c0338ffSzrj 		pglob->gl_statv = NULL;
1952c0338ffSzrj 		if (!(flags & GLOB_DOOFFS))
1962c0338ffSzrj 			pglob->gl_offs = 0;
1972c0338ffSzrj 	}
1982c0338ffSzrj 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
1992c0338ffSzrj 	pglob->gl_errfunc = errfunc;
2002c0338ffSzrj 	pglob->gl_matchc = 0;
2012c0338ffSzrj 
202*bc9cc675SDaniel Fojt 	if (strnlen(pattern, PATH_MAX) == PATH_MAX)
203*bc9cc675SDaniel Fojt 		return(GLOB_NOMATCH);
204*bc9cc675SDaniel Fojt 
205*bc9cc675SDaniel Fojt 	if (pglob->gl_offs >= SSIZE_MAX || pglob->gl_pathc >= SSIZE_MAX ||
206*bc9cc675SDaniel Fojt 	    pglob->gl_pathc >= SSIZE_MAX - pglob->gl_offs - 1)
2072c0338ffSzrj 		return GLOB_NOSPACE;
2082c0338ffSzrj 
2092c0338ffSzrj 	bufnext = patbuf;
210*bc9cc675SDaniel Fojt 	bufend = bufnext + PATH_MAX - 1;
2112c0338ffSzrj 	if (flags & GLOB_NOESCAPE)
2122c0338ffSzrj 		while (bufnext < bufend && (c = *patnext++) != EOS)
2132c0338ffSzrj 			*bufnext++ = c;
2142c0338ffSzrj 	else {
2152c0338ffSzrj 		/* Protect the quoted characters. */
2162c0338ffSzrj 		while (bufnext < bufend && (c = *patnext++) != EOS)
2172c0338ffSzrj 			if (c == QUOTE) {
2182c0338ffSzrj 				if ((c = *patnext++) == EOS) {
2192c0338ffSzrj 					c = QUOTE;
2202c0338ffSzrj 					--patnext;
2212c0338ffSzrj 				}
2222c0338ffSzrj 				*bufnext++ = c | M_PROTECT;
2232c0338ffSzrj 			} else
2242c0338ffSzrj 				*bufnext++ = c;
2252c0338ffSzrj 	}
2262c0338ffSzrj 	*bufnext = EOS;
2272c0338ffSzrj 
2282c0338ffSzrj 	if (flags & GLOB_BRACE)
2292c0338ffSzrj 		return globexp1(patbuf, pglob, &limit);
2302c0338ffSzrj 	else
2312c0338ffSzrj 		return glob0(patbuf, pglob, &limit);
2322c0338ffSzrj }
2332c0338ffSzrj 
2342c0338ffSzrj /*
2352c0338ffSzrj  * Expand recursively a glob {} pattern. When there is no more expansion
2362c0338ffSzrj  * invoke the standard globbing routine to glob the rest of the magic
2372c0338ffSzrj  * characters
2382c0338ffSzrj  */
2392c0338ffSzrj static int
globexp1(const Char * pattern,glob_t * pglob,struct glob_lim * limitp)2402c0338ffSzrj globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
2412c0338ffSzrj {
2422c0338ffSzrj 	const Char* ptr = pattern;
2432c0338ffSzrj 
2442c0338ffSzrj 	/* Protect a single {}, for find(1), like csh */
2452c0338ffSzrj 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
2462c0338ffSzrj 		return glob0(pattern, pglob, limitp);
2472c0338ffSzrj 
2482c0338ffSzrj 	if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
2492c0338ffSzrj 		return globexp2(ptr, pattern, pglob, limitp);
2502c0338ffSzrj 
2512c0338ffSzrj 	return glob0(pattern, pglob, limitp);
2522c0338ffSzrj }
2532c0338ffSzrj 
2542c0338ffSzrj 
2552c0338ffSzrj /*
2562c0338ffSzrj  * Recursive brace globbing helper. Tries to expand a single brace.
2572c0338ffSzrj  * If it succeeds then it invokes globexp1 with the new pattern.
2582c0338ffSzrj  * If it fails then it tries to glob the rest of the pattern and returns.
2592c0338ffSzrj  */
2602c0338ffSzrj static int
globexp2(const Char * ptr,const Char * pattern,glob_t * pglob,struct glob_lim * limitp)2612c0338ffSzrj globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
2622c0338ffSzrj     struct glob_lim *limitp)
2632c0338ffSzrj {
2642c0338ffSzrj 	int     i, rv;
2652c0338ffSzrj 	Char   *lm, *ls;
2662c0338ffSzrj 	const Char *pe, *pm, *pl;
267*bc9cc675SDaniel Fojt 	Char    patbuf[PATH_MAX];
2682c0338ffSzrj 
2692c0338ffSzrj 	/* copy part up to the brace */
2702c0338ffSzrj 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
2712c0338ffSzrj 		;
2722c0338ffSzrj 	*lm = EOS;
2732c0338ffSzrj 	ls = lm;
2742c0338ffSzrj 
2752c0338ffSzrj 	/* Find the balanced brace */
2762c0338ffSzrj 	for (i = 0, pe = ++ptr; *pe; pe++)
2772c0338ffSzrj 		if (*pe == LBRACKET) {
2782c0338ffSzrj 			/* Ignore everything between [] */
2792c0338ffSzrj 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
2802c0338ffSzrj 				;
2812c0338ffSzrj 			if (*pe == EOS) {
2822c0338ffSzrj 				/*
2832c0338ffSzrj 				 * We could not find a matching RBRACKET.
2842c0338ffSzrj 				 * Ignore and just look for RBRACE
2852c0338ffSzrj 				 */
2862c0338ffSzrj 				pe = pm;
2872c0338ffSzrj 			}
2882c0338ffSzrj 		} else if (*pe == LBRACE)
2892c0338ffSzrj 			i++;
2902c0338ffSzrj 		else if (*pe == RBRACE) {
2912c0338ffSzrj 			if (i == 0)
2922c0338ffSzrj 				break;
2932c0338ffSzrj 			i--;
2942c0338ffSzrj 		}
2952c0338ffSzrj 
2962c0338ffSzrj 	/* Non matching braces; just glob the pattern */
2972c0338ffSzrj 	if (i != 0 || *pe == EOS)
2982c0338ffSzrj 		return glob0(patbuf, pglob, limitp);
2992c0338ffSzrj 
3002c0338ffSzrj 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
3012c0338ffSzrj 		switch (*pm) {
3022c0338ffSzrj 		case LBRACKET:
3032c0338ffSzrj 			/* Ignore everything between [] */
3042c0338ffSzrj 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
3052c0338ffSzrj 				;
3062c0338ffSzrj 			if (*pm == EOS) {
3072c0338ffSzrj 				/*
3082c0338ffSzrj 				 * We could not find a matching RBRACKET.
3092c0338ffSzrj 				 * Ignore and just look for RBRACE
3102c0338ffSzrj 				 */
3112c0338ffSzrj 				pm = pl;
3122c0338ffSzrj 			}
3132c0338ffSzrj 			break;
3142c0338ffSzrj 
3152c0338ffSzrj 		case LBRACE:
3162c0338ffSzrj 			i++;
3172c0338ffSzrj 			break;
3182c0338ffSzrj 
3192c0338ffSzrj 		case RBRACE:
3202c0338ffSzrj 			if (i) {
3212c0338ffSzrj 				i--;
3222c0338ffSzrj 				break;
3232c0338ffSzrj 			}
3242c0338ffSzrj 			/* FALLTHROUGH */
3252c0338ffSzrj 		case COMMA:
3262c0338ffSzrj 			if (i && *pm == COMMA)
3272c0338ffSzrj 				break;
3282c0338ffSzrj 			else {
3292c0338ffSzrj 				/* Append the current string */
3302c0338ffSzrj 				for (lm = ls; (pl < pm); *lm++ = *pl++)
3312c0338ffSzrj 					;
3322c0338ffSzrj 
3332c0338ffSzrj 				/*
3342c0338ffSzrj 				 * Append the rest of the pattern after the
3352c0338ffSzrj 				 * closing brace
3362c0338ffSzrj 				 */
3372c0338ffSzrj 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
3382c0338ffSzrj 					;
3392c0338ffSzrj 
3402c0338ffSzrj 				/* Expand the current pattern */
3412c0338ffSzrj #ifdef DEBUG
3422c0338ffSzrj 				qprintf("globexp2:", patbuf);
3432c0338ffSzrj #endif
3442c0338ffSzrj 				rv = globexp1(patbuf, pglob, limitp);
3452c0338ffSzrj 				if (rv && rv != GLOB_NOMATCH)
3462c0338ffSzrj 					return rv;
3472c0338ffSzrj 
3482c0338ffSzrj 				/* move after the comma, to the next string */
3492c0338ffSzrj 				pl = pm + 1;
3502c0338ffSzrj 			}
3512c0338ffSzrj 			break;
3522c0338ffSzrj 
3532c0338ffSzrj 		default:
3542c0338ffSzrj 			break;
3552c0338ffSzrj 		}
3562c0338ffSzrj 	}
3572c0338ffSzrj 	return 0;
3582c0338ffSzrj }
3592c0338ffSzrj 
3602c0338ffSzrj 
3612c0338ffSzrj 
3622c0338ffSzrj /*
3632c0338ffSzrj  * expand tilde from the passwd file.
3642c0338ffSzrj  */
3652c0338ffSzrj static const Char *
globtilde(const Char * pattern,Char * patbuf,size_t patbuf_len,glob_t * pglob)3662c0338ffSzrj globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
3672c0338ffSzrj {
3682c0338ffSzrj 	struct passwd *pwd;
3692c0338ffSzrj 	char *h;
3702c0338ffSzrj 	const Char *p;
3712c0338ffSzrj 	Char *b, *eb;
3722c0338ffSzrj 
3732c0338ffSzrj 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
3742c0338ffSzrj 		return pattern;
3752c0338ffSzrj 
3762c0338ffSzrj 	/* Copy up to the end of the string or / */
3772c0338ffSzrj 	eb = &patbuf[patbuf_len - 1];
3782c0338ffSzrj 	for (p = pattern + 1, h = (char *) patbuf;
3792c0338ffSzrj 	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
3802c0338ffSzrj 		;
3812c0338ffSzrj 
3822c0338ffSzrj 	*h = EOS;
3832c0338ffSzrj 
3842c0338ffSzrj #if 0
3852c0338ffSzrj 	if (h == (char *)eb)
3862c0338ffSzrj 		return what;
3872c0338ffSzrj #endif
3882c0338ffSzrj 
3892c0338ffSzrj 	if (((char *) patbuf)[0] == EOS) {
3902c0338ffSzrj 		/*
3912c0338ffSzrj 		 * handle a plain ~ or ~/ by expanding $HOME
3922c0338ffSzrj 		 * first and then trying the password file
3932c0338ffSzrj 		 */
3942c0338ffSzrj #if 0
3952c0338ffSzrj 		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
3962c0338ffSzrj #endif
3972c0338ffSzrj 		if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
3982c0338ffSzrj 			if ((pwd = getpwuid(getuid())) == NULL)
3992c0338ffSzrj 				return pattern;
4002c0338ffSzrj 			else
4012c0338ffSzrj 				h = pwd->pw_dir;
4022c0338ffSzrj 		}
4032c0338ffSzrj 	} else {
4042c0338ffSzrj 		/*
4052c0338ffSzrj 		 * Expand a ~user
4062c0338ffSzrj 		 */
4072c0338ffSzrj 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
4082c0338ffSzrj 			return pattern;
4092c0338ffSzrj 		else
4102c0338ffSzrj 			h = pwd->pw_dir;
4112c0338ffSzrj 	}
4122c0338ffSzrj 
4132c0338ffSzrj 	/* Copy the home directory */
4142c0338ffSzrj 	for (b = patbuf; b < eb && *h; *b++ = *h++)
4152c0338ffSzrj 		;
4162c0338ffSzrj 
4172c0338ffSzrj 	/* Append the rest of the pattern */
4182c0338ffSzrj 	while (b < eb && (*b++ = *p++) != EOS)
4192c0338ffSzrj 		;
4202c0338ffSzrj 	*b = EOS;
4212c0338ffSzrj 
4222c0338ffSzrj 	return patbuf;
4232c0338ffSzrj }
4242c0338ffSzrj 
4252c0338ffSzrj static int
4262c0338ffSzrj g_strncmp(const Char *s1, const char *s2, size_t n)
4272c0338ffSzrj {
4282c0338ffSzrj 	int rv = 0;
4292c0338ffSzrj 
4302c0338ffSzrj 	while (n--) {
4312c0338ffSzrj 		rv = *(Char *)s1 - *(const unsigned char *)s2++;
4322c0338ffSzrj 		if (rv)
4332c0338ffSzrj 			break;
4342c0338ffSzrj 		if (*s1++ == '\0')
4352c0338ffSzrj 			break;
4362c0338ffSzrj 	}
4372c0338ffSzrj 	return rv;
4382c0338ffSzrj }
4392c0338ffSzrj 
4402c0338ffSzrj static int
4412c0338ffSzrj g_charclass(const Char **patternp, Char **bufnextp)
4422c0338ffSzrj {
4432c0338ffSzrj 	const Char *pattern = *patternp + 1;
4442c0338ffSzrj 	Char *bufnext = *bufnextp;
4452c0338ffSzrj 	const Char *colon;
4462c0338ffSzrj 	struct cclass *cc;
4472c0338ffSzrj 	size_t len;
4482c0338ffSzrj 
4492c0338ffSzrj 	if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
4502c0338ffSzrj 		return 1;	/* not a character class */
4512c0338ffSzrj 
4522c0338ffSzrj 	len = (size_t)(colon - pattern);
4532c0338ffSzrj 	for (cc = cclasses; cc->name != NULL; cc++) {
4542c0338ffSzrj 		if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
4552c0338ffSzrj 			break;
4562c0338ffSzrj 	}
4572c0338ffSzrj 	if (cc->name == NULL)
4582c0338ffSzrj 		return -1;	/* invalid character class */
4592c0338ffSzrj 	*bufnext++ = M_CLASS;
4602c0338ffSzrj 	*bufnext++ = (Char)(cc - &cclasses[0]);
4612c0338ffSzrj 	*bufnextp = bufnext;
4622c0338ffSzrj 	*patternp += len + 3;
4632c0338ffSzrj 
4642c0338ffSzrj 	return 0;
4652c0338ffSzrj }
4662c0338ffSzrj 
4672c0338ffSzrj /*
4682c0338ffSzrj  * The main glob() routine: compiles the pattern (optionally processing
4692c0338ffSzrj  * quotes), calls glob1() to do the real pattern matching, and finally
4702c0338ffSzrj  * sorts the list (unless unsorted operation is requested).  Returns 0
4712c0338ffSzrj  * if things went well, nonzero if errors occurred.  It is not an error
4722c0338ffSzrj  * to find no matches.
4732c0338ffSzrj  */
4742c0338ffSzrj static int
4752c0338ffSzrj glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
4762c0338ffSzrj {
4772c0338ffSzrj 	const Char *qpatnext;
478*bc9cc675SDaniel Fojt 	int c, err;
479*bc9cc675SDaniel Fojt 	size_t oldpathc;
480*bc9cc675SDaniel Fojt 	Char *bufnext, patbuf[PATH_MAX];
4812c0338ffSzrj 
482*bc9cc675SDaniel Fojt 	qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
4832c0338ffSzrj 	oldpathc = pglob->gl_pathc;
4842c0338ffSzrj 	bufnext = patbuf;
4852c0338ffSzrj 
4862c0338ffSzrj 	/* We don't need to check for buffer overflow any more. */
4872c0338ffSzrj 	while ((c = *qpatnext++) != EOS) {
4882c0338ffSzrj 		switch (c) {
4892c0338ffSzrj 		case LBRACKET:
4902c0338ffSzrj 			c = *qpatnext;
4912c0338ffSzrj 			if (c == NOT)
4922c0338ffSzrj 				++qpatnext;
4932c0338ffSzrj 			if (*qpatnext == EOS ||
4942c0338ffSzrj 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
4952c0338ffSzrj 				*bufnext++ = LBRACKET;
4962c0338ffSzrj 				if (c == NOT)
4972c0338ffSzrj 					--qpatnext;
4982c0338ffSzrj 				break;
4992c0338ffSzrj 			}
5002c0338ffSzrj 			*bufnext++ = M_SET;
5012c0338ffSzrj 			if (c == NOT)
5022c0338ffSzrj 				*bufnext++ = M_NOT;
5032c0338ffSzrj 			c = *qpatnext++;
5042c0338ffSzrj 			do {
5052c0338ffSzrj 				if (c == LBRACKET && *qpatnext == ':') {
5062c0338ffSzrj 					do {
5072c0338ffSzrj 						err = g_charclass(&qpatnext,
5082c0338ffSzrj 						    &bufnext);
5092c0338ffSzrj 						if (err)
5102c0338ffSzrj 							break;
5112c0338ffSzrj 						c = *qpatnext++;
5122c0338ffSzrj 					} while (c == LBRACKET && *qpatnext == ':');
5132c0338ffSzrj 					if (err == -1 &&
5142c0338ffSzrj 					    !(pglob->gl_flags & GLOB_NOCHECK))
5152c0338ffSzrj 						return GLOB_NOMATCH;
5162c0338ffSzrj 					if (c == RBRACKET)
5172c0338ffSzrj 						break;
5182c0338ffSzrj 				}
5192c0338ffSzrj 				*bufnext++ = CHAR(c);
5202c0338ffSzrj 				if (*qpatnext == RANGE &&
5212c0338ffSzrj 				    (c = qpatnext[1]) != RBRACKET) {
5222c0338ffSzrj 					*bufnext++ = M_RNG;
5232c0338ffSzrj 					*bufnext++ = CHAR(c);
5242c0338ffSzrj 					qpatnext += 2;
5252c0338ffSzrj 				}
5262c0338ffSzrj 			} while ((c = *qpatnext++) != RBRACKET);
5272c0338ffSzrj 			pglob->gl_flags |= GLOB_MAGCHAR;
5282c0338ffSzrj 			*bufnext++ = M_END;
5292c0338ffSzrj 			break;
5302c0338ffSzrj 		case QUESTION:
5312c0338ffSzrj 			pglob->gl_flags |= GLOB_MAGCHAR;
5322c0338ffSzrj 			*bufnext++ = M_ONE;
5332c0338ffSzrj 			break;
5342c0338ffSzrj 		case STAR:
5352c0338ffSzrj 			pglob->gl_flags |= GLOB_MAGCHAR;
5362c0338ffSzrj 			/* collapse adjacent stars to one,
5372c0338ffSzrj 			 * to avoid exponential behavior
5382c0338ffSzrj 			 */
5392c0338ffSzrj 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
5402c0338ffSzrj 				*bufnext++ = M_ALL;
5412c0338ffSzrj 			break;
5422c0338ffSzrj 		default:
5432c0338ffSzrj 			*bufnext++ = CHAR(c);
5442c0338ffSzrj 			break;
5452c0338ffSzrj 		}
5462c0338ffSzrj 	}
5472c0338ffSzrj 	*bufnext = EOS;
5482c0338ffSzrj #ifdef DEBUG
5492c0338ffSzrj 	qprintf("glob0:", patbuf);
5502c0338ffSzrj #endif
5512c0338ffSzrj 
552*bc9cc675SDaniel Fojt 	if ((err = glob1(patbuf, patbuf+PATH_MAX-1, pglob, limitp)) != 0)
5532c0338ffSzrj 		return(err);
5542c0338ffSzrj 
5552c0338ffSzrj 	/*
5562c0338ffSzrj 	 * If there was no match we are going to append the pattern
5572c0338ffSzrj 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
5582c0338ffSzrj 	 * and the pattern did not contain any magic characters
5592c0338ffSzrj 	 * GLOB_NOMAGIC is there just for compatibility with csh.
5602c0338ffSzrj 	 */
5612c0338ffSzrj 	if (pglob->gl_pathc == oldpathc) {
5622c0338ffSzrj 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
5632c0338ffSzrj 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
5642c0338ffSzrj 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
5652c0338ffSzrj 			return(globextend(pattern, pglob, limitp, NULL));
5662c0338ffSzrj 		else
5672c0338ffSzrj 			return(GLOB_NOMATCH);
5682c0338ffSzrj 	}
5692c0338ffSzrj 	if (!(pglob->gl_flags & GLOB_NOSORT)) {
5702c0338ffSzrj 		if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
5712c0338ffSzrj 			/* Keep the paths and stat info synced during sort */
5722c0338ffSzrj 			struct glob_path_stat *path_stat;
573*bc9cc675SDaniel Fojt 			size_t i;
574*bc9cc675SDaniel Fojt 			size_t n = pglob->gl_pathc - oldpathc;
575*bc9cc675SDaniel Fojt 			size_t o = pglob->gl_offs + oldpathc;
5762c0338ffSzrj 
5772c0338ffSzrj 			if ((path_stat = calloc(n, sizeof(*path_stat))) == NULL)
5782c0338ffSzrj 				return GLOB_NOSPACE;
5792c0338ffSzrj 			for (i = 0; i < n; i++) {
5802c0338ffSzrj 				path_stat[i].gps_path = pglob->gl_pathv[o + i];
5812c0338ffSzrj 				path_stat[i].gps_stat = pglob->gl_statv[o + i];
5822c0338ffSzrj 			}
5832c0338ffSzrj 			qsort(path_stat, n, sizeof(*path_stat), compare_gps);
5842c0338ffSzrj 			for (i = 0; i < n; i++) {
5852c0338ffSzrj 				pglob->gl_pathv[o + i] = path_stat[i].gps_path;
5862c0338ffSzrj 				pglob->gl_statv[o + i] = path_stat[i].gps_stat;
5872c0338ffSzrj 			}
5882c0338ffSzrj 			free(path_stat);
5892c0338ffSzrj 		} else {
5902c0338ffSzrj 			qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
5912c0338ffSzrj 			    pglob->gl_pathc - oldpathc, sizeof(char *),
5922c0338ffSzrj 			    compare);
5932c0338ffSzrj 		}
5942c0338ffSzrj 	}
5952c0338ffSzrj 	return(0);
5962c0338ffSzrj }
5972c0338ffSzrj 
5982c0338ffSzrj static int
5992c0338ffSzrj compare(const void *p, const void *q)
6002c0338ffSzrj {
6012c0338ffSzrj 	return(strcmp(*(char **)p, *(char **)q));
6022c0338ffSzrj }
6032c0338ffSzrj 
6042c0338ffSzrj static int
6052c0338ffSzrj compare_gps(const void *_p, const void *_q)
6062c0338ffSzrj {
6072c0338ffSzrj 	const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
6082c0338ffSzrj 	const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
6092c0338ffSzrj 
6102c0338ffSzrj 	return(strcmp(p->gps_path, q->gps_path));
6112c0338ffSzrj }
6122c0338ffSzrj 
6132c0338ffSzrj static int
6142c0338ffSzrj glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
6152c0338ffSzrj {
616*bc9cc675SDaniel Fojt 	Char pathbuf[PATH_MAX];
6172c0338ffSzrj 
6182c0338ffSzrj 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
6192c0338ffSzrj 	if (*pattern == EOS)
6202c0338ffSzrj 		return(0);
621*bc9cc675SDaniel Fojt 	return(glob2(pathbuf, pathbuf+PATH_MAX-1,
622*bc9cc675SDaniel Fojt 	    pathbuf, pathbuf+PATH_MAX-1,
6232c0338ffSzrj 	    pattern, pattern_last, pglob, limitp));
6242c0338ffSzrj }
6252c0338ffSzrj 
6262c0338ffSzrj /*
6272c0338ffSzrj  * The functions glob2 and glob3 are mutually recursive; there is one level
6282c0338ffSzrj  * of recursion for each segment in the pattern that contains one or more
6292c0338ffSzrj  * meta characters.
6302c0338ffSzrj  */
6312c0338ffSzrj static int
6322c0338ffSzrj glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
6332c0338ffSzrj     Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *limitp)
6342c0338ffSzrj {
6352c0338ffSzrj 	struct stat sb;
6362c0338ffSzrj 	Char *p, *q;
6372c0338ffSzrj 	int anymeta;
6382c0338ffSzrj 
6392c0338ffSzrj 	/*
6402c0338ffSzrj 	 * Loop over pattern segments until end of pattern or until
6412c0338ffSzrj 	 * segment with meta character found.
6422c0338ffSzrj 	 */
6432c0338ffSzrj 	for (anymeta = 0;;) {
6442c0338ffSzrj 		if (*pattern == EOS) {		/* End of pattern? */
6452c0338ffSzrj 			*pathend = EOS;
6462c0338ffSzrj 
6472c0338ffSzrj 			if ((pglob->gl_flags & GLOB_LIMIT) &&
6482c0338ffSzrj 			    limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
6492c0338ffSzrj 				errno = 0;
6502c0338ffSzrj 				*pathend++ = SEP;
6512c0338ffSzrj 				*pathend = EOS;
6522c0338ffSzrj 				return(GLOB_NOSPACE);
6532c0338ffSzrj 			}
654*bc9cc675SDaniel Fojt 			if (g_lstat(pathbuf, &sb, pglob))
655*bc9cc675SDaniel Fojt 				return(0);
6562c0338ffSzrj 
6572c0338ffSzrj 			if (((pglob->gl_flags & GLOB_MARK) &&
6582c0338ffSzrj 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
6592c0338ffSzrj 			    (S_ISLNK(sb.st_mode) &&
6602c0338ffSzrj 			    (g_stat(pathbuf, &sb, pglob) == 0) &&
6612c0338ffSzrj 			    S_ISDIR(sb.st_mode)))) {
6622c0338ffSzrj 				if (pathend+1 > pathend_last)
6632c0338ffSzrj 					return (1);
6642c0338ffSzrj 				*pathend++ = SEP;
6652c0338ffSzrj 				*pathend = EOS;
6662c0338ffSzrj 			}
6672c0338ffSzrj 			++pglob->gl_matchc;
6682c0338ffSzrj 			return(globextend(pathbuf, pglob, limitp, &sb));
6692c0338ffSzrj 		}
6702c0338ffSzrj 
6712c0338ffSzrj 		/* Find end of next segment, copy tentatively to pathend. */
6722c0338ffSzrj 		q = pathend;
6732c0338ffSzrj 		p = pattern;
6742c0338ffSzrj 		while (*p != EOS && *p != SEP) {
6752c0338ffSzrj 			if (ismeta(*p))
6762c0338ffSzrj 				anymeta = 1;
6772c0338ffSzrj 			if (q+1 > pathend_last)
6782c0338ffSzrj 				return (1);
6792c0338ffSzrj 			*q++ = *p++;
6802c0338ffSzrj 		}
6812c0338ffSzrj 
6822c0338ffSzrj 		if (!anymeta) {		/* No expansion, do next segment. */
6832c0338ffSzrj 			pathend = q;
6842c0338ffSzrj 			pattern = p;
6852c0338ffSzrj 			while (*pattern == SEP) {
6862c0338ffSzrj 				if (pathend+1 > pathend_last)
6872c0338ffSzrj 					return (1);
6882c0338ffSzrj 				*pathend++ = *pattern++;
6892c0338ffSzrj 			}
6902c0338ffSzrj 		} else
6912c0338ffSzrj 			/* Need expansion, recurse. */
6922c0338ffSzrj 			return(glob3(pathbuf, pathbuf_last, pathend,
6932c0338ffSzrj 			    pathend_last, pattern, p, pattern_last,
6942c0338ffSzrj 			    pglob, limitp));
6952c0338ffSzrj 	}
6962c0338ffSzrj 	/* NOTREACHED */
6972c0338ffSzrj }
6982c0338ffSzrj 
6992c0338ffSzrj static int
7002c0338ffSzrj glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
7012c0338ffSzrj     Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
7022c0338ffSzrj     struct glob_lim *limitp)
7032c0338ffSzrj {
7042c0338ffSzrj 	struct dirent *dp;
7052c0338ffSzrj 	DIR *dirp;
7062c0338ffSzrj 	int err;
707*bc9cc675SDaniel Fojt 	char buf[PATH_MAX];
7082c0338ffSzrj 
7092c0338ffSzrj 	/*
7102c0338ffSzrj 	 * The readdirfunc declaration can't be prototyped, because it is
7112c0338ffSzrj 	 * assigned, below, to two functions which are prototyped in glob.h
7122c0338ffSzrj 	 * and dirent.h as taking pointers to differently typed opaque
7132c0338ffSzrj 	 * structures.
7142c0338ffSzrj 	 */
7152c0338ffSzrj 	struct dirent *(*readdirfunc)(void *);
7162c0338ffSzrj 
7172c0338ffSzrj 	if (pathend > pathend_last)
7182c0338ffSzrj 		return (1);
7192c0338ffSzrj 	*pathend = EOS;
7202c0338ffSzrj 	errno = 0;
7212c0338ffSzrj 
7222c0338ffSzrj 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
7232c0338ffSzrj 		/* TODO: don't call for ENOENT or ENOTDIR? */
7242c0338ffSzrj 		if (pglob->gl_errfunc) {
7252c0338ffSzrj 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
7262c0338ffSzrj 				return(GLOB_ABORTED);
7272c0338ffSzrj 			if (pglob->gl_errfunc(buf, errno) ||
7282c0338ffSzrj 			    pglob->gl_flags & GLOB_ERR)
7292c0338ffSzrj 				return(GLOB_ABORTED);
7302c0338ffSzrj 		}
7312c0338ffSzrj 		return(0);
7322c0338ffSzrj 	}
7332c0338ffSzrj 
7342c0338ffSzrj 	err = 0;
7352c0338ffSzrj 
7362c0338ffSzrj 	/* Search directory for matching names. */
7372c0338ffSzrj 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
7382c0338ffSzrj 		readdirfunc = pglob->gl_readdir;
7392c0338ffSzrj 	else
7402c0338ffSzrj 		readdirfunc = (struct dirent *(*)(void *))readdir;
7412c0338ffSzrj 	while ((dp = (*readdirfunc)(dirp))) {
7422c0338ffSzrj 		u_char *sc;
7432c0338ffSzrj 		Char *dc;
7442c0338ffSzrj 
7452c0338ffSzrj 		if ((pglob->gl_flags & GLOB_LIMIT) &&
7462c0338ffSzrj 		    limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
7472c0338ffSzrj 			errno = 0;
7482c0338ffSzrj 			*pathend++ = SEP;
7492c0338ffSzrj 			*pathend = EOS;
7502c0338ffSzrj 			err = GLOB_NOSPACE;
7512c0338ffSzrj 			break;
7522c0338ffSzrj 		}
7532c0338ffSzrj 
7542c0338ffSzrj 		/* Initial DOT must be matched literally. */
7552c0338ffSzrj 		if (dp->d_name[0] == DOT && *pattern != DOT)
7562c0338ffSzrj 			continue;
7572c0338ffSzrj 		dc = pathend;
7582c0338ffSzrj 		sc = (u_char *) dp->d_name;
7592c0338ffSzrj 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
7602c0338ffSzrj 			;
7612c0338ffSzrj 		if (dc >= pathend_last) {
7622c0338ffSzrj 			*dc = EOS;
7632c0338ffSzrj 			err = 1;
7642c0338ffSzrj 			break;
7652c0338ffSzrj 		}
7662c0338ffSzrj 
767*bc9cc675SDaniel Fojt 		if (!match(pathend, pattern, restpattern)) {
7682c0338ffSzrj 			*pathend = EOS;
7692c0338ffSzrj 			continue;
7702c0338ffSzrj 		}
7712c0338ffSzrj 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
7722c0338ffSzrj 		    restpattern, restpattern_last, pglob, limitp);
7732c0338ffSzrj 		if (err)
7742c0338ffSzrj 			break;
7752c0338ffSzrj 	}
7762c0338ffSzrj 
7772c0338ffSzrj 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
7782c0338ffSzrj 		(*pglob->gl_closedir)(dirp);
7792c0338ffSzrj 	else
7802c0338ffSzrj 		closedir(dirp);
7812c0338ffSzrj 	return(err);
7822c0338ffSzrj }
7832c0338ffSzrj 
7842c0338ffSzrj 
7852c0338ffSzrj /*
7862c0338ffSzrj  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
7872c0338ffSzrj  * add the new item, and update gl_pathc.
7882c0338ffSzrj  *
7892c0338ffSzrj  * This assumes the BSD realloc, which only copies the block when its size
7902c0338ffSzrj  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
7912c0338ffSzrj  * behavior.
7922c0338ffSzrj  *
7932c0338ffSzrj  * Return 0 if new item added, error code if memory couldn't be allocated.
7942c0338ffSzrj  *
7952c0338ffSzrj  * Invariant of the glob_t structure:
7962c0338ffSzrj  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
7972c0338ffSzrj  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
7982c0338ffSzrj  */
7992c0338ffSzrj static int
8002c0338ffSzrj globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
8012c0338ffSzrj     struct stat *sb)
8022c0338ffSzrj {
8032c0338ffSzrj 	char **pathv;
804*bc9cc675SDaniel Fojt 	size_t i, newn, len;
8052c0338ffSzrj 	char *copy = NULL;
8062c0338ffSzrj 	const Char *p;
8072c0338ffSzrj 	struct stat **statv;
8082c0338ffSzrj 
8092c0338ffSzrj 	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
810*bc9cc675SDaniel Fojt 	if (pglob->gl_offs >= SSIZE_MAX ||
811*bc9cc675SDaniel Fojt 	    pglob->gl_pathc >= SSIZE_MAX ||
812*bc9cc675SDaniel Fojt 	    newn >= SSIZE_MAX ||
8132c0338ffSzrj 	    SIZE_MAX / sizeof(*pathv) <= newn ||
8142c0338ffSzrj 	    SIZE_MAX / sizeof(*statv) <= newn) {
8152c0338ffSzrj  nospace:
816*bc9cc675SDaniel Fojt 		for (i = pglob->gl_offs; i < newn - 2; i++) {
8172c0338ffSzrj 			if (pglob->gl_pathv && pglob->gl_pathv[i])
8182c0338ffSzrj 				free(pglob->gl_pathv[i]);
8192c0338ffSzrj 			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
8202c0338ffSzrj 			    pglob->gl_pathv && pglob->gl_pathv[i])
8212c0338ffSzrj 				free(pglob->gl_statv[i]);
8222c0338ffSzrj 		}
8232c0338ffSzrj 		free(pglob->gl_pathv);
8242c0338ffSzrj 		pglob->gl_pathv = NULL;
8252c0338ffSzrj 		free(pglob->gl_statv);
8262c0338ffSzrj 		pglob->gl_statv = NULL;
8272c0338ffSzrj 		return(GLOB_NOSPACE);
8282c0338ffSzrj 	}
8292c0338ffSzrj 
830*bc9cc675SDaniel Fojt 	pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
8312c0338ffSzrj 	if (pathv == NULL)
8322c0338ffSzrj 		goto nospace;
8332c0338ffSzrj 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
8342c0338ffSzrj 		/* first time around -- clear initial gl_offs items */
8352c0338ffSzrj 		pathv += pglob->gl_offs;
836*bc9cc675SDaniel Fojt 		for (i = pglob->gl_offs; i > 0; i--)
8372c0338ffSzrj 			*--pathv = NULL;
8382c0338ffSzrj 	}
8392c0338ffSzrj 	pglob->gl_pathv = pathv;
8402c0338ffSzrj 
8412c0338ffSzrj 	if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
842*bc9cc675SDaniel Fojt 		statv = reallocarray(pglob->gl_statv, newn, sizeof(*statv));
8432c0338ffSzrj 		if (statv == NULL)
8442c0338ffSzrj 			goto nospace;
8452c0338ffSzrj 		if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
8462c0338ffSzrj 			/* first time around -- clear initial gl_offs items */
8472c0338ffSzrj 			statv += pglob->gl_offs;
848*bc9cc675SDaniel Fojt 			for (i = pglob->gl_offs; i > 0; i--)
8492c0338ffSzrj 				*--statv = NULL;
8502c0338ffSzrj 		}
8512c0338ffSzrj 		pglob->gl_statv = statv;
8522c0338ffSzrj 		if (sb == NULL)
8532c0338ffSzrj 			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
8542c0338ffSzrj 		else {
8552c0338ffSzrj 			limitp->glim_malloc += sizeof(**statv);
8562c0338ffSzrj 			if ((pglob->gl_flags & GLOB_LIMIT) &&
8572c0338ffSzrj 			    limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
8582c0338ffSzrj 				errno = 0;
8592c0338ffSzrj 				return(GLOB_NOSPACE);
8602c0338ffSzrj 			}
8612c0338ffSzrj 			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
8622c0338ffSzrj 			    malloc(sizeof(**statv))) == NULL)
8632c0338ffSzrj 				goto copy_error;
8642c0338ffSzrj 			memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
8652c0338ffSzrj 			    sizeof(*sb));
8662c0338ffSzrj 		}
8672c0338ffSzrj 		statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
8682c0338ffSzrj 	}
8692c0338ffSzrj 
8702c0338ffSzrj 	for (p = path; *p++;)
8712c0338ffSzrj 		;
8722c0338ffSzrj 	len = (size_t)(p - path);
8732c0338ffSzrj 	limitp->glim_malloc += len;
8742c0338ffSzrj 	if ((copy = malloc(len)) != NULL) {
8752c0338ffSzrj 		if (g_Ctoc(path, copy, len)) {
8762c0338ffSzrj 			free(copy);
8772c0338ffSzrj 			return(GLOB_NOSPACE);
8782c0338ffSzrj 		}
8792c0338ffSzrj 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
8802c0338ffSzrj 	}
8812c0338ffSzrj 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
8822c0338ffSzrj 
8832c0338ffSzrj 	if ((pglob->gl_flags & GLOB_LIMIT) &&
8842c0338ffSzrj 	    (newn * sizeof(*pathv)) + limitp->glim_malloc >
8852c0338ffSzrj 	    GLOB_LIMIT_MALLOC) {
8862c0338ffSzrj 		errno = 0;
8872c0338ffSzrj 		return(GLOB_NOSPACE);
8882c0338ffSzrj 	}
8892c0338ffSzrj  copy_error:
8902c0338ffSzrj 	return(copy == NULL ? GLOB_NOSPACE : 0);
8912c0338ffSzrj }
8922c0338ffSzrj 
8932c0338ffSzrj 
8942c0338ffSzrj /*
8952c0338ffSzrj  * pattern matching function for filenames.  Each occurrence of the *
896*bc9cc675SDaniel Fojt  * pattern causes an iteration.
897*bc9cc675SDaniel Fojt  *
898*bc9cc675SDaniel Fojt  * Note, this function differs from the original as per the discussion
899*bc9cc675SDaniel Fojt  * here: https://research.swtch.com/glob
900*bc9cc675SDaniel Fojt  *
901*bc9cc675SDaniel Fojt  * Basically we removed the recursion and made it use the algorithm
902*bc9cc675SDaniel Fojt  * from Russ Cox to not go quadratic on cases like a file called
903*bc9cc675SDaniel Fojt  * ("a" x 100) . "x" matched against a pattern like "a*a*a*a*a*a*a*y".
9042c0338ffSzrj  */
9052c0338ffSzrj static int
906*bc9cc675SDaniel Fojt match(Char *name, Char *pat, Char *patend)
9072c0338ffSzrj {
9082c0338ffSzrj 	int ok, negate_range;
9092c0338ffSzrj 	Char c, k;
910*bc9cc675SDaniel Fojt 	Char *nextp = NULL;
911*bc9cc675SDaniel Fojt 	Char *nextn = NULL;
9122c0338ffSzrj 
913*bc9cc675SDaniel Fojt loop:
9142c0338ffSzrj 	while (pat < patend) {
9152c0338ffSzrj 		c = *pat++;
9162c0338ffSzrj 		switch (c & M_MASK) {
9172c0338ffSzrj 		case M_ALL:
9182c0338ffSzrj 			while (pat < patend && (*pat & M_MASK) == M_ALL)
9192c0338ffSzrj 				pat++;	/* eat consecutive '*' */
9202c0338ffSzrj 			if (pat == patend)
9212c0338ffSzrj 				return(1);
922*bc9cc675SDaniel Fojt 			if (*name == EOS)
9232c0338ffSzrj 				return(0);
924*bc9cc675SDaniel Fojt 			nextn = name + 1;
925*bc9cc675SDaniel Fojt 			nextp = pat - 1;
926*bc9cc675SDaniel Fojt 			break;
9272c0338ffSzrj 		case M_ONE:
9282c0338ffSzrj 			if (*name++ == EOS)
929*bc9cc675SDaniel Fojt 				goto fail;
9302c0338ffSzrj 			break;
9312c0338ffSzrj 		case M_SET:
9322c0338ffSzrj 			ok = 0;
9332c0338ffSzrj 			if ((k = *name++) == EOS)
934*bc9cc675SDaniel Fojt 				goto fail;
9352c0338ffSzrj 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
9362c0338ffSzrj 				++pat;
9372c0338ffSzrj 			while (((c = *pat++) & M_MASK) != M_END) {
9382c0338ffSzrj 				if ((c & M_MASK) == M_CLASS) {
9392c0338ffSzrj 					Char idx = *pat & M_MASK;
9402c0338ffSzrj 					if (idx < NCCLASSES &&
9412c0338ffSzrj 					    cclasses[idx].isctype(k))
9422c0338ffSzrj 						ok = 1;
9432c0338ffSzrj 					++pat;
9442c0338ffSzrj 				}
9452c0338ffSzrj 				if ((*pat & M_MASK) == M_RNG) {
9462c0338ffSzrj 					if (c <= k && k <= pat[1])
9472c0338ffSzrj 						ok = 1;
9482c0338ffSzrj 					pat += 2;
9492c0338ffSzrj 				} else if (c == k)
9502c0338ffSzrj 					ok = 1;
9512c0338ffSzrj 			}
9522c0338ffSzrj 			if (ok == negate_range)
953*bc9cc675SDaniel Fojt 				goto fail;
9542c0338ffSzrj 			break;
9552c0338ffSzrj 		default:
9562c0338ffSzrj 			if (*name++ != c)
957*bc9cc675SDaniel Fojt 				goto fail;
9582c0338ffSzrj 			break;
9592c0338ffSzrj 		}
9602c0338ffSzrj 	}
961*bc9cc675SDaniel Fojt 	if (*name == EOS)
962*bc9cc675SDaniel Fojt 		return(1);
963*bc9cc675SDaniel Fojt 
964*bc9cc675SDaniel Fojt fail:
965*bc9cc675SDaniel Fojt 	if (nextn) {
966*bc9cc675SDaniel Fojt 		pat = nextp;
967*bc9cc675SDaniel Fojt 		name = nextn;
968*bc9cc675SDaniel Fojt 		goto loop;
969*bc9cc675SDaniel Fojt 	}
970*bc9cc675SDaniel Fojt 	return(0);
9712c0338ffSzrj }
9722c0338ffSzrj 
9732c0338ffSzrj /* Free allocated data belonging to a glob_t structure. */
9742c0338ffSzrj void
9752c0338ffSzrj globfree(glob_t *pglob)
9762c0338ffSzrj {
977*bc9cc675SDaniel Fojt 	size_t i;
9782c0338ffSzrj 	char **pp;
9792c0338ffSzrj 
9802c0338ffSzrj 	if (pglob->gl_pathv != NULL) {
9812c0338ffSzrj 		pp = pglob->gl_pathv + pglob->gl_offs;
9822c0338ffSzrj 		for (i = pglob->gl_pathc; i--; ++pp)
9832c0338ffSzrj 			free(*pp);
9842c0338ffSzrj 		free(pglob->gl_pathv);
9852c0338ffSzrj 		pglob->gl_pathv = NULL;
9862c0338ffSzrj 	}
9872c0338ffSzrj 	if (pglob->gl_statv != NULL) {
9882c0338ffSzrj 		for (i = 0; i < pglob->gl_pathc; i++) {
9892c0338ffSzrj 			free(pglob->gl_statv[i]);
9902c0338ffSzrj 		}
9912c0338ffSzrj 		free(pglob->gl_statv);
9922c0338ffSzrj 		pglob->gl_statv = NULL;
9932c0338ffSzrj 	}
9942c0338ffSzrj }
9952c0338ffSzrj 
9962c0338ffSzrj static DIR *
9972c0338ffSzrj g_opendir(Char *str, glob_t *pglob)
9982c0338ffSzrj {
999*bc9cc675SDaniel Fojt 	char buf[PATH_MAX];
10002c0338ffSzrj 
10012c0338ffSzrj 	if (!*str)
10022c0338ffSzrj 		strlcpy(buf, ".", sizeof buf);
10032c0338ffSzrj 	else {
10042c0338ffSzrj 		if (g_Ctoc(str, buf, sizeof(buf)))
10052c0338ffSzrj 			return(NULL);
10062c0338ffSzrj 	}
10072c0338ffSzrj 
10082c0338ffSzrj 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
10092c0338ffSzrj 		return((*pglob->gl_opendir)(buf));
10102c0338ffSzrj 
10112c0338ffSzrj 	return(opendir(buf));
10122c0338ffSzrj }
10132c0338ffSzrj 
10142c0338ffSzrj static int
10152c0338ffSzrj g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
10162c0338ffSzrj {
1017*bc9cc675SDaniel Fojt 	char buf[PATH_MAX];
10182c0338ffSzrj 
10192c0338ffSzrj 	if (g_Ctoc(fn, buf, sizeof(buf)))
10202c0338ffSzrj 		return(-1);
10212c0338ffSzrj 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
10222c0338ffSzrj 		return((*pglob->gl_lstat)(buf, sb));
10232c0338ffSzrj 	return(lstat(buf, sb));
10242c0338ffSzrj }
10252c0338ffSzrj 
10262c0338ffSzrj static int
10272c0338ffSzrj g_stat(Char *fn, struct stat *sb, glob_t *pglob)
10282c0338ffSzrj {
1029*bc9cc675SDaniel Fojt 	char buf[PATH_MAX];
10302c0338ffSzrj 
10312c0338ffSzrj 	if (g_Ctoc(fn, buf, sizeof(buf)))
10322c0338ffSzrj 		return(-1);
10332c0338ffSzrj 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
10342c0338ffSzrj 		return((*pglob->gl_stat)(buf, sb));
10352c0338ffSzrj 	return(stat(buf, sb));
10362c0338ffSzrj }
10372c0338ffSzrj 
10382c0338ffSzrj static Char *
10392c0338ffSzrj g_strchr(const Char *str, int ch)
10402c0338ffSzrj {
10412c0338ffSzrj 	do {
10422c0338ffSzrj 		if (*str == ch)
10432c0338ffSzrj 			return ((Char *)str);
10442c0338ffSzrj 	} while (*str++);
10452c0338ffSzrj 	return (NULL);
10462c0338ffSzrj }
10472c0338ffSzrj 
10482c0338ffSzrj static int
1049*bc9cc675SDaniel Fojt g_Ctoc(const Char *str, char *buf, size_t len)
10502c0338ffSzrj {
10512c0338ffSzrj 
10522c0338ffSzrj 	while (len--) {
10532c0338ffSzrj 		if ((*buf++ = *str++) == EOS)
10542c0338ffSzrj 			return (0);
10552c0338ffSzrj 	}
10562c0338ffSzrj 	return (1);
10572c0338ffSzrj }
10582c0338ffSzrj 
10592c0338ffSzrj #ifdef DEBUG
10602c0338ffSzrj static void
10612c0338ffSzrj qprintf(const char *str, Char *s)
10622c0338ffSzrj {
10632c0338ffSzrj 	Char *p;
10642c0338ffSzrj 
10652c0338ffSzrj 	(void)printf("%s:\n", str);
10662c0338ffSzrj 	for (p = s; *p; p++)
10672c0338ffSzrj 		(void)printf("%c", CHAR(*p));
10682c0338ffSzrj 	(void)printf("\n");
10692c0338ffSzrj 	for (p = s; *p; p++)
10702c0338ffSzrj 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
10712c0338ffSzrj 	(void)printf("\n");
10722c0338ffSzrj 	for (p = s; *p; p++)
10732c0338ffSzrj 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
10742c0338ffSzrj 	(void)printf("\n");
10752c0338ffSzrj }
10762c0338ffSzrj #endif
10772c0338ffSzrj 
10782c0338ffSzrj #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
10792c0338ffSzrj           !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) */
1080