Print this page
1097 glob(3c) needs to support non-POSIX options
3341 The sftp command should use the native glob()
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * This code is MKS code ported to Solaris originally with minimum
  29  * modifications so that upgrades from MKS would readily integrate.
  30  * The MKS basis for this modification was:
  31  *
  32  *      $Id: glob.c 1.31 1994/04/07 22:50:43 mark

  33  *
  34  * Additional modifications have been made to this code to make it
  35  * 64-bit clean.





















  36  */
  37 
  38 /*
  39  * glob, globfree -- POSIX.2 compatible file name expansion routines.
  40  *
  41  * Copyright 1985, 1991 by Mortice Kern Systems Inc.  All rights reserved.
  42  *
  43  * Written by Eric Gisin.

















  44  */
  45 
  46 #pragma ident   "%Z%%M% %I%     %E% SMI"

  47 
  48 #pragma weak _glob = glob
  49 #pragma weak _globfree = globfree
  50 
  51 #include "lint.h"
  52 #include <stdio.h>
  53 #include <unistd.h>
  54 #include <limits.h>


  55 #include <stdlib.h>
  56 #include <string.h>
  57 #include <dirent.h>
  58 #include <sys/stat.h>
  59 #include <glob.h>
  60 #include <errno.h>
  61 #include <fnmatch.h>
  62 
  63 #define GLOB__CHECK     0x80    /* stat generated paths */

















  64 
  65 #define INITIAL 8               /* initial pathv allocation */
  66 #define NULLCPP ((char **)0)    /* Null char ** */
  67 #define NAME_MAX        1024    /* something large */
  68 
  69 static int      globit(size_t, const char *, glob_t *, int,
  70         int (*)(const char *, int), char **);
  71 static int      pstrcmp(const void *, const void *);
  72 static int      append(glob_t *, const char *);
  73 













































































































































  74 /*
  75  * Free all space consumed by glob.


  76  */
  77 void
  78 globfree(glob_t *gp)

  79 {
  80         size_t i;
  81 
  82         if (gp->gl_pathv == 0)
  83                 return;


  84 
  85         for (i = gp->gl_offs; i < gp->gl_offs + gp->gl_pathc; ++i)
  86                 free(gp->gl_pathv[i]);
  87         free((void *)gp->gl_pathv);
  88 
  89         gp->gl_pathc = 0;
  90         gp->gl_pathv = NULLCPP;
  91 }
  92 

  93 /*
  94  * Do filename expansion.


  95  */
  96 int
  97 glob(const char *pattern, int flags,
  98         int (*errfn)(const char *, int), glob_t *gp)
  99 {
 100         int rv;
 101         size_t i;
 102         size_t ipathc;
 103         char    *path;
 104 
 105         if ((flags & GLOB_DOOFFS) == 0)
 106                 gp->gl_offs = 0;




 107 
 108         if (!(flags & GLOB_APPEND)) {
 109                 gp->gl_pathc = 0;
 110                 gp->gl_pathn = gp->gl_offs + INITIAL;
 111                 gp->gl_pathv = (char **)malloc(sizeof (char *) * gp->gl_pathn);

















 112 
 113                 if (gp->gl_pathv == NULLCPP)
 114                         return (GLOB_NOSPACE);
 115                 gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
 116 
 117                 for (i = 0; i < gp->gl_offs; ++i)
 118                         gp->gl_pathv[i] = NULL;











 119         }

 120 
 121         if ((path = malloc(strlen(pattern)+1)) == NULL)
 122                 return (GLOB_NOSPACE);

 123 
 124         ipathc = gp->gl_pathc;
 125         rv = globit(0, pattern, gp, flags, errfn, &path);











 126 
 127         if (rv == GLOB_ABORTED) {
 128                 /*
 129                  * User's error function returned non-zero, or GLOB_ERR was
 130                  * set, and we encountered a directory we couldn't search.
 131                  */
 132                 free(path);
 133                 return (GLOB_ABORTED);









 134         }

 135 
 136         i = gp->gl_pathc - ipathc;
 137         if (i >= 1 && !(flags & GLOB_NOSORT)) {
 138                 qsort((char *)(gp->gl_pathp+ipathc), i, sizeof (char *),
 139                     pstrcmp);
 140         }
 141         if (i == 0) {
 142                 if (flags & GLOB_NOCHECK)
 143                         (void) append(gp, pattern);









































 144                 else
 145                         rv = GLOB_NOMATCH;
 146         }
 147         gp->gl_pathp[gp->gl_pathc] = NULL;
 148         free(path);







 149 
 150         return (rv);





















 151 }
 152 









 153 






































 154 /*
 155  * Recursive routine to match glob pattern, and walk directories.




 156  */
 157 int
 158 globit(size_t dend, const char *sp, glob_t *gp, int flags,
 159         int (*errfn)(const char *, int), char **path)
 160 {
 161         size_t n;
 162         size_t m;
 163         ssize_t end = 0;        /* end of expanded directory */
 164         char *pat = (char *)sp; /* pattern component */
 165         char *dp = (*path) + dend;
 166         int expand = 0;         /* path has pattern */
 167         char *cp;
 168         struct stat64 sb;
 169         DIR *dirp;
 170         struct dirent64 *d;
 171         int err;
 172 
 173         for (;;)
 174                 switch (*dp++ = *(unsigned char *)sp++) {
 175                 case '\0':      /* end of source path */
 176                         if (expand)
 177                                 goto Expand;
 178                         else {
 179                                 if (!(flags & GLOB_NOCHECK) ||
 180                                     flags & (GLOB__CHECK|GLOB_MARK))
 181                                         if (stat64(*path, &sb) < 0) {
 182                                                 return (0);





 183                                         }
 184                                 if (flags & GLOB_MARK && S_ISDIR(sb.st_mode)) {
 185                                         *dp = '\0';
 186                                         *--dp = '/';








 187                                 }
 188                                 if (append(gp, *path) < 0) {



















































































































 189                                         return (GLOB_NOSPACE);



 190                                 }
 191                                 return (0);



 192                         }
 193                         /*NOTREACHED*/








 194 
 195                 case '*':
 196                 case '?':
 197                 case '[':
 198                 case '\\':
 199                         ++expand;
 200                         break;
 201 
 202                 case '/':
 203                         if (expand)
 204                                 goto Expand;
 205                         end = dp - *path;
 206                         pat = (char *)sp;
 207                         break;
 208 
 209                 Expand:
 210                         /* determine directory and open it */
 211                         (*path)[end] = '\0';
 212                         dirp = opendir(**path == '\0' ? "." : *path);
 213                         if (dirp == NULL) {
 214                                 if (errfn != 0 && errfn(*path, errno) != 0 ||
 215                                     flags&GLOB_ERR) {
 216                                         return (GLOB_ABORTED);








































 217                                 }

 218                                 return (0);














 219                         }



 220 
 221                         /* extract pattern component */
 222                         n = sp - pat;
 223                         if ((cp = malloc(n)) == NULL) {
 224                                 (void) closedir(dirp);



 225                                 return (GLOB_NOSPACE);

 226                         }
 227                         pat = memcpy(cp, pat, n);
 228                         pat[n-1] = '\0';
 229                         if (*--sp != '\0')
 230                                 flags |= GLOB__CHECK;
 231 
 232                         /* expand path to max. expansion */
 233                         n = dp - *path;
 234                         *path = realloc(*path,
 235                             strlen(*path) + NAME_MAX + strlen(sp) + 1);
 236                         if (*path == NULL) {
 237                                 (void) closedir(dirp);
 238                                 free(pat);
 239                                 return (GLOB_NOSPACE);

 240                         }
 241                         dp = (*path) + n;








 242 
 243                         /* read directory and match entries */




































 244                         err = 0;
 245                         while ((d = readdir64(dirp)) != NULL) {
 246                                 cp = d->d_name;
 247                                 if ((flags&GLOB_NOESCAPE)
 248                                     ? fnmatch(pat, cp, FNM_PERIOD|FNM_NOESCAPE)
 249                                     : fnmatch(pat, cp, FNM_PERIOD))




















 250                                         continue;





























 251 
 252                                 n = strlen(cp);
 253                                 (void) memcpy((*path) + end, cp, n);
 254                                 m = dp - *path;
 255                                 err = globit(end+n, sp, gp, flags, errfn, path);
 256                                 dp = (*path) + m;   /* globit can move path */
 257                                 if (err != 0)



 258                                         break;
 259                         }
 260 
 261                         (void) closedir(dirp);
 262                         free(pat);


 263                         return (err);
 264                 }
 265                 /* NOTREACHED */
 266 }
 267 

 268 /*
 269  * Comparison routine for two name arguments, called by qsort.











 270  */
 271 int
 272 pstrcmp(const void *npp1, const void *npp2)

 273 {
 274         return (strcoll(*(char **)npp1, *(char **)npp2));






































































































 275 }
 276 

 277 /*
 278  * Add a new matched filename to the glob_t structure, increasing the
 279  * size of that array, as required.
 280  */
 281 int
 282 append(glob_t *gp, const char *str)
 283 {
 284         char *cp;

 285 
 286         if ((cp = malloc(strlen(str)+1)) == NULL)
 287                 return (GLOB_NOSPACE);
 288         gp->gl_pathp[gp->gl_pathc++] = strcpy(cp, str);
 289 
 290         if ((gp->gl_pathc + gp->gl_offs) >= gp->gl_pathn) {
 291                 gp->gl_pathn *= 2;
 292                 gp->gl_pathv = (char **)realloc((void *)gp->gl_pathv,
 293                     gp->gl_pathn * sizeof (char *));
 294                 if (gp->gl_pathv == NULLCPP)
 295                         return (GLOB_NOSPACE);
 296                 gp->gl_pathp = gp->gl_pathv + gp->gl_offs;


 297         }









 298         return (0);






















































 299 }





















































































































   1 /*
   2  * Copyright (c) 2012 Gary Mills

















   3  */
   4 /*      $OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
   5 /*
   6  * Copyright (c) 1989, 1993
   7  *      The Regents of the University of California.  All rights reserved.






   8  *
   9  * This code is derived from software contributed to Berkeley by
  10  * Guido van Rossum.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  * 1. Redistributions of source code must retain the above copyright
  16  *    notice, this list of conditions and the following disclaimer.
  17  * 2. Redistributions in binary form must reproduce the above copyright
  18  *    notice, this list of conditions and the following disclaimer in the
  19  *    documentation and/or other materials provided with the distribution.
  20  * 3. Neither the name of the University nor the names of its contributors
  21  *    may be used to endorse or promote products derived from this software
  22  *    without specific prior written permission.
  23  *
  24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34  * SUCH DAMAGE.
  35  */
  36 
  37 /*
  38  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  39  *
  40  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  41  *
  42  * Optional extra services, controlled by flags not defined by POSIX:
  43  *
  44  * GLOB_QUOTE:
  45  *      Escaping convention: \ inhibits any special meaning the following
  46  *      character might have (except \ at end of string is retained).
  47  * GLOB_MAGCHAR:
  48  *      Set in gl_flags if pattern contained a globbing character.
  49  * GLOB_NOMAGIC:
  50  *      Same as GLOB_NOCHECK, but it will only append pattern if it did
  51  *      not contain any magic characters.  [Used in csh style globbing]
  52  * GLOB_ALTDIRFUNC:
  53  *      Use alternately specified directory access functions.
  54  * GLOB_TILDE:
  55  *      expand ~user/foo to the /home/dir/of/user/foo
  56  * GLOB_BRACE:
  57  *      expand {1,2}{a,b} to 1a 1b 2a 2b
  58  * gl_matchc:
  59  *      Number of matches in the current invocation of glob.
  60  */
  61 
  62 #include <sys/param.h>
  63 #include <sys/stat.h>
  64 
  65 #include <ctype.h>
  66 #include <dirent.h>
  67 #include <errno.h>
  68 #include <glob.h>


  69 #include <limits.h>
  70 #include <pwd.h>
  71 #include <stdio.h>
  72 #include <stdlib.h>
  73 #include <string.h>
  74 #include <unistd.h>
  75 #include <wchar.h>
  76 #include <wctype.h>


  77 
  78 #define DOLLAR          '$'
  79 #define DOT             '.'
  80 #define EOS             '\0'
  81 #define LBRACKET        '['
  82 #define NOT             '!'
  83 #define QUESTION        '?'
  84 #define QUOTE           '\\'
  85 #define RANGE           '-'
  86 #define RBRACKET        ']'
  87 #define SEP             '/'
  88 #define STAR            '*'
  89 #define TILDE           '~'
  90 #define UNDERSCORE      '_'
  91 #define LBRACE          '{'
  92 #define RBRACE          '}'
  93 #define SLASH           '/'
  94 #define COMMA           ','
  95 #define COLON           ':'
  96 
  97 #define M_QUOTE         0x800000
  98 #define M_PROTECT       0x400000

  99 
 100 typedef struct wcat {
 101         wchar_t w_wc;
 102         uint_t w_at;
 103 } wcat_t;
 104 
 105 #define M_ALL           '*'     /* Plus M_QUOTE */
 106 #define M_END           ']'     /* Plus M_QUOTE */
 107 #define M_NOT           '!'     /* Plus M_QUOTE */
 108 #define M_ONE           '?'     /* Plus M_QUOTE */
 109 #define M_RNG           '-'     /* Plus M_QUOTE */
 110 #define M_SET           '['     /* Plus M_QUOTE */
 111 #define M_CLASS         ':'     /* Plus M_QUOTE */
 112 #define ismeta(c)       (((c).w_at&M_QUOTE) != 0)
 113 
 114 #define GLOB_LIMIT_MALLOC       65536
 115 #define GLOB_LIMIT_STAT         2048
 116 #define GLOB_LIMIT_READDIR      16384
 117 
 118 /* Limit of recursion during matching attempts. */
 119 #define GLOB_LIMIT_RECUR        64
 120 
 121 struct glob_lim {
 122         size_t  glim_malloc;
 123         size_t  glim_stat;
 124         size_t  glim_readdir;
 125 };
 126 
 127 struct glob_path_stat {
 128         char            *gps_path;
 129         struct stat     *gps_stat;
 130 };
 131 
 132 static int       compare(const void *, const void *);
 133 static int       compare_gps(const void *, const void *);
 134 static int       g_Ctoc(const wcat_t *, char *, uint_t);
 135 static int       g_lstat(wcat_t *, struct stat *, glob_t *);
 136 static DIR      *g_opendir(wcat_t *, glob_t *);
 137 static wcat_t   *g_strchr(const wcat_t *, wchar_t);
 138 static int       g_stat(wcat_t *, struct stat *, glob_t *);
 139 static int       glob0(const wcat_t *, glob_t *, struct glob_lim *,
 140                         int (*)(const char *, int));
 141 static int       glob1(wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
 142                         int (*)(const char *, int));
 143 static int       glob2(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
 144                         wcat_t *, glob_t *, struct glob_lim *,
 145                         int (*)(const char *, int));
 146 static int       glob3(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
 147                         wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
 148                         int (*)(const char *, int));
 149 static int       globextend(const wcat_t *, glob_t *, struct glob_lim *,
 150                     struct stat *);
 151 static
 152 const wcat_t    *globtilde(const wcat_t *, wcat_t *, size_t, glob_t *);
 153 static int       globexp1(const wcat_t *, glob_t *, struct glob_lim *,
 154                     int (*)(const char *, int));
 155 static int       globexp2(const wcat_t *, const wcat_t *, glob_t *,
 156                     struct glob_lim *, int (*)(const char *, int));
 157 static int       match(wcat_t *, wcat_t *, wcat_t *, int);
 158 #ifdef DEBUG
 159 static void      qprintf(const char *, wcat_t *);
 160 #endif
 161 
 162 int
 163 glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
 164     glob_t *pglob)
 165 {
 166         const char *patnext;
 167         size_t n, patlen;
 168         wchar_t c;
 169         wcat_t *bufnext, *bufend, patbuf[MAXPATHLEN];
 170         struct glob_lim limit = { 0, 0, 0 };
 171 
 172         if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX)
 173                 return (GLOB_NOMATCH);
 174 
 175         patnext = pattern;
 176         if (!(flags & GLOB_APPEND)) {
 177                 pglob->gl_pathc = 0;
 178                 pglob->gl_pathv = NULL;
 179                 if ((flags & GLOB_KEEPSTAT) != 0)
 180                         pglob->gl_statv = NULL;
 181                 if (!(flags & GLOB_DOOFFS))
 182                         pglob->gl_offs = 0;
 183         }
 184         pglob->gl_flags = flags & ~GLOB_MAGCHAR;
 185         pglob->gl_matchc = 0;
 186 
 187         if (pglob->gl_offs < 0 || pglob->gl_pathc < 0 ||
 188             pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
 189             pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
 190                 return (GLOB_NOSPACE);
 191 
 192         bufnext = patbuf;
 193         bufend = bufnext + MAXPATHLEN - 1;
 194         patlen += 1;
 195         if (flags & GLOB_NOESCAPE) {
 196                 while (bufnext < bufend) {
 197                         if ((n = mbtowc(&c, patnext, patlen)) > 0) {
 198                                 patnext += n;
 199                                 patlen -= n;
 200                                 bufnext->w_at = 0;
 201                                 (bufnext++)->w_wc = c;
 202                         } else if (n == 0) {
 203                                 break;
 204                         } else {
 205                                 return (GLOB_NOMATCH);
 206                         }
 207                 }
 208         } else {
 209                 /* Protect the quoted characters. */
 210                 while (bufnext < bufend) {
 211                         if ((n = mbtowc(&c, patnext, patlen)) > 0) {
 212                                 patnext += n;
 213                                 patlen -= n;
 214                                 if (c == QUOTE) {
 215                                         n = mbtowc(&c, patnext, patlen);
 216                                         if (n < 0)
 217                                                 return (GLOB_NOMATCH);
 218                                         if (n > 0) {
 219                                                 patnext += n;
 220                                                 patlen -= n;
 221                                         }
 222                                         if (n == 0)
 223                                                 c = QUOTE;
 224                                         bufnext->w_at = M_PROTECT;
 225                                         (bufnext++)->w_wc = c;
 226                                 } else {
 227                                         bufnext->w_at = 0;
 228                                         (bufnext++)->w_wc = c;
 229                                 }
 230                         } else if (n == 0) {
 231                                 break;
 232                         } else {
 233                                 return (GLOB_NOMATCH);
 234                         }
 235                 }
 236         }
 237         bufnext->w_at = 0;
 238         bufnext->w_wc = EOS;
 239 
 240         if (flags & GLOB_BRACE)
 241                 return (globexp1(patbuf, pglob, &limit, errfunc));
 242         else
 243                 return (glob0(patbuf, pglob, &limit, errfunc));
 244 }
 245 
 246 /*
 247  * Expand recursively a glob {} pattern. When there is no more expansion
 248  * invoke the standard globbing routine to glob the rest of the magic
 249  * characters
 250  */
 251 static int
 252 globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
 253     int (*errfunc)(const char *, int))
 254 {
 255         const wcat_t *ptr = pattern;
 256 
 257         /* Protect a single {}, for find(1), like csh */
 258         if (pattern[0].w_wc == LBRACE && pattern[1].w_wc == RBRACE &&
 259             pattern[2].w_wc == EOS)
 260                 return (glob0(pattern, pglob, limitp, errfunc));
 261 
 262         if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL)
 263                 return (globexp2(ptr, pattern, pglob, limitp, errfunc));

 264 
 265         return (glob0(pattern, pglob, limitp, errfunc));

 266 }
 267 
 268 
 269 /*
 270  * Recursive brace globbing helper. Tries to expand a single brace.
 271  * If it succeeds then it invokes globexp1 with the new pattern.
 272  * If it fails then it tries to glob the rest of the pattern and returns.
 273  */
 274 static int
 275 globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob,
 276     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 277 {
 278         int     i, rv;
 279         wcat_t   *lm, *ls;
 280         const wcat_t *pe, *pm, *pl;
 281         wcat_t    patbuf[MAXPATHLEN];
 282 
 283         /* copy part up to the brace */
 284         for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
 285                 ;
 286         lm->w_at = 0;
 287         lm->w_wc = EOS;
 288         ls = lm;
 289 
 290         /* Find the balanced brace */
 291         for (i = 0, pe = ++ptr; pe->w_wc != EOS; pe++)
 292                 if (pe->w_wc == LBRACKET) {
 293                         /* Ignore everything between [] */
 294                         for (pm = pe++; pe->w_wc != RBRACKET &&
 295                             pe->w_wc != EOS; pe++)
 296                                 ;
 297                         if (pe->w_wc == EOS) {
 298                                 /*
 299                                  * We could not find a matching RBRACKET.
 300                                  * Ignore and just look for RBRACE
 301                                  */
 302                                 pe = pm;
 303                         }
 304                 } else if (pe->w_wc == LBRACE) {
 305                         i++;
 306                 } else if (pe->w_wc == RBRACE) {
 307                         if (i == 0)
 308                                 break;
 309                         i--;
 310                 }
 311 
 312         /* Non matching braces; just glob the pattern */
 313         if (i != 0 || pe->w_wc == EOS)
 314                 return (glob0(patbuf, pglob, limitp, errfunc));
 315 
 316         for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
 317                 switch (pm->w_wc) {
 318                 case LBRACKET:
 319                         /* Ignore everything between [] */
 320                         for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS;
 321                             pm++)
 322                                 ;
 323                         if (pm->w_wc == EOS) {
 324                                 /*
 325                                  * We could not find a matching RBRACKET.
 326                                  * Ignore and just look for RBRACE
 327                                  */
 328                                 pm = pl;
 329                         }
 330                         break;
 331 
 332                 case LBRACE:
 333                         i++;
 334                         break;
 335 
 336                 case RBRACE:
 337                         if (i) {
 338                                 i--;
 339                                 break;
 340                         }
 341                         /* FALLTHROUGH */
 342                 case COMMA:
 343                         if (i && pm->w_wc == COMMA)
 344                                 break;
 345                         else {
 346                                 /* Append the current string */
 347                                 for (lm = ls; (pl < pm); *lm++ = *pl++)
 348                                         ;
 349 

 350                                 /*
 351                                  * Append the rest of the pattern after the
 352                                  * closing brace
 353                                  */
 354                                 for (pl = pe + 1;
 355                                     (*lm++ = *pl++).w_wc != EOS; /* */)
 356                                         ;
 357 
 358                                 /* Expand the current pattern */
 359                                 rv = globexp1(patbuf, pglob, limitp, errfunc);
 360                                 if (rv && rv != GLOB_NOMATCH)
 361                                         return (rv);
 362 
 363                                 /* move after the comma, to the next string */
 364                                 pl = pm + 1;
 365                         }
 366                         break;
 367 
 368                 default:
 369                         break;


 370                 }
 371         }
 372         return (0);
 373 }
 374 
 375 
 376 
 377 /*
 378  * expand tilde from the passwd file.
 379  */
 380 static const wcat_t *
 381 globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len,
 382     glob_t *pglob)
 383 {
 384         struct passwd *pwd;
 385         char *h;
 386         const wcat_t *p;
 387         wcat_t *b, *eb, *q;
 388         size_t n, lenh;
 389         wchar_t c;
 390 
 391         if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
 392                 return (pattern);
 393 
 394         /* Copy up to the end of the string or / */
 395         eb = &patbuf[patbuf_len - 1];
 396         for (p = pattern + 1, q = patbuf;
 397             q < eb && p->w_wc != EOS && p->w_wc != SLASH; *q++ = *p++)
 398                 ;
 399 
 400         q->w_at = 0;
 401         q->w_wc = EOS;
 402 
 403         /* What to do if patbuf is full? */
 404 
 405         if (patbuf[0].w_wc == EOS) {
 406                 /*
 407                  * handle a plain ~ or ~/ by expanding $HOME
 408                  * first and then trying the password file
 409                  */
 410                 if (issetugid() != 0)
 411                         return (pattern);
 412                 if ((h = getenv("HOME")) == NULL) {
 413                         if ((pwd = getpwuid(getuid())) == NULL)
 414                                 return (pattern);
 415                         else
 416                                 h = pwd->pw_dir;
 417                 }
 418         } else {
 419                 /*
 420                  * Expand a ~user
 421                  */
 422                 if ((pwd = getpwnam((char *)patbuf)) == NULL)
 423                         return (pattern);
 424                 else
 425                         h = pwd->pw_dir;
 426         }
 427 
 428         /* Copy the home directory */
 429         lenh = strlen(h) + 1;
 430         for (b = patbuf; b < eb && *h != EOS; b++) {
 431                 if ((n = mbtowc(&c, h, lenh)) > 0) {
 432                         h += n;
 433                         lenh -= n;
 434                         b->w_at = 0;
 435                         b->w_wc = c;
 436                 } else if (n < 0) {
 437                         return (pattern);
 438                 } else {
 439                         break;
 440                 }
 441         }
 442 
 443         /* Append the rest of the pattern */
 444         while (b < eb && (*b++ = *p++).w_wc != EOS)
 445                 ;
 446         b->w_at = 0;
 447         b->w_wc = EOS;
 448 
 449         return (patbuf);
 450 }
 451 
 452 static int
 453 g_charclass(const wcat_t **patternp, wcat_t **bufnextp)
 454 {
 455         const wcat_t *pattern = *patternp + 1;
 456         wcat_t *bufnext = *bufnextp;
 457         const wcat_t *colon;
 458         char cbuf[MB_LEN_MAX + 32];
 459         wctype_t cc;
 460         size_t len;
 461 
 462         if ((colon = g_strchr(pattern, COLON)) == NULL ||
 463             colon[1].w_wc != RBRACKET)
 464                 return (1);     /* not a character class */
 465 
 466         len = (size_t)(colon - pattern);
 467         if (len + MB_LEN_MAX + 1 > sizeof (cbuf))
 468                 return (-1);    /* invalid character class */
 469         {
 470                 wchar_t w;
 471                 const wcat_t *s1 = pattern;
 472                 char *s2 = cbuf;
 473                 size_t n = len;
 474 
 475                 /* Copy the string. */
 476                 while (n > 0) {
 477                         w = (s1++)->w_wc;
 478                         /* Character class names must be ASCII. */
 479                         if (iswascii(w)) {
 480                                 n--;
 481                                 *s2++ = w;
 482                         } else {
 483                                 return (-1);    /* invalid character class */
 484                         }
 485                 }
 486                 *s2 = EOS;
 487         }
 488         if ((cc = wctype(cbuf)) == 0)
 489                 return (-1);    /* invalid character class */
 490         bufnext->w_at = M_QUOTE;
 491         (bufnext++)->w_wc = M_CLASS;
 492         bufnext->w_at = 0;
 493         (bufnext++)->w_wc = cc;
 494         *bufnextp = bufnext;
 495         *patternp += len + 3;
 496 
 497         return (0);
 498 }
 499 
 500 /*
 501  * The main glob() routine: compiles the pattern (optionally processing
 502  * quotes), calls glob1() to do the real pattern matching, and finally
 503  * sorts the list (unless unsorted operation is requested).  Returns 0
 504  * if things went well, nonzero if errors occurred.  It is not an error
 505  * to find no matches.
 506  */
 507 static int
 508 glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
 509     int (*errfunc)(const char *, int))
 510 {
 511         const wcat_t *qpatnext;
 512         int err, oldpathc;
 513         wchar_t c;
 514         int a;
 515         wcat_t *bufnext, patbuf[MAXPATHLEN];






 516 
 517         qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
 518         oldpathc = pglob->gl_pathc;
 519         bufnext = patbuf;
 520 
 521         /*
 522          * We don't need to check for buffer overflow any more.
 523          * The pattern has already been copied to an internal buffer.
 524          */
 525         while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) {
 526                 switch (c) {
 527                 case LBRACKET:
 528                         if (a != 0) {
 529                                 bufnext->w_at = a;
 530                                 (bufnext++)->w_wc = c;
 531                                 break;
 532                         }
 533                         a = qpatnext->w_at;
 534                         c = qpatnext->w_wc;
 535                         if (a == 0 && c == NOT)
 536                                 ++qpatnext;
 537                         if (qpatnext->w_wc == EOS ||
 538                             g_strchr(qpatnext+1, RBRACKET) == NULL) {
 539                                 bufnext->w_at = 0;
 540                                 (bufnext++)->w_wc = LBRACKET;
 541                                 if (a == 0 && c == NOT)
 542                                         --qpatnext;
 543                                 break;
 544                         }
 545                         bufnext->w_at = M_QUOTE;
 546                         (bufnext++)->w_wc = M_SET;
 547                         if (a == 0 && c == NOT) {
 548                                 bufnext->w_at = M_QUOTE;
 549                                 (bufnext++)->w_wc = M_NOT;
 550                         }
 551                         a = qpatnext->w_at;
 552                         c = (qpatnext++)->w_wc;
 553                         do {
 554                                 if (a == 0 && c == LBRACKET &&
 555                                     qpatnext->w_wc == COLON) {
 556                                         do {
 557                                                 err = g_charclass(&qpatnext,
 558                                                     &bufnext);
 559                                                 if (err)
 560                                                         break;
 561                                                 a = qpatnext->w_at;
 562                                                 c = (qpatnext++)->w_wc;
 563                                         } while (a == 0 && c == LBRACKET &&
 564                                             qpatnext->w_wc == COLON);
 565                                         if (err == -1 &&
 566                                             !(pglob->gl_flags & GLOB_NOCHECK))
 567                                                 return (GLOB_NOMATCH);
 568                                         if (a == 0 && c == RBRACKET)
 569                                                 break;
 570                                 }
 571                                 bufnext->w_at = a;
 572                                 (bufnext++)->w_wc = c;
 573                                 if (qpatnext->w_at == 0 &&
 574                                     qpatnext->w_wc == RANGE) {
 575                                         a = qpatnext[1].w_at;
 576                                         c = qpatnext[1].w_wc;
 577                                         if (qpatnext[1].w_at != 0 ||
 578                                             qpatnext[1].w_wc != RBRACKET) {
 579                                                 bufnext->w_at = M_QUOTE;
 580                                                 (bufnext++)->w_wc = M_RNG;
 581                                                 bufnext->w_at = a;
 582                                                 (bufnext++)->w_wc = c;
 583                                                 qpatnext += 2;
 584                                         }
 585                                 }
 586                                 a = qpatnext->w_at;
 587                                 c = (qpatnext++)->w_wc;
 588                         } while (a != 0 || c != RBRACKET);
 589                         pglob->gl_flags |= GLOB_MAGCHAR;
 590                         bufnext->w_at = M_QUOTE;
 591                         (bufnext++)->w_wc = M_END;
 592                         break;
 593                 case QUESTION:
 594                         if (a != 0) {
 595                                 bufnext->w_at = a;
 596                                 (bufnext++)->w_wc = c;
 597                                 break;
 598                         }
 599                         pglob->gl_flags |= GLOB_MAGCHAR;
 600                         bufnext->w_at = M_QUOTE;
 601                         (bufnext++)->w_wc = M_ONE;
 602                         break;
 603                 case STAR:
 604                         if (a != 0) {
 605                                 bufnext->w_at = a;
 606                                 (bufnext++)->w_wc = c;
 607                                 break;
 608                         }
 609                         pglob->gl_flags |= GLOB_MAGCHAR;
 610                         /*
 611                          * collapse adjacent stars to one,
 612                          * to avoid exponential behavior
 613                          */
 614                         if (bufnext == patbuf ||
 615                             bufnext[-1].w_at != M_QUOTE ||
 616                             bufnext[-1].w_wc != M_ALL) {
 617                                 bufnext->w_at = M_QUOTE;
 618                                 (bufnext++)->w_wc = M_ALL;
 619                         }
 620                         break;
 621                 default:
 622                         bufnext->w_at = a;
 623                         (bufnext++)->w_wc = c;
 624                         break;
 625                 }
 626         }
 627         bufnext->w_at = 0;
 628         bufnext->w_wc = EOS;
 629 #ifdef DEBUG
 630         qprintf("glob0:glob1:patbuf", patbuf);
 631 #endif
 632 
 633         if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp, errfunc))
 634             != 0)
 635                 return (err);
 636 
 637         /*
 638          * If there was no match we are going to append the pattern
 639          * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
 640          * and the pattern did not contain any magic characters
 641          * GLOB_NOMAGIC is there just for compatibility with csh.
 642          */
 643         if (pglob->gl_pathc == oldpathc) {
 644                 if ((pglob->gl_flags & GLOB_NOCHECK) ||
 645                     ((pglob->gl_flags & GLOB_NOMAGIC) &&
 646                     !(pglob->gl_flags & GLOB_MAGCHAR)))
 647                         return (globextend(pattern, pglob, limitp, NULL));
 648                 else
 649                         return (GLOB_NOMATCH);
 650         }
 651         if (!(pglob->gl_flags & GLOB_NOSORT)) {
 652                 if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
 653                         /* Keep the paths and stat info synced during sort */
 654                         struct glob_path_stat *path_stat;
 655                         int i;
 656                         int n = pglob->gl_pathc - oldpathc;
 657                         int o = pglob->gl_offs + oldpathc;
 658 
 659                         if ((path_stat = calloc(n, sizeof (*path_stat))) ==
 660                             NULL)
 661                                 return (GLOB_NOSPACE);
 662                         for (i = 0; i < n; i++) {
 663                                 path_stat[i].gps_path = pglob->gl_pathv[o + i];
 664                                 path_stat[i].gps_stat = pglob->gl_statv[o + i];
 665                         }
 666                         qsort(path_stat, n, sizeof (*path_stat), compare_gps);
 667                         for (i = 0; i < n; i++) {
 668                                 pglob->gl_pathv[o + i] = path_stat[i].gps_path;
 669                                 pglob->gl_statv[o + i] = path_stat[i].gps_stat;
 670                         }
 671                         free(path_stat);
 672                 } else {
 673                         qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
 674                             pglob->gl_pathc - oldpathc, sizeof (char *),
 675                             compare);
 676                 }
 677         }
 678         return (0);
 679 }
 680 
 681 static int
 682 compare(const void *p, const void *q)
 683 {
 684         return (strcmp(*(char **)p, *(char **)q));
 685 }

 686 
 687 static int
 688 compare_gps(const void *_p, const void *_q)
 689 {
 690         const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
 691         const struct glob_path_stat *q = (const struct glob_path_stat *)_q;

 692 
 693         return (strcmp(p->gps_path, q->gps_path));
 694 }
 695 
 696 static int
 697 glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob,
 698     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 699 {
 700         wcat_t pathbuf[MAXPATHLEN];
 701 
 702         /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
 703         if (pattern->w_wc == EOS)
 704                 return (0);
 705         return (glob2(pathbuf, pathbuf+MAXPATHLEN-1,
 706             pathbuf, pathbuf+MAXPATHLEN-1,
 707             pattern, pattern_last, pglob, limitp, errfunc));
 708 }
 709 
 710 /*
 711  * The functions glob2 and glob3 are mutually recursive; there is one level
 712  * of recursion for each segment in the pattern that contains one or more
 713  * meta characters.
 714  */
 715 static int
 716 glob2(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
 717     wcat_t *pathend_last, wcat_t *pattern, wcat_t *pattern_last,
 718     glob_t *pglob, struct glob_lim *limitp, int (*errfunc)(const char *, int))
 719 {
 720         struct stat sb;
 721         wcat_t *p, *q;
 722         int anymeta;
 723 
 724         /*
 725          * Loop over pattern segments until end of pattern or until
 726          * segment with meta character found.
 727          */
 728         for (anymeta = 0; ; ) {
 729                 if (pattern->w_wc == EOS) {          /* End of pattern? */
 730                         pathend->w_at = 0;
 731                         pathend->w_wc = EOS;
 732 
 733                         if ((pglob->gl_flags & GLOB_LIMIT) &&
 734                             limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
 735                                 errno = 0;
 736                                 pathend->w_at = 0;
 737                                 (pathend++)->w_wc = SEP;
 738                                 pathend->w_at = 0;
 739                                 pathend->w_wc = EOS;
 740                                 return (GLOB_NOSPACE);
 741                         }
 742                         if (g_lstat(pathbuf, &sb, pglob))
 743                                 return (0);
 744 
 745                         if (((pglob->gl_flags & GLOB_MARK) &&
 746                             (pathend[-1].w_at != 0 ||
 747                             pathend[-1].w_wc != SEP)) &&
 748                             (S_ISDIR(sb.st_mode) ||
 749                             (S_ISLNK(sb.st_mode) &&
 750                             (g_stat(pathbuf, &sb, pglob) == 0) &&
 751                             S_ISDIR(sb.st_mode)))) {
 752                                 if (pathend+1 > pathend_last)
 753                                         return (GLOB_NOSPACE);
 754                                 pathend->w_at = 0;
 755                                 (pathend++)->w_wc = SEP;
 756                                 pathend->w_at = 0;
 757                                 pathend->w_wc = EOS;
 758                         }
 759                         ++pglob->gl_matchc;
 760                         return (globextend(pathbuf, pglob, limitp, &sb));
 761                 }
 762 
 763                 /* Find end of next segment, copy tentatively to pathend. */
 764                 q = pathend;
 765                 p = pattern;
 766                 while (p->w_wc != EOS && p->w_wc != SEP) {
 767                         if (ismeta(*p))
 768                                 anymeta = 1;
 769                         if (q+1 > pathend_last)
 770                                 return (GLOB_NOSPACE);
 771                         *q++ = *p++;
 772                 }




 773 
 774                 if (!anymeta) {         /* No expansion, do next segment. */
 775                         pathend = q;
 776                         pattern = p;
 777                         while (pattern->w_wc == SEP) {
 778                                 if (pathend+1 > pathend_last)


 779                                         return (GLOB_NOSPACE);
 780                                 *pathend++ = *pattern++;
 781                         }
 782                 } else  {
 783                         /* Need expansion, recurse. */
 784                         return (glob3(pathbuf, pathbuf_last, pathend,
 785                             pathend_last, pattern, p, pattern_last,
 786                             pglob, limitp, errfunc));
 787                 }
 788         }
 789         /* NOTREACHED */
 790 }
 791 
 792 static int
 793 glob3(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
 794     wcat_t *pathend_last, wcat_t *pattern, wcat_t *restpattern,
 795     wcat_t *restpattern_last, glob_t *pglob, struct glob_lim *limitp,
 796     int (*errfunc)(const char *, int))
 797 {
 798         struct dirent *dp;
 799         DIR *dirp;
 800         int err;
 801         char buf[MAXPATHLEN];
 802 
 803         /*
 804          * The readdirfunc declaration can't be prototyped, because it is
 805          * assigned, below, to two functions which are prototyped in glob.h
 806          * and dirent.h as taking pointers to differently typed opaque
 807          * structures.
 808          */
 809         struct dirent *(*readdirfunc)(void *);
 810 
 811         if (pathend > pathend_last)
 812                 return (GLOB_NOSPACE);
 813         pathend->w_at = 0;
 814         pathend->w_wc = EOS;
 815         errno = 0;
 816 
 817         if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
 818                 /* TODO: don't call for ENOENT or ENOTDIR? */
 819                 if (errfunc) {
 820                         if (g_Ctoc(pathbuf, buf, sizeof (buf)))
 821                                 return (GLOB_ABORTED);
 822                         if (errfunc(buf, errno) ||
 823                             pglob->gl_flags & GLOB_ERR)
 824                                 return (GLOB_ABORTED);
 825                 }
 826                 return (0);
 827         }
 828 
 829         err = 0;
 830 
 831         /* Search directory for matching names. */
 832         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 833                 readdirfunc = pglob->gl_readdir;
 834         else
 835                 readdirfunc = (struct dirent *(*)(void *))readdir;
 836         while ((dp = (*readdirfunc)(dirp))) {
 837                 char *sc;
 838                 wcat_t *dc;
 839                 size_t n, lensc;
 840                 wchar_t w;
 841 
 842                 if ((pglob->gl_flags & GLOB_LIMIT) &&
 843                     limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
 844                         errno = 0;
 845                         pathend->w_at = 0;
 846                         (pathend++)->w_wc = SEP;
 847                         pathend->w_at = 0;
 848                         pathend->w_wc = EOS;
 849                         err = GLOB_NOSPACE;
 850                         break;
 851                 }
 852 
 853                 /* Initial DOT must be matched literally. */
 854                 if (dp->d_name[0] == DOT && pattern->w_wc != DOT)
 855                         continue;
 856                 dc = pathend;
 857                 sc = dp->d_name;
 858                 lensc = strlen(sc) + 1;
 859                 while (dc < pathend_last) {
 860                         if ((n = mbtowc(&w, sc, lensc)) <= 0) {
 861                                 sc += 1;
 862                                 lensc -= 1;
 863                                 dc->w_at = 0;
 864                                 dc->w_wc = EOS;
 865                         } else {
 866                                 sc += n;
 867                                 lensc -= n;
 868                                 dc->w_at = 0;
 869                                 dc->w_wc = w;
 870                         }
 871                         dc++;
 872                         if (n <= 0)
 873                                 break;
 874                 }
 875                 if (dc >= pathend_last) {
 876                         dc->w_at = 0;
 877                         dc->w_wc = EOS;
 878                         err = GLOB_NOSPACE;
 879                         break;
 880                 }
 881                 if (n < 0) {
 882                         err = GLOB_NOMATCH;
 883                         break;
 884                 }
 885 
 886                 if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
 887                         pathend->w_at = 0;
 888                         pathend->w_wc = EOS;
 889                         continue;
 890                 }
 891                 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
 892                     restpattern, restpattern_last, pglob, limitp,
 893                     errfunc);
 894                 if (err)
 895                         break;
 896         }
 897 
 898         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 899                 (*pglob->gl_closedir)(dirp);
 900         else
 901                 closedir(dirp);
 902         return (err);


 903 }
 904 
 905 
 906 /*
 907  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
 908  * add the new item, and update gl_pathc.
 909  *
 910  * This assumes the BSD realloc, which only copies the block when its size
 911  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
 912  * behavior.
 913  *
 914  * Return 0 if new item added, error code if memory couldn't be allocated.
 915  *
 916  * Invariant of the glob_t structure:
 917  *      Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
 918  *      gl_pathv points to (gl_offs + gl_pathc + 1) items.
 919  */
 920 static int
 921 globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp,
 922     struct stat *sb)
 923 {
 924         char **pathv;
 925         ssize_t i;
 926         size_t newn, len;
 927         char *copy = NULL;
 928         const wcat_t *p;
 929         struct stat **statv;
 930         char junk[MB_LEN_MAX];
 931         int n;
 932 
 933         newn = 2 + pglob->gl_pathc + pglob->gl_offs;
 934         if (pglob->gl_offs >= INT_MAX ||
 935             pglob->gl_pathc >= INT_MAX ||
 936             newn >= INT_MAX ||
 937             SIZE_MAX / sizeof (*pathv) <= newn ||
 938             SIZE_MAX / sizeof (*statv) <= newn) {
 939         nospace:
 940                 for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); i++) {
 941                         if (pglob->gl_pathv && pglob->gl_pathv[i])
 942                                 free(pglob->gl_pathv[i]);
 943                         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
 944                             pglob->gl_statv && pglob->gl_statv[i])
 945                                 free(pglob->gl_statv[i]);
 946                 }
 947                 if (pglob->gl_pathv) {
 948                         free(pglob->gl_pathv);
 949                         pglob->gl_pathv = NULL;
 950                 }
 951                 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
 952                     pglob->gl_statv) {
 953                         free(pglob->gl_statv);
 954                         pglob->gl_statv = NULL;
 955                 }
 956                 return (GLOB_NOSPACE);
 957         }
 958 
 959         pathv = realloc(pglob->gl_pathv, newn * sizeof (*pathv));
 960         if (pathv == NULL)
 961                 goto nospace;
 962         if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
 963                 /* first time around -- clear initial gl_offs items */
 964                 pathv += pglob->gl_offs;
 965                 for (i = pglob->gl_offs; --i >= 0; )
 966                         *--pathv = NULL;
 967         }
 968         pglob->gl_pathv = pathv;
 969 
 970         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
 971                 statv = realloc(pglob->gl_statv, newn * sizeof (*statv));
 972                 if (statv == NULL)
 973                         goto nospace;
 974                 if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
 975                         /* first time around -- clear initial gl_offs items */
 976                         statv += pglob->gl_offs;
 977                         for (i = pglob->gl_offs; --i >= 0; )
 978                                 *--statv = NULL;
 979                 }
 980                 pglob->gl_statv = statv;
 981                 if (sb == NULL)
 982                         statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
 983                 else {
 984                         limitp->glim_malloc += sizeof (**statv);
 985                         if ((pglob->gl_flags & GLOB_LIMIT) &&
 986                             limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
 987                                 errno = 0;
 988                                 return (GLOB_NOSPACE);
 989                         }
 990                         if ((statv[pglob->gl_offs + pglob->gl_pathc] =
 991                             malloc(sizeof (**statv))) == NULL)
 992                                 goto copy_error;
 993                         memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
 994                             sizeof (*sb));
 995                 }
 996                 statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
 997         }
 998 
 999         len = MB_LEN_MAX;
