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 (c) 2012 Gary Mills
  24  */
  25 
  26 /*      $OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
  27 /*
  28  * Copyright (c) 1989, 1993
  29  *      The Regents of the University of California.  All rights reserved.
  30  *
  31  * This code is derived from software contributed to Berkeley by
  32  * Guido van Rossum.
  33  *
  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.
  57  */
  58 
  59 /*
  60  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  61  *
  62  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  63  *
  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.
  82  */
  83 
  84 #include <sys/param.h>
  85 #include <sys/stat.h>
  86 
  87 #include <ctype.h>
  88 #include <dirent.h>
  89 #include <errno.h>
  90 #include <glob.h>
  91 #include <limits.h>
  92 #include <pwd.h>
  93 #include <stdio.h>
  94 #include <stdlib.h>
  95 #include <string.h>
  96 #include <unistd.h>
  97 #include <wchar.h>
  98 
  99 #include "charclass.h"
 100 
 101 #define DOLLAR          '$'
 102 #define DOT             '.'
 103 #define EOS             '\0'
 104 #define LBRACKET        '['
 105 #define NOT             '!'
 106 #define QUESTION        '?'
 107 #define QUOTE           '\\'
 108 #define RANGE           '-'
 109 #define RBRACKET        ']'
 110 #define SEP             '/'
 111 #define STAR            '*'
 112 #define TILDE           '~'
 113 #define UNDERSCORE      '_'
 114 #define LBRACE          '{'
 115 #define RBRACE          '}'
 116 #define SLASH           '/'
 117 #define COMMA           ','
 118 #define COLON           ':'
 119 
 120 #define M_QUOTE         0x800000
 121 #define M_PROTECT       0x400000
 122 
 123 typedef struct Char_s {
 124         wchar_t wc;
 125         uint_t at;
 126 } Char;
 127 
 128 #define M_ALL           '*'     /* Plus M_QUOTE */
 129 #define M_END           ']'     /* Plus M_QUOTE */
 130 #define M_NOT           '!'     /* Plus M_QUOTE */
 131 #define M_ONE           '?'     /* Plus M_QUOTE */
 132 #define M_RNG           '-'     /* Plus M_QUOTE */
 133 #define M_SET           '['     /* Plus M_QUOTE */
 134 #define M_CLASS         ':'     /* Plus M_QUOTE */
 135 #define ismeta(c)       (((c).at&M_QUOTE) != 0)
 136 
 137 #define GLOB_LIMIT_MALLOC       65536
 138 #define GLOB_LIMIT_STAT         2048
 139 #define GLOB_LIMIT_READDIR      16384
 140 
 141 /* Limit of recursion during matching attempts. */
 142 #define GLOB_LIMIT_RECUR        64
 143 
 144 struct glob_lim {
 145         size_t  glim_malloc;
 146         size_t  glim_stat;
 147         size_t  glim_readdir;
 148 };
 149 
 150 struct glob_path_stat {
 151         char            *gps_path;
 152         struct stat     *gps_stat;
 153 };
 154 
 155 static int       compare(const void *, const void *);
 156 static int       compare_gps(const void *, const void *);
 157 static int       g_Ctoc(const Char *, char *, uint_t);
 158 static int       g_lstat(Char *, struct stat *, glob_t *);
 159 static DIR      *g_opendir(Char *, glob_t *);
 160 static Char     *g_strchr(const Char *, wchar_t);
 161 static int       g_stat(Char *, struct stat *, glob_t *);
 162 static int       glob0(const Char *, glob_t *, struct glob_lim *,
 163                         int (*)(const char *, int));
 164 static int       glob1(Char *, Char *, glob_t *, struct glob_lim *,
 165                         int (*)(const char *, int));
 166 static int       glob2(Char *, Char *, Char *, Char *, Char *, Char *,
 167                         glob_t *, struct glob_lim *,
 168                         int (*)(const char *, int));
 169 static int       glob3(Char *, Char *, Char *, Char *, Char *,
 170                         Char *, Char *, glob_t *, struct glob_lim *,
 171                         int (*)(const char *, int));
 172 static int       globextend(const Char *, glob_t *, struct glob_lim *,
 173                     struct stat *);
 174 static
 175 const Char      *globtilde(const Char *, Char *, size_t, glob_t *);
 176 static int       globexp1(const Char *, glob_t *, struct glob_lim *,
 177                     int (*)(const char *, int));
 178 static int       globexp2(const Char *, const Char *, glob_t *,
 179                     struct glob_lim *, int (*)(const char *, int));
 180 static int       match(Char *, Char *, Char *, int);
 181 #ifdef DEBUG
 182 static void      qprintf(const char *, Char *);
 183 #endif
 184 
 185 int
 186 glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
 187     glob_t *pglob)
 188 {
 189         const char *patnext;
 190         size_t n;
 191         wchar_t c;
 192         Char *bufnext, *bufend, patbuf[MAXPATHLEN];
 193         struct glob_lim limit = { 0, 0, 0 };
 194 
 195         if (strnlen(pattern, PATH_MAX) == PATH_MAX)
 196                 return (GLOB_NOMATCH);
 197 
 198         patnext = pattern;
 199         if (!(flags & GLOB_APPEND)) {
 200                 pglob->gl_pathc = 0;
 201                 pglob->gl_pathv = NULL;
 202                 if ((flags & GLOB_KEEPSTAT) != 0)
 203                         pglob->gl_statv = NULL;
 204                 if (!(flags & GLOB_DOOFFS))
 205                         pglob->gl_offs = 0;
 206         }
 207         pglob->gl_flags = flags & ~GLOB_MAGCHAR;
 208         pglob->gl_matchc = 0;
 209 
 210         if (pglob->gl_offs < 0 || pglob->gl_pathc < 0 ||
 211             pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
 212             pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
 213                 return (GLOB_NOSPACE);
 214 
 215         bufnext = patbuf;
 216         bufend = bufnext + MAXPATHLEN - 1;
 217         if (flags & GLOB_NOESCAPE) {
 218                 while (bufnext < bufend) {
 219                         if ((n = mbtowc(&c, patnext, PATH_MAX)) > 0) {
 220                                 patnext += n;
 221                                 bufnext->at = 0;
 222                                 (bufnext++)->wc = c;
 223                         } else if (n == 0) {
 224                                 break;
 225                         } else {
 226                                 return (GLOB_NOMATCH);
 227                         }
 228                 }
 229         } else {
 230                 /* Protect the quoted characters. */
 231                 while (bufnext < bufend) {
 232                         if ((n = mbtowc(&c, patnext, PATH_MAX)) > 0) {
 233                                 patnext += n;
 234                                 if (c == QUOTE) {
 235                                         n = mbtowc(&c, patnext, PATH_MAX);
 236                                         if (n < 0)
 237                                                 return (GLOB_NOMATCH);
 238                                         if (n > 0)
 239                                                 patnext += n;
 240                                         if (n == 0)
 241                                                 c = QUOTE;
 242                                         bufnext->at = M_PROTECT;
 243                                         (bufnext++)->wc = c;
 244                                 } else {
 245                                         bufnext->at = 0;
 246                                         (bufnext++)->wc = c;
 247                                 }
 248                         } else if (n == 0) {
 249                                 break;
 250                         } else {
 251                                 return (GLOB_NOMATCH);
 252                         }
 253                 }
 254         }
 255         bufnext->at = 0;
 256         bufnext->wc = EOS;
 257 
 258         if (flags & GLOB_BRACE)
 259                 return (globexp1(patbuf, pglob, &limit, errfunc));
 260         else
 261                 return (glob0(patbuf, pglob, &limit, errfunc));
 262 }
 263 
 264 /*
 265  * Expand recursively a glob {} pattern. When there is no more expansion
 266  * invoke the standard globbing routine to glob the rest of the magic
 267  * characters
 268  */
 269 static int
 270 globexp1(const Char *pattern, glob_t *pglob, struct glob_lim *limitp,
 271     int (*errfunc)(const char *, int))
 272 {
 273         const Char* ptr = pattern;
 274 
 275         /* Protect a single {}, for find(1), like csh */
 276         if (pattern[0].wc == LBRACE && pattern[1].wc == RBRACE &&
 277             pattern[2].wc == EOS)
 278                 return (glob0(pattern, pglob, limitp, errfunc));
 279 
 280         if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
 281                 return (globexp2(ptr, pattern, pglob, limitp, errfunc));
 282 
 283         return (glob0(pattern, pglob, limitp, errfunc));
 284 }
 285 
 286 
 287 /*
 288  * Recursive brace globbing helper. Tries to expand a single brace.
 289  * If it succeeds then it invokes globexp1 with the new pattern.
 290  * If it fails then it tries to glob the rest of the pattern and returns.
 291  */
 292 static int
 293 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
 294     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 295 {
 296         int     i, rv;
 297         Char   *lm, *ls;
 298         const Char *pe, *pm, *pl;
 299         Char    patbuf[MAXPATHLEN];
 300 
 301         /* copy part up to the brace */
 302         for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
 303                 ;
 304         lm->at = 0;
 305         lm->wc = EOS;
 306         ls = lm;
 307 
 308         /* Find the balanced brace */
 309         for (i = 0, pe = ++ptr; pe->wc != EOS; pe++)
 310                 if (pe->wc == LBRACKET) {
 311                         /* Ignore everything between [] */
 312                         for (pm = pe++; pe->wc != RBRACKET &&
 313                             pe->wc != EOS; pe++)
 314                                 ;
 315                         if (pe->wc == EOS) {
 316                                 /*
 317                                  * We could not find a matching RBRACKET.
 318                                  * Ignore and just look for RBRACE
 319                                  */
 320                                 pe = pm;
 321                         }
 322                 } else if (pe->wc == LBRACE) {
 323                         i++;
 324                 } else if (pe->wc == RBRACE) {
 325                         if (i == 0)
 326                                 break;
 327                         i--;
 328                 }
 329 
 330         /* Non matching braces; just glob the pattern */
 331         if (i != 0 || pe->wc == EOS)
 332                 return (glob0(patbuf, pglob, limitp, errfunc));
 333 
 334         for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
 335                 switch (pm->wc) {
 336                 case LBRACKET:
 337                         /* Ignore everything between [] */
 338                         for (pl = pm++; pm->wc != RBRACKET && pm->wc != EOS;
 339                             pm++)
 340                                 ;
 341                         if (pm->wc == EOS) {
 342                                 /*
 343                                  * We could not find a matching RBRACKET.
 344                                  * Ignore and just look for RBRACE
 345                                  */
 346                                 pm = pl;
 347                         }
 348                         break;
 349 
 350                 case LBRACE:
 351                         i++;
 352                         break;
 353 
 354                 case RBRACE:
 355                         if (i) {
 356                                 i--;
 357                                 break;
 358                         }
 359                         /* FALLTHROUGH */
 360                 case COMMA:
 361                         if (i && pm->wc == COMMA)
 362                                 break;
 363                         else {
 364                                 /* Append the current string */
 365                                 for (lm = ls; (pl < pm); *lm++ = *pl++)
 366                                         ;
 367 
 368                                 /*
 369                                  * Append the rest of the pattern after the
 370                                  * closing brace
 371                                  */
 372                                 for (pl = pe + 1;
 373                                     (*lm++ = *pl++).wc != EOS; /* */)
 374                                         ;
 375 
 376                                 /* Expand the current pattern */
 377                                 rv = globexp1(patbuf, pglob, limitp, errfunc);
 378                                 if (rv && rv != GLOB_NOMATCH)
 379                                         return (rv);
 380 
 381                                 /* move after the comma, to the next string */
 382                                 pl = pm + 1;
 383                         }
 384                         break;
 385 
 386                 default:
 387                         break;
 388                 }
 389         }
 390         return (0);
 391 }
 392 
 393 
 394 
 395 /*
 396  * expand tilde from the passwd file.
 397  */
 398 static const Char *
 399 globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
 400 {
 401         struct passwd *pwd;
 402         char *h;
 403         const Char *p;
 404         Char *b, *eb, *q;
 405         size_t n;
 406         wchar_t c;
 407 
 408         if (pattern->wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
 409                 return (pattern);
 410 
 411         /* Copy up to the end of the string or / */
 412         eb = &patbuf[patbuf_len - 1];
 413         for (p = pattern + 1, q = patbuf;
 414             q < eb && p->wc != EOS && p->wc != SLASH; *q++ = *p++)
 415                 ;
 416 
 417         q->at = 0;
 418         q->wc = EOS;
 419 
 420         /* What to do if patbuf is full? */
 421 
 422         if (patbuf[0].wc == EOS) {
 423                 /*
 424                  * handle a plain ~ or ~/ by expanding $HOME
 425                  * first and then trying the password file
 426                  */
 427                 if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
 428                         if ((pwd = getpwuid(getuid())) == NULL)
 429                                 return (pattern);
 430                         else
 431                                 h = pwd->pw_dir;
 432                 }
 433         } else {
 434                 /*
 435                  * Expand a ~user
 436                  */
 437                 if ((pwd = getpwnam((char *)patbuf)) == NULL)
 438                         return (pattern);
 439                 else
 440                         h = pwd->pw_dir;
 441         }
 442 
 443         /* Copy the home directory */
 444         for (b = patbuf; b < eb && *h != EOS; b++) {
 445                 if ((n = mbtowc(&c, h, PATH_MAX)) > 0) {
 446                         h += n;
 447                         b->at = 0;
 448                         b->wc = c;
 449                 } else {
 450                         break;
 451                 }
 452         }
 453 
 454         /* Append the rest of the pattern */
 455         while (b < eb && (*b++ = *p++).wc != EOS)
 456                 ;
 457         b->at = 0;
 458         b->wc = EOS;
 459 
 460         return (patbuf);
 461 }
 462 
 463 static int
 464 g_charclass(const Char **patternp, Char **bufnextp)
 465 {
 466         const Char *pattern = *patternp + 1;
 467         Char *bufnext = *bufnextp;
 468         const Char *colon;
 469         struct cclass *cc;
 470         size_t len;
 471 
 472         if ((colon = g_strchr(pattern, COLON)) == NULL ||
 473             colon[1].wc != RBRACKET)
 474                 return (1);     /* not a character class */
 475 
 476         len = (size_t)(colon - pattern);
 477         for (cc = cclasses; cc->name != NULL; cc++) {
 478                 wchar_t w;
 479                 const Char *s1 = pattern;
 480                 const char *s2 = cc->name;
 481                 size_t n = len;
 482 
 483                 /* Are the strings the same? */
 484                 while (n > 0 && (w = (s1++)->wc) == *s2 && w != EOS) {
 485                         n--;
 486                         s2++;
 487                 }
 488                 if (n == 0 && *s2 == EOS)
 489                         break;
 490         }
 491         if (cc->name == NULL)
 492                 return (-1);    /* invalid character class */
 493         bufnext->at = M_QUOTE;
 494         (bufnext++)->wc = M_CLASS;
 495         bufnext->at = (cc - &cclasses[0]);
 496         (bufnext++)->wc = COLON;
 497         *bufnextp = bufnext;
 498         *patternp += len + 3;
 499 
 500         return (0);
 501 }
 502 
 503 /*
 504  * The main glob() routine: compiles the pattern (optionally processing
 505  * quotes), calls glob1() to do the real pattern matching, and finally
 506  * sorts the list (unless unsorted operation is requested).  Returns 0
 507  * if things went well, nonzero if errors occurred.  It is not an error
 508  * to find no matches.
 509  */
 510 static int
 511 glob0(const Char *pattern, glob_t *pglob, struct glob_lim *limitp,
 512     int (*errfunc)(const char *, int))
 513 {
 514         const Char *qpatnext;
 515         int err, oldpathc;
 516         wchar_t c;
 517         int a;
 518         Char *bufnext, patbuf[MAXPATHLEN];
 519 
 520         qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
 521         oldpathc = pglob->gl_pathc;
 522         bufnext = patbuf;
 523 
 524         /* We don't need to check for buffer overflow any more. */
 525         while ((a = qpatnext->at), (c = (qpatnext++)->wc) != EOS) {
 526                 switch (c) {
 527                 case LBRACKET:
 528                         if (a != 0) {
 529                                 bufnext->at = a;
 530                                 (bufnext++)->wc = c;
 531                                 break;
 532                         }
 533                         a = qpatnext->at;
 534                         c = qpatnext->wc;
 535                         if (a == 0 && c == NOT)
 536                                 ++qpatnext;
 537                         if (qpatnext->wc == EOS ||
 538                             g_strchr(qpatnext+1, RBRACKET) == NULL) {
 539                                 bufnext->at = 0;
 540                                 (bufnext++)->wc = LBRACKET;
 541                                 if (a == 0 && c == NOT)
 542                                         --qpatnext;
 543                                 break;
 544                         }
 545                         bufnext->at = M_QUOTE;
 546                         (bufnext++)->wc = M_SET;
 547                         if (a == 0 && c == NOT) {
 548                                 bufnext->at = M_QUOTE;
 549                                 (bufnext++)->wc = M_NOT;
 550                         }
 551                         a = qpatnext->at;
 552                         c = (qpatnext++)->wc;
 553                         do {
 554                                 if (a == 0 && c == LBRACKET &&
 555                                     qpatnext->wc == COLON) {
 556                                         do {
 557                                                 err = g_charclass(&qpatnext,
 558                                                     &bufnext);
 559                                                 if (err)
 560                                                         break;
 561                                                 a = qpatnext->at;
 562                                                 c = (qpatnext++)->wc;
 563                                         } while (a == 0 && c == LBRACKET &&
 564                                             qpatnext->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->at = a;
 572                                 (bufnext++)->wc = c;
 573                                 if (qpatnext->at == 0 &&
 574                                     qpatnext->wc == RANGE) {
 575                                         a = qpatnext[1].at;
 576                                         c = qpatnext[1].wc;
 577                                         if (qpatnext[1].at != 0 ||
 578                                             qpatnext[1].wc != RBRACKET) {
 579                                                 bufnext->at = M_QUOTE;
 580                                                 (bufnext++)->wc = M_RNG;
 581                                                 bufnext->at = a;
 582                                                 (bufnext++)->wc = c;
 583                                                 qpatnext += 2;
 584                                         }
 585                                 }
 586                                 a = qpatnext->at;
 587                                 c = (qpatnext++)->wc;
 588                         } while (a != 0 || c != RBRACKET);
 589                         pglob->gl_flags |= GLOB_MAGCHAR;
 590                         bufnext->at = M_QUOTE;
 591                         (bufnext++)->wc = M_END;
 592                         break;
 593                 case QUESTION:
 594                         if (a != 0) {
 595                                 bufnext->at = a;
 596                                 (bufnext++)->wc = c;
 597                                 break;
 598                         }
 599                         pglob->gl_flags |= GLOB_MAGCHAR;
 600                         bufnext->at = M_QUOTE;
 601                         (bufnext++)->wc = M_ONE;
 602                         break;
 603                 case STAR:
 604                         if (a != 0) {
 605                                 bufnext->at = a;
 606                                 (bufnext++)->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].at != M_QUOTE ||
 616                             bufnext[-1].wc != M_ALL) {
 617                                 bufnext->at = M_QUOTE;
 618                                 (bufnext++)->wc = M_ALL;
 619                         }
 620                         break;
 621                 default:
 622                         bufnext->at = a;
 623                         (bufnext++)->wc = c;
 624                         break;
 625                 }
 626         }
 627         bufnext->at = 0;
 628         bufnext->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(Char *pattern, Char *pattern_last, glob_t *pglob,
 698     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 699 {
 700         Char pathbuf[MAXPATHLEN];
 701 
 702         /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
 703         if (pattern->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(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
 717     Char *pattern, Char *pattern_last, glob_t *pglob,
 718     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 719 {
 720         struct stat sb;
 721         Char *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->wc == EOS) {            /* End of pattern? */
 730                         pathend->at = 0;
 731                         pathend->wc = EOS;
 732 
 733                         if ((pglob->gl_flags & GLOB_LIMIT) &&
 734                             limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
 735                                 errno = 0;
 736                                 pathend->at = 0;
 737                                 (pathend++)->wc = SEP;
 738                                 pathend->at = 0;
 739                                 pathend->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].at != 0 ||
 747                             pathend[-1].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->at = 0;
 755                                 (pathend++)->wc = SEP;
 756                                 pathend->at = 0;
 757                                 pathend->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->wc != EOS && p->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->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(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
 794     Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
 795     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 796 {
 797         struct dirent *dp;
 798         DIR *dirp;
 799         int err;
 800         char buf[MAXPATHLEN];
 801 
 802         /*
 803          * The readdirfunc declaration can't be prototyped, because it is
 804          * assigned, below, to two functions which are prototyped in glob.h
 805          * and dirent.h as taking pointers to differently typed opaque
 806          * structures.
 807          */
 808         struct dirent *(*readdirfunc)(void *);
 809 
 810         if (pathend > pathend_last)
 811                 return (GLOB_NOSPACE);
 812         pathend->at = 0;
 813         pathend->wc = EOS;
 814         errno = 0;
 815 
 816         if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
 817                 /* TODO: don't call for ENOENT or ENOTDIR? */
 818                 if (errfunc) {
 819                         if (g_Ctoc(pathbuf, buf, sizeof (buf)))
 820                                 return (GLOB_ABORTED);
 821                         if (errfunc(buf, errno) ||
 822                             pglob->gl_flags & GLOB_ERR)
 823                                 return (GLOB_ABORTED);
 824                 }
 825                 return (0);
 826         }
 827 
 828         err = 0;
 829 
 830         /* Search directory for matching names. */
 831         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 832                 readdirfunc = pglob->gl_readdir;
 833         else
 834                 readdirfunc = (struct dirent *(*)(void *))readdir;
 835         while ((dp = (*readdirfunc)(dirp))) {
 836                 char *sc;
 837                 Char *dc;
 838                 size_t n;
 839                 wchar_t w;
 840 
 841                 if ((pglob->gl_flags & GLOB_LIMIT) &&
 842                     limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
 843                         errno = 0;
 844                         pathend->at = 0;
 845                         (pathend++)->wc = SEP;
 846                         pathend->at = 0;
 847                         pathend->wc = EOS;
 848                         err = GLOB_NOSPACE;
 849                         break;
 850                 }
 851 
 852                 /* Initial DOT must be matched literally. */
 853                 if (dp->d_name[0] == DOT && pattern->wc != DOT)
 854                         continue;
 855                 dc = pathend;
 856                 sc = dp->d_name;
 857                 while (dc < pathend_last) {
 858                         if ((n = mbtowc(&w, sc, MB_LEN_MAX)) <= 0) {
 859                                 sc += 1;
 860                                 dc->at = 0;
 861                                 dc->wc = EOS;
 862                         } else {
 863                                 sc += n;
 864                                 dc->at = 0;
 865                                 dc->wc = w;
 866                         }
 867                         dc++;
 868                         if (n <= 0)
 869                                 break;
 870                 }
 871                 if (dc >= pathend_last) {
 872                         dc->at = 0;
 873                         dc->wc = EOS;
 874                         err = GLOB_NOSPACE;
 875                         break;
 876                 }
 877                 if (n < 0) {
 878                         dc->at = 0;
 879                         dc->wc = EOS;
 880                         continue;
 881                 }
 882 
 883                 if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
 884                         pathend->at = 0;
 885                         pathend->wc = EOS;
 886                         continue;
 887                 }
 888                 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
 889                     restpattern, restpattern_last, pglob, limitp,
 890                     errfunc);
 891                 if (err)
 892                         break;
 893         }
 894 
 895         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 896                 (*pglob->gl_closedir)(dirp);
 897         else
 898                 closedir(dirp);
 899         return (err);
 900 }
 901 
 902 
 903 /*
 904  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
 905  * add the new item, and update gl_pathc.
 906  *
 907  * This assumes the BSD realloc, which only copies the block when its size
 908  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
 909  * behavior.
 910  *
 911  * Return 0 if new item added, error code if memory couldn't be allocated.
 912  *
 913  * Invariant of the glob_t structure:
 914  *      Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
 915  *      gl_pathv points to (gl_offs + gl_pathc + 1) items.
 916  */
 917 static int
 918 globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
 919     struct stat *sb)
 920 {
 921         char **pathv;
 922         ssize_t i;
 923         size_t newn, len;
 924         char *copy = NULL;
 925         const Char *p;
 926         struct stat **statv;
 927         char junk[MB_LEN_MAX];
 928         int n;
 929 
 930         newn = 2 + pglob->gl_pathc + pglob->gl_offs;
 931         if (pglob->gl_offs >= INT_MAX ||
 932             pglob->gl_pathc >= INT_MAX ||
 933             newn >= INT_MAX ||
 934             SIZE_MAX / sizeof (*pathv) <= newn ||
 935             SIZE_MAX / sizeof (*statv) <= newn) {
 936         nospace:
 937                 for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); i++) {
 938                         if (pglob->gl_pathv && pglob->gl_pathv[i])
 939                                 free(pglob->gl_pathv[i]);
 940                         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
 941                             pglob->gl_pathv && pglob->gl_pathv[i])
 942                                 free(pglob->gl_statv[i]);
 943                 }
 944                 if (pglob->gl_pathv) {
 945                         free(pglob->gl_pathv);
 946                         pglob->gl_pathv = NULL;
 947                 }
 948                 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
 949                     pglob->gl_statv) {
 950                         free(pglob->gl_statv);
 951                         pglob->gl_statv = NULL;
 952                 }
 953                 return (GLOB_NOSPACE);
 954         }
 955 
 956         pathv = realloc(pglob->gl_pathv, newn * sizeof (*pathv));
 957         if (pathv == NULL)
 958                 goto nospace;
 959         if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
 960                 /* first time around -- clear initial gl_offs items */
 961                 pathv += pglob->gl_offs;
 962                 for (i = pglob->gl_offs; --i >= 0; )
 963                         *--pathv = NULL;
 964         }
 965         pglob->gl_pathv = pathv;
 966 
 967         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
 968                 statv = realloc(pglob->gl_statv, newn * sizeof (*statv));
 969                 if (statv == NULL)
 970                         goto nospace;
 971                 if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
 972                         /* first time around -- clear initial gl_offs items */
 973                         statv += pglob->gl_offs;
 974                         for (i = pglob->gl_offs; --i >= 0; )
 975                                 *--statv = NULL;
 976                 }
 977                 pglob->gl_statv = statv;
 978                 if (sb == NULL)
 979                         statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
 980                 else {
 981                         limitp->glim_malloc += sizeof (**statv);
 982                         if ((pglob->gl_flags & GLOB_LIMIT) &&
 983                             limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
 984                                 errno = 0;
 985                                 return (GLOB_NOSPACE);
 986                         }
 987                         if ((statv[pglob->gl_offs + pglob->gl_pathc] =
 988                             malloc(sizeof (**statv))) == NULL)
 989                                 goto copy_error;
 990                         memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
 991                             sizeof (*sb));
 992                 }
 993                 statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
 994         }
 995 
 996         len = MB_LEN_MAX;
 997         p = path;
 998         while ((n = wctomb(junk, p->wc)) > 0) {
 999                 len += n;
1000                 if ((p++)->wc == EOS)
1001                         break;
1002         }
1003 
1004         limitp->glim_malloc += len;
1005         if ((copy = malloc(len)) != NULL) {
1006                 if (g_Ctoc(path, copy, len)) {
1007                         free(copy);
1008                         return (GLOB_NOSPACE);
1009                 }
1010                 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1011         }
1012         pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1013 
1014         if ((pglob->gl_flags & GLOB_LIMIT) &&
1015             (newn * sizeof (*pathv)) + limitp->glim_malloc >
1016             GLOB_LIMIT_MALLOC) {
1017                 errno = 0;
1018                 return (GLOB_NOSPACE);
1019         }
1020         copy_error:
1021         return (copy == NULL ? GLOB_NOSPACE : 0);
1022 }
1023 
1024 
1025 /*
1026  * pattern matching function for filenames.  Each occurrence of the *
1027  * pattern causes a recursion level.
1028  */
1029 static int
1030 match(Char *name, Char *pat, Char *patend, int recur)
1031 {
1032         int ok, negate_range;
1033         Char c, k;
1034 
1035         if (recur-- == 0)
1036                 return (1);
1037 
1038         while (pat < patend) {
1039                 c = *pat++;
1040                 switch (c.wc) {
1041                 case M_ALL:
1042                         if (c.at != M_QUOTE) {
1043                                 k = *name++;
1044                                 if (k.at != c.at || k.wc != c.wc)
1045                                         return (0);
1046                                 break;
1047                         }
1048                         while (pat < patend && pat->at == M_QUOTE &&
1049                             pat->wc == M_ALL)
1050                                 pat++;  /* eat consecutive '*' */
1051                         if (pat == patend)
1052                                 return (1);
1053                         do {
1054                                 if (match(name, pat, patend, recur))
1055                                         return (1);
1056                         } while ((name++)->wc != EOS);
1057                         return (0);
1058                 case M_ONE:
1059                         if (c.at != M_QUOTE) {
1060                                 k = *name++;
1061                                 if (k.at != c.at || k.wc != c.wc)
1062                                         return (0);
1063                                 break;
1064                         }
1065                         if ((name++)->wc == EOS)
1066                                 return (0);
1067                         break;
1068                 case M_SET:
1069                         if (c.at != M_QUOTE) {
1070                                 k = *name++;
1071                                 if (k.at != c.at || k.wc != c.wc)
1072                                         return (0);
1073                                 break;
1074                         }
1075                         ok = 0;
1076                         if ((k = *name++).wc == EOS)
1077                                 return (0);
1078                         if ((negate_range = (pat->at == M_QUOTE &&
1079                             pat->wc == M_NOT)) != 0)
1080                                 ++pat;
1081                         while (((c = *pat++).at != M_QUOTE) || c.wc != M_END) {
1082                                 if (c.at == M_QUOTE && c.wc == M_CLASS) {
1083                                         Char idx;
1084 
1085                                         idx.at = pat->at;
1086                                         idx.wc = pat->wc;
1087                                         if (idx.at < NCCLASSES &&
1088                                             cclasses[idx.at].isctype(k.wc))
1089                                                 ok = 1;
1090                                         ++pat;
1091                                 }
1092                                 if (pat->at == M_QUOTE && pat->wc == M_RNG) {
1093                                         if (c.wc <= k.wc && k.wc <= pat[1].wc)
1094                                                 ok = 1;
1095                                         pat += 2;
1096                                 } else if (c.wc == k.wc)
1097                                         ok = 1;
1098                         }
1099                         if (ok == negate_range)
1100                                 return (0);
1101                         break;
1102                 default:
1103                         k = *name++;
1104                         if (k.at != c.at || k.wc != c.wc)
1105                                 return (0);
1106                         break;
1107                 }
1108         }
1109         return (name->wc == EOS);
1110 }
1111 
1112 /* Free allocated data belonging to a glob_t structure. */
1113 void
1114 globfree(glob_t *pglob)
1115 {
1116         int i;
1117         char **pp;
1118 
1119         if (pglob->gl_pathv != NULL) {
1120                 pp = pglob->gl_pathv + pglob->gl_offs;
1121                 for (i = pglob->gl_pathc; i--; ++pp)
1122                         if (*pp)
1123                                 free(*pp);
1124                 free(pglob->gl_pathv);
1125                 pglob->gl_pathv = NULL;
1126         }
1127         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1128             pglob->gl_statv != NULL) {
1129                 for (i = 0; i < pglob->gl_pathc; i++) {
1130                         if (pglob->gl_statv[i] != NULL)
1131                                 free(pglob->gl_statv[i]);
1132                 }
1133                 free(pglob->gl_statv);
1134                 pglob->gl_statv = NULL;
1135         }
1136 }
1137 
1138 static DIR *
1139 g_opendir(Char *str, glob_t *pglob)
1140 {
1141         char buf[MAXPATHLEN];
1142 
1143         if (str->wc == EOS)
1144                 strlcpy(buf, ".", sizeof (buf));
1145         else {
1146                 if (g_Ctoc(str, buf, sizeof (buf)))
1147                         return (NULL);
1148         }
1149 
1150         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1151                 return ((*pglob->gl_opendir)(buf));
1152 
1153         return (opendir(buf));
1154 }
1155 
1156 static int
1157 g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
1158 {
1159         char buf[MAXPATHLEN];
1160 
1161         if (g_Ctoc(fn, buf, sizeof (buf)))
1162                 return (-1);
1163         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1164                 return ((*pglob->gl_lstat)(buf, sb));
1165         return (lstat(buf, sb));
1166 }
1167 
1168 static int
1169 g_stat(Char *fn, struct stat *sb, glob_t *pglob)
1170 {
1171         char buf[MAXPATHLEN];
1172 
1173         if (g_Ctoc(fn, buf, sizeof (buf)))
1174                 return (-1);
1175         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1176                 return ((*pglob->gl_stat)(buf, sb));
1177         return (stat(buf, sb));
1178 }
1179 
1180 static Char *
1181 g_strchr(const Char *str, wchar_t ch)
1182 {
1183         do {
1184                 if (str->at == 0 && str->wc == ch)
1185                         return ((Char *)str);
1186         } while ((str++)->wc != EOS);
1187         return (NULL);
1188 }
1189 
1190 static int
1191 g_Ctoc(const Char *str, char *buf, uint_t len)
1192 {
1193         int n;
1194         wchar_t w;
1195 
1196         while (len >= MB_LEN_MAX) {
1197                 w = (str++)->wc;
1198                 if ((n = wctomb(buf, w)) > 0) {
1199                         len -= n;
1200                         buf += n;
1201                 }
1202                 if (n < 0)
1203                         break;
1204                 if (w == EOS)
1205                         return (0);
1206         }
1207         return (1);
1208 }
1209 
1210 #ifdef DEBUG
1211 static void
1212 qprintf(const char *str, Char *s)
1213 {
1214         Char *p;
1215 
1216         (void) printf("%s:\n", str);
1217         for (p = s; p->wc != EOS; p++)
1218                 (void) printf("%wc", p->wc);
1219         (void) printf("\n");
1220         for (p = s; p->wc != EOS; p++)
1221                 (void) printf("%c", p->at & M_PROTECT ? '"' : ' ');
1222         (void) printf("\n");
1223         for (p = s; p->wc != EOS; p++)
1224                 (void) printf("%c", ismeta(*p) ? '_' : ' ');
1225         (void) printf("\n");
1226 }
1227 #endif