169921123SKonstantin Belousov /* 269921123SKonstantin Belousov * Copyright (c) 1989, 1993 369921123SKonstantin Belousov * The Regents of the University of California. All rights reserved. 469921123SKonstantin Belousov * 569921123SKonstantin Belousov * This code is derived from software contributed to Berkeley by 669921123SKonstantin Belousov * Guido van Rossum. 769921123SKonstantin Belousov * 869921123SKonstantin Belousov * Copyright (c) 2011 The FreeBSD Foundation 969921123SKonstantin Belousov * All rights reserved. 1069921123SKonstantin Belousov * Portions of this software were developed by David Chisnall 1169921123SKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 1269921123SKonstantin Belousov * 1369921123SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 1469921123SKonstantin Belousov * modification, are permitted provided that the following conditions 1569921123SKonstantin Belousov * are met: 1669921123SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 1769921123SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 1869921123SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 1969921123SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 2069921123SKonstantin Belousov * documentation and/or other materials provided with the distribution. 2169921123SKonstantin Belousov * 3. Neither the name of the University nor the names of its contributors 2269921123SKonstantin Belousov * may be used to endorse or promote products derived from this software 2369921123SKonstantin Belousov * without specific prior written permission. 2469921123SKonstantin Belousov * 2569921123SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2669921123SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2769921123SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2869921123SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2969921123SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3069921123SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3169921123SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3269921123SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3369921123SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3469921123SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3569921123SKonstantin Belousov * SUCH DAMAGE. 3669921123SKonstantin Belousov * 37c1920558SJohn Baldwin * From: @(#)glob.c 8.3 (Berkeley) 10/13/93 38c1920558SJohn Baldwin * From: FreeBSD: head/lib/libc/gen/glob.c 317913 2017-05-07 19:52:56Z jilles 3969921123SKonstantin Belousov */ 4069921123SKonstantin Belousov 4169921123SKonstantin Belousov #include <sys/cdefs.h> 4269921123SKonstantin Belousov __FBSDID("$FreeBSD$"); 4369921123SKonstantin Belousov 4469921123SKonstantin Belousov #include <sys/param.h> 4569921123SKonstantin Belousov #define _WANT_FREEBSD11_STAT 4669921123SKonstantin Belousov #include <sys/stat.h> 4769921123SKonstantin Belousov 4869921123SKonstantin Belousov #include <ctype.h> 4969921123SKonstantin Belousov #define _WANT_FREEBSD11_DIRENT 5069921123SKonstantin Belousov #include <dirent.h> 5169921123SKonstantin Belousov #include <errno.h> 5269921123SKonstantin Belousov #include <glob.h> 5369921123SKonstantin Belousov #include <limits.h> 5469921123SKonstantin Belousov #include <pwd.h> 5569921123SKonstantin Belousov #include <stdint.h> 5669921123SKonstantin Belousov #include <stdio.h> 5769921123SKonstantin Belousov #include <stdlib.h> 5869921123SKonstantin Belousov #include <string.h> 5969921123SKonstantin Belousov #include <unistd.h> 6069921123SKonstantin Belousov #include <wchar.h> 6169921123SKonstantin Belousov 6269921123SKonstantin Belousov #include "collate.h" 6369921123SKonstantin Belousov #include "gen-compat.h" 6469921123SKonstantin Belousov #include "glob-compat11.h" 6569921123SKonstantin Belousov 6669921123SKonstantin Belousov /* 6769921123SKonstantin Belousov * glob(3) expansion limits. Stop the expansion if any of these limits 6869921123SKonstantin Belousov * is reached. This caps the runtime in the face of DoS attacks. See 6969921123SKonstantin Belousov * also CVE-2010-2632 7069921123SKonstantin Belousov */ 7169921123SKonstantin Belousov #define GLOB_LIMIT_BRACE 128 /* number of brace calls */ 7269921123SKonstantin Belousov #define GLOB_LIMIT_PATH 65536 /* number of path elements */ 7369921123SKonstantin Belousov #define GLOB_LIMIT_READDIR 16384 /* number of readdirs */ 7469921123SKonstantin Belousov #define GLOB_LIMIT_STAT 1024 /* number of stat system calls */ 7569921123SKonstantin Belousov #define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */ 7669921123SKonstantin Belousov 7769921123SKonstantin Belousov struct glob_limit { 7869921123SKonstantin Belousov size_t l_brace_cnt; 7969921123SKonstantin Belousov size_t l_path_lim; 8069921123SKonstantin Belousov size_t l_readdir_cnt; 8169921123SKonstantin Belousov size_t l_stat_cnt; 8269921123SKonstantin Belousov size_t l_string_cnt; 8369921123SKonstantin Belousov }; 8469921123SKonstantin Belousov 8569921123SKonstantin Belousov #define DOT L'.' 8669921123SKonstantin Belousov #define EOS L'\0' 8769921123SKonstantin Belousov #define LBRACKET L'[' 8869921123SKonstantin Belousov #define NOT L'!' 8969921123SKonstantin Belousov #define QUESTION L'?' 9069921123SKonstantin Belousov #define QUOTE L'\\' 9169921123SKonstantin Belousov #define RANGE L'-' 9269921123SKonstantin Belousov #define RBRACKET L']' 9369921123SKonstantin Belousov #define SEP L'/' 9469921123SKonstantin Belousov #define STAR L'*' 9569921123SKonstantin Belousov #define TILDE L'~' 9669921123SKonstantin Belousov #define LBRACE L'{' 9769921123SKonstantin Belousov #define RBRACE L'}' 9869921123SKonstantin Belousov #define COMMA L',' 9969921123SKonstantin Belousov 10069921123SKonstantin Belousov #define M_QUOTE 0x8000000000ULL 10169921123SKonstantin Belousov #define M_PROTECT 0x4000000000ULL 10269921123SKonstantin Belousov #define M_MASK 0xffffffffffULL 10369921123SKonstantin Belousov #define M_CHAR 0x00ffffffffULL 10469921123SKonstantin Belousov 10569921123SKonstantin Belousov typedef uint_fast64_t Char; 10669921123SKonstantin Belousov 10769921123SKonstantin Belousov #define CHAR(c) ((Char)((c)&M_CHAR)) 10869921123SKonstantin Belousov #define META(c) ((Char)((c)|M_QUOTE)) 10969921123SKonstantin Belousov #define UNPROT(c) ((c) & ~M_PROTECT) 11069921123SKonstantin Belousov #define M_ALL META(L'*') 11169921123SKonstantin Belousov #define M_END META(L']') 11269921123SKonstantin Belousov #define M_NOT META(L'!') 11369921123SKonstantin Belousov #define M_ONE META(L'?') 11469921123SKonstantin Belousov #define M_RNG META(L'-') 11569921123SKonstantin Belousov #define M_SET META(L'[') 11669921123SKonstantin Belousov #define ismeta(c) (((c)&M_QUOTE) != 0) 11769921123SKonstantin Belousov #ifdef DEBUG 11869921123SKonstantin Belousov #define isprot(c) (((c)&M_PROTECT) != 0) 11969921123SKonstantin Belousov #endif 12069921123SKonstantin Belousov 12169921123SKonstantin Belousov static int compare(const void *, const void *); 12269921123SKonstantin Belousov static int g_Ctoc(const Char *, char *, size_t); 12369921123SKonstantin Belousov static int g_lstat(Char *, struct freebsd11_stat *, glob11_t *); 12469921123SKonstantin Belousov static DIR *g_opendir(Char *, glob11_t *); 12569921123SKonstantin Belousov static const Char *g_strchr(const Char *, wchar_t); 12669921123SKonstantin Belousov #ifdef notdef 12769921123SKonstantin Belousov static Char *g_strcat(Char *, const Char *); 12869921123SKonstantin Belousov #endif 12969921123SKonstantin Belousov static int g_stat(Char *, struct freebsd11_stat *, glob11_t *); 13069921123SKonstantin Belousov static int glob0(const Char *, glob11_t *, struct glob_limit *, 13169921123SKonstantin Belousov const char *); 13269921123SKonstantin Belousov static int glob1(Char *, glob11_t *, struct glob_limit *); 13369921123SKonstantin Belousov static int glob2(Char *, Char *, Char *, Char *, glob11_t *, 13469921123SKonstantin Belousov struct glob_limit *); 13569921123SKonstantin Belousov static int glob3(Char *, Char *, Char *, Char *, Char *, glob11_t *, 13669921123SKonstantin Belousov struct glob_limit *); 13769921123SKonstantin Belousov static int globextend(const Char *, glob11_t *, struct glob_limit *, 13869921123SKonstantin Belousov const char *); 13969921123SKonstantin Belousov static const Char * 14069921123SKonstantin Belousov globtilde(const Char *, Char *, size_t, glob11_t *); 14169921123SKonstantin Belousov static int globexp0(const Char *, glob11_t *, struct glob_limit *, 14269921123SKonstantin Belousov const char *); 14369921123SKonstantin Belousov static int globexp1(const Char *, glob11_t *, struct glob_limit *); 14469921123SKonstantin Belousov static int globexp2(const Char *, const Char *, glob11_t *, 14569921123SKonstantin Belousov struct glob_limit *); 14669921123SKonstantin Belousov static int globfinal(glob11_t *, struct glob_limit *, size_t, 14769921123SKonstantin Belousov const char *); 14869921123SKonstantin Belousov static int match(Char *, Char *, Char *); 14969921123SKonstantin Belousov static int err_nomatch(glob11_t *, struct glob_limit *, const char *); 15069921123SKonstantin Belousov static int err_aborted(glob11_t *, int, char *); 15169921123SKonstantin Belousov #ifdef DEBUG 15269921123SKonstantin Belousov static void qprintf(const char *, Char *); 15369921123SKonstantin Belousov #endif 15469921123SKonstantin Belousov 15569921123SKonstantin Belousov int 15669921123SKonstantin Belousov freebsd11_glob(const char * __restrict pattern, int flags, 15769921123SKonstantin Belousov int (*errfunc)(const char *, int), glob11_t * __restrict pglob) 15869921123SKonstantin Belousov { 15969921123SKonstantin Belousov struct glob_limit limit = { 0, 0, 0, 0, 0 }; 16069921123SKonstantin Belousov const char *patnext; 16169921123SKonstantin Belousov Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot; 16269921123SKonstantin Belousov mbstate_t mbs; 16369921123SKonstantin Belousov wchar_t wc; 16469921123SKonstantin Belousov size_t clen; 16569921123SKonstantin Belousov int too_long; 16669921123SKonstantin Belousov 16769921123SKonstantin Belousov patnext = pattern; 16869921123SKonstantin Belousov if (!(flags & GLOB_APPEND)) { 16969921123SKonstantin Belousov pglob->gl_pathc = 0; 17069921123SKonstantin Belousov pglob->gl_pathv = NULL; 17169921123SKonstantin Belousov if (!(flags & GLOB_DOOFFS)) 17269921123SKonstantin Belousov pglob->gl_offs = 0; 17369921123SKonstantin Belousov } 17469921123SKonstantin Belousov if (flags & GLOB_LIMIT) { 17569921123SKonstantin Belousov limit.l_path_lim = pglob->gl_matchc; 17669921123SKonstantin Belousov if (limit.l_path_lim == 0) 17769921123SKonstantin Belousov limit.l_path_lim = GLOB_LIMIT_PATH; 17869921123SKonstantin Belousov } 17969921123SKonstantin Belousov pglob->gl_flags = flags & ~GLOB_MAGCHAR; 18069921123SKonstantin Belousov pglob->gl_errfunc = errfunc; 18169921123SKonstantin Belousov pglob->gl_matchc = 0; 18269921123SKonstantin Belousov 18369921123SKonstantin Belousov bufnext = patbuf; 18469921123SKonstantin Belousov bufend = bufnext + MAXPATHLEN - 1; 18569921123SKonstantin Belousov too_long = 1; 18669921123SKonstantin Belousov if (flags & GLOB_NOESCAPE) { 18769921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 18869921123SKonstantin Belousov while (bufnext <= bufend) { 18969921123SKonstantin Belousov clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); 19069921123SKonstantin Belousov if (clen == (size_t)-1 || clen == (size_t)-2) 19169921123SKonstantin Belousov return (err_nomatch(pglob, &limit, pattern)); 19269921123SKonstantin Belousov else if (clen == 0) { 19369921123SKonstantin Belousov too_long = 0; 19469921123SKonstantin Belousov break; 19569921123SKonstantin Belousov } 19669921123SKonstantin Belousov *bufnext++ = wc; 19769921123SKonstantin Belousov patnext += clen; 19869921123SKonstantin Belousov } 19969921123SKonstantin Belousov } else { 20069921123SKonstantin Belousov /* Protect the quoted characters. */ 20169921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 20269921123SKonstantin Belousov while (bufnext <= bufend) { 20369921123SKonstantin Belousov if (*patnext == '\\') { 20469921123SKonstantin Belousov if (*++patnext == '\0') { 20569921123SKonstantin Belousov *bufnext++ = QUOTE; 20669921123SKonstantin Belousov continue; 20769921123SKonstantin Belousov } 20869921123SKonstantin Belousov prot = M_PROTECT; 20969921123SKonstantin Belousov } else 21069921123SKonstantin Belousov prot = 0; 21169921123SKonstantin Belousov clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); 21269921123SKonstantin Belousov if (clen == (size_t)-1 || clen == (size_t)-2) 21369921123SKonstantin Belousov return (err_nomatch(pglob, &limit, pattern)); 21469921123SKonstantin Belousov else if (clen == 0) { 21569921123SKonstantin Belousov too_long = 0; 21669921123SKonstantin Belousov break; 21769921123SKonstantin Belousov } 21869921123SKonstantin Belousov *bufnext++ = wc | prot; 21969921123SKonstantin Belousov patnext += clen; 22069921123SKonstantin Belousov } 22169921123SKonstantin Belousov } 22269921123SKonstantin Belousov if (too_long) 22369921123SKonstantin Belousov return (err_nomatch(pglob, &limit, pattern)); 22469921123SKonstantin Belousov *bufnext = EOS; 22569921123SKonstantin Belousov 22669921123SKonstantin Belousov if (flags & GLOB_BRACE) 22769921123SKonstantin Belousov return (globexp0(patbuf, pglob, &limit, pattern)); 22869921123SKonstantin Belousov else 22969921123SKonstantin Belousov return (glob0(patbuf, pglob, &limit, pattern)); 23069921123SKonstantin Belousov } 23169921123SKonstantin Belousov 23269921123SKonstantin Belousov static int 23369921123SKonstantin Belousov globexp0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit, 23469921123SKonstantin Belousov const char *origpat) { 23569921123SKonstantin Belousov int rv; 23669921123SKonstantin Belousov size_t oldpathc; 23769921123SKonstantin Belousov 23869921123SKonstantin Belousov /* Protect a single {}, for find(1), like csh */ 23969921123SKonstantin Belousov if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) { 24069921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_LIMIT) && 24169921123SKonstantin Belousov limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { 24269921123SKonstantin Belousov errno = E2BIG; 24369921123SKonstantin Belousov return (GLOB_NOSPACE); 24469921123SKonstantin Belousov } 24569921123SKonstantin Belousov return (glob0(pattern, pglob, limit, origpat)); 24669921123SKonstantin Belousov } 24769921123SKonstantin Belousov 24869921123SKonstantin Belousov oldpathc = pglob->gl_pathc; 24969921123SKonstantin Belousov 25069921123SKonstantin Belousov if ((rv = globexp1(pattern, pglob, limit)) != 0) 25169921123SKonstantin Belousov return rv; 25269921123SKonstantin Belousov 25369921123SKonstantin Belousov return (globfinal(pglob, limit, oldpathc, origpat)); 25469921123SKonstantin Belousov } 25569921123SKonstantin Belousov 25669921123SKonstantin Belousov /* 25769921123SKonstantin Belousov * Expand recursively a glob {} pattern. When there is no more expansion 25869921123SKonstantin Belousov * invoke the standard globbing routine to glob the rest of the magic 25969921123SKonstantin Belousov * characters 26069921123SKonstantin Belousov */ 26169921123SKonstantin Belousov static int 26269921123SKonstantin Belousov globexp1(const Char *pattern, glob11_t *pglob, struct glob_limit *limit) 26369921123SKonstantin Belousov { 26469921123SKonstantin Belousov const Char* ptr; 26569921123SKonstantin Belousov 26669921123SKonstantin Belousov if ((ptr = g_strchr(pattern, LBRACE)) != NULL) { 26769921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_LIMIT) && 26869921123SKonstantin Belousov limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { 26969921123SKonstantin Belousov errno = E2BIG; 27069921123SKonstantin Belousov return (GLOB_NOSPACE); 27169921123SKonstantin Belousov } 27269921123SKonstantin Belousov return (globexp2(ptr, pattern, pglob, limit)); 27369921123SKonstantin Belousov } 27469921123SKonstantin Belousov 27569921123SKonstantin Belousov return (glob0(pattern, pglob, limit, NULL)); 27669921123SKonstantin Belousov } 27769921123SKonstantin Belousov 27869921123SKonstantin Belousov 27969921123SKonstantin Belousov /* 28069921123SKonstantin Belousov * Recursive brace globbing helper. Tries to expand a single brace. 28169921123SKonstantin Belousov * If it succeeds then it invokes globexp1 with the new pattern. 28269921123SKonstantin Belousov * If it fails then it tries to glob the rest of the pattern and returns. 28369921123SKonstantin Belousov */ 28469921123SKonstantin Belousov static int 28569921123SKonstantin Belousov globexp2(const Char *ptr, const Char *pattern, glob11_t *pglob, 28669921123SKonstantin Belousov struct glob_limit *limit) 28769921123SKonstantin Belousov { 28869921123SKonstantin Belousov int i, rv; 28969921123SKonstantin Belousov Char *lm, *ls; 29069921123SKonstantin Belousov const Char *pe, *pm, *pm1, *pl; 29169921123SKonstantin Belousov Char patbuf[MAXPATHLEN]; 29269921123SKonstantin Belousov 29369921123SKonstantin Belousov /* copy part up to the brace */ 29469921123SKonstantin Belousov for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) 29569921123SKonstantin Belousov continue; 29669921123SKonstantin Belousov *lm = EOS; 29769921123SKonstantin Belousov ls = lm; 29869921123SKonstantin Belousov 29969921123SKonstantin Belousov /* Find the balanced brace */ 30069921123SKonstantin Belousov for (i = 0, pe = ++ptr; *pe != EOS; pe++) 30169921123SKonstantin Belousov if (*pe == LBRACKET) { 30269921123SKonstantin Belousov /* Ignore everything between [] */ 30369921123SKonstantin Belousov for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) 30469921123SKonstantin Belousov continue; 30569921123SKonstantin Belousov if (*pe == EOS) { 30669921123SKonstantin Belousov /* 30769921123SKonstantin Belousov * We could not find a matching RBRACKET. 30869921123SKonstantin Belousov * Ignore and just look for RBRACE 30969921123SKonstantin Belousov */ 31069921123SKonstantin Belousov pe = pm; 31169921123SKonstantin Belousov } 31269921123SKonstantin Belousov } 31369921123SKonstantin Belousov else if (*pe == LBRACE) 31469921123SKonstantin Belousov i++; 31569921123SKonstantin Belousov else if (*pe == RBRACE) { 31669921123SKonstantin Belousov if (i == 0) 31769921123SKonstantin Belousov break; 31869921123SKonstantin Belousov i--; 31969921123SKonstantin Belousov } 32069921123SKonstantin Belousov 32169921123SKonstantin Belousov /* Non matching braces; just glob the pattern */ 32269921123SKonstantin Belousov if (i != 0 || *pe == EOS) 32369921123SKonstantin Belousov return (glob0(pattern, pglob, limit, NULL)); 32469921123SKonstantin Belousov 32569921123SKonstantin Belousov for (i = 0, pl = pm = ptr; pm <= pe; pm++) 32669921123SKonstantin Belousov switch (*pm) { 32769921123SKonstantin Belousov case LBRACKET: 32869921123SKonstantin Belousov /* Ignore everything between [] */ 32969921123SKonstantin Belousov for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) 33069921123SKonstantin Belousov continue; 33169921123SKonstantin Belousov if (*pm == EOS) { 33269921123SKonstantin Belousov /* 33369921123SKonstantin Belousov * We could not find a matching RBRACKET. 33469921123SKonstantin Belousov * Ignore and just look for RBRACE 33569921123SKonstantin Belousov */ 33669921123SKonstantin Belousov pm = pm1; 33769921123SKonstantin Belousov } 33869921123SKonstantin Belousov break; 33969921123SKonstantin Belousov 34069921123SKonstantin Belousov case LBRACE: 34169921123SKonstantin Belousov i++; 34269921123SKonstantin Belousov break; 34369921123SKonstantin Belousov 34469921123SKonstantin Belousov case RBRACE: 34569921123SKonstantin Belousov if (i) { 34669921123SKonstantin Belousov i--; 34769921123SKonstantin Belousov break; 34869921123SKonstantin Belousov } 34969921123SKonstantin Belousov /* FALLTHROUGH */ 35069921123SKonstantin Belousov case COMMA: 35169921123SKonstantin Belousov if (i && *pm == COMMA) 35269921123SKonstantin Belousov break; 35369921123SKonstantin Belousov else { 35469921123SKonstantin Belousov /* Append the current string */ 35569921123SKonstantin Belousov for (lm = ls; (pl < pm); *lm++ = *pl++) 35669921123SKonstantin Belousov continue; 35769921123SKonstantin Belousov /* 35869921123SKonstantin Belousov * Append the rest of the pattern after the 35969921123SKonstantin Belousov * closing brace 36069921123SKonstantin Belousov */ 36169921123SKonstantin Belousov for (pl = pe + 1; (*lm++ = *pl++) != EOS;) 36269921123SKonstantin Belousov continue; 36369921123SKonstantin Belousov 36469921123SKonstantin Belousov /* Expand the current pattern */ 36569921123SKonstantin Belousov #ifdef DEBUG 36669921123SKonstantin Belousov qprintf("globexp2:", patbuf); 36769921123SKonstantin Belousov #endif 36869921123SKonstantin Belousov rv = globexp1(patbuf, pglob, limit); 36969921123SKonstantin Belousov if (rv) 37069921123SKonstantin Belousov return (rv); 37169921123SKonstantin Belousov 37269921123SKonstantin Belousov /* move after the comma, to the next string */ 37369921123SKonstantin Belousov pl = pm + 1; 37469921123SKonstantin Belousov } 37569921123SKonstantin Belousov break; 37669921123SKonstantin Belousov 37769921123SKonstantin Belousov default: 37869921123SKonstantin Belousov break; 37969921123SKonstantin Belousov } 38069921123SKonstantin Belousov return (0); 38169921123SKonstantin Belousov } 38269921123SKonstantin Belousov 38369921123SKonstantin Belousov 38469921123SKonstantin Belousov 38569921123SKonstantin Belousov /* 38669921123SKonstantin Belousov * expand tilde from the passwd file. 38769921123SKonstantin Belousov */ 38869921123SKonstantin Belousov static const Char * 38969921123SKonstantin Belousov globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob11_t *pglob) 39069921123SKonstantin Belousov { 39169921123SKonstantin Belousov struct passwd *pwd; 39269921123SKonstantin Belousov char *h, *sc; 39369921123SKonstantin Belousov const Char *p; 39469921123SKonstantin Belousov Char *b, *eb; 39569921123SKonstantin Belousov wchar_t wc; 39669921123SKonstantin Belousov wchar_t wbuf[MAXPATHLEN]; 39769921123SKonstantin Belousov wchar_t *wbufend, *dc; 39869921123SKonstantin Belousov size_t clen; 39969921123SKonstantin Belousov mbstate_t mbs; 40069921123SKonstantin Belousov int too_long; 40169921123SKonstantin Belousov 40269921123SKonstantin Belousov if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) 40369921123SKonstantin Belousov return (pattern); 40469921123SKonstantin Belousov 40569921123SKonstantin Belousov /* 40669921123SKonstantin Belousov * Copy up to the end of the string or / 40769921123SKonstantin Belousov */ 40869921123SKonstantin Belousov eb = &patbuf[patbuf_len - 1]; 40969921123SKonstantin Belousov for (p = pattern + 1, b = patbuf; 41069921123SKonstantin Belousov b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++) 41169921123SKonstantin Belousov continue; 41269921123SKonstantin Belousov 41369921123SKonstantin Belousov if (*p != EOS && UNPROT(*p) != SEP) 41469921123SKonstantin Belousov return (NULL); 41569921123SKonstantin Belousov 41669921123SKonstantin Belousov *b = EOS; 41769921123SKonstantin Belousov h = NULL; 41869921123SKonstantin Belousov 41969921123SKonstantin Belousov if (patbuf[0] == EOS) { 42069921123SKonstantin Belousov /* 42169921123SKonstantin Belousov * handle a plain ~ or ~/ by expanding $HOME first (iff 42269921123SKonstantin Belousov * we're not running setuid or setgid) and then trying 42369921123SKonstantin Belousov * the password file 42469921123SKonstantin Belousov */ 425*68ca8363SMark Johnston if ((h = secure_getenv("HOME")) == NULL) { 42669921123SKonstantin Belousov if (((h = getlogin()) != NULL && 42769921123SKonstantin Belousov (pwd = getpwnam(h)) != NULL) || 42869921123SKonstantin Belousov (pwd = getpwuid(getuid())) != NULL) 42969921123SKonstantin Belousov h = pwd->pw_dir; 43069921123SKonstantin Belousov else 43169921123SKonstantin Belousov return (pattern); 43269921123SKonstantin Belousov } 43369921123SKonstantin Belousov } 43469921123SKonstantin Belousov else { 43569921123SKonstantin Belousov /* 43669921123SKonstantin Belousov * Expand a ~user 43769921123SKonstantin Belousov */ 43869921123SKonstantin Belousov if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf))) 43969921123SKonstantin Belousov return (NULL); 44069921123SKonstantin Belousov if ((pwd = getpwnam((char *)wbuf)) == NULL) 44169921123SKonstantin Belousov return (pattern); 44269921123SKonstantin Belousov else 44369921123SKonstantin Belousov h = pwd->pw_dir; 44469921123SKonstantin Belousov } 44569921123SKonstantin Belousov 44669921123SKonstantin Belousov /* Copy the home directory */ 44769921123SKonstantin Belousov dc = wbuf; 44869921123SKonstantin Belousov sc = h; 44969921123SKonstantin Belousov wbufend = wbuf + MAXPATHLEN - 1; 45069921123SKonstantin Belousov too_long = 1; 45169921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 45269921123SKonstantin Belousov while (dc <= wbufend) { 45369921123SKonstantin Belousov clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); 45469921123SKonstantin Belousov if (clen == (size_t)-1 || clen == (size_t)-2) { 45569921123SKonstantin Belousov /* XXX See initial comment #2. */ 45669921123SKonstantin Belousov wc = (unsigned char)*sc; 45769921123SKonstantin Belousov clen = 1; 45869921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 45969921123SKonstantin Belousov } 46069921123SKonstantin Belousov if ((*dc++ = wc) == EOS) { 46169921123SKonstantin Belousov too_long = 0; 46269921123SKonstantin Belousov break; 46369921123SKonstantin Belousov } 46469921123SKonstantin Belousov sc += clen; 46569921123SKonstantin Belousov } 46669921123SKonstantin Belousov if (too_long) 46769921123SKonstantin Belousov return (NULL); 46869921123SKonstantin Belousov 46969921123SKonstantin Belousov dc = wbuf; 47069921123SKonstantin Belousov for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT) 47169921123SKonstantin Belousov continue; 47269921123SKonstantin Belousov if (*dc != EOS) 47369921123SKonstantin Belousov return (NULL); 47469921123SKonstantin Belousov 47569921123SKonstantin Belousov /* Append the rest of the pattern */ 47669921123SKonstantin Belousov if (*p != EOS) { 47769921123SKonstantin Belousov too_long = 1; 47869921123SKonstantin Belousov while (b <= eb) { 47969921123SKonstantin Belousov if ((*b++ = *p++) == EOS) { 48069921123SKonstantin Belousov too_long = 0; 48169921123SKonstantin Belousov break; 48269921123SKonstantin Belousov } 48369921123SKonstantin Belousov } 48469921123SKonstantin Belousov if (too_long) 48569921123SKonstantin Belousov return (NULL); 48669921123SKonstantin Belousov } else 48769921123SKonstantin Belousov *b = EOS; 48869921123SKonstantin Belousov 48969921123SKonstantin Belousov return (patbuf); 49069921123SKonstantin Belousov } 49169921123SKonstantin Belousov 49269921123SKonstantin Belousov 49369921123SKonstantin Belousov /* 49469921123SKonstantin Belousov * The main glob() routine: compiles the pattern (optionally processing 49569921123SKonstantin Belousov * quotes), calls glob1() to do the real pattern matching, and finally 49669921123SKonstantin Belousov * sorts the list (unless unsorted operation is requested). Returns 0 49769921123SKonstantin Belousov * if things went well, nonzero if errors occurred. 49869921123SKonstantin Belousov */ 49969921123SKonstantin Belousov static int 50069921123SKonstantin Belousov glob0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit, 50169921123SKonstantin Belousov const char *origpat) { 50269921123SKonstantin Belousov const Char *qpatnext; 50369921123SKonstantin Belousov int err; 50469921123SKonstantin Belousov size_t oldpathc; 50569921123SKonstantin Belousov Char *bufnext, c, patbuf[MAXPATHLEN]; 50669921123SKonstantin Belousov 50769921123SKonstantin Belousov qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); 50869921123SKonstantin Belousov if (qpatnext == NULL) { 50969921123SKonstantin Belousov errno = E2BIG; 51069921123SKonstantin Belousov return (GLOB_NOSPACE); 51169921123SKonstantin Belousov } 51269921123SKonstantin Belousov oldpathc = pglob->gl_pathc; 51369921123SKonstantin Belousov bufnext = patbuf; 51469921123SKonstantin Belousov 51569921123SKonstantin Belousov /* We don't need to check for buffer overflow any more. */ 51669921123SKonstantin Belousov while ((c = *qpatnext++) != EOS) { 51769921123SKonstantin Belousov switch (c) { 51869921123SKonstantin Belousov case LBRACKET: 51969921123SKonstantin Belousov c = *qpatnext; 52069921123SKonstantin Belousov if (c == NOT) 52169921123SKonstantin Belousov ++qpatnext; 52269921123SKonstantin Belousov if (*qpatnext == EOS || 52369921123SKonstantin Belousov g_strchr(qpatnext+1, RBRACKET) == NULL) { 52469921123SKonstantin Belousov *bufnext++ = LBRACKET; 52569921123SKonstantin Belousov if (c == NOT) 52669921123SKonstantin Belousov --qpatnext; 52769921123SKonstantin Belousov break; 52869921123SKonstantin Belousov } 52969921123SKonstantin Belousov *bufnext++ = M_SET; 53069921123SKonstantin Belousov if (c == NOT) 53169921123SKonstantin Belousov *bufnext++ = M_NOT; 53269921123SKonstantin Belousov c = *qpatnext++; 53369921123SKonstantin Belousov do { 53469921123SKonstantin Belousov *bufnext++ = CHAR(c); 53569921123SKonstantin Belousov if (*qpatnext == RANGE && 53669921123SKonstantin Belousov (c = qpatnext[1]) != RBRACKET) { 53769921123SKonstantin Belousov *bufnext++ = M_RNG; 53869921123SKonstantin Belousov *bufnext++ = CHAR(c); 53969921123SKonstantin Belousov qpatnext += 2; 54069921123SKonstantin Belousov } 54169921123SKonstantin Belousov } while ((c = *qpatnext++) != RBRACKET); 54269921123SKonstantin Belousov pglob->gl_flags |= GLOB_MAGCHAR; 54369921123SKonstantin Belousov *bufnext++ = M_END; 54469921123SKonstantin Belousov break; 54569921123SKonstantin Belousov case QUESTION: 54669921123SKonstantin Belousov pglob->gl_flags |= GLOB_MAGCHAR; 54769921123SKonstantin Belousov *bufnext++ = M_ONE; 54869921123SKonstantin Belousov break; 54969921123SKonstantin Belousov case STAR: 55069921123SKonstantin Belousov pglob->gl_flags |= GLOB_MAGCHAR; 55169921123SKonstantin Belousov /* collapse adjacent stars to one, 55269921123SKonstantin Belousov * to avoid exponential behavior 55369921123SKonstantin Belousov */ 55469921123SKonstantin Belousov if (bufnext == patbuf || bufnext[-1] != M_ALL) 55569921123SKonstantin Belousov *bufnext++ = M_ALL; 55669921123SKonstantin Belousov break; 55769921123SKonstantin Belousov default: 55869921123SKonstantin Belousov *bufnext++ = CHAR(c); 55969921123SKonstantin Belousov break; 56069921123SKonstantin Belousov } 56169921123SKonstantin Belousov } 56269921123SKonstantin Belousov *bufnext = EOS; 56369921123SKonstantin Belousov #ifdef DEBUG 56469921123SKonstantin Belousov qprintf("glob0:", patbuf); 56569921123SKonstantin Belousov #endif 56669921123SKonstantin Belousov 56769921123SKonstantin Belousov if ((err = glob1(patbuf, pglob, limit)) != 0) 56869921123SKonstantin Belousov return(err); 56969921123SKonstantin Belousov 57069921123SKonstantin Belousov if (origpat != NULL) 57169921123SKonstantin Belousov return (globfinal(pglob, limit, oldpathc, origpat)); 57269921123SKonstantin Belousov 57369921123SKonstantin Belousov return (0); 57469921123SKonstantin Belousov } 57569921123SKonstantin Belousov 57669921123SKonstantin Belousov static int 57769921123SKonstantin Belousov globfinal(glob11_t *pglob, struct glob_limit *limit, size_t oldpathc, 57869921123SKonstantin Belousov const char *origpat) { 57969921123SKonstantin Belousov if (pglob->gl_pathc == oldpathc) 58069921123SKonstantin Belousov return (err_nomatch(pglob, limit, origpat)); 58169921123SKonstantin Belousov 58269921123SKonstantin Belousov if (!(pglob->gl_flags & GLOB_NOSORT)) 58369921123SKonstantin Belousov qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 58469921123SKonstantin Belousov pglob->gl_pathc - oldpathc, sizeof(char *), compare); 58569921123SKonstantin Belousov 58669921123SKonstantin Belousov return (0); 58769921123SKonstantin Belousov } 58869921123SKonstantin Belousov 58969921123SKonstantin Belousov static int 59069921123SKonstantin Belousov compare(const void *p, const void *q) 59169921123SKonstantin Belousov { 59269921123SKonstantin Belousov return (strcoll(*(char **)p, *(char **)q)); 59369921123SKonstantin Belousov } 59469921123SKonstantin Belousov 59569921123SKonstantin Belousov static int 59669921123SKonstantin Belousov glob1(Char *pattern, glob11_t *pglob, struct glob_limit *limit) 59769921123SKonstantin Belousov { 59869921123SKonstantin Belousov Char pathbuf[MAXPATHLEN]; 59969921123SKonstantin Belousov 60069921123SKonstantin Belousov /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 60169921123SKonstantin Belousov if (*pattern == EOS) 60269921123SKonstantin Belousov return (0); 60369921123SKonstantin Belousov return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, 60469921123SKonstantin Belousov pattern, pglob, limit)); 60569921123SKonstantin Belousov } 60669921123SKonstantin Belousov 60769921123SKonstantin Belousov /* 60869921123SKonstantin Belousov * The functions glob2 and glob3 are mutually recursive; there is one level 60969921123SKonstantin Belousov * of recursion for each segment in the pattern that contains one or more 61069921123SKonstantin Belousov * meta characters. 61169921123SKonstantin Belousov */ 61269921123SKonstantin Belousov static int 61369921123SKonstantin Belousov glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, 61469921123SKonstantin Belousov glob11_t *pglob, struct glob_limit *limit) 61569921123SKonstantin Belousov { 61669921123SKonstantin Belousov struct freebsd11_stat sb; 61769921123SKonstantin Belousov Char *p, *q; 61869921123SKonstantin Belousov int anymeta; 61969921123SKonstantin Belousov 62069921123SKonstantin Belousov /* 62169921123SKonstantin Belousov * Loop over pattern segments until end of pattern or until 62269921123SKonstantin Belousov * segment with meta character found. 62369921123SKonstantin Belousov */ 62469921123SKonstantin Belousov for (anymeta = 0;;) { 62569921123SKonstantin Belousov if (*pattern == EOS) { /* End of pattern? */ 62669921123SKonstantin Belousov *pathend = EOS; 62769921123SKonstantin Belousov if (g_lstat(pathbuf, &sb, pglob)) 62869921123SKonstantin Belousov return (0); 62969921123SKonstantin Belousov 63069921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_LIMIT) && 63169921123SKonstantin Belousov limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) { 63269921123SKonstantin Belousov errno = E2BIG; 63369921123SKonstantin Belousov return (GLOB_NOSPACE); 63469921123SKonstantin Belousov } 63569921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_MARK) && 63669921123SKonstantin Belousov UNPROT(pathend[-1]) != SEP && 63769921123SKonstantin Belousov (S_ISDIR(sb.st_mode) || 63869921123SKonstantin Belousov (S_ISLNK(sb.st_mode) && 63969921123SKonstantin Belousov g_stat(pathbuf, &sb, pglob) == 0 && 64069921123SKonstantin Belousov S_ISDIR(sb.st_mode)))) { 64169921123SKonstantin Belousov if (pathend + 1 > pathend_last) { 64269921123SKonstantin Belousov errno = E2BIG; 64369921123SKonstantin Belousov return (GLOB_NOSPACE); 64469921123SKonstantin Belousov } 64569921123SKonstantin Belousov *pathend++ = SEP; 64669921123SKonstantin Belousov *pathend = EOS; 64769921123SKonstantin Belousov } 64869921123SKonstantin Belousov ++pglob->gl_matchc; 64969921123SKonstantin Belousov return (globextend(pathbuf, pglob, limit, NULL)); 65069921123SKonstantin Belousov } 65169921123SKonstantin Belousov 65269921123SKonstantin Belousov /* Find end of next segment, copy tentatively to pathend. */ 65369921123SKonstantin Belousov q = pathend; 65469921123SKonstantin Belousov p = pattern; 65569921123SKonstantin Belousov while (*p != EOS && UNPROT(*p) != SEP) { 65669921123SKonstantin Belousov if (ismeta(*p)) 65769921123SKonstantin Belousov anymeta = 1; 65869921123SKonstantin Belousov if (q + 1 > pathend_last) { 65969921123SKonstantin Belousov errno = E2BIG; 66069921123SKonstantin Belousov return (GLOB_NOSPACE); 66169921123SKonstantin Belousov } 66269921123SKonstantin Belousov *q++ = *p++; 66369921123SKonstantin Belousov } 66469921123SKonstantin Belousov 66569921123SKonstantin Belousov if (!anymeta) { /* No expansion, do next segment. */ 66669921123SKonstantin Belousov pathend = q; 66769921123SKonstantin Belousov pattern = p; 66869921123SKonstantin Belousov while (UNPROT(*pattern) == SEP) { 66969921123SKonstantin Belousov if (pathend + 1 > pathend_last) { 67069921123SKonstantin Belousov errno = E2BIG; 67169921123SKonstantin Belousov return (GLOB_NOSPACE); 67269921123SKonstantin Belousov } 67369921123SKonstantin Belousov *pathend++ = *pattern++; 67469921123SKonstantin Belousov } 67569921123SKonstantin Belousov } else /* Need expansion, recurse. */ 67669921123SKonstantin Belousov return (glob3(pathbuf, pathend, pathend_last, pattern, 67769921123SKonstantin Belousov p, pglob, limit)); 67869921123SKonstantin Belousov } 67969921123SKonstantin Belousov /* NOTREACHED */ 68069921123SKonstantin Belousov } 68169921123SKonstantin Belousov 68269921123SKonstantin Belousov static int 68369921123SKonstantin Belousov glob3(Char *pathbuf, Char *pathend, Char *pathend_last, 68469921123SKonstantin Belousov Char *pattern, Char *restpattern, 68569921123SKonstantin Belousov glob11_t *pglob, struct glob_limit *limit) 68669921123SKonstantin Belousov { 68769921123SKonstantin Belousov struct freebsd11_dirent *dp; 68869921123SKonstantin Belousov DIR *dirp; 68969921123SKonstantin Belousov int err, too_long, saverrno, saverrno2; 69069921123SKonstantin Belousov char buf[MAXPATHLEN + MB_LEN_MAX - 1]; 69169921123SKonstantin Belousov 69269921123SKonstantin Belousov struct freebsd11_dirent *(*readdirfunc)(DIR *); 69369921123SKonstantin Belousov 69469921123SKonstantin Belousov if (pathend > pathend_last) { 69569921123SKonstantin Belousov errno = E2BIG; 69669921123SKonstantin Belousov return (GLOB_NOSPACE); 69769921123SKonstantin Belousov } 69869921123SKonstantin Belousov *pathend = EOS; 69969921123SKonstantin Belousov if (pglob->gl_errfunc != NULL && 70069921123SKonstantin Belousov g_Ctoc(pathbuf, buf, sizeof(buf))) { 70169921123SKonstantin Belousov errno = E2BIG; 70269921123SKonstantin Belousov return (GLOB_NOSPACE); 70369921123SKonstantin Belousov } 70469921123SKonstantin Belousov 70569921123SKonstantin Belousov saverrno = errno; 70669921123SKonstantin Belousov errno = 0; 70769921123SKonstantin Belousov if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 70869921123SKonstantin Belousov if (errno == ENOENT || errno == ENOTDIR) 70969921123SKonstantin Belousov return (0); 71069921123SKonstantin Belousov err = err_aborted(pglob, errno, buf); 71169921123SKonstantin Belousov if (errno == 0) 71269921123SKonstantin Belousov errno = saverrno; 71369921123SKonstantin Belousov return (err); 71469921123SKonstantin Belousov } 71569921123SKonstantin Belousov 71669921123SKonstantin Belousov err = 0; 71769921123SKonstantin Belousov 71869921123SKonstantin Belousov /* pglob->gl_readdir takes a void *, fix this manually */ 71969921123SKonstantin Belousov if (pglob->gl_flags & GLOB_ALTDIRFUNC) 72069921123SKonstantin Belousov readdirfunc = 72169921123SKonstantin Belousov (struct freebsd11_dirent *(*)(DIR *))pglob->gl_readdir; 72269921123SKonstantin Belousov else 72369921123SKonstantin Belousov readdirfunc = freebsd11_readdir; 72469921123SKonstantin Belousov 72569921123SKonstantin Belousov errno = 0; 72669921123SKonstantin Belousov /* Search directory for matching names. */ 72769921123SKonstantin Belousov while ((dp = (*readdirfunc)(dirp)) != NULL) { 72869921123SKonstantin Belousov char *sc; 72969921123SKonstantin Belousov Char *dc; 73069921123SKonstantin Belousov wchar_t wc; 73169921123SKonstantin Belousov size_t clen; 73269921123SKonstantin Belousov mbstate_t mbs; 73369921123SKonstantin Belousov 73469921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_LIMIT) && 73569921123SKonstantin Belousov limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { 73669921123SKonstantin Belousov errno = E2BIG; 73769921123SKonstantin Belousov err = GLOB_NOSPACE; 73869921123SKonstantin Belousov break; 73969921123SKonstantin Belousov } 74069921123SKonstantin Belousov 74169921123SKonstantin Belousov /* Initial DOT must be matched literally. */ 74269921123SKonstantin Belousov if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) { 74369921123SKonstantin Belousov errno = 0; 74469921123SKonstantin Belousov continue; 74569921123SKonstantin Belousov } 74669921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 74769921123SKonstantin Belousov dc = pathend; 74869921123SKonstantin Belousov sc = dp->d_name; 74969921123SKonstantin Belousov too_long = 1; 75069921123SKonstantin Belousov while (dc <= pathend_last) { 75169921123SKonstantin Belousov clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); 75269921123SKonstantin Belousov if (clen == (size_t)-1 || clen == (size_t)-2) { 75369921123SKonstantin Belousov /* XXX See initial comment #2. */ 75469921123SKonstantin Belousov wc = (unsigned char)*sc; 75569921123SKonstantin Belousov clen = 1; 75669921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 75769921123SKonstantin Belousov } 75869921123SKonstantin Belousov if ((*dc++ = wc) == EOS) { 75969921123SKonstantin Belousov too_long = 0; 76069921123SKonstantin Belousov break; 76169921123SKonstantin Belousov } 76269921123SKonstantin Belousov sc += clen; 76369921123SKonstantin Belousov } 76469921123SKonstantin Belousov if (too_long && (err = err_aborted(pglob, ENAMETOOLONG, 76569921123SKonstantin Belousov buf))) { 76669921123SKonstantin Belousov errno = ENAMETOOLONG; 76769921123SKonstantin Belousov break; 76869921123SKonstantin Belousov } 76969921123SKonstantin Belousov if (too_long || !match(pathend, pattern, restpattern)) { 77069921123SKonstantin Belousov *pathend = EOS; 77169921123SKonstantin Belousov errno = 0; 77269921123SKonstantin Belousov continue; 77369921123SKonstantin Belousov } 77469921123SKonstantin Belousov if (errno == 0) 77569921123SKonstantin Belousov errno = saverrno; 77669921123SKonstantin Belousov err = glob2(pathbuf, --dc, pathend_last, restpattern, 77769921123SKonstantin Belousov pglob, limit); 77869921123SKonstantin Belousov if (err) 77969921123SKonstantin Belousov break; 78069921123SKonstantin Belousov errno = 0; 78169921123SKonstantin Belousov } 78269921123SKonstantin Belousov 78369921123SKonstantin Belousov saverrno2 = errno; 78469921123SKonstantin Belousov if (pglob->gl_flags & GLOB_ALTDIRFUNC) 78569921123SKonstantin Belousov (*pglob->gl_closedir)(dirp); 78669921123SKonstantin Belousov else 78769921123SKonstantin Belousov closedir(dirp); 78869921123SKonstantin Belousov errno = saverrno2; 78969921123SKonstantin Belousov 79069921123SKonstantin Belousov if (err) 79169921123SKonstantin Belousov return (err); 79269921123SKonstantin Belousov 79369921123SKonstantin Belousov if (dp == NULL && errno != 0 && 79469921123SKonstantin Belousov (err = err_aborted(pglob, errno, buf))) 79569921123SKonstantin Belousov return (err); 79669921123SKonstantin Belousov 79769921123SKonstantin Belousov if (errno == 0) 79869921123SKonstantin Belousov errno = saverrno; 79969921123SKonstantin Belousov return (0); 80069921123SKonstantin Belousov } 80169921123SKonstantin Belousov 80269921123SKonstantin Belousov 80369921123SKonstantin Belousov /* 80469921123SKonstantin Belousov * Extend the gl_pathv member of a glob11_t structure to accommodate a new item, 80569921123SKonstantin Belousov * add the new item, and update gl_pathc. 80669921123SKonstantin Belousov * 80769921123SKonstantin Belousov * This assumes the BSD realloc, which only copies the block when its size 80869921123SKonstantin Belousov * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 80969921123SKonstantin Belousov * behavior. 81069921123SKonstantin Belousov * 81169921123SKonstantin Belousov * Return 0 if new item added, error code if memory couldn't be allocated. 81269921123SKonstantin Belousov * 81369921123SKonstantin Belousov * Invariant of the glob11_t structure: 81469921123SKonstantin Belousov * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 81569921123SKonstantin Belousov * gl_pathv points to (gl_offs + gl_pathc + 1) items. 81669921123SKonstantin Belousov */ 81769921123SKonstantin Belousov static int 81869921123SKonstantin Belousov globextend(const Char *path, glob11_t *pglob, struct glob_limit *limit, 81969921123SKonstantin Belousov const char *origpat) 82069921123SKonstantin Belousov { 82169921123SKonstantin Belousov char **pathv; 82269921123SKonstantin Belousov size_t i, newn, len; 82369921123SKonstantin Belousov char *copy; 82469921123SKonstantin Belousov const Char *p; 82569921123SKonstantin Belousov 82669921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_LIMIT) && 82769921123SKonstantin Belousov pglob->gl_matchc > limit->l_path_lim) { 82869921123SKonstantin Belousov errno = E2BIG; 82969921123SKonstantin Belousov return (GLOB_NOSPACE); 83069921123SKonstantin Belousov } 83169921123SKonstantin Belousov 83269921123SKonstantin Belousov newn = 2 + pglob->gl_pathc + pglob->gl_offs; 83369921123SKonstantin Belousov /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */ 83469921123SKonstantin Belousov pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv)); 83569921123SKonstantin Belousov if (pathv == NULL) 83669921123SKonstantin Belousov return (GLOB_NOSPACE); 83769921123SKonstantin Belousov 83869921123SKonstantin Belousov if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 83969921123SKonstantin Belousov /* first time around -- clear initial gl_offs items */ 84069921123SKonstantin Belousov pathv += pglob->gl_offs; 84169921123SKonstantin Belousov for (i = pglob->gl_offs + 1; --i > 0; ) 84269921123SKonstantin Belousov *--pathv = NULL; 84369921123SKonstantin Belousov } 84469921123SKonstantin Belousov pglob->gl_pathv = pathv; 84569921123SKonstantin Belousov 84669921123SKonstantin Belousov if (origpat != NULL) 84769921123SKonstantin Belousov copy = strdup(origpat); 84869921123SKonstantin Belousov else { 84969921123SKonstantin Belousov for (p = path; *p++ != EOS;) 85069921123SKonstantin Belousov continue; 85169921123SKonstantin Belousov len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ 85269921123SKonstantin Belousov if ((copy = malloc(len)) != NULL) { 85369921123SKonstantin Belousov if (g_Ctoc(path, copy, len)) { 85469921123SKonstantin Belousov free(copy); 85569921123SKonstantin Belousov errno = E2BIG; 85669921123SKonstantin Belousov return (GLOB_NOSPACE); 85769921123SKonstantin Belousov } 85869921123SKonstantin Belousov } 85969921123SKonstantin Belousov } 86069921123SKonstantin Belousov if (copy != NULL) { 86169921123SKonstantin Belousov limit->l_string_cnt += strlen(copy) + 1; 86269921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_LIMIT) && 86369921123SKonstantin Belousov limit->l_string_cnt >= GLOB_LIMIT_STRING) { 86469921123SKonstantin Belousov free(copy); 86569921123SKonstantin Belousov errno = E2BIG; 86669921123SKonstantin Belousov return (GLOB_NOSPACE); 86769921123SKonstantin Belousov } 86869921123SKonstantin Belousov pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 86969921123SKonstantin Belousov } 87069921123SKonstantin Belousov pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 87169921123SKonstantin Belousov return (copy == NULL ? GLOB_NOSPACE : 0); 87269921123SKonstantin Belousov } 87369921123SKonstantin Belousov 87469921123SKonstantin Belousov /* 87569921123SKonstantin Belousov * pattern matching function for filenames. 87669921123SKonstantin Belousov */ 87769921123SKonstantin Belousov static int 87869921123SKonstantin Belousov match(Char *name, Char *pat, Char *patend) 87969921123SKonstantin Belousov { 88069921123SKonstantin Belousov int ok, negate_range; 88169921123SKonstantin Belousov Char c, k, *nextp, *nextn; 88269921123SKonstantin Belousov struct xlocale_collate *table = 88369921123SKonstantin Belousov (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; 88469921123SKonstantin Belousov 88569921123SKonstantin Belousov nextn = NULL; 88669921123SKonstantin Belousov nextp = NULL; 88769921123SKonstantin Belousov 88869921123SKonstantin Belousov while (1) { 88969921123SKonstantin Belousov while (pat < patend) { 89069921123SKonstantin Belousov c = *pat++; 89169921123SKonstantin Belousov switch (c & M_MASK) { 89269921123SKonstantin Belousov case M_ALL: 89369921123SKonstantin Belousov if (pat == patend) 89469921123SKonstantin Belousov return (1); 89569921123SKonstantin Belousov if (*name == EOS) 89669921123SKonstantin Belousov return (0); 89769921123SKonstantin Belousov nextn = name + 1; 89869921123SKonstantin Belousov nextp = pat - 1; 89969921123SKonstantin Belousov break; 90069921123SKonstantin Belousov case M_ONE: 90169921123SKonstantin Belousov if (*name++ == EOS) 90269921123SKonstantin Belousov goto fail; 90369921123SKonstantin Belousov break; 90469921123SKonstantin Belousov case M_SET: 90569921123SKonstantin Belousov ok = 0; 90669921123SKonstantin Belousov if ((k = *name++) == EOS) 90769921123SKonstantin Belousov goto fail; 90869921123SKonstantin Belousov negate_range = ((*pat & M_MASK) == M_NOT); 90969921123SKonstantin Belousov if (negate_range != 0) 91069921123SKonstantin Belousov ++pat; 91169921123SKonstantin Belousov while (((c = *pat++) & M_MASK) != M_END) 91269921123SKonstantin Belousov if ((*pat & M_MASK) == M_RNG) { 91369921123SKonstantin Belousov if (table->__collate_load_error ? 91469921123SKonstantin Belousov CHAR(c) <= CHAR(k) && 91569921123SKonstantin Belousov CHAR(k) <= CHAR(pat[1]) : 91669921123SKonstantin Belousov __wcollate_range_cmp(CHAR(c), 91769921123SKonstantin Belousov CHAR(k)) <= 0 && 91869921123SKonstantin Belousov __wcollate_range_cmp(CHAR(k), 91969921123SKonstantin Belousov CHAR(pat[1])) <= 0) 92069921123SKonstantin Belousov ok = 1; 92169921123SKonstantin Belousov pat += 2; 92269921123SKonstantin Belousov } else if (c == k) 92369921123SKonstantin Belousov ok = 1; 92469921123SKonstantin Belousov if (ok == negate_range) 92569921123SKonstantin Belousov goto fail; 92669921123SKonstantin Belousov break; 92769921123SKonstantin Belousov default: 92869921123SKonstantin Belousov if (*name++ != c) 92969921123SKonstantin Belousov goto fail; 93069921123SKonstantin Belousov break; 93169921123SKonstantin Belousov } 93269921123SKonstantin Belousov } 93369921123SKonstantin Belousov if (*name == EOS) 93469921123SKonstantin Belousov return (1); 93569921123SKonstantin Belousov 93669921123SKonstantin Belousov fail: 93769921123SKonstantin Belousov if (nextn == NULL) 93869921123SKonstantin Belousov break; 93969921123SKonstantin Belousov pat = nextp; 94069921123SKonstantin Belousov name = nextn; 94169921123SKonstantin Belousov } 94269921123SKonstantin Belousov return (0); 94369921123SKonstantin Belousov } 94469921123SKonstantin Belousov 94569921123SKonstantin Belousov /* Free allocated data belonging to a glob11_t structure. */ 94669921123SKonstantin Belousov void 94769921123SKonstantin Belousov freebsd11_globfree(glob11_t *pglob) 94869921123SKonstantin Belousov { 94969921123SKonstantin Belousov size_t i; 95069921123SKonstantin Belousov char **pp; 95169921123SKonstantin Belousov 95269921123SKonstantin Belousov if (pglob->gl_pathv != NULL) { 95369921123SKonstantin Belousov pp = pglob->gl_pathv + pglob->gl_offs; 95469921123SKonstantin Belousov for (i = pglob->gl_pathc; i--; ++pp) 95569921123SKonstantin Belousov if (*pp) 95669921123SKonstantin Belousov free(*pp); 95769921123SKonstantin Belousov free(pglob->gl_pathv); 95869921123SKonstantin Belousov pglob->gl_pathv = NULL; 95969921123SKonstantin Belousov } 96069921123SKonstantin Belousov } 96169921123SKonstantin Belousov 96269921123SKonstantin Belousov static DIR * 96369921123SKonstantin Belousov g_opendir(Char *str, glob11_t *pglob) 96469921123SKonstantin Belousov { 96569921123SKonstantin Belousov char buf[MAXPATHLEN + MB_LEN_MAX - 1]; 96669921123SKonstantin Belousov 96769921123SKonstantin Belousov if (*str == EOS) 96869921123SKonstantin Belousov strcpy(buf, "."); 96969921123SKonstantin Belousov else { 97069921123SKonstantin Belousov if (g_Ctoc(str, buf, sizeof(buf))) { 97169921123SKonstantin Belousov errno = ENAMETOOLONG; 97269921123SKonstantin Belousov return (NULL); 97369921123SKonstantin Belousov } 97469921123SKonstantin Belousov } 97569921123SKonstantin Belousov 97669921123SKonstantin Belousov if (pglob->gl_flags & GLOB_ALTDIRFUNC) 97769921123SKonstantin Belousov return ((*pglob->gl_opendir)(buf)); 97869921123SKonstantin Belousov 97969921123SKonstantin Belousov return (opendir(buf)); 98069921123SKonstantin Belousov } 98169921123SKonstantin Belousov 98269921123SKonstantin Belousov static int 98369921123SKonstantin Belousov g_lstat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob) 98469921123SKonstantin Belousov { 98569921123SKonstantin Belousov char buf[MAXPATHLEN + MB_LEN_MAX - 1]; 98669921123SKonstantin Belousov 98769921123SKonstantin Belousov if (g_Ctoc(fn, buf, sizeof(buf))) { 98869921123SKonstantin Belousov errno = ENAMETOOLONG; 98969921123SKonstantin Belousov return (-1); 99069921123SKonstantin Belousov } 99169921123SKonstantin Belousov if (pglob->gl_flags & GLOB_ALTDIRFUNC) 99269921123SKonstantin Belousov return((*pglob->gl_lstat)(buf, sb)); 99369921123SKonstantin Belousov return (freebsd11_lstat(buf, sb)); 99469921123SKonstantin Belousov } 99569921123SKonstantin Belousov 99669921123SKonstantin Belousov static int 99769921123SKonstantin Belousov g_stat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob) 99869921123SKonstantin Belousov { 99969921123SKonstantin Belousov char buf[MAXPATHLEN + MB_LEN_MAX - 1]; 100069921123SKonstantin Belousov 100169921123SKonstantin Belousov if (g_Ctoc(fn, buf, sizeof(buf))) { 100269921123SKonstantin Belousov errno = ENAMETOOLONG; 100369921123SKonstantin Belousov return (-1); 100469921123SKonstantin Belousov } 100569921123SKonstantin Belousov if (pglob->gl_flags & GLOB_ALTDIRFUNC) 100669921123SKonstantin Belousov return ((*pglob->gl_stat)(buf, sb)); 100769921123SKonstantin Belousov return (freebsd11_stat(buf, sb)); 100869921123SKonstantin Belousov } 100969921123SKonstantin Belousov 101069921123SKonstantin Belousov static const Char * 101169921123SKonstantin Belousov g_strchr(const Char *str, wchar_t ch) 101269921123SKonstantin Belousov { 101369921123SKonstantin Belousov 101469921123SKonstantin Belousov do { 101569921123SKonstantin Belousov if (*str == ch) 101669921123SKonstantin Belousov return (str); 101769921123SKonstantin Belousov } while (*str++); 101869921123SKonstantin Belousov return (NULL); 101969921123SKonstantin Belousov } 102069921123SKonstantin Belousov 102169921123SKonstantin Belousov static int 102269921123SKonstantin Belousov g_Ctoc(const Char *str, char *buf, size_t len) 102369921123SKonstantin Belousov { 102469921123SKonstantin Belousov mbstate_t mbs; 102569921123SKonstantin Belousov size_t clen; 102669921123SKonstantin Belousov 102769921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 102869921123SKonstantin Belousov while (len >= MB_CUR_MAX) { 102969921123SKonstantin Belousov clen = wcrtomb(buf, CHAR(*str), &mbs); 103069921123SKonstantin Belousov if (clen == (size_t)-1) { 103169921123SKonstantin Belousov /* XXX See initial comment #2. */ 103269921123SKonstantin Belousov *buf = (char)CHAR(*str); 103369921123SKonstantin Belousov clen = 1; 103469921123SKonstantin Belousov memset(&mbs, 0, sizeof(mbs)); 103569921123SKonstantin Belousov } 103669921123SKonstantin Belousov if (CHAR(*str) == EOS) 103769921123SKonstantin Belousov return (0); 103869921123SKonstantin Belousov str++; 103969921123SKonstantin Belousov buf += clen; 104069921123SKonstantin Belousov len -= clen; 104169921123SKonstantin Belousov } 104269921123SKonstantin Belousov return (1); 104369921123SKonstantin Belousov } 104469921123SKonstantin Belousov 104569921123SKonstantin Belousov static int 104669921123SKonstantin Belousov err_nomatch(glob11_t *pglob, struct glob_limit *limit, const char *origpat) { 104769921123SKonstantin Belousov /* 104869921123SKonstantin Belousov * If there was no match we are going to append the origpat 104969921123SKonstantin Belousov * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified 105069921123SKonstantin Belousov * and the origpat did not contain any magic characters 105169921123SKonstantin Belousov * GLOB_NOMAGIC is there just for compatibility with csh. 105269921123SKonstantin Belousov */ 105369921123SKonstantin Belousov if ((pglob->gl_flags & GLOB_NOCHECK) || 105469921123SKonstantin Belousov ((pglob->gl_flags & GLOB_NOMAGIC) && 105569921123SKonstantin Belousov !(pglob->gl_flags & GLOB_MAGCHAR))) 105669921123SKonstantin Belousov return (globextend(NULL, pglob, limit, origpat)); 105769921123SKonstantin Belousov return (GLOB_NOMATCH); 105869921123SKonstantin Belousov } 105969921123SKonstantin Belousov 106069921123SKonstantin Belousov static int 106169921123SKonstantin Belousov err_aborted(glob11_t *pglob, int err, char *buf) { 106269921123SKonstantin Belousov if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) || 106369921123SKonstantin Belousov (pglob->gl_flags & GLOB_ERR)) 106469921123SKonstantin Belousov return (GLOB_ABORTED); 106569921123SKonstantin Belousov return (0); 106669921123SKonstantin Belousov } 106769921123SKonstantin Belousov 106869921123SKonstantin Belousov #ifdef DEBUG 106969921123SKonstantin Belousov static void 107069921123SKonstantin Belousov qprintf(const char *str, Char *s) 107169921123SKonstantin Belousov { 107269921123SKonstantin Belousov Char *p; 107369921123SKonstantin Belousov 107469921123SKonstantin Belousov (void)printf("%s\n", str); 107569921123SKonstantin Belousov if (s != NULL) { 107669921123SKonstantin Belousov for (p = s; *p != EOS; p++) 107769921123SKonstantin Belousov (void)printf("%c", (char)CHAR(*p)); 107869921123SKonstantin Belousov (void)printf("\n"); 107969921123SKonstantin Belousov for (p = s; *p != EOS; p++) 108069921123SKonstantin Belousov (void)printf("%c", (isprot(*p) ? '\\' : ' ')); 108169921123SKonstantin Belousov (void)printf("\n"); 108269921123SKonstantin Belousov for (p = s; *p != EOS; p++) 108369921123SKonstantin Belousov (void)printf("%c", (ismeta(*p) ? '_' : ' ')); 108469921123SKonstantin Belousov (void)printf("\n"); 108569921123SKonstantin Belousov } 108669921123SKonstantin Belousov } 108769921123SKonstantin Belousov #endif 108869921123SKonstantin Belousov 108969921123SKonstantin Belousov __sym_compat(glob, freebsd11_glob, FBSD_1.0); 109069921123SKonstantin Belousov __sym_compat(globfree, freebsd11_globfree, FBSD_1.0); 1091