1 /*
   2  * Copyright (c) 1989, 1993
   3  *      The Regents of the University of California.  All rights reserved.
   4  *
   5  * This code is derived from software contributed to Berkeley by
   6  * Guido van Rossum.
   7  *
   8  * Redistribution and use in source and binary forms, with or without
   9  * modification, are permitted provided that the following conditions
  10  * are met:
  11  * 1. Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  * 3. Neither the name of the University nor the names of its contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 /*
  34  * Copyright (c) 2013 Gary Mills
  35  */
  36 
  37 /*
  38  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  39  *
  40  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  41  *
  42  * Optional extra services, controlled by flags not defined by POSIX:
  43  *
  44  * GLOB_QUOTE:
  45  *      Escaping convention: \ inhibits any special meaning the following
  46  *      character might have (except \ at end of string is retained).
  47  * GLOB_MAGCHAR:
  48  *      Set in gl_flags if pattern contained a globbing character.
  49  * GLOB_NOMAGIC:
  50  *      Same as GLOB_NOCHECK, but it will only append pattern if it did
  51  *      not contain any magic characters.  [Used in csh style globbing]
  52  * GLOB_ALTDIRFUNC:
  53  *      Use alternately specified directory access functions.
  54  * GLOB_TILDE:
  55  *      expand ~user/foo to the /home/dir/of/user/foo
  56  * GLOB_BRACE:
  57  *      expand {1,2}{a,b} to 1a 1b 2a 2b
  58  * gl_matchc:
  59  *      Number of matches in the current invocation of glob.
  60  */
  61 
  62 #include "lint.h"
  63 
  64 #include <sys/param.h>
  65 #include <sys/stat.h>
  66 
  67 #include <ctype.h>
  68 #include <dirent.h>
  69 #include <errno.h>
  70 #include <glob.h>
  71 #include <limits.h>
  72 #include <pwd.h>
  73 #include <stdint.h>
  74 #include <stdio.h>
  75 #include <stdlib.h>
  76 #include <string.h>
  77 #include <unistd.h>
  78 #include <wchar.h>
  79 #include <wctype.h>
  80 
  81 /*
  82  * This is the legacy glob_t prior to illumos enhancement 1097,
  83  * used when old programs call the old libc glob functions.
  84  * (New programs call the _glob_ext, _globfree_ext functions.)
  85  * This struct should be considered "carved in stone".
  86  */
  87 typedef struct  old_glob        {
  88         size_t  gl_pathc;               /* Count of paths matched by pattern */
  89         char    **gl_pathv;             /* List of matched pathnames */
  90         size_t  gl_offs;                /* # of slots reserved in gl_pathv */
  91         /* following are internal to the implementation */
  92         char    **gl_pathp;             /* gl_pathv + gl_offs */
  93         int     gl_pathn;               /* # of elements allocated */
  94 }       old_glob_t;
  95 
  96 /*
  97  * For old programs, the external names need to be the old names:
  98  * glob() and globfree() .  We've redefined those already to
  99  *  _glob_ext() and _globfree_ext() .  Now redefine old_glob()
 100  * and old_globfree() to glob() and globfree() .
 101  */
 102 #ifdef __PRAGMA_REDEFINE_EXTNAME
 103 #pragma redefine_extname        old_glob        glob
 104 #pragma redefine_extname        old_globfree    globfree
 105 #endif /* __PRAGMA_REDEFINE_EXTNAME */
 106 extern int old_glob(const char *, int, int (*)(const char *, int),
 107     old_glob_t *);
 108 extern void old_globfree(old_glob_t *);
 109 
 110 /*
 111  * The various extensions to glob(3C) allow for stat and dirent structures to
 112  * show up whose size may change in a largefile environment. If libc defines
 113  * _FILE_OFFSET_BITS to be 64 that is the key to indicate that we're building
 114  * the LFS version of this file. As such, we rename the public functions here,
 115  * _glob_ext() and _globfree_ext() to have a 64 suffix. When building the LFS
 116  * version, we do not include the old versions.
 117  */
 118 #if !defined(_LP64) && _FILE_OFFSET_BITS == 64
 119 #define _glob_ext       _glob_ext64
 120 #define _globfree_ext   _globfree_ext64
 121 #endif  /* !_LP64 && _FILE_OFFSET_BITS == 64 */
 122 
 123 #define DOLLAR          '$'
 124 #define DOT             '.'
 125 #define EOS             '\0'
 126 #define LBRACKET        '['
 127 #define NOT             '!'
 128 #define QUESTION        '?'
 129 #define QUOTE           '\\'
 130 #define RANGE           '-'
 131 #define RBRACKET        ']'
 132 #define SEP             '/'
 133 #define STAR            '*'
 134 #define TILDE           '~'
 135 #define UNDERSCORE      '_'
 136 #define LBRACE          '{'
 137 #define RBRACE          '}'
 138 #define SLASH           '/'
 139 #define COMMA           ','
 140 #define COLON           ':'
 141 
 142 #define M_QUOTE         0x800000
 143 #define M_PROTECT       0x400000
 144 
 145 typedef struct wcat {
 146         wchar_t w_wc;
 147         uint_t w_at;
 148 } wcat_t;
 149 
 150 #define M_ALL           '*'     /* Plus M_QUOTE */
 151 #define M_END           ']'     /* Plus M_QUOTE */
 152 #define M_NOT           '!'     /* Plus M_QUOTE */
 153 #define M_ONE           '?'     /* Plus M_QUOTE */
 154 #define M_RNG           '-'     /* Plus M_QUOTE */
 155 #define M_SET           '['     /* Plus M_QUOTE */
 156 #define M_CLASS         ':'     /* Plus M_QUOTE */
 157 #define ismeta(c)       (((c).w_at&M_QUOTE) != 0)
 158 
 159 #define INITIAL                 8       /* initial pathv allocation */
 160 
 161 #define GLOB_LIMIT_MALLOC       65536
 162 #define GLOB_LIMIT_STAT         2048
 163 #define GLOB_LIMIT_READDIR      16384
 164 
 165 struct glob_lim {
 166         size_t  glim_malloc;
 167         size_t  glim_stat;
 168         size_t  glim_readdir;
 169 };
 170 
 171 struct glob_path_stat {
 172         char            *gps_path;
 173         struct stat     *gps_stat;
 174 };
 175 
 176 static int       compare(const void *, const void *);
 177 static int       compare_gps(const void *, const void *);
 178 static int       g_Ctoc(const wcat_t *, char *, uint_t);
 179 static int       g_lstat(wcat_t *, struct stat *, glob_t *);
 180 static DIR      *g_opendir(wcat_t *, glob_t *);
 181 static wcat_t   *g_strchr(const wcat_t *, wchar_t);
 182 static int       g_stat(wcat_t *, struct stat *, glob_t *);
 183 static int       glob0(const wcat_t *, glob_t *, struct glob_lim *,
 184                         int (*)(const char *, int));
 185 static int       glob1(wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
 186                         int (*)(const char *, int));
 187 static int       glob2(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
 188                         wcat_t *, glob_t *, struct glob_lim *,
 189                         int (*)(const char *, int));
 190 static int       glob3(wcat_t *, wcat_t *, wcat_t *, wcat_t *, wcat_t *,
 191                         wcat_t *, wcat_t *, glob_t *, struct glob_lim *,
 192                         int (*)(const char *, int));
 193 static int       globextend(const wcat_t *, glob_t *, struct glob_lim *,
 194                     struct stat *);
 195 static
 196 const wcat_t    *globtilde(const wcat_t *, wcat_t *, size_t, glob_t *);
 197 static int       globexp1(const wcat_t *, glob_t *, struct glob_lim *,
 198                     int (*)(const char *, int));
 199 static int       globexp2(const wcat_t *, const wcat_t *, glob_t *,
 200                     struct glob_lim *, int (*)(const char *, int));
 201 static int       match(wcat_t *, wcat_t *, wcat_t *);
 202 
 203 /*
 204  * Extended glob() function, selected by #pragma redefine_extname
 205  * in glob.h with the external name _glob_ext() .
 206  */
 207 int
 208 _glob_ext(const char *pattern, int flags, int (*errfunc)(const char *, int),
 209     glob_t *pglob)
 210 {
 211         const char *patnext;
 212         int n;
 213         size_t patlen;
 214         wchar_t c;
 215         wcat_t *bufnext, *bufend, patbuf[PATH_MAX];
 216         struct glob_lim limit = { 0, 0, 0 };
 217 
 218         patnext = pattern;
 219         if (!(flags & GLOB_APPEND)) {
 220                 pglob->gl_pathc = 0;
 221                 pglob->gl_pathn = 0;
 222                 pglob->gl_pathv = NULL;
 223                 if ((flags & GLOB_KEEPSTAT) != 0)
 224                         pglob->gl_statv = NULL;
 225                 if (!(flags & GLOB_DOOFFS))
 226                         pglob->gl_offs = 0;
 227         }
 228         pglob->gl_flags = flags & ~GLOB_MAGCHAR;
 229         pglob->gl_matchc = 0;
 230 
 231         if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX)
 232                 return (GLOB_NOMATCH);
 233 
 234         if (pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
 235             pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
 236                 return (GLOB_NOSPACE);
 237 
 238         bufnext = patbuf;
 239         bufend = bufnext + PATH_MAX - 1;
 240         patlen += 1;
 241         if (flags & GLOB_NOESCAPE) {
 242                 while (bufnext < bufend) {
 243                         if ((n = mbtowc(&c, patnext, patlen)) > 0) {
 244                                 patnext += n;
 245                                 patlen -= n;
 246                                 bufnext->w_at = 0;
 247                                 (bufnext++)->w_wc = c;
 248                         } else if (n == 0) {
 249                                 break;
 250                         } else {
 251                                 return (GLOB_NOMATCH);
 252                         }
 253                 }
 254         } else {
 255                 /* Protect the quoted characters. */
 256                 while (bufnext < bufend) {
 257                         if ((n = mbtowc(&c, patnext, patlen)) > 0) {
 258                                 patnext += n;
 259                                 patlen -= n;
 260                                 if (c == QUOTE) {
 261                                         n = mbtowc(&c, patnext, patlen);
 262                                         if (n < 0)
 263                                                 return (GLOB_NOMATCH);
 264                                         if (n > 0) {
 265                                                 patnext += n;
 266                                                 patlen -= n;
 267                                         }
 268                                         if (n == 0)
 269                                                 c = QUOTE;
 270                                         bufnext->w_at = M_PROTECT;
 271                                         (bufnext++)->w_wc = c;
 272                                 } else {
 273                                         bufnext->w_at = 0;
 274                                         (bufnext++)->w_wc = c;
 275                                 }
 276                         } else if (n == 0) {
 277                                 break;
 278                         } else {
 279                                 return (GLOB_NOMATCH);
 280                         }
 281                 }
 282         }
 283         bufnext->w_at = 0;
 284         bufnext->w_wc = EOS;
 285 
 286         if (flags & GLOB_BRACE)
 287                 return (globexp1(patbuf, pglob, &limit, errfunc));
 288         else
 289                 return (glob0(patbuf, pglob, &limit, errfunc));
 290 }
 291 
 292 /*
 293  * Expand recursively a glob {} pattern. When there is no more expansion
 294  * invoke the standard globbing routine to glob the rest of the magic
 295  * characters
 296  */
 297 static int
 298 globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
 299     int (*errfunc)(const char *, int))
 300 {
 301         const wcat_t *ptr = pattern;
 302 
 303         /* Protect a single {}, for find(1), like csh */
 304         if (pattern[0].w_wc == LBRACE && pattern[1].w_wc == RBRACE &&
 305             pattern[2].w_wc == EOS)
 306                 return (glob0(pattern, pglob, limitp, errfunc));
 307 
 308         if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL)
 309                 return (globexp2(ptr, pattern, pglob, limitp, errfunc));
 310 
 311         return (glob0(pattern, pglob, limitp, errfunc));
 312 }
 313 
 314 
 315 /*
 316  * Recursive brace globbing helper. Tries to expand a single brace.
 317  * If it succeeds then it invokes globexp1 with the new pattern.
 318  * If it fails then it tries to glob the rest of the pattern and returns.
 319  */
 320 static int
 321 globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob,
 322     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 323 {
 324         int     i, rv;
 325         wcat_t   *lm, *ls;
 326         const wcat_t *pe, *pm, *pl;
 327         wcat_t    patbuf[PATH_MAX];
 328 
 329         /* copy part up to the brace */
 330         for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
 331                 ;
 332         lm->w_at = 0;
 333         lm->w_wc = EOS;
 334         ls = lm;
 335 
 336         /* Find the balanced brace */
 337         for (i = 0, pe = ++ptr; pe->w_wc != EOS; pe++)
 338                 if (pe->w_wc == LBRACKET) {
 339                         /* Ignore everything between [] */
 340                         for (pm = pe++; pe->w_wc != RBRACKET &&
 341                             pe->w_wc != EOS; pe++)
 342                                 ;
 343                         if (pe->w_wc == EOS) {
 344                                 /*
 345                                  * We could not find a matching RBRACKET.
 346                                  * Ignore and just look for RBRACE
 347                                  */
 348                                 pe = pm;
 349                         }
 350                 } else if (pe->w_wc == LBRACE) {
 351                         i++;
 352                 } else if (pe->w_wc == RBRACE) {
 353                         if (i == 0)
 354                                 break;
 355                         i--;
 356                 }
 357 
 358         /* Non matching braces; just glob the pattern */
 359         if (i != 0 || pe->w_wc == EOS)
 360                 return (glob0(patbuf, pglob, limitp, errfunc));
 361 
 362         for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
 363                 switch (pm->w_wc) {
 364                 case LBRACKET:
 365                         /* Ignore everything between [] */
 366                         for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS;
 367                             pm++)
 368                                 ;
 369                         if (pm->w_wc == EOS) {
 370                                 /*
 371                                  * We could not find a matching RBRACKET.
 372                                  * Ignore and just look for RBRACE
 373                                  */
 374                                 pm = pl;
 375                         }
 376                         break;
 377 
 378                 case LBRACE:
 379                         i++;
 380                         break;
 381 
 382                 case RBRACE:
 383                         if (i) {
 384                                 i--;
 385                                 break;
 386                         }
 387                         /* FALLTHROUGH */
 388                 case COMMA:
 389                         if (i && pm->w_wc == COMMA)
 390                                 break;
 391                         else {
 392                                 /* Append the current string */
 393                                 for (lm = ls; (pl < pm); *lm++ = *pl++)
 394                                         ;
 395 
 396                                 /*
 397                                  * Append the rest of the pattern after the
 398                                  * closing brace
 399                                  */
 400                                 for (pl = pe + 1;
 401                                     (*lm++ = *pl++).w_wc != EOS; /* */)
 402                                         ;
 403 
 404                                 /* Expand the current pattern */
 405                                 rv = globexp1(patbuf, pglob, limitp, errfunc);
 406                                 if (rv && rv != GLOB_NOMATCH)
 407                                         return (rv);
 408 
 409                                 /* move after the comma, to the next string */
 410                                 pl = pm + 1;
 411                         }
 412                         break;
 413 
 414                 default:
 415                         break;
 416                 }
 417         }
 418         return (0);
 419 }
 420 
 421 
 422 
 423 /*
 424  * expand tilde from the passwd file.
 425  */
 426 static const wcat_t *
 427 globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len,
 428     glob_t *pglob)
 429 {
 430         struct passwd *pwd;
 431         char *h;
 432         const wcat_t *p;
 433         wcat_t *b, *eb, *q;
 434         int n;
 435         size_t lenh;
 436         wchar_t c;
 437 
 438         if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
 439                 return (pattern);
 440 
 441         /* Copy up to the end of the string or / */
 442         eb = &patbuf[patbuf_len - 1];
 443         for (p = pattern + 1, q = patbuf;
 444             q < eb && p->w_wc != EOS && p->w_wc != SLASH; *q++ = *p++)
 445                 ;
 446 
 447         q->w_at = 0;
 448         q->w_wc = EOS;
 449 
 450         /* What to do if patbuf is full? */
 451 
 452         if (patbuf[0].w_wc == EOS) {
 453                 /*
 454                  * handle a plain ~ or ~/ by expanding $HOME
 455                  * first and then trying the password file
 456                  */
 457                 if (issetugid() != 0)
 458                         return (pattern);
 459                 if ((h = getenv("HOME")) == NULL) {
 460                         if ((pwd = getpwuid(getuid())) == NULL)
 461                                 return (pattern);
 462                         else
 463                                 h = pwd->pw_dir;
 464                 }
 465         } else {
 466                 /*
 467                  * Expand a ~user
 468                  */
 469                 if ((pwd = getpwnam((char *)patbuf)) == NULL)
 470                         return (pattern);
 471                 else
 472                         h = pwd->pw_dir;
 473         }
 474 
 475         /* Copy the home directory */
 476         lenh = strlen(h) + 1;
 477         for (b = patbuf; b < eb && *h != EOS; b++) {
 478                 if ((n = mbtowc(&c, h, lenh)) > 0) {
 479                         h += n;
 480                         lenh -= n;
 481                         b->w_at = 0;
 482                         b->w_wc = c;
 483                 } else if (n < 0) {
 484                         return (pattern);
 485                 } else {
 486                         break;
 487                 }
 488         }
 489 
 490         /* Append the rest of the pattern */
 491         while (b < eb && (*b++ = *p++).w_wc != EOS)
 492                 ;
 493         b->w_at = 0;
 494         b->w_wc = EOS;
 495 
 496         return (patbuf);
 497 }
 498 
 499 static int
 500 g_charclass(const wcat_t **patternp, wcat_t **bufnextp)
 501 {
 502         const wcat_t *pattern = *patternp + 1;
 503         wcat_t *bufnext = *bufnextp;
 504         const wcat_t *colon;
 505         char cbuf[MB_LEN_MAX + 32];
 506         wctype_t cc;
 507         size_t len;
 508 
 509         if ((colon = g_strchr(pattern, COLON)) == NULL ||
 510             colon[1].w_wc != RBRACKET)
 511                 return (1);     /* not a character class */
 512 
 513         len = (size_t)(colon - pattern);
 514         if (len + MB_LEN_MAX + 1 > sizeof (cbuf))
 515                 return (-1);    /* invalid character class */
 516         {
 517                 wchar_t w;
 518                 const wcat_t *s1 = pattern;
 519                 char *s2 = cbuf;
 520                 size_t n = len;
 521 
 522                 /* Copy the string. */
 523                 while (n > 0) {
 524                         w = (s1++)->w_wc;
 525                         /* Character class names must be ASCII. */
 526                         if (iswascii(w)) {
 527                                 n--;
 528                                 *s2++ = w;
 529                         } else {
 530                                 return (-1);    /* invalid character class */
 531                         }
 532                 }
 533                 *s2 = EOS;
 534         }
 535         if ((cc = wctype(cbuf)) == 0)
 536                 return (-1);    /* invalid character class */
 537         bufnext->w_at = M_QUOTE;
 538         (bufnext++)->w_wc = M_CLASS;
 539         bufnext->w_at = 0;
 540         (bufnext++)->w_wc = cc;
 541         *bufnextp = bufnext;
 542         *patternp += len + 3;
 543 
 544         return (0);
 545 }
 546 
 547 /*
 548  * The main glob() routine: compiles the pattern (optionally processing
 549  * quotes), calls glob1() to do the real pattern matching, and finally
 550  * sorts the list (unless unsorted operation is requested).  Returns 0
 551  * if things went well, nonzero if errors occurred.  It is not an error
 552  * to find no matches.
 553  */
 554 static int
 555 glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
 556     int (*errfunc)(const char *, int))
 557 {
 558         const wcat_t *qpatnext;
 559         int err, oldpathc;
 560         wchar_t c;
 561         int a;
 562         wcat_t *bufnext, patbuf[PATH_MAX];
 563 
 564         qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
 565         oldpathc = pglob->gl_pathc;
 566         bufnext = patbuf;
 567 
 568         /*
 569          * We don't need to check for buffer overflow any more.
 570          * The pattern has already been copied to an internal buffer.
 571          */
 572         while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) {
 573                 switch (c) {
 574                 case LBRACKET:
 575                         if (a != 0) {
 576                                 bufnext->w_at = a;
 577                                 (bufnext++)->w_wc = c;
 578                                 break;
 579                         }
 580                         a = qpatnext->w_at;
 581                         c = qpatnext->w_wc;
 582                         if (a == 0 && c == NOT)
 583                                 ++qpatnext;
 584                         if (qpatnext->w_wc == EOS ||
 585                             g_strchr(qpatnext+1, RBRACKET) == NULL) {
 586                                 bufnext->w_at = 0;
 587                                 (bufnext++)->w_wc = LBRACKET;
 588                                 if (a == 0 && c == NOT)
 589                                         --qpatnext;
 590                                 break;
 591                         }
 592                         bufnext->w_at = M_QUOTE;
 593                         (bufnext++)->w_wc = M_SET;
 594                         if (a == 0 && c == NOT) {
 595                                 bufnext->w_at = M_QUOTE;
 596                                 (bufnext++)->w_wc = M_NOT;
 597                         }
 598                         a = qpatnext->w_at;
 599                         c = (qpatnext++)->w_wc;
 600                         do {
 601                                 if (a == 0 && c == LBRACKET &&
 602                                     qpatnext->w_wc == COLON) {
 603                                         do {
 604                                                 err = g_charclass(&qpatnext,
 605                                                     &bufnext);
 606                                                 if (err)
 607                                                         break;
 608                                                 a = qpatnext->w_at;
 609                                                 c = (qpatnext++)->w_wc;
 610                                         } while (a == 0 && c == LBRACKET &&
 611                                             qpatnext->w_wc == COLON);
 612                                         if (err == -1 &&
 613                                             !(pglob->gl_flags & GLOB_NOCHECK))
 614                                                 return (GLOB_NOMATCH);
 615                                         if (a == 0 && c == RBRACKET)
 616                                                 break;
 617                                 }
 618                                 bufnext->w_at = a;
 619                                 (bufnext++)->w_wc = c;
 620                                 if (qpatnext->w_at == 0 &&
 621                                     qpatnext->w_wc == RANGE) {
 622                                         a = qpatnext[1].w_at;
 623                                         c = qpatnext[1].w_wc;
 624                                         if (qpatnext[1].w_at != 0 ||
 625                                             qpatnext[1].w_wc != RBRACKET) {
 626                                                 bufnext->w_at = M_QUOTE;
 627                                                 (bufnext++)->w_wc = M_RNG;
 628                                                 bufnext->w_at = a;
 629                                                 (bufnext++)->w_wc = c;
 630                                                 qpatnext += 2;
 631                                         }
 632                                 }
 633                                 a = qpatnext->w_at;
 634                                 c = (qpatnext++)->w_wc;
 635                         } while (a != 0 || c != RBRACKET);
 636                         pglob->gl_flags |= GLOB_MAGCHAR;
 637                         bufnext->w_at = M_QUOTE;
 638                         (bufnext++)->w_wc = M_END;
 639                         break;
 640                 case QUESTION:
 641                         if (a != 0) {
 642                                 bufnext->w_at = a;
 643                                 (bufnext++)->w_wc = c;
 644                                 break;
 645                         }
 646                         pglob->gl_flags |= GLOB_MAGCHAR;
 647                         bufnext->w_at = M_QUOTE;
 648                         (bufnext++)->w_wc = M_ONE;
 649                         break;
 650                 case STAR:
 651                         if (a != 0) {
 652                                 bufnext->w_at = a;
 653                                 (bufnext++)->w_wc = c;
 654                                 break;
 655                         }
 656                         pglob->gl_flags |= GLOB_MAGCHAR;
 657                         /*
 658                          * collapse adjacent stars to one,
 659                          * to avoid exponential behavior
 660                          */
 661                         if (bufnext == patbuf ||
 662                             bufnext[-1].w_at != M_QUOTE ||
 663                             bufnext[-1].w_wc != M_ALL) {
 664                                 bufnext->w_at = M_QUOTE;
 665                                 (bufnext++)->w_wc = M_ALL;
 666                         }
 667                         break;
 668                 default:
 669                         bufnext->w_at = a;
 670                         (bufnext++)->w_wc = c;
 671                         break;
 672                 }
 673         }
 674         bufnext->w_at = 0;
 675         bufnext->w_wc = EOS;
 676 
 677         if ((err = glob1(patbuf, patbuf+PATH_MAX-1, pglob, limitp, errfunc))
 678             != 0)
 679                 return (err);
 680 
 681         /*
 682          * If there was no match we are going to append the pattern
 683          * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
 684          * and the pattern did not contain any magic characters
 685          * GLOB_NOMAGIC is there just for compatibility with csh.
 686          */
 687         if (pglob->gl_pathc == oldpathc) {
 688                 if ((pglob->gl_flags & GLOB_NOCHECK) ||
 689                     ((pglob->gl_flags & GLOB_NOMAGIC) &&
 690                     !(pglob->gl_flags & GLOB_MAGCHAR)))
 691                         return (globextend(pattern, pglob, limitp, NULL));
 692                 else
 693                         return (GLOB_NOMATCH);
 694         }
 695         if (!(pglob->gl_flags & GLOB_NOSORT)) {
 696                 if ((pglob->gl_flags & GLOB_KEEPSTAT)) {
 697                         /* Keep the paths and stat info synced during sort */
 698                         struct glob_path_stat *path_stat;
 699                         int i;
 700                         int n = pglob->gl_pathc - oldpathc;
 701                         int o = pglob->gl_offs + oldpathc;
 702 
 703                         if ((path_stat = calloc(n, sizeof (*path_stat))) ==
 704                             NULL)
 705                                 return (GLOB_NOSPACE);
 706                         for (i = 0; i < n; i++) {
 707                                 path_stat[i].gps_path = pglob->gl_pathv[o + i];
 708                                 path_stat[i].gps_stat = pglob->gl_statv[o + i];
 709                         }
 710                         qsort(path_stat, n, sizeof (*path_stat), compare_gps);
 711                         for (i = 0; i < n; i++) {
 712                                 pglob->gl_pathv[o + i] = path_stat[i].gps_path;
 713                                 pglob->gl_statv[o + i] = path_stat[i].gps_stat;
 714                         }
 715                         free(path_stat);
 716                 } else {
 717                         qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
 718                             pglob->gl_pathc - oldpathc, sizeof (char *),
 719                             compare);
 720                 }
 721         }
 722         return (0);
 723 }
 724 
 725 static int
 726 compare(const void *p, const void *q)
 727 {
 728         return (strcmp(*(char **)p, *(char **)q));
 729 }
 730 
 731 static int
 732 compare_gps(const void *_p, const void *_q)
 733 {
 734         const struct glob_path_stat *p = (const struct glob_path_stat *)_p;
 735         const struct glob_path_stat *q = (const struct glob_path_stat *)_q;
 736 
 737         return (strcmp(p->gps_path, q->gps_path));
 738 }
 739 
 740 static int
 741 glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob,
 742     struct glob_lim *limitp, int (*errfunc)(const char *, int))
 743 {
 744         wcat_t pathbuf[PATH_MAX];
 745 
 746         /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
 747         if (pattern->w_wc == EOS)
 748                 return (0);
 749         return (glob2(pathbuf, pathbuf+PATH_MAX-1,
 750             pathbuf, pathbuf+PATH_MAX-1,
 751             pattern, pattern_last, pglob, limitp, errfunc));
 752 }
 753 
 754 /*
 755  * The functions glob2 and glob3 are mutually recursive; there is one level
 756  * of recursion for each segment in the pattern that contains one or more
 757  * meta characters.
 758  */
 759 static int
 760 glob2(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
 761     wcat_t *pathend_last, wcat_t *pattern, wcat_t *pattern_last,
 762     glob_t *pglob, struct glob_lim *limitp, int (*errfunc)(const char *, int))
 763 {
 764         struct stat sb;
 765         wcat_t *p, *q;
 766         int anymeta;
 767 
 768         /*
 769          * Loop over pattern segments until end of pattern or until
 770          * segment with meta character found.
 771          */
 772         for (anymeta = 0; ; ) {
 773                 if (pattern->w_wc == EOS) {          /* End of pattern? */
 774                         pathend->w_at = 0;
 775                         pathend->w_wc = EOS;
 776 
 777                         if ((pglob->gl_flags & GLOB_LIMIT) &&
 778                             limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
 779                                 errno = 0;
 780                                 pathend->w_at = 0;
 781                                 (pathend++)->w_wc = SEP;
 782                                 pathend->w_at = 0;
 783                                 pathend->w_wc = EOS;
 784                                 return (GLOB_NOSPACE);
 785                         }
 786                         if (g_lstat(pathbuf, &sb, pglob))
 787                                 return (0);
 788 
 789                         if (((pglob->gl_flags & GLOB_MARK) &&
 790                             (pathend[-1].w_at != 0 ||
 791                             pathend[-1].w_wc != SEP)) &&
 792                             (S_ISDIR(sb.st_mode) ||
 793                             (S_ISLNK(sb.st_mode) &&
 794                             (g_stat(pathbuf, &sb, pglob) == 0) &&
 795                             S_ISDIR(sb.st_mode)))) {
 796                                 if (pathend+1 > pathend_last)
 797                                         return (GLOB_NOSPACE);
 798                                 pathend->w_at = 0;
 799                                 (pathend++)->w_wc = SEP;
 800                                 pathend->w_at = 0;
 801                                 pathend->w_wc = EOS;
 802                         }
 803                         ++pglob->gl_matchc;
 804                         return (globextend(pathbuf, pglob, limitp, &sb));
 805                 }
 806 
 807                 /* Find end of next segment, copy tentatively to pathend. */
 808                 q = pathend;
 809                 p = pattern;
 810                 while (p->w_wc != EOS && p->w_wc != SEP) {
 811                         if (ismeta(*p))
 812                                 anymeta = 1;
 813                         if (q+1 > pathend_last)
 814                                 return (GLOB_NOSPACE);
 815                         *q++ = *p++;
 816                 }
 817 
 818                 if (!anymeta) {         /* No expansion, do next segment. */
 819                         pathend = q;
 820                         pattern = p;
 821                         while (pattern->w_wc == SEP) {
 822                                 if (pathend+1 > pathend_last)
 823                                         return (GLOB_NOSPACE);
 824                                 *pathend++ = *pattern++;
 825                         }
 826                 } else  {
 827                         /* Need expansion, recurse. */
 828                         return (glob3(pathbuf, pathbuf_last, pathend,
 829                             pathend_last, pattern, p, pattern_last,
 830                             pglob, limitp, errfunc));
 831                 }
 832         }
 833         /* NOTREACHED */
 834 }
 835 
 836 static int
 837 glob3(wcat_t *pathbuf, wcat_t *pathbuf_last, wcat_t *pathend,
 838     wcat_t *pathend_last, wcat_t *pattern, wcat_t *restpattern,
 839     wcat_t *restpattern_last, glob_t *pglob, struct glob_lim *limitp,
 840     int (*errfunc)(const char *, int))
 841 {
 842         struct dirent *dp;
 843         DIR *dirp;
 844         int err;
 845         char buf[PATH_MAX];
 846 
 847         /*
 848          * The readdirfunc declaration can't be prototyped, because it is
 849          * assigned, below, to two functions which are prototyped in glob.h
 850          * and dirent.h as taking pointers to differently typed opaque
 851          * structures.
 852          */
 853         struct dirent *(*readdirfunc)(void *);
 854 
 855         if (pathend > pathend_last)
 856                 return (GLOB_NOSPACE);
 857         pathend->w_at = 0;
 858         pathend->w_wc = EOS;
 859         errno = 0;
 860 
 861         if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
 862                 /* TODO: don't call for ENOENT or ENOTDIR? */
 863                 if (errfunc) {
 864                         if (g_Ctoc(pathbuf, buf, sizeof (buf)))
 865                                 return (GLOB_ABORTED);
 866                         if (errfunc(buf, errno) ||
 867                             pglob->gl_flags & GLOB_ERR)
 868                                 return (GLOB_ABORTED);
 869                 }
 870                 return (0);
 871         }
 872 
 873         err = 0;
 874 
 875         /* Search directory for matching names. */
 876         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 877                 readdirfunc = pglob->gl_readdir;
 878         else
 879                 readdirfunc = (struct dirent *(*)(void *))readdir;
 880         while ((dp = (*readdirfunc)(dirp))) {
 881                 char *sc;
 882                 wcat_t *dc;
 883                 int n;
 884                 int lensc;
 885                 wchar_t w;
 886 
 887                 if ((pglob->gl_flags & GLOB_LIMIT) &&
 888                     limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
 889                         errno = 0;
 890                         pathend->w_at = 0;
 891                         (pathend++)->w_wc = SEP;
 892                         pathend->w_at = 0;
 893                         pathend->w_wc = EOS;
 894                         err = GLOB_NOSPACE;
 895                         break;
 896                 }
 897 
 898                 /* Initial DOT must be matched literally. */
 899                 if (dp->d_name[0] == DOT && pattern->w_wc != DOT)
 900                         continue;
 901                 dc = pathend;
 902                 sc = dp->d_name;
 903                 lensc = strlen(sc) + 1;
 904                 while (dc < pathend_last) {
 905                         if ((n = mbtowc(&w, sc, lensc)) <= 0) {
 906                                 sc += 1;
 907                                 lensc -= 1;
 908                                 dc->w_at = 0;
 909                                 dc->w_wc = EOS;
 910                         } else {
 911                                 sc += n;
 912                                 lensc -= n;
 913                                 dc->w_at = 0;
 914                                 dc->w_wc = w;
 915                         }
 916                         dc++;
 917                         if (n <= 0)
 918                                 break;
 919                 }
 920                 if (dc >= pathend_last) {
 921                         dc->w_at = 0;
 922                         dc->w_wc = EOS;
 923                         err = GLOB_NOSPACE;
 924                         break;
 925                 }
 926                 if (n < 0) {
 927                         err = GLOB_NOMATCH;
 928                         break;
 929                 }
 930 
 931                 if (!match(pathend, pattern, restpattern)) {
 932                         pathend->w_at = 0;
 933                         pathend->w_wc = EOS;
 934                         continue;
 935                 }
 936                 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
 937                     restpattern, restpattern_last, pglob, limitp,
 938                     errfunc);
 939                 if (err)
 940                         break;
 941         }
 942 
 943         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 944                 (*pglob->gl_closedir)(dirp);
 945         else
 946                 (void) closedir(dirp);
 947         return (err);
 948 }
 949 
 950 
 951 /*
 952  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
 953  * add the new item, and update gl_pathc.  Avoids excessive reallocation
 954  * by doubling the number of elements each time.  Uses gl_pathn to contain
 955  * the number.
 956  *
 957  * Return 0 if new item added, error code if memory couldn't be allocated.
 958  *
 959  * Invariant of the glob_t structure:
 960  *      Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
 961  *      gl_pathv points to (gl_offs + gl_pathc + 1) items.
 962  */
 963 static int
 964 globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp,
 965     struct stat *sb)
 966 {
 967         char **pathv;
 968         ssize_t i;
 969         size_t allocn, newn, len;
 970         char *copy = NULL;
 971         const wcat_t *p;
 972         struct stat **statv;
 973         char junk[MB_LEN_MAX];
 974         int n;
 975 
 976         allocn = pglob->gl_pathn;
 977         newn = 2 + pglob->gl_pathc + pglob->gl_offs;
 978 
 979         if (newn <= allocn) {
 980                 pathv = pglob->gl_pathv;
 981                 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0)
 982                         statv = pglob->gl_statv;
 983         } else {
 984                 if (allocn == 0)
 985                         allocn = pglob->gl_offs + INITIAL;
 986                 allocn *= 2;
 987                 if (pglob->gl_offs >= INT_MAX ||
 988                     pglob->gl_pathc >= INT_MAX ||
 989                     allocn >= INT_MAX ||
 990                     SIZE_MAX / sizeof (*pathv) <= allocn ||
 991                     SIZE_MAX / sizeof (*statv) <= allocn) {
 992                 nospace:
 993                         for (i = pglob->gl_offs; i < (ssize_t)(newn - 2);
 994                             i++) {
 995                                 if (pglob->gl_pathv && pglob->gl_pathv[i])
 996                                         free(pglob->gl_pathv[i]);
 997                                 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
 998                                     pglob->gl_statv && pglob->gl_statv[i])
 999                                         free(pglob->gl_statv[i]);
1000                         }
1001                         free(pglob->gl_pathv);
1002                         pglob->gl_pathv = NULL;
1003                         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
1004                                 free(pglob->gl_statv);
1005                                 pglob->gl_statv = NULL;
1006                         }
1007                         return (GLOB_NOSPACE);
1008                 }
1009                 limitp->glim_malloc += allocn * sizeof (*pathv);
1010                 pathv = reallocarray(pglob->gl_pathv, allocn, sizeof (*pathv));
1011                 if (pathv == NULL)
1012                         goto nospace;
1013                 if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
1014                         limitp->glim_malloc += allocn * sizeof (*statv);
1015                         statv = reallocarray(pglob->gl_statv, allocn,
1016                             sizeof (*statv));
1017                         if (statv == NULL)
1018                                 goto nospace;
1019                 }
1020         }
1021         pglob->gl_pathn = allocn;
1022 
1023         if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
1024                 /* first time around -- clear initial gl_offs items */
1025                 pathv += pglob->gl_offs;
1026                 for (i = pglob->gl_offs; --i >= 0; )
1027                         *--pathv = NULL;
1028         }
1029         pglob->gl_pathv = pathv;
1030 
1031         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
1032                 if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
1033                         /* first time around -- clear initial gl_offs items */
1034                         statv += pglob->gl_offs;
1035                         for (i = pglob->gl_offs; --i >= 0; )
1036                                 *--statv = NULL;
1037                 }
1038                 pglob->gl_statv = statv;
1039                 if (sb == NULL)
1040                         statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1041                 else {
1042                         limitp->glim_malloc += sizeof (**statv);
1043                         if ((statv[pglob->gl_offs + pglob->gl_pathc] =
1044                             malloc(sizeof (**statv))) == NULL)
1045                                 goto copy_error;
1046                         (void) memcpy(statv[pglob->gl_offs + pglob->gl_pathc],
1047                             sb, sizeof (*sb));
1048                 }
1049                 statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
1050         }
1051 
1052         len = MB_LEN_MAX;
1053         p = path;
1054         while ((n = wctomb(junk, p->w_wc)) > 0) {
1055                 len += n;
1056                 if ((p++)->w_wc == EOS)
1057                         break;
1058         }
1059         if (n < 0)
1060                 return (GLOB_NOMATCH);
1061 
1062         limitp->glim_malloc += len;
1063         if ((copy = malloc(len)) != NULL) {
1064                 if (g_Ctoc(path, copy, len)) {
1065                         free(copy);
1066                         return (GLOB_NOSPACE);
1067                 }
1068                 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1069         }
1070         pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1071 
1072         if ((pglob->gl_flags & GLOB_LIMIT) &&
1073             limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
1074                 errno = 0;
1075                 return (GLOB_NOSPACE);
1076         }
1077         copy_error:
1078         return (copy == NULL ? GLOB_NOSPACE : 0);
1079 }
1080 
1081 
1082 /*
1083  * pattern matching function for filenames.  Each occurrence of the *
1084  * pattern causes an iteration.
1085  *
1086  * Note, this function differs from the original as per the discussion
1087  * here: https://research.swtch.com/glob
1088  *
1089  * Basically we removed the recursion and made it use the algorithm
1090  * from Russ Cox to not go quadratic on cases like a file called
1091  * ("a" x 100) . "x" matched against a pattern like "a*a*a*a*a*a*a*y".
1092  */
1093 static int
1094 match(wcat_t *name, wcat_t *pat, wcat_t *patend)
1095 {
1096         int ok, negate_range;
1097         wcat_t c, k;
1098         wcat_t *nextp = NULL;
1099         wcat_t *nextn = NULL;
1100 
1101 loop:
1102         while (pat < patend) {
1103                 c = *pat++;
1104                 switch (c.w_wc) {
1105                 case M_ALL:
1106                         if (c.w_at != M_QUOTE) {
1107                                 k = *name++;
1108                                 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1109                                         return (0);
1110                                 break;
1111                         }
1112                         while (pat < patend && pat->w_at == M_QUOTE &&
1113                             pat->w_wc == M_ALL)
1114                                 pat++;  /* eat consecutive '*' */
1115                         if (pat == patend)
1116                                 return (1);
1117                         if (name->w_wc == EOS)
1118                                 return (0);
1119                         nextn = name + 1;
1120                         nextp = pat - 1;
1121                         break;
1122                 case M_ONE:
1123                         if (c.w_at != M_QUOTE) {
1124                                 k = *name++;
1125                                 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1126                                         goto fail;
1127                                 break;
1128                         }
1129                         if ((name++)->w_wc == EOS)
1130                                 goto fail;
1131                         break;
1132                 case M_SET:
1133                         if (c.w_at != M_QUOTE) {
1134                                 k = *name++;
1135                                 if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1136                                         goto fail;
1137                                 break;
1138                         }
1139                         ok = 0;
1140                         if ((k = *name++).w_wc == EOS)
1141                                 goto fail;
1142                         if ((negate_range = (pat->w_at == M_QUOTE &&
1143                             pat->w_wc == M_NOT)) != 0)
1144                                 ++pat;
1145                         while (((c = *pat++).w_at != M_QUOTE) ||
1146                             c.w_wc != M_END) {
1147                                 if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) {
1148                                         wcat_t cc;
1149 
1150                                         cc.w_at = pat->w_at;
1151                                         cc.w_wc = pat->w_wc;
1152                                         if (iswctype(k.w_wc, cc.w_wc))
1153                                                 ok = 1;
1154                                         ++pat;
1155                                 }
1156                                 if (pat->w_at == M_QUOTE &&
1157                                     pat->w_wc == M_RNG) {
1158                                         if (c.w_wc <= k.w_wc &&
1159                                             k.w_wc <= pat[1].w_wc)
1160                                                 ok = 1;
1161                                         pat += 2;
1162                                 } else if (c.w_wc == k.w_wc)
1163                                         ok = 1;
1164                         }
1165                         if (ok == negate_range)
1166                                 goto fail;
1167                         break;
1168                 default:
1169                         k = *name++;
1170                         if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1171                                 goto fail;
1172                         break;
1173                 }
1174         }
1175         if (name->w_wc == EOS)
1176                 return (1);
1177 
1178 fail:
1179         if (nextn) {
1180                 pat = nextp;
1181                 name = nextn;
1182                 goto loop;
1183         }
1184         return (0);
1185 }
1186 
1187 /*
1188  * Extended globfree() function, selected by #pragma redefine_extname
1189  * in glob.h with the external name _globfree_ext() .
1190  */
1191 void
1192 _globfree_ext(glob_t *pglob)
1193 {
1194         int i;
1195         char **pp;
1196 
1197         if (pglob->gl_pathv != NULL) {
1198                 pp = pglob->gl_pathv + pglob->gl_offs;
1199                 for (i = pglob->gl_pathc; i--; ++pp)
1200                         free(*pp);
1201                 free(pglob->gl_pathv);
1202                 pglob->gl_pathv = NULL;
1203         }
1204         if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1205             pglob->gl_statv != NULL) {
1206                 for (i = 0; i < pglob->gl_pathc; i++) {
1207                         free(pglob->gl_statv[i]);
1208                 }
1209                 free(pglob->gl_statv);
1210                 pglob->gl_statv = NULL;
1211         }
1212 }
1213 
1214 static DIR *
1215 g_opendir(wcat_t *str, glob_t *pglob)
1216 {
1217         char buf[PATH_MAX];
1218 
1219         if (str->w_wc == EOS)
1220                 (void) strlcpy(buf, ".", sizeof (buf));
1221         else {
1222                 if (g_Ctoc(str, buf, sizeof (buf)))
1223                         return (NULL);
1224         }
1225 
1226         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1227                 return ((*pglob->gl_opendir)(buf));
1228 
1229         return (opendir(buf));
1230 }
1231 
1232 static int
1233 g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1234 {
1235         char buf[PATH_MAX];
1236 
1237         if (g_Ctoc(fn, buf, sizeof (buf)))
1238                 return (-1);
1239         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1240                 return ((*pglob->gl_lstat)(buf, sb));
1241         return (lstat(buf, sb));
1242 }
1243 
1244 static int
1245 g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1246 {
1247         char buf[PATH_MAX];
1248 
1249         if (g_Ctoc(fn, buf, sizeof (buf)))
1250                 return (-1);
1251         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1252                 return ((*pglob->gl_stat)(buf, sb));
1253         return (stat(buf, sb));
1254 }
1255 
1256 static wcat_t *
1257 g_strchr(const wcat_t *str, wchar_t ch)
1258 {
1259         do {
1260                 if (str->w_at == 0 && str->w_wc == ch)
1261                         return ((wcat_t *)str);
1262         } while ((str++)->w_wc != EOS);
1263         return (NULL);
1264 }
1265 
1266 static int
1267 g_Ctoc(const wcat_t *str, char *buf, uint_t len)
1268 {
1269         int n;
1270         wchar_t w;
1271 
1272         while (len >= MB_LEN_MAX) {
1273                 w = (str++)->w_wc;
1274                 if ((n = wctomb(buf, w)) > 0) {
1275                         len -= n;
1276                         buf += n;
1277                 }
1278                 if (n < 0)
1279                         break;
1280                 if (w == EOS)
1281                         return (0);
1282         }
1283         return (1);
1284 }
1285 
1286 #if defined(_LP64) || _FILE_OFFSET_BITS != 64
1287 
1288 /* glob() function with legacy glob structure */
1289 int
1290 old_glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
1291     old_glob_t *pglob)
1292 {
1293 
1294         glob_t gl;
1295         int rv;
1296 
1297         flags &= GLOB_POSIX;
1298 
1299         (void) memset(&gl, 0, sizeof (gl));
1300 
1301         /*
1302          * Copy all the members, old to new.  There's
1303          * really no point in micro-optimizing the copying.
1304          * Other members are set to zero.
1305          */
1306         gl.gl_pathc = pglob->gl_pathc;
1307         gl.gl_pathv = pglob->gl_pathv;
1308         gl.gl_offs = pglob->gl_offs;
1309         gl.gl_pathp = pglob->gl_pathp;
1310         gl.gl_pathn = pglob->gl_pathn;
1311 
1312         rv = _glob_ext(pattern, flags, errfunc, &gl);
1313 
1314         /*
1315          * Copy all the members, new to old.  There's
1316          * really no point in micro-optimizing the copying.
1317          */
1318         pglob->gl_pathc = gl.gl_pathc;
1319         pglob->gl_pathv = gl.gl_pathv;
1320         pglob->gl_offs = gl.gl_offs;
1321         pglob->gl_pathp = gl.gl_pathp;
1322         pglob->gl_pathn = gl.gl_pathn;
1323 
1324         return (rv);
1325 }
1326 
1327 /* globfree() function with legacy glob structure */
1328 void
1329 old_globfree(old_glob_t *pglob)
1330 {
1331         glob_t gl;
1332 
1333         (void) memset(&gl, 0, sizeof (gl));
1334 
1335         /*
1336          * Copy all the members, old to new.  There's
1337          * really no point in micro-optimizing the copying.
1338          * Other members are set to zero.
1339          */
1340         gl.gl_pathc = pglob->gl_pathc;
1341         gl.gl_pathv = pglob->gl_pathv;
1342         gl.gl_offs = pglob->gl_offs;
1343         gl.gl_pathp = pglob->gl_pathp;
1344         gl.gl_pathn = pglob->gl_pathn;
1345 
1346         _globfree_ext(&gl);
1347 
1348         /*
1349          * Copy all the members, new to old.  There's
1350          * really no point in micro-optimizing the copying.
1351          */
1352         pglob->gl_pathc = gl.gl_pathc;
1353         pglob->gl_pathv = gl.gl_pathv;
1354         pglob->gl_offs = gl.gl_offs;
1355         pglob->gl_pathp = gl.gl_pathp;
1356         pglob->gl_pathn = gl.gl_pathn;
1357 
1358 }
1359 
1360 #endif  /* _LP64 || _FILE_OFFSET_BITS != 64 */