1331722Seadler/*
21573Srgrimes * Copyright (c) 1989, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Guido van Rossum.
71573Srgrimes *
8227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation
9227753Stheraven * All rights reserved.
10227753Stheraven * Portions of this software were developed by David Chisnall
11227753Stheraven * under sponsorship from the FreeBSD Foundation.
12227753Stheraven *
131573Srgrimes * Redistribution and use in source and binary forms, with or without
141573Srgrimes * modification, are permitted provided that the following conditions
151573Srgrimes * are met:
161573Srgrimes * 1. Redistributions of source code must retain the above copyright
171573Srgrimes *    notice, this list of conditions and the following disclaimer.
181573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191573Srgrimes *    notice, this list of conditions and the following disclaimer in the
201573Srgrimes *    documentation and/or other materials provided with the distribution.
211573Srgrimes * 4. Neither the name of the University nor the names of its contributors
221573Srgrimes *    may be used to endorse or promote products derived from this software
231573Srgrimes *    without specific prior written permission.
241573Srgrimes *
251573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351573Srgrimes * SUCH DAMAGE.
361573Srgrimes */
371573Srgrimes
381573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
391573Srgrimesstatic char sccsid[] = "@(#)glob.c	8.3 (Berkeley) 10/13/93";
401573Srgrimes#endif /* LIBC_SCCS and not lint */
4190045Sobrien#include <sys/cdefs.h>
4290045Sobrien__FBSDID("$FreeBSD: stable/11/lib/libc/gen/glob.c 316613 2017-04-07 16:08:04Z pfg $");
431573Srgrimes
441573Srgrimes/*
451573Srgrimes * glob(3) -- a superset of the one defined in POSIX 1003.2.
461573Srgrimes *
471573Srgrimes * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
481573Srgrimes *
491573Srgrimes * Optional extra services, controlled by flags not defined by POSIX:
501573Srgrimes *
511573Srgrimes * GLOB_QUOTE:
521573Srgrimes *	Escaping convention: \ inhibits any special meaning the following
531573Srgrimes *	character might have (except \ at end of string is retained).
541573Srgrimes * GLOB_MAGCHAR:
551573Srgrimes *	Set in gl_flags if pattern contained a globbing character.
561573Srgrimes * GLOB_NOMAGIC:
571573Srgrimes *	Same as GLOB_NOCHECK, but it will only append pattern if it did
581573Srgrimes *	not contain any magic characters.  [Used in csh style globbing]
591573Srgrimes * GLOB_ALTDIRFUNC:
601573Srgrimes *	Use alternately specified directory access functions.
611573Srgrimes * GLOB_TILDE:
621573Srgrimes *	expand ~user/foo to the /home/dir/of/user/foo
631573Srgrimes * GLOB_BRACE:
648870Srgrimes *	expand {1,2}{a,b} to 1a 1b 2a 2b
651573Srgrimes * gl_matchc:
661573Srgrimes *	Number of matches in the current invocation of glob.
671573Srgrimes */
681573Srgrimes
69132817Stjr/*
70132817Stjr * Some notes on multibyte character support:
71132817Stjr * 1. Patterns with illegal byte sequences match nothing - even if
72132817Stjr *    GLOB_NOCHECK is specified.
73132817Stjr * 2. Illegal byte sequences in filenames are handled by treating them as
74304284Sache *    single-byte characters with a values of such bytes of the sequence
75132817Stjr *    cast to wchar_t.
76132817Stjr * 3. State-dependent encodings are not currently supported.
77132817Stjr */
78132817Stjr
791573Srgrimes#include <sys/param.h>
801573Srgrimes#include <sys/stat.h>
811573Srgrimes
821573Srgrimes#include <ctype.h>
831573Srgrimes#include <dirent.h>
841573Srgrimes#include <errno.h>
851573Srgrimes#include <glob.h>
86132817Stjr#include <limits.h>
871573Srgrimes#include <pwd.h>
88132817Stjr#include <stdint.h>
891573Srgrimes#include <stdio.h>
901573Srgrimes#include <stdlib.h>
911573Srgrimes#include <string.h>
921573Srgrimes#include <unistd.h>
93132817Stjr#include <wchar.h>
941573Srgrimes
9519276Sache#include "collate.h"
9619276Sache
97243779Smarcel/*
98243779Smarcel * glob(3) expansion limits. Stop the expansion if any of these limits
99243779Smarcel * is reached. This caps the runtime in the face of DoS attacks. See
100243779Smarcel * also CVE-2010-2632
101243779Smarcel */
102243779Smarcel#define	GLOB_LIMIT_BRACE	128	/* number of brace calls */
103243779Smarcel#define	GLOB_LIMIT_PATH		65536	/* number of path elements */
104243779Smarcel#define	GLOB_LIMIT_READDIR	16384	/* number of readdirs */
105243779Smarcel#define	GLOB_LIMIT_STAT		1024	/* number of stat system calls */
106243779Smarcel#define	GLOB_LIMIT_STRING	ARG_MAX	/* maximum total size for paths */
107243779Smarcel
108243779Smarcelstruct glob_limit {
109243779Smarcel	size_t	l_brace_cnt;
110243779Smarcel	size_t	l_path_lim;
111243779Smarcel	size_t	l_readdir_cnt;
112243779Smarcel	size_t	l_stat_cnt;
113243779Smarcel	size_t	l_string_cnt;
114243779Smarcel};
115243779Smarcel
116304284Sache#define	DOT		L'.'
117304284Sache#define	EOS		L'\0'
118304284Sache#define	LBRACKET	L'['
119304284Sache#define	NOT		L'!'
120304284Sache#define	QUESTION	L'?'
121304284Sache#define	QUOTE		L'\\'
122304284Sache#define	RANGE		L'-'
123304284Sache#define	RBRACKET	L']'
124304284Sache#define	SEP		L'/'
125304284Sache#define	STAR		L'*'
126304284Sache#define	TILDE		L'~'
127304284Sache#define	LBRACE		L'{'
128304284Sache#define	RBRACE		L'}'
129304284Sache#define	COMMA		L','
1301573Srgrimes
131132817Stjr#define	M_QUOTE		0x8000000000ULL
132132817Stjr#define	M_PROTECT	0x4000000000ULL
133132817Stjr#define	M_MASK		0xffffffffffULL
134132817Stjr#define	M_CHAR		0x00ffffffffULL
1351573Srgrimes
136132817Stjrtypedef uint_fast64_t Char;
1371573Srgrimes
138132817Stjr#define	CHAR(c)		((Char)((c)&M_CHAR))
1391573Srgrimes#define	META(c)		((Char)((c)|M_QUOTE))
140304284Sache#define	UNPROT(c)	((c) & ~M_PROTECT)
141304284Sache#define	M_ALL		META(L'*')
142304284Sache#define	M_END		META(L']')
143304284Sache#define	M_NOT		META(L'!')
144304284Sache#define	M_ONE		META(L'?')
145304284Sache#define	M_RNG		META(L'-')
146304284Sache#define	M_SET		META(L'[')
1471573Srgrimes#define	ismeta(c)	(((c)&M_QUOTE) != 0)
148304284Sache#ifdef DEBUG
149304284Sache#define	isprot(c)	(((c)&M_PROTECT) != 0)
150304284Sache#endif
1511573Srgrimes
15290045Sobrienstatic int	 compare(const void *, const void *);
153158812Sachestatic int	 g_Ctoc(const Char *, char *, size_t);
15490045Sobrienstatic int	 g_lstat(Char *, struct stat *, glob_t *);
15590045Sobrienstatic DIR	*g_opendir(Char *, glob_t *);
156180021Smtmstatic const Char *g_strchr(const Char *, wchar_t);
1571573Srgrimes#ifdef notdef
15890045Sobrienstatic Char	*g_strcat(Char *, const Char *);
1591573Srgrimes#endif
16090045Sobrienstatic int	 g_stat(Char *, struct stat *, glob_t *);
161304284Sachestatic int	 glob0(const Char *, glob_t *, struct glob_limit *,
162304284Sache    const char *);
163243779Smarcelstatic int	 glob1(Char *, glob_t *, struct glob_limit *);
164243779Smarcelstatic int	 glob2(Char *, Char *, Char *, Char *, glob_t *,
165243779Smarcel    struct glob_limit *);
166243779Smarcelstatic int	 glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
167243779Smarcel    struct glob_limit *);
168304284Sachestatic int	 globextend(const Char *, glob_t *, struct glob_limit *,
169304284Sache    const char *);
170243779Smarcelstatic const Char *
17190045Sobrien		 globtilde(const Char *, Char *, size_t, glob_t *);
172304284Sachestatic int	 globexp0(const Char *, glob_t *, struct glob_limit *,
173304284Sache    const char *);
174243779Smarcelstatic int	 globexp1(const Char *, glob_t *, struct glob_limit *);
175304284Sachestatic int	 globexp2(const Char *, const Char *, glob_t *,
176243779Smarcel    struct glob_limit *);
177304284Sachestatic int	 globfinal(glob_t *, struct glob_limit *, size_t,
178304284Sache    const char *);
17990045Sobrienstatic int	 match(Char *, Char *, Char *);
180304284Sachestatic int	 err_nomatch(glob_t *, struct glob_limit *, const char *);
181304284Sachestatic int	 err_aborted(glob_t *, int, char *);
1821573Srgrimes#ifdef DEBUG
18390045Sobrienstatic void	 qprintf(const char *, Char *);
1841573Srgrimes#endif
1851573Srgrimes
1861573Srgrimesint
187228754Seadlerglob(const char * __restrict pattern, int flags,
188228754Seadler	 int (*errfunc)(const char *, int), glob_t * __restrict pglob)
1891573Srgrimes{
190243779Smarcel	struct glob_limit limit = { 0, 0, 0, 0, 0 };
191159294Sdelphij	const char *patnext;
192132817Stjr	Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
193132817Stjr	mbstate_t mbs;
194132817Stjr	wchar_t wc;
195132817Stjr	size_t clen;
196304284Sache	int too_long;
1971573Srgrimes
198159294Sdelphij	patnext = pattern;
1991573Srgrimes	if (!(flags & GLOB_APPEND)) {
2001573Srgrimes		pglob->gl_pathc = 0;
2011573Srgrimes		pglob->gl_pathv = NULL;
2021573Srgrimes		if (!(flags & GLOB_DOOFFS))
2031573Srgrimes			pglob->gl_offs = 0;
2041573Srgrimes	}
20580525Smikeh	if (flags & GLOB_LIMIT) {
206243779Smarcel		limit.l_path_lim = pglob->gl_matchc;
207243779Smarcel		if (limit.l_path_lim == 0)
208243779Smarcel			limit.l_path_lim = GLOB_LIMIT_PATH;
209243779Smarcel	}
2101573Srgrimes	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
2111573Srgrimes	pglob->gl_errfunc = errfunc;
2121573Srgrimes	pglob->gl_matchc = 0;
2131573Srgrimes
2141573Srgrimes	bufnext = patbuf;
21574963Speter	bufend = bufnext + MAXPATHLEN - 1;
216304284Sache	too_long = 1;
217132817Stjr	if (flags & GLOB_NOESCAPE) {
218132817Stjr		memset(&mbs, 0, sizeof(mbs));
219304284Sache		while (bufnext <= bufend) {
220132817Stjr			clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
221132817Stjr			if (clen == (size_t)-1 || clen == (size_t)-2)
222304284Sache				return (err_nomatch(pglob, &limit, pattern));
223304284Sache			else if (clen == 0) {
224304284Sache				too_long = 0;
225132817Stjr				break;
226304284Sache			}
227132817Stjr			*bufnext++ = wc;
228132817Stjr			patnext += clen;
229132817Stjr		}
230132817Stjr	} else {
2311573Srgrimes		/* Protect the quoted characters. */
232132817Stjr		memset(&mbs, 0, sizeof(mbs));
233304284Sache		while (bufnext <= bufend) {
234304284Sache			if (*patnext == '\\') {
235304284Sache				if (*++patnext == '\0') {
236304284Sache					*bufnext++ = QUOTE;
237132817Stjr					continue;
2381573Srgrimes				}
239132817Stjr				prot = M_PROTECT;
240132817Stjr			} else
241132817Stjr				prot = 0;
242132817Stjr			clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
243132817Stjr			if (clen == (size_t)-1 || clen == (size_t)-2)
244304284Sache				return (err_nomatch(pglob, &limit, pattern));
245304284Sache			else if (clen == 0) {
246304284Sache				too_long = 0;
247132817Stjr				break;
248304284Sache			}
249132817Stjr			*bufnext++ = wc | prot;
250132817Stjr			patnext += clen;
251132817Stjr		}
2521573Srgrimes	}
253304284Sache	if (too_long)
254304284Sache		return (err_nomatch(pglob, &limit, pattern));
2551573Srgrimes	*bufnext = EOS;
2561573Srgrimes
2571573Srgrimes	if (flags & GLOB_BRACE)
258304284Sache	    return (globexp0(patbuf, pglob, &limit, pattern));
2591573Srgrimes	else
260304284Sache	    return (glob0(patbuf, pglob, &limit, pattern));
2611573Srgrimes}
2621573Srgrimes
263304284Sachestatic int
264304284Sacheglobexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
265304284Sache    const char *origpat) {
266304284Sache	int rv;
267304284Sache	size_t oldpathc;
268304284Sache
269304284Sache	/* Protect a single {}, for find(1), like csh */
270304284Sache	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
271304284Sache		if ((pglob->gl_flags & GLOB_LIMIT) &&
272304284Sache		    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
273304284Sache			errno = E2BIG;
274304284Sache			return (GLOB_NOSPACE);
275304284Sache		}
276304284Sache		return (glob0(pattern, pglob, limit, origpat));
277304284Sache	}
278304284Sache
279304284Sache	oldpathc = pglob->gl_pathc;
280304284Sache
281304284Sache	if ((rv = globexp1(pattern, pglob, limit)) != 0)
282304284Sache		return rv;
283304284Sache
284304284Sache	return (globfinal(pglob, limit, oldpathc, origpat));
285304284Sache}
286304284Sache
2871573Srgrimes/*
2881573Srgrimes * Expand recursively a glob {} pattern. When there is no more expansion
2891573Srgrimes * invoke the standard globbing routine to glob the rest of the magic
2901573Srgrimes * characters
2911573Srgrimes */
29274963Speterstatic int
293243779Smarcelglobexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
2941573Srgrimes{
295304284Sache	const Char* ptr;
2961573Srgrimes
297304284Sache	if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
298304284Sache		if ((pglob->gl_flags & GLOB_LIMIT) &&
299304284Sache		    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
300304284Sache			errno = E2BIG;
301304284Sache			return (GLOB_NOSPACE);
302304284Sache		}
303304284Sache		return (globexp2(ptr, pattern, pglob, limit));
304243779Smarcel	}
305243779Smarcel
306304284Sache	return (glob0(pattern, pglob, limit, NULL));
3071573Srgrimes}
3081573Srgrimes
3091573Srgrimes
3101573Srgrimes/*
3111573Srgrimes * Recursive brace globbing helper. Tries to expand a single brace.
3121573Srgrimes * If it succeeds then it invokes globexp1 with the new pattern.
3131573Srgrimes * If it fails then it tries to glob the rest of the pattern and returns.
3141573Srgrimes */
31574963Speterstatic int
316304284Sacheglobexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
317243779Smarcel    struct glob_limit *limit)
3181573Srgrimes{
319304284Sache	int     i, rv;
3201573Srgrimes	Char   *lm, *ls;
321150137Sache	const Char *pe, *pm, *pm1, *pl;
32274963Speter	Char    patbuf[MAXPATHLEN];
3231573Srgrimes
3241573Srgrimes	/* copy part up to the brace */
3251573Srgrimes	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
3261573Srgrimes		continue;
32774963Speter	*lm = EOS;
3281573Srgrimes	ls = lm;
3291573Srgrimes
3301573Srgrimes	/* Find the balanced brace */
331304284Sache	for (i = 0, pe = ++ptr; *pe != EOS; pe++)
3321573Srgrimes		if (*pe == LBRACKET) {
3331573Srgrimes			/* Ignore everything between [] */
3341573Srgrimes			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
3351573Srgrimes				continue;
3361573Srgrimes			if (*pe == EOS) {
3378870Srgrimes				/*
3381573Srgrimes				 * We could not find a matching RBRACKET.
3391573Srgrimes				 * Ignore and just look for RBRACE
3401573Srgrimes				 */
3411573Srgrimes				pe = pm;
3421573Srgrimes			}
3431573Srgrimes		}
3441573Srgrimes		else if (*pe == LBRACE)
3451573Srgrimes			i++;
3461573Srgrimes		else if (*pe == RBRACE) {
3471573Srgrimes			if (i == 0)
3481573Srgrimes				break;
3491573Srgrimes			i--;
3501573Srgrimes		}
3511573Srgrimes
3521573Srgrimes	/* Non matching braces; just glob the pattern */
353304284Sache	if (i != 0 || *pe == EOS)
354304284Sache		return (glob0(pattern, pglob, limit, NULL));
3551573Srgrimes
3561573Srgrimes	for (i = 0, pl = pm = ptr; pm <= pe; pm++)
3571573Srgrimes		switch (*pm) {
3581573Srgrimes		case LBRACKET:
3591573Srgrimes			/* Ignore everything between [] */
360150137Sache			for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
3611573Srgrimes				continue;
3621573Srgrimes			if (*pm == EOS) {
3638870Srgrimes				/*
3641573Srgrimes				 * We could not find a matching RBRACKET.
3651573Srgrimes				 * Ignore and just look for RBRACE
3661573Srgrimes				 */
367150137Sache				pm = pm1;
3681573Srgrimes			}
3691573Srgrimes			break;
3701573Srgrimes
3711573Srgrimes		case LBRACE:
3721573Srgrimes			i++;
3731573Srgrimes			break;
3741573Srgrimes
3751573Srgrimes		case RBRACE:
3761573Srgrimes			if (i) {
3771573Srgrimes			    i--;
3781573Srgrimes			    break;
3791573Srgrimes			}
3801573Srgrimes			/* FALLTHROUGH */
3811573Srgrimes		case COMMA:
3821573Srgrimes			if (i && *pm == COMMA)
3831573Srgrimes				break;
3841573Srgrimes			else {
3851573Srgrimes				/* Append the current string */
3861573Srgrimes				for (lm = ls; (pl < pm); *lm++ = *pl++)
3871573Srgrimes					continue;
3888870Srgrimes				/*
3891573Srgrimes				 * Append the rest of the pattern after the
3901573Srgrimes				 * closing brace
3911573Srgrimes				 */
3921573Srgrimes				for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
3931573Srgrimes					continue;
3941573Srgrimes
3951573Srgrimes				/* Expand the current pattern */
3961573Srgrimes#ifdef DEBUG
3971573Srgrimes				qprintf("globexp2:", patbuf);
3981573Srgrimes#endif
399304284Sache				rv = globexp1(patbuf, pglob, limit);
400304284Sache				if (rv)
401304284Sache					return (rv);
4021573Srgrimes
4031573Srgrimes				/* move after the comma, to the next string */
4041573Srgrimes				pl = pm + 1;
4051573Srgrimes			}
4061573Srgrimes			break;
4071573Srgrimes
4081573Srgrimes		default:
4091573Srgrimes			break;
4101573Srgrimes		}
411228755Seadler	return (0);
4121573Srgrimes}
4131573Srgrimes
4141573Srgrimes
4151573Srgrimes
4161573Srgrimes/*
4171573Srgrimes * expand tilde from the passwd file.
4181573Srgrimes */
4191573Srgrimesstatic const Char *
420159294Sdelphijglobtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
4211573Srgrimes{
4221573Srgrimes	struct passwd *pwd;
423304284Sache	char *h, *sc;
4241573Srgrimes	const Char *p;
42524158Simp	Char *b, *eb;
426304284Sache	wchar_t wc;
427304284Sache	wchar_t wbuf[MAXPATHLEN];
428304284Sache	wchar_t *wbufend, *dc;
429304284Sache	size_t clen;
430304284Sache	mbstate_t mbs;
431304284Sache	int too_long;
4321573Srgrimes
4331573Srgrimes	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
434228755Seadler		return (pattern);
4351573Srgrimes
43624158Simp	/*
43724158Simp	 * Copy up to the end of the string or /
43824158Simp	 */
43924158Simp	eb = &patbuf[patbuf_len - 1];
440304284Sache	for (p = pattern + 1, b = patbuf;
441304284Sache	    b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
4421573Srgrimes		continue;
4431573Srgrimes
444304284Sache	if (*p != EOS && UNPROT(*p) != SEP)
445304284Sache		return (NULL);
4461573Srgrimes
447304284Sache	*b = EOS;
448304284Sache	h = NULL;
449304284Sache
450304284Sache	if (patbuf[0] == EOS) {
4518870Srgrimes		/*
45228820Simp		 * handle a plain ~ or ~/ by expanding $HOME first (iff
45328820Simp		 * we're not running setuid or setgid) and then trying
45428820Simp		 * the password file
4551573Srgrimes		 */
456121667Stjr		if (issetugid() != 0 ||
45733664Sjb		    (h = getenv("HOME")) == NULL) {
45828836Sache			if (((h = getlogin()) != NULL &&
45928836Sache			     (pwd = getpwnam(h)) != NULL) ||
46028836Sache			    (pwd = getpwuid(getuid())) != NULL)
46128836Sache				h = pwd->pw_dir;
46228836Sache			else
463228755Seadler				return (pattern);
4641573Srgrimes		}
4651573Srgrimes	}
4661573Srgrimes	else {
4671573Srgrimes		/*
4681573Srgrimes		 * Expand a ~user
4691573Srgrimes		 */
470304284Sache		if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf)))
471304284Sache			return (NULL);
472304284Sache		if ((pwd = getpwnam((char *)wbuf)) == NULL)
473228755Seadler			return (pattern);
4741573Srgrimes		else
4751573Srgrimes			h = pwd->pw_dir;
4761573Srgrimes	}
4771573Srgrimes
4781573Srgrimes	/* Copy the home directory */
479304284Sache	dc = wbuf;
480304284Sache	sc = h;
481304284Sache	wbufend = wbuf + MAXPATHLEN - 1;
482304284Sache	too_long = 1;
483304284Sache	memset(&mbs, 0, sizeof(mbs));
484304284Sache	while (dc <= wbufend) {
485304284Sache		clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
486304284Sache		if (clen == (size_t)-1 || clen == (size_t)-2) {
487304284Sache			/* XXX See initial comment #2. */
488304284Sache			wc = (unsigned char)*sc;
489304284Sache			clen = 1;
490304284Sache			memset(&mbs, 0, sizeof(mbs));
491304284Sache		}
492304284Sache		if ((*dc++ = wc) == EOS) {
493304284Sache			too_long = 0;
494304284Sache			break;
495304284Sache		}
496304284Sache		sc += clen;
497304284Sache	}
498304284Sache	if (too_long)
499304284Sache		return (NULL);
500304284Sache
501304284Sache	dc = wbuf;
502304284Sache	for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
5031573Srgrimes		continue;
504304284Sache	if (*dc != EOS)
505304284Sache		return (NULL);
5068870Srgrimes
5071573Srgrimes	/* Append the rest of the pattern */
508304284Sache	if (*p != EOS) {
509304284Sache		too_long = 1;
510304284Sache		while (b <= eb) {
511304284Sache			if ((*b++ = *p++) == EOS) {
512304284Sache				too_long = 0;
513304284Sache				break;
514304284Sache			}
515304284Sache		}
516304284Sache		if (too_long)
517304284Sache			return (NULL);
518304284Sache	} else
519304284Sache		*b = EOS;
5201573Srgrimes
521228755Seadler	return (patbuf);
5221573Srgrimes}
5231573Srgrimes
5248870Srgrimes
5251573Srgrimes/*
5261573Srgrimes * The main glob() routine: compiles the pattern (optionally processing
5271573Srgrimes * quotes), calls glob1() to do the real pattern matching, and finally
5281573Srgrimes * sorts the list (unless unsorted operation is requested).  Returns 0
529100217Smikeh * if things went well, nonzero if errors occurred.
5301573Srgrimes */
5311573Srgrimesstatic int
532304284Sacheglob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
533304284Sache    const char *origpat) {
5341573Srgrimes	const Char *qpatnext;
535207981Sgordon	int err;
536158812Sache	size_t oldpathc;
537207981Sgordon	Char *bufnext, c, patbuf[MAXPATHLEN];
5381573Srgrimes
53974963Speter	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
540304284Sache	if (qpatnext == NULL) {
541304284Sache		errno = E2BIG;
542304284Sache		return (GLOB_NOSPACE);
543304284Sache	}
5441573Srgrimes	oldpathc = pglob->gl_pathc;
5451573Srgrimes	bufnext = patbuf;
5461573Srgrimes
5471573Srgrimes	/* We don't need to check for buffer overflow any more. */
5481573Srgrimes	while ((c = *qpatnext++) != EOS) {
5491573Srgrimes		switch (c) {
5501573Srgrimes		case LBRACKET:
5511573Srgrimes			c = *qpatnext;
5521573Srgrimes			if (c == NOT)
5531573Srgrimes				++qpatnext;
5541573Srgrimes			if (*qpatnext == EOS ||
555180021Smtm			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
5561573Srgrimes				*bufnext++ = LBRACKET;
5571573Srgrimes				if (c == NOT)
5581573Srgrimes					--qpatnext;
5591573Srgrimes				break;
5601573Srgrimes			}
5611573Srgrimes			*bufnext++ = M_SET;
5621573Srgrimes			if (c == NOT)
5631573Srgrimes				*bufnext++ = M_NOT;
5641573Srgrimes			c = *qpatnext++;
5651573Srgrimes			do {
5661573Srgrimes				*bufnext++ = CHAR(c);
5671573Srgrimes				if (*qpatnext == RANGE &&
5681573Srgrimes				    (c = qpatnext[1]) != RBRACKET) {
5691573Srgrimes					*bufnext++ = M_RNG;
5701573Srgrimes					*bufnext++ = CHAR(c);
5711573Srgrimes					qpatnext += 2;
5721573Srgrimes				}
5731573Srgrimes			} while ((c = *qpatnext++) != RBRACKET);
5741573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
5751573Srgrimes			*bufnext++ = M_END;
5761573Srgrimes			break;
5771573Srgrimes		case QUESTION:
5781573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
5791573Srgrimes			*bufnext++ = M_ONE;
5801573Srgrimes			break;
5811573Srgrimes		case STAR:
5821573Srgrimes			pglob->gl_flags |= GLOB_MAGCHAR;
5838870Srgrimes			/* collapse adjacent stars to one,
5841573Srgrimes			 * to avoid exponential behavior
5851573Srgrimes			 */
5861573Srgrimes			if (bufnext == patbuf || bufnext[-1] != M_ALL)
5871573Srgrimes			    *bufnext++ = M_ALL;
5881573Srgrimes			break;
5891573Srgrimes		default:
5901573Srgrimes			*bufnext++ = CHAR(c);
5911573Srgrimes			break;
5921573Srgrimes		}
5931573Srgrimes	}
5941573Srgrimes	*bufnext = EOS;
5951573Srgrimes#ifdef DEBUG
5961573Srgrimes	qprintf("glob0:", patbuf);
5971573Srgrimes#endif
5981573Srgrimes
59974469Sjlemon	if ((err = glob1(patbuf, pglob, limit)) != 0)
6001573Srgrimes		return(err);
6011573Srgrimes
602304284Sache	if (origpat != NULL)
603304284Sache		return (globfinal(pglob, limit, oldpathc, origpat));
604304284Sache
605304284Sache	return (0);
606304284Sache}
607304284Sache
608304284Sachestatic int
609304284Sacheglobfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc,
610304284Sache    const char *origpat) {
611304284Sache	if (pglob->gl_pathc == oldpathc)
612304284Sache		return (err_nomatch(pglob, limit, origpat));
613304284Sache
614100217Smikeh	if (!(pglob->gl_flags & GLOB_NOSORT))
6151573Srgrimes		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
6161573Srgrimes		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
617304284Sache
618228755Seadler	return (0);
6191573Srgrimes}
6201573Srgrimes
6211573Srgrimesstatic int
622159294Sdelphijcompare(const void *p, const void *q)
6231573Srgrimes{
624304284Sache	return (strcoll(*(char **)p, *(char **)q));
6251573Srgrimes}
6261573Srgrimes
6271573Srgrimesstatic int
628243779Smarcelglob1(Char *pattern, glob_t *pglob, struct glob_limit *limit)
6291573Srgrimes{
63074963Speter	Char pathbuf[MAXPATHLEN];
6311573Srgrimes
6321573Srgrimes	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
6331573Srgrimes	if (*pattern == EOS)
634228755Seadler		return (0);
635228755Seadler	return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
63674963Speter	    pattern, pglob, limit));
6371573Srgrimes}
6381573Srgrimes
6391573Srgrimes/*
6401573Srgrimes * The functions glob2 and glob3 are mutually recursive; there is one level
6411573Srgrimes * of recursion for each segment in the pattern that contains one or more
6421573Srgrimes * meta characters.
6431573Srgrimes */
6441573Srgrimesstatic int
645159294Sdelphijglob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
646243779Smarcel      glob_t *pglob, struct glob_limit *limit)
6471573Srgrimes{
6481573Srgrimes	struct stat sb;
6491573Srgrimes	Char *p, *q;
6501573Srgrimes	int anymeta;
6511573Srgrimes
6521573Srgrimes	/*
6531573Srgrimes	 * Loop over pattern segments until end of pattern or until
6541573Srgrimes	 * segment with meta character found.
6551573Srgrimes	 */
6561573Srgrimes	for (anymeta = 0;;) {
6571573Srgrimes		if (*pattern == EOS) {		/* End of pattern? */
6581573Srgrimes			*pathend = EOS;
6591573Srgrimes			if (g_lstat(pathbuf, &sb, pglob))
660228755Seadler				return (0);
6618870Srgrimes
662243779Smarcel			if ((pglob->gl_flags & GLOB_LIMIT) &&
663243779Smarcel			    limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
664304284Sache				errno = E2BIG;
665243779Smarcel				return (GLOB_NOSPACE);
666243779Smarcel			}
667304284Sache			if ((pglob->gl_flags & GLOB_MARK) &&
668304284Sache			    UNPROT(pathend[-1]) != SEP &&
669304284Sache			    (S_ISDIR(sb.st_mode) ||
670304284Sache			    (S_ISLNK(sb.st_mode) &&
671304284Sache			    g_stat(pathbuf, &sb, pglob) == 0 &&
6721573Srgrimes			    S_ISDIR(sb.st_mode)))) {
673304284Sache				if (pathend + 1 > pathend_last) {
674304284Sache					errno = E2BIG;
675304284Sache					return (GLOB_NOSPACE);
676304284Sache				}
6771573Srgrimes				*pathend++ = SEP;
6781573Srgrimes				*pathend = EOS;
6791573Srgrimes			}
6801573Srgrimes			++pglob->gl_matchc;
681304284Sache			return (globextend(pathbuf, pglob, limit, NULL));
6821573Srgrimes		}
6831573Srgrimes
6841573Srgrimes		/* Find end of next segment, copy tentatively to pathend. */
6851573Srgrimes		q = pathend;
6861573Srgrimes		p = pattern;
687304284Sache		while (*p != EOS && UNPROT(*p) != SEP) {
6881573Srgrimes			if (ismeta(*p))
6891573Srgrimes				anymeta = 1;
690304284Sache			if (q + 1 > pathend_last) {
691304284Sache				errno = E2BIG;
692304284Sache				return (GLOB_NOSPACE);
693304284Sache			}
6941573Srgrimes			*q++ = *p++;
6951573Srgrimes		}
6961573Srgrimes
6971573Srgrimes		if (!anymeta) {		/* No expansion, do next segment. */
6981573Srgrimes			pathend = q;
6991573Srgrimes			pattern = p;
700304284Sache			while (UNPROT(*pattern) == SEP) {
701304284Sache				if (pathend + 1 > pathend_last) {
702304284Sache					errno = E2BIG;
703304284Sache					return (GLOB_NOSPACE);
704304284Sache				}
7051573Srgrimes				*pathend++ = *pattern++;
70674963Speter			}
7071573Srgrimes		} else			/* Need expansion, recurse. */
708228755Seadler			return (glob3(pathbuf, pathend, pathend_last, pattern,
709228755Seadler			    p, pglob, limit));
7101573Srgrimes	}
7111573Srgrimes	/* NOTREACHED */
7121573Srgrimes}
7131573Srgrimes
7141573Srgrimesstatic int
715159294Sdelphijglob3(Char *pathbuf, Char *pathend, Char *pathend_last,
716159294Sdelphij      Char *pattern, Char *restpattern,
717243779Smarcel      glob_t *pglob, struct glob_limit *limit)
7181573Srgrimes{
71990045Sobrien	struct dirent *dp;
7201573Srgrimes	DIR *dirp;
721304284Sache	int err, too_long, saverrno, saverrno2;
722304284Sache	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
7231573Srgrimes
724288098Srodrigc	struct dirent *(*readdirfunc)(DIR *);
7251573Srgrimes
726304284Sache	if (pathend > pathend_last) {
727304284Sache		errno = E2BIG;
728304284Sache		return (GLOB_NOSPACE);
729304284Sache	}
7301573Srgrimes	*pathend = EOS;
731304284Sache	if (pglob->gl_errfunc != NULL &&
732304284Sache	    g_Ctoc(pathbuf, buf, sizeof(buf))) {
733304284Sache		errno = E2BIG;
734304284Sache		return (GLOB_NOSPACE);
735304284Sache	}
736304284Sache
737304284Sache	saverrno = errno;
7381573Srgrimes	errno = 0;
7391573Srgrimes	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
740304284Sache		if (errno == ENOENT || errno == ENOTDIR)
741304284Sache			return (0);
742304284Sache		err = err_aborted(pglob, errno, buf);
743304284Sache		if (errno == 0)
744304284Sache			errno = saverrno;
745304284Sache		return (err);
7461573Srgrimes	}
7471573Srgrimes
7481573Srgrimes	err = 0;
7491573Srgrimes
750288098Srodrigc	/* pglob->gl_readdir takes a void *, fix this manually */
7511573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
752288098Srodrigc		readdirfunc = (struct dirent *(*)(DIR *))pglob->gl_readdir;
7531573Srgrimes	else
7541573Srgrimes		readdirfunc = readdir;
755288098Srodrigc
756304284Sache	errno = 0;
757288098Srodrigc	/* Search directory for matching names. */
758288098Srodrigc	while ((dp = (*readdirfunc)(dirp)) != NULL) {
759159294Sdelphij		char *sc;
76090045Sobrien		Char *dc;
761132817Stjr		wchar_t wc;
762132817Stjr		size_t clen;
763132817Stjr		mbstate_t mbs;
7641573Srgrimes
765243779Smarcel		if ((pglob->gl_flags & GLOB_LIMIT) &&
766243779Smarcel		    limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
767304284Sache			errno = E2BIG;
768304284Sache			err = GLOB_NOSPACE;
769243779Smarcel			break;
770243779Smarcel		}
771243779Smarcel
7721573Srgrimes		/* Initial DOT must be matched literally. */
773304284Sache		if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
774304284Sache			errno = 0;
7751573Srgrimes			continue;
776304284Sache		}
777132817Stjr		memset(&mbs, 0, sizeof(mbs));
77874963Speter		dc = pathend;
779159294Sdelphij		sc = dp->d_name;
780304284Sache		too_long = 1;
781304284Sache		while (dc <= pathend_last) {
782132817Stjr			clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
783132817Stjr			if (clen == (size_t)-1 || clen == (size_t)-2) {
784304284Sache				/* XXX See initial comment #2. */
785304284Sache				wc = (unsigned char)*sc;
786132817Stjr				clen = 1;
787132817Stjr				memset(&mbs, 0, sizeof(mbs));
788132817Stjr			}
789304284Sache			if ((*dc++ = wc) == EOS) {
790304284Sache				too_long = 0;
791132817Stjr				break;
792304284Sache			}
793132817Stjr			sc += clen;
794132817Stjr		}
795304284Sache		if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
796304284Sache		    buf))) {
797304284Sache			errno = ENAMETOOLONG;
798304284Sache			break;
799304284Sache		}
800304284Sache		if (too_long || !match(pathend, pattern, restpattern)) {
8011573Srgrimes			*pathend = EOS;
802304284Sache			errno = 0;
8031573Srgrimes			continue;
8041573Srgrimes		}
805304284Sache		if (errno == 0)
806304284Sache			errno = saverrno;
80774963Speter		err = glob2(pathbuf, --dc, pathend_last, restpattern,
80874963Speter		    pglob, limit);
8091573Srgrimes		if (err)
8101573Srgrimes			break;
811304284Sache		errno = 0;
8121573Srgrimes	}
8131573Srgrimes
814304284Sache	saverrno2 = errno;
8151573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
8161573Srgrimes		(*pglob->gl_closedir)(dirp);
8171573Srgrimes	else
8181573Srgrimes		closedir(dirp);
819304284Sache	errno = saverrno2;
820304284Sache
821304284Sache	if (err)
822304284Sache		return (err);
823304284Sache
824304284Sache	if (dp == NULL && errno != 0 &&
825304284Sache	    (err = err_aborted(pglob, errno, buf)))
826304284Sache		return (err);
827304284Sache
828304284Sache	if (errno == 0)
829304284Sache		errno = saverrno;
830304284Sache	return (0);
8311573Srgrimes}
8321573Srgrimes
8331573Srgrimes
8341573Srgrimes/*
835249381Semaste * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
8361573Srgrimes * add the new item, and update gl_pathc.
8371573Srgrimes *
8381573Srgrimes * This assumes the BSD realloc, which only copies the block when its size
8391573Srgrimes * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
8401573Srgrimes * behavior.
8411573Srgrimes *
8421573Srgrimes * Return 0 if new item added, error code if memory couldn't be allocated.
8431573Srgrimes *
8441573Srgrimes * Invariant of the glob_t structure:
8451573Srgrimes *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
8461573Srgrimes *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
8471573Srgrimes */
8481573Srgrimesstatic int
849304284Sacheglobextend(const Char *path, glob_t *pglob, struct glob_limit *limit,
850304284Sache    const char *origpat)
8511573Srgrimes{
85290045Sobrien	char **pathv;
853316613Spfg	size_t i, newn, len;
8541573Srgrimes	char *copy;
8551573Srgrimes	const Char *p;
8561573Srgrimes
857243779Smarcel	if ((pglob->gl_flags & GLOB_LIMIT) &&
858243779Smarcel	    pglob->gl_matchc > limit->l_path_lim) {
859304284Sache		errno = E2BIG;
86080525Smikeh		return (GLOB_NOSPACE);
86180525Smikeh	}
86274307Sjlemon
863316613Spfg	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
864316613Spfg	/* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
865316613Spfg	pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
866243758Smarcel	if (pathv == NULL)
867228755Seadler		return (GLOB_NOSPACE);
8681573Srgrimes
8691573Srgrimes	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
8701573Srgrimes		/* first time around -- clear initial gl_offs items */
8711573Srgrimes		pathv += pglob->gl_offs;
872158812Sache		for (i = pglob->gl_offs + 1; --i > 0; )
8731573Srgrimes			*--pathv = NULL;
8741573Srgrimes	}
8751573Srgrimes	pglob->gl_pathv = pathv;
8761573Srgrimes
877304284Sache	if (origpat != NULL)
878304284Sache		copy = strdup(origpat);
879304284Sache	else {
880304284Sache		for (p = path; *p++ != EOS;)
881304284Sache			continue;
882304284Sache		len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
883304284Sache		if ((copy = malloc(len)) != NULL) {
884304284Sache			if (g_Ctoc(path, copy, len)) {
885304284Sache				free(copy);
886304284Sache				errno = E2BIG;
887304284Sache				return (GLOB_NOSPACE);
888304284Sache			}
889304284Sache		}
890243779Smarcel	}
891304284Sache	if (copy != NULL) {
892304284Sache		limit->l_string_cnt += strlen(copy) + 1;
893304284Sache		if ((pglob->gl_flags & GLOB_LIMIT) &&
894304284Sache		    limit->l_string_cnt >= GLOB_LIMIT_STRING) {
89574918Speter			free(copy);
896304284Sache			errno = E2BIG;
89774918Speter			return (GLOB_NOSPACE);
89874918Speter		}
8991573Srgrimes		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
9001573Srgrimes	}
9011573Srgrimes	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
902228755Seadler	return (copy == NULL ? GLOB_NOSPACE : 0);
9031573Srgrimes}
9041573Srgrimes
9051573Srgrimes/*
9061573Srgrimes * pattern matching function for filenames.  Each occurrence of the *
9071573Srgrimes * pattern causes a recursion level.
9081573Srgrimes */
9091573Srgrimesstatic int
910159294Sdelphijmatch(Char *name, Char *pat, Char *patend)
9111573Srgrimes{
9121573Srgrimes	int ok, negate_range;
9131573Srgrimes	Char c, k;
914227753Stheraven	struct xlocale_collate *table =
915227753Stheraven		(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
9161573Srgrimes
9171573Srgrimes	while (pat < patend) {
9181573Srgrimes		c = *pat++;
9191573Srgrimes		switch (c & M_MASK) {
9201573Srgrimes		case M_ALL:
9211573Srgrimes			if (pat == patend)
922228755Seadler				return (1);
9238870Srgrimes			do
9241573Srgrimes			    if (match(name, pat, patend))
925228755Seadler				    return (1);
9261573Srgrimes			while (*name++ != EOS);
927228755Seadler			return (0);
9281573Srgrimes		case M_ONE:
9291573Srgrimes			if (*name++ == EOS)
930228755Seadler				return (0);
9311573Srgrimes			break;
9321573Srgrimes		case M_SET:
9331573Srgrimes			ok = 0;
9341573Srgrimes			if ((k = *name++) == EOS)
935228755Seadler				return (0);
936304284Sache			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != 0)
9371573Srgrimes				++pat;
9381573Srgrimes			while (((c = *pat++) & M_MASK) != M_END)
9391573Srgrimes				if ((*pat & M_MASK) == M_RNG) {
940227753Stheraven					if (table->__collate_load_error ?
941304284Sache					    CHAR(c) <= CHAR(k) &&
942304284Sache					    CHAR(k) <= CHAR(pat[1]) :
943304284Sache					    __wcollate_range_cmp(CHAR(c),
944304284Sache					    CHAR(k)) <= 0 &&
945304284Sache					    __wcollate_range_cmp(CHAR(k),
946304284Sache					    CHAR(pat[1])) <= 0)
9471573Srgrimes						ok = 1;
9481573Srgrimes					pat += 2;
9491573Srgrimes				} else if (c == k)
9501573Srgrimes					ok = 1;
9511573Srgrimes			if (ok == negate_range)
952228755Seadler				return (0);
9531573Srgrimes			break;
9541573Srgrimes		default:
9551573Srgrimes			if (*name++ != c)
956228755Seadler				return (0);
9571573Srgrimes			break;
9581573Srgrimes		}
9591573Srgrimes	}
960228755Seadler	return (*name == EOS);
9611573Srgrimes}
9621573Srgrimes
9631573Srgrimes/* Free allocated data belonging to a glob_t structure. */
9641573Srgrimesvoid
965159294Sdelphijglobfree(glob_t *pglob)
9661573Srgrimes{
967158812Sache	size_t i;
96890045Sobrien	char **pp;
9691573Srgrimes
9701573Srgrimes	if (pglob->gl_pathv != NULL) {
9711573Srgrimes		pp = pglob->gl_pathv + pglob->gl_offs;
9721573Srgrimes		for (i = pglob->gl_pathc; i--; ++pp)
9731573Srgrimes			if (*pp)
9741573Srgrimes				free(*pp);
9751573Srgrimes		free(pglob->gl_pathv);
97674918Speter		pglob->gl_pathv = NULL;
9771573Srgrimes	}
9781573Srgrimes}
9791573Srgrimes
9801573Srgrimesstatic DIR *
981159294Sdelphijg_opendir(Char *str, glob_t *pglob)
9821573Srgrimes{
983304284Sache	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
9841573Srgrimes
985304284Sache	if (*str == EOS)
9861573Srgrimes		strcpy(buf, ".");
98774918Speter	else {
988304284Sache		if (g_Ctoc(str, buf, sizeof(buf))) {
989304284Sache			errno = ENAMETOOLONG;
99074918Speter			return (NULL);
991304284Sache		}
99274918Speter	}
9931573Srgrimes
9941573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
995228755Seadler		return ((*pglob->gl_opendir)(buf));
9961573Srgrimes
997228755Seadler	return (opendir(buf));
9981573Srgrimes}
9991573Srgrimes
10001573Srgrimesstatic int
1001159294Sdelphijg_lstat(Char *fn, struct stat *sb, glob_t *pglob)
10021573Srgrimes{
1003304284Sache	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
10041573Srgrimes
100574921Speter	if (g_Ctoc(fn, buf, sizeof(buf))) {
100674918Speter		errno = ENAMETOOLONG;
100774918Speter		return (-1);
100874918Speter	}
10091573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
10101573Srgrimes		return((*pglob->gl_lstat)(buf, sb));
1011228755Seadler	return (lstat(buf, sb));
10121573Srgrimes}
10131573Srgrimes
10141573Srgrimesstatic int
1015159294Sdelphijg_stat(Char *fn, struct stat *sb, glob_t *pglob)
10161573Srgrimes{
1017304284Sache	char buf[MAXPATHLEN + MB_LEN_MAX - 1];
10181573Srgrimes
101974921Speter	if (g_Ctoc(fn, buf, sizeof(buf))) {
102074918Speter		errno = ENAMETOOLONG;
102174918Speter		return (-1);
102274918Speter	}
10231573Srgrimes	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1024228755Seadler		return ((*pglob->gl_stat)(buf, sb));
1025228755Seadler	return (stat(buf, sb));
10261573Srgrimes}
10271573Srgrimes
1028180021Smtmstatic const Char *
1029180021Smtmg_strchr(const Char *str, wchar_t ch)
10301573Srgrimes{
1031159294Sdelphij
10321573Srgrimes	do {
10331573Srgrimes		if (*str == ch)
10341573Srgrimes			return (str);
10351573Srgrimes	} while (*str++);
10361573Srgrimes	return (NULL);
10371573Srgrimes}
10381573Srgrimes
103974918Speterstatic int
1040159294Sdelphijg_Ctoc(const Char *str, char *buf, size_t len)
10411573Srgrimes{
1042132817Stjr	mbstate_t mbs;
1043132817Stjr	size_t clen;
10441573Srgrimes
1045132817Stjr	memset(&mbs, 0, sizeof(mbs));
1046132817Stjr	while (len >= MB_CUR_MAX) {
1047304284Sache		clen = wcrtomb(buf, CHAR(*str), &mbs);
1048304284Sache		if (clen == (size_t)-1) {
1049304284Sache			/* XXX See initial comment #2. */
1050304284Sache			*buf = (char)CHAR(*str);
1051304284Sache			clen = 1;
1052304284Sache			memset(&mbs, 0, sizeof(mbs));
1053304284Sache		}
1054304284Sache		if (CHAR(*str) == EOS)
105574921Speter			return (0);
1056132817Stjr		str++;
1057132817Stjr		buf += clen;
1058132817Stjr		len -= clen;
105974921Speter	}
106074921Speter	return (1);
10611573Srgrimes}
10621573Srgrimes
1063304284Sachestatic int
1064304284Sacheerr_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) {
1065304284Sache	/*
1066304284Sache	 * If there was no match we are going to append the origpat
1067304284Sache	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
1068304284Sache	 * and the origpat did not contain any magic characters
1069304284Sache	 * GLOB_NOMAGIC is there just for compatibility with csh.
1070304284Sache	 */
1071304284Sache	if ((pglob->gl_flags & GLOB_NOCHECK) ||
1072304284Sache	    ((pglob->gl_flags & GLOB_NOMAGIC) &&
1073304284Sache	    !(pglob->gl_flags & GLOB_MAGCHAR)))
1074304284Sache		return (globextend(NULL, pglob, limit, origpat));
1075304284Sache	return (GLOB_NOMATCH);
1076304284Sache}
1077304284Sache
1078304284Sachestatic int
1079304284Sacheerr_aborted(glob_t *pglob, int err, char *buf) {
1080304284Sache	if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
1081304284Sache	    (pglob->gl_flags & GLOB_ERR))
1082304284Sache		return (GLOB_ABORTED);
1083304284Sache	return (0);
1084304284Sache}
1085304284Sache
10861573Srgrimes#ifdef DEBUG
10878870Srgrimesstatic void
1088159294Sdelphijqprintf(const char *str, Char *s)
10891573Srgrimes{
109090045Sobrien	Char *p;
10911573Srgrimes
1092304284Sache	(void)printf("%s\n", str);
1093304284Sache	if (s != NULL) {
1094304284Sache		for (p = s; *p != EOS; p++)
1095304284Sache			(void)printf("%c", (char)CHAR(*p));
1096304284Sache		(void)printf("\n");
1097304284Sache		for (p = s; *p != EOS; p++)
1098304284Sache			(void)printf("%c", (isprot(*p) ? '\\' : ' '));
1099304284Sache		(void)printf("\n");
1100304284Sache		for (p = s; *p != EOS; p++)
1101304284Sache			(void)printf("%c", (ismeta(*p) ? '_' : ' '));
1102304284Sache		(void)printf("\n");
1103304284Sache	}
11041573Srgrimes}
11051573Srgrimes#endif
1106