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