Print this page
1097 glob(3c) needs to support non-POSIX options
3341 The sftp command should use the native glob()

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