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