1000         p = path;
1001         while ((n = wctomb(junk, p->w_wc)) > 0) {
1002                 len += n;
1003                 if ((p++)->w_wc == EOS)
1004                         break;
1005         }
1006         if (n < 0)
1007                 return (GLOB_NOMATCH);
1008 
1009         limitp->glim_malloc += len;
1010         if ((copy = malloc(len)) != NULL) {
1011                 if (g_Ctoc(path, copy, len)) {
1012                         free(copy);
1013                         return (GLOB_NOSPACE);
1014                 }
1015                 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1016         }
1017         pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1018 
1019         if ((pglob->gl_flags & GLOB_LIMIT) &&
1020             (newn * sizeof (*pathv)) + limitp->glim_malloc >
1021             GLOB_LIMIT_MALLOC) {
1022                 errno = 0;
1023                 return (GLOB_NOSPACE);
1024         }
1025         copy_error:
1026         return (copy == NULL ? GLOB_NOSPACE : 0);
1027 }
1028 
1029 
1030 /*
1031  * pattern matching function for filenames.  Each occurrence of the *
1032  * pattern causes a recursion level.
1033  */
1034 static int
1035 match(wcat_t *name, wcat_t *pat, wcat_t *patend, int recur)
1036 {
1037         int ok, negate_range;
1038         wcat_t c, k;
1039 
1040         if (recur-- == 0)
1041                 return (1);

1042 
1043         while (pat < patend) {
1044                 c = *pat++;
1045                 switch (c.w_wc) {
1046                 case M_ALL:
1047                         if (c.w_at != M_QUOTE) {
1048                                 k = *name++;
1049                                 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1050                                         return (0);
1051                                 break;
1052                         }
1053                         while (pat < patend && pat->w_at == M_QUOTE &&
1054                             pat->w_wc == M_ALL)
1055                                 pat++;  /* eat consecutive '*' */
1056                         if (pat == patend)
1057                                 return (1);
1058                         do {
1059                                 if (match(name, pat, patend, recur))
1060                                         return (1);
1061                         } while ((name++)->w_wc != EOS);
1062                         return (0);
1063                 case M_ONE:
1064                         if (c.w_at != M_QUOTE) {
1065                                 k = *name++;
1066                                 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1067                                         return (0);
1068                                 break;
1069                         }
1070                         if ((name++)->w_wc == EOS)
1071                                 return (0);
1072                         break;
1073                 case M_SET:
1074                         if (c.w_at != M_QUOTE) {
1075                                 k = *name++;
1076                                 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1077                                         return (0);
1078                                 break;
1079                         }
1080                         ok = 0;
1081                         if ((k = *name++).w_wc == EOS)
1082                                 return (0);
1083                         if ((negate_range = (pat->w_at == M_QUOTE &&
1084                             pat->w_wc == M_NOT)) != 0)
1085                                 ++pat;
1086                         while (((c = *pat++).w_at != M_QUOTE) ||
1087                             c.w_wc != M_END) {
1088                                 if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) {
1089                                         wcat_t cc;
1090 
1091                                         cc.w_at = pat->w_at;
1092                                         cc.w_wc = pat->w_wc;
1093                                         if (iswctype(k.w_wc, cc.w_wc))
1094                                                 ok = 1;
1095                                         ++pat;
1096                                 }
1097                                 if (pat->w_at == M_QUOTE &&
1098                                     pat->w_wc == M_RNG) {
1099                                         if (c.w_wc <= k.w_wc &&
1100                                             k.w_wc <= pat[1].w_wc)
1101                                                 ok = 1;
1102                                         pat += 2;
1103                                 } else if (c.w_wc == k.w_wc)
1104                                         ok = 1;
1105                         }
1106                         if (ok == negate_range)
1107                                 return (0);
1108                         break;
1109                 default:
1110                         k = *name++;
1111                         if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1112                                 return (0);
1113                         break;
1114                 }
1115         }
1116         return (name->w_wc == EOS);
1117 }
1118 
1119 /* Free allocated data belonging to a glob_t structure. */
1120 void
1121 globfree(glob_t *pglob)
1122 {
1123         int i;
1124         char **pp;
1125 
1126         if (pglob->gl_pathv != NULL) {
1127                 pp = pglob->gl_pathv + pglob->gl_offs;
1128                 for (i = pglob->gl_pathc; i--; ++pp)
1129                         if (*pp)
1130                                 free(*pp);
1131                 free(pglob->gl_pathv);
1132                 pglob->gl_pathv = NULL;
1133         }
1134         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1135             pglob->gl_statv != NULL) {
1136                 for (i = 0; i < pglob->gl_pathc; i++) {
1137                         if (pglob->gl_statv[i] != NULL)
1138                                 free(pglob->gl_statv[i]);
1139                 }
1140                 free(pglob->gl_statv);
1141                 pglob->gl_statv = NULL;
1142         }
1143 }
1144 
1145 static DIR *
1146 g_opendir(wcat_t *str, glob_t *pglob)
1147 {
1148         char buf[MAXPATHLEN];
1149 
1150         if (str->w_wc == EOS)
1151                 strlcpy(buf, ".", sizeof (buf));
1152         else {
1153                 if (g_Ctoc(str, buf, sizeof (buf)))
1154                         return (NULL);
1155         }
1156 
1157         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1158                 return ((*pglob->gl_opendir)(buf));
1159 
1160         return (opendir(buf));
1161 }
1162 
1163 static int
1164 g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1165 {
1166         char buf[MAXPATHLEN];
1167 
1168         if (g_Ctoc(fn, buf, sizeof (buf)))
1169                 return (-1);
1170         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1171                 return ((*pglob->gl_lstat)(buf, sb));
1172         return (lstat(buf, sb));
1173 }
1174 
1175 static int
1176 g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1177 {
1178         char buf[MAXPATHLEN];
1179 
1180         if (g_Ctoc(fn, buf, sizeof (buf)))
1181                 return (-1);
1182         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1183                 return ((*pglob->gl_stat)(buf, sb));
1184         return (stat(buf, sb));
1185 }
1186 
1187 static wcat_t *
1188 g_strchr(const wcat_t *str, wchar_t ch)
1189 {
1190         do {
1191                 if (str->w_at == 0 && str->w_wc == ch)
1192                         return ((wcat_t *)str);
1193         } while ((str++)->w_wc != EOS);
1194         return (NULL);
1195 }
1196 
1197 static int
1198 g_Ctoc(const wcat_t *str, char *buf, uint_t len)
1199 {
1200         int n;
1201         wchar_t w;
1202 
1203         while (len >= MB_LEN_MAX) {
1204                 w = (str++)->w_wc;
1205                 if ((n = wctomb(buf, w)) > 0) {
1206                         len -= n;
1207                         buf += n;
1208                 }
1209                 if (n < 0)
1210                         break;
1211                 if (w == EOS)
1212                         return (0);
1213         }
1214         return (1);
1215 }
1216 
1217 #ifdef DEBUG
1218 static void
1219 qprintf(const char *str, wcat_t *s)
1220 {
1221         wcat_t *p;
1222 
1223         (void) printf("%s:\n", str);
1224         for (p = s; p->w_wc != EOS; p++)
1225                 (void) printf("%wc", p->w_wc);
1226         (void) printf("\n");
1227         for (p = s; p->w_wc != EOS; p++)
1228                 (void) printf("%c", p->w_at & M_PROTECT ? '"' : ' ');
1229         (void) printf("\n");
1230         for (p = s; p->w_wc != EOS; p++)
1231                 (void) printf("%c", ismeta(*p) ? '_' : ' ');
1232         (void) printf("\n");
1233 }
1234 #endif