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