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