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