1 /* $NetBSD: glob.c,v 1.18 2006/12/01 18:57:29 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Guido van Rossum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #if defined(LIBC_SCCS) && !defined(lint) 37 #if 0 38 static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; 39 #else 40 __RCSID("$NetBSD: glob.c,v 1.18 2006/12/01 18:57:29 christos Exp $"); 41 #endif 42 #endif /* LIBC_SCCS and not lint */ 43 44 /* 45 * glob(3) -- a superset of the one defined in POSIX 1003.2. 46 * 47 * The [!...] convention to negate a range is supported (SysV, Posix, ksh). 48 * 49 * Optional extra services, controlled by flags not defined by POSIX: 50 * 51 * GLOB_MAGCHAR: 52 * Set in gl_flags if pattern contained a globbing character. 53 * GLOB_NOMAGIC: 54 * Same as GLOB_NOCHECK, but it will only append pattern if it did 55 * not contain any magic characters. [Used in csh style globbing] 56 * GLOB_ALTDIRFUNC: 57 * Use alternately specified directory access functions. 58 * GLOB_TILDE: 59 * expand ~user/foo to the /home/dir/of/user/foo 60 * GLOB_BRACE: 61 * expand {1,2}{a,b} to 1a 1b 2a 2b 62 * gl_matchc: 63 * Number of matches in the current invocation of glob. 64 */ 65 66 #include "namespace.h" 67 #include <sys/param.h> 68 #include <sys/stat.h> 69 70 #include <assert.h> 71 #include <ctype.h> 72 #include <dirent.h> 73 #include <errno.h> 74 #include <glob.h> 75 #include <pwd.h> 76 #include <stdio.h> 77 #include <stdlib.h> 78 #include <string.h> 79 #include <unistd.h> 80 81 #ifdef HAVE_NBTOOL_CONFIG_H 82 #define NO_GETPW_R 83 #endif 84 85 /* 86 * XXX: For NetBSD 1.4.x compatibility. (kill me l8r) 87 */ 88 #ifndef _DIAGASSERT 89 #define _DIAGASSERT(a) 90 #endif 91 92 #define DOLLAR '$' 93 #define DOT '.' 94 #define EOS '\0' 95 #define LBRACKET '[' 96 #define NOT '!' 97 #define QUESTION '?' 98 #define QUOTE '\\' 99 #define RANGE '-' 100 #define RBRACKET ']' 101 #define SEP '/' 102 #define STAR '*' 103 #define TILDE '~' 104 #define UNDERSCORE '_' 105 #define LBRACE '{' 106 #define RBRACE '}' 107 #define SLASH '/' 108 #define COMMA ',' 109 110 #ifndef USE_8BIT_CHARS 111 112 #define M_QUOTE 0x8000 113 #define M_PROTECT 0x4000 114 #define M_MASK 0xffff 115 #define M_ASCII 0x00ff 116 117 typedef u_short Char; 118 119 #else 120 121 #define M_QUOTE (Char)0x80 122 #define M_PROTECT (Char)0x40 123 #define M_MASK (Char)0xff 124 #define M_ASCII (Char)0x7f 125 126 typedef char Char; 127 128 #endif 129 130 131 #define CHAR(c) ((Char)((c)&M_ASCII)) 132 #define META(c) ((Char)((c)|M_QUOTE)) 133 #define M_ALL META('*') 134 #define M_END META(']') 135 #define M_NOT META('!') 136 #define M_ONE META('?') 137 #define M_RNG META('-') 138 #define M_SET META('[') 139 #define ismeta(c) (((c)&M_QUOTE) != 0) 140 141 142 static int compare(const void *, const void *); 143 static int g_Ctoc(const Char *, char *, size_t); 144 static int g_lstat(Char *, __gl_stat_t *, glob_t *); 145 static DIR *g_opendir(Char *, glob_t *); 146 static Char *g_strchr(const Char *, int); 147 static int g_stat(Char *, __gl_stat_t *, glob_t *); 148 static int glob0(const Char *, glob_t *); 149 static int glob1(Char *, glob_t *, size_t *); 150 static int glob2(Char *, Char *, Char *, Char *, glob_t *, 151 size_t *); 152 static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, 153 size_t *); 154 static int globextend(const Char *, glob_t *, size_t *); 155 static const Char *globtilde(const Char *, Char *, size_t, glob_t *); 156 static int globexp1(const Char *, glob_t *); 157 static int globexp2(const Char *, const Char *, glob_t *, int *); 158 static int match(Char *, Char *, Char *); 159 #ifdef DEBUG 160 static void qprintf(const char *, Char *); 161 #endif 162 163 int 164 glob(const char *pattern, int flags, int (*errfunc)(const char *, int), 165 glob_t *pglob) 166 { 167 const u_char *patnext; 168 int c; 169 Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; 170 171 _DIAGASSERT(pattern != NULL); 172 173 patnext = (const u_char *) pattern; 174 if (!(flags & GLOB_APPEND)) { 175 pglob->gl_pathc = 0; 176 pglob->gl_pathv = NULL; 177 if (!(flags & GLOB_DOOFFS)) 178 pglob->gl_offs = 0; 179 } 180 pglob->gl_flags = flags & ~GLOB_MAGCHAR; 181 pglob->gl_errfunc = errfunc; 182 pglob->gl_matchc = 0; 183 184 bufnext = patbuf; 185 bufend = bufnext + MAXPATHLEN; 186 if (flags & GLOB_NOESCAPE) { 187 while (bufnext < bufend && (c = *patnext++) != EOS) 188 *bufnext++ = c; 189 } else { 190 /* Protect the quoted characters. */ 191 while (bufnext < bufend && (c = *patnext++) != EOS) 192 if (c == QUOTE) { 193 if ((c = *patnext++) == EOS) { 194 c = QUOTE; 195 --patnext; 196 } 197 *bufnext++ = c | M_PROTECT; 198 } 199 else 200 *bufnext++ = c; 201 } 202 *bufnext = EOS; 203 204 if (flags & GLOB_BRACE) 205 return globexp1(patbuf, pglob); 206 else 207 return glob0(patbuf, pglob); 208 } 209 210 /* 211 * Expand recursively a glob {} pattern. When there is no more expansion 212 * invoke the standard globbing routine to glob the rest of the magic 213 * characters 214 */ 215 static int 216 globexp1(const Char *pattern, glob_t *pglob) 217 { 218 const Char* ptr = pattern; 219 int rv; 220 221 _DIAGASSERT(pattern != NULL); 222 _DIAGASSERT(pglob != NULL); 223 224 /* Protect a single {}, for find(1), like csh */ 225 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) 226 return glob0(pattern, pglob); 227 228 while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) 229 if (!globexp2(ptr, pattern, pglob, &rv)) 230 return rv; 231 232 return glob0(pattern, pglob); 233 } 234 235 236 /* 237 * Recursive brace globbing helper. Tries to expand a single brace. 238 * If it succeeds then it invokes globexp1 with the new pattern. 239 * If it fails then it tries to glob the rest of the pattern and returns. 240 */ 241 static int 242 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv) 243 { 244 int i; 245 Char *lm, *ls; 246 const Char *pe, *pm, *pl; 247 Char patbuf[MAXPATHLEN + 1]; 248 249 _DIAGASSERT(ptr != NULL); 250 _DIAGASSERT(pattern != NULL); 251 _DIAGASSERT(pglob != NULL); 252 _DIAGASSERT(rv != NULL); 253 254 /* copy part up to the brace */ 255 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) 256 continue; 257 ls = lm; 258 259 /* Find the balanced brace */ 260 for (i = 0, pe = ++ptr; *pe; pe++) 261 if (*pe == LBRACKET) { 262 /* Ignore everything between [] */ 263 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) 264 continue; 265 if (*pe == EOS) { 266 /* 267 * We could not find a matching RBRACKET. 268 * Ignore and just look for RBRACE 269 */ 270 pe = pm; 271 } 272 } 273 else if (*pe == LBRACE) 274 i++; 275 else if (*pe == RBRACE) { 276 if (i == 0) 277 break; 278 i--; 279 } 280 281 /* Non matching braces; just glob the pattern */ 282 if (i != 0 || *pe == EOS) { 283 /* 284 * we use `pattern', not `patbuf' here so that that 285 * unbalanced braces are passed to the match 286 */ 287 *rv = glob0(pattern, pglob); 288 return 0; 289 } 290 291 for (i = 0, pl = pm = ptr; pm <= pe; pm++) { 292 switch (*pm) { 293 case LBRACKET: 294 /* Ignore everything between [] */ 295 for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) 296 continue; 297 if (*pm == EOS) { 298 /* 299 * We could not find a matching RBRACKET. 300 * Ignore and just look for RBRACE 301 */ 302 pm = pl; 303 } 304 break; 305 306 case LBRACE: 307 i++; 308 break; 309 310 case RBRACE: 311 if (i) { 312 i--; 313 break; 314 } 315 /* FALLTHROUGH */ 316 case COMMA: 317 if (i && *pm == COMMA) 318 break; 319 else { 320 /* Append the current string */ 321 for (lm = ls; (pl < pm); *lm++ = *pl++) 322 continue; 323 /* 324 * Append the rest of the pattern after the 325 * closing brace 326 */ 327 for (pl = pe + 1; (*lm++ = *pl++) != EOS;) 328 continue; 329 330 /* Expand the current pattern */ 331 #ifdef DEBUG 332 qprintf("globexp2:", patbuf); 333 #endif 334 *rv = globexp1(patbuf, pglob); 335 336 /* move after the comma, to the next string */ 337 pl = pm + 1; 338 } 339 break; 340 341 default: 342 break; 343 } 344 } 345 *rv = 0; 346 return 0; 347 } 348 349 350 351 /* 352 * expand tilde from the passwd file. 353 */ 354 static const Char * 355 globtilde(const Char *pattern, Char *patbuf, size_t patsize, glob_t *pglob) 356 { 357 struct passwd *pwd; 358 const char *h; 359 const Char *p; 360 Char *b; 361 char *d; 362 Char *pend = &patbuf[patsize / sizeof(Char)]; 363 #ifndef NO_GETPW_R 364 struct passwd pwres; 365 char pwbuf[1024]; 366 #endif 367 368 pend--; 369 370 _DIAGASSERT(pattern != NULL); 371 _DIAGASSERT(patbuf != NULL); 372 _DIAGASSERT(pglob != NULL); 373 374 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) 375 return pattern; 376 377 /* Copy up to the end of the string or / */ 378 for (p = pattern + 1, d = (char *)(void *)patbuf; 379 d < (char *)(void *)pend && *p && *p != SLASH; 380 *d++ = *p++) 381 continue; 382 383 if (d == (char *)(void *)pend) 384 return NULL; 385 386 *d = EOS; 387 d = (char *)(void *)patbuf; 388 389 if (*d == EOS) { 390 /* 391 * handle a plain ~ or ~/ by expanding $HOME 392 * first and then trying the password file 393 */ 394 if ((h = getenv("HOME")) == NULL) { 395 #ifdef NO_GETPW_R 396 if ((pwd = getpwuid(getuid())) == NULL) 397 #else 398 if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), 399 &pwd) != 0 || pwd == NULL) 400 #endif 401 return pattern; 402 else 403 h = pwd->pw_dir; 404 } 405 } 406 else { 407 /* 408 * Expand a ~user 409 */ 410 #ifdef NO_GETPW_R 411 if ((pwd = getpwnam(d)) == NULL) 412 #else 413 if (getpwnam_r(d, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || 414 pwd == NULL) 415 #endif 416 return pattern; 417 else 418 h = pwd->pw_dir; 419 } 420 421 /* Copy the home directory */ 422 for (b = patbuf; b < pend && *h; *b++ = *h++) 423 continue; 424 425 if (b == pend) 426 return NULL; 427 428 /* Append the rest of the pattern */ 429 while (b < pend && (*b++ = *p++) != EOS) 430 continue; 431 432 if (b == pend) 433 return NULL; 434 435 return patbuf; 436 } 437 438 439 /* 440 * The main glob() routine: compiles the pattern (optionally processing 441 * quotes), calls glob1() to do the real pattern matching, and finally 442 * sorts the list (unless unsorted operation is requested). Returns 0 443 * if things went well, nonzero if errors occurred. It is not an error 444 * to find no matches. 445 */ 446 static int 447 glob0(const Char *pattern, glob_t *pglob) 448 { 449 const Char *qpatnext; 450 int c, error; 451 __gl_size_t oldpathc; 452 Char *bufnext, patbuf[MAXPATHLEN+1]; 453 size_t limit = 0; 454 455 _DIAGASSERT(pattern != NULL); 456 _DIAGASSERT(pglob != NULL); 457 458 if ((qpatnext = globtilde(pattern, patbuf, sizeof(patbuf), 459 pglob)) == NULL) 460 return GLOB_ABEND; 461 oldpathc = pglob->gl_pathc; 462 bufnext = patbuf; 463 464 /* We don't need to check for buffer overflow any more. */ 465 while ((c = *qpatnext++) != EOS) { 466 switch (c) { 467 case LBRACKET: 468 c = *qpatnext; 469 if (c == NOT) 470 ++qpatnext; 471 if (*qpatnext == EOS || 472 g_strchr(qpatnext+1, RBRACKET) == NULL) { 473 *bufnext++ = LBRACKET; 474 if (c == NOT) 475 --qpatnext; 476 break; 477 } 478 *bufnext++ = M_SET; 479 if (c == NOT) 480 *bufnext++ = M_NOT; 481 c = *qpatnext++; 482 do { 483 *bufnext++ = CHAR(c); 484 if (*qpatnext == RANGE && 485 (c = qpatnext[1]) != RBRACKET) { 486 *bufnext++ = M_RNG; 487 *bufnext++ = CHAR(c); 488 qpatnext += 2; 489 } 490 } while ((c = *qpatnext++) != RBRACKET); 491 pglob->gl_flags |= GLOB_MAGCHAR; 492 *bufnext++ = M_END; 493 break; 494 case QUESTION: 495 pglob->gl_flags |= GLOB_MAGCHAR; 496 *bufnext++ = M_ONE; 497 break; 498 case STAR: 499 pglob->gl_flags |= GLOB_MAGCHAR; 500 /* collapse adjacent stars to one, 501 * to avoid exponential behavior 502 */ 503 if (bufnext == patbuf || bufnext[-1] != M_ALL) 504 *bufnext++ = M_ALL; 505 break; 506 default: 507 *bufnext++ = CHAR(c); 508 break; 509 } 510 } 511 *bufnext = EOS; 512 #ifdef DEBUG 513 qprintf("glob0:", patbuf); 514 #endif 515 516 if ((error = glob1(patbuf, pglob, &limit)) != 0) 517 return error; 518 519 if (pglob->gl_pathc == oldpathc) { 520 /* 521 * If there was no match we are going to append the pattern 522 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was 523 * specified and the pattern did not contain any magic 524 * characters GLOB_NOMAGIC is there just for compatibility 525 * with csh. 526 */ 527 if ((pglob->gl_flags & GLOB_NOCHECK) || 528 ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR)) 529 == GLOB_NOMAGIC)) { 530 return globextend(pattern, pglob, &limit); 531 } else { 532 return GLOB_NOMATCH; 533 } 534 } else if (!(pglob->gl_flags & GLOB_NOSORT)) { 535 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, 536 (size_t)pglob->gl_pathc - oldpathc, sizeof(char *), 537 compare); 538 } 539 540 return 0; 541 } 542 543 static int 544 compare(const void *p, const void *q) 545 { 546 547 _DIAGASSERT(p != NULL); 548 _DIAGASSERT(q != NULL); 549 550 return strcoll(*(const char * const *)p, *(const char * const *)q); 551 } 552 553 static int 554 glob1(Char *pattern, glob_t *pglob, size_t *limit) 555 { 556 Char pathbuf[MAXPATHLEN+1]; 557 558 _DIAGASSERT(pattern != NULL); 559 _DIAGASSERT(pglob != NULL); 560 561 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ 562 if (*pattern == EOS) 563 return 0; 564 /* 565 * we save one character so that we can use ptr >= limit, 566 * in the general case when we are appending non nul chars only. 567 */ 568 return glob2(pathbuf, pathbuf, 569 pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1, pattern, 570 pglob, limit); 571 } 572 573 /* 574 * The functions glob2 and glob3 are mutually recursive; there is one level 575 * of recursion for each segment in the pattern that contains one or more 576 * meta characters. 577 */ 578 static int 579 glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob, 580 size_t *limit) 581 { 582 __gl_stat_t sb; 583 Char *p, *q; 584 int anymeta; 585 586 _DIAGASSERT(pathbuf != NULL); 587 _DIAGASSERT(pathend != NULL); 588 _DIAGASSERT(pattern != NULL); 589 _DIAGASSERT(pglob != NULL); 590 591 /* 592 * Loop over pattern segments until end of pattern or until 593 * segment with meta character found. 594 */ 595 for (anymeta = 0;;) { 596 if (*pattern == EOS) { /* End of pattern? */ 597 *pathend = EOS; 598 if (g_lstat(pathbuf, &sb, pglob)) 599 return 0; 600 601 if (((pglob->gl_flags & GLOB_MARK) && 602 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || 603 (S_ISLNK(sb.st_mode) && 604 (g_stat(pathbuf, &sb, pglob) == 0) && 605 S_ISDIR(sb.st_mode)))) { 606 if (pathend >= pathlim) 607 return GLOB_ABORTED; 608 *pathend++ = SEP; 609 *pathend = EOS; 610 } 611 ++pglob->gl_matchc; 612 return globextend(pathbuf, pglob, limit); 613 } 614 615 /* Find end of next segment, copy tentatively to pathend. */ 616 q = pathend; 617 p = pattern; 618 while (*p != EOS && *p != SEP) { 619 if (ismeta(*p)) 620 anymeta = 1; 621 if (q >= pathlim) 622 return GLOB_ABORTED; 623 *q++ = *p++; 624 } 625 626 if (!anymeta) { /* No expansion, do next segment. */ 627 pathend = q; 628 pattern = p; 629 while (*pattern == SEP) { 630 if (pathend >= pathlim) 631 return GLOB_ABORTED; 632 *pathend++ = *pattern++; 633 } 634 } else /* Need expansion, recurse. */ 635 return glob3(pathbuf, pathend, pathlim, pattern, p, 636 pglob, limit); 637 } 638 /* NOTREACHED */ 639 } 640 641 static int 642 glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, 643 Char *restpattern, glob_t *pglob, size_t *limit) 644 { 645 struct dirent *dp; 646 DIR *dirp; 647 int error; 648 char buf[MAXPATHLEN]; 649 650 /* 651 * The readdirfunc declaration can't be prototyped, because it is 652 * assigned, below, to two functions which are prototyped in glob.h 653 * and dirent.h as taking pointers to differently typed opaque 654 * structures. 655 */ 656 struct dirent *(*readdirfunc)(void *); 657 658 _DIAGASSERT(pathbuf != NULL); 659 _DIAGASSERT(pathend != NULL); 660 _DIAGASSERT(pattern != NULL); 661 _DIAGASSERT(restpattern != NULL); 662 _DIAGASSERT(pglob != NULL); 663 664 *pathend = EOS; 665 errno = 0; 666 667 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { 668 if (pglob->gl_errfunc) { 669 if (g_Ctoc(pathbuf, buf, sizeof(buf))) 670 return GLOB_ABORTED; 671 if (pglob->gl_errfunc(buf, errno) || 672 pglob->gl_flags & GLOB_ERR) 673 return GLOB_ABORTED; 674 } 675 /* 676 * Posix/XOpen: glob should return when it encounters a 677 * directory that it cannot open or read 678 * XXX: Should we ignore ENOTDIR and ENOENT though? 679 * I think that Posix had in mind EPERM... 680 */ 681 if (pglob->gl_flags & GLOB_ERR) 682 return GLOB_ABORTED; 683 684 return 0; 685 } 686 687 error = 0; 688 689 /* Search directory for matching names. */ 690 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 691 readdirfunc = pglob->gl_readdir; 692 else 693 readdirfunc = (struct dirent *(*)__P((void *))) readdir; 694 while ((dp = (*readdirfunc)(dirp)) != NULL) { 695 u_char *sc; 696 Char *dc; 697 698 /* Initial DOT must be matched literally. */ 699 if (dp->d_name[0] == DOT && *pattern != DOT) 700 continue; 701 /* 702 * The resulting string contains EOS, so we can 703 * use the pathlim character, if it is the nul 704 */ 705 for (sc = (u_char *) dp->d_name, dc = pathend; 706 dc <= pathlim && (*dc++ = *sc++) != EOS;) 707 continue; 708 709 /* 710 * Have we filled the buffer without seeing EOS? 711 */ 712 if (dc > pathlim && *pathlim != EOS) { 713 /* 714 * Abort when requested by caller, otherwise 715 * reset pathend back to last SEP and continue 716 * with next dir entry. 717 */ 718 if (pglob->gl_flags & GLOB_ERR) { 719 error = GLOB_ABORTED; 720 break; 721 } 722 else { 723 *pathend = EOS; 724 continue; 725 } 726 } 727 728 if (!match(pathend, pattern, restpattern)) { 729 *pathend = EOS; 730 continue; 731 } 732 error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, limit); 733 if (error) 734 break; 735 } 736 737 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 738 (*pglob->gl_closedir)(dirp); 739 else 740 closedir(dirp); 741 742 /* 743 * Again Posix X/Open issue with regards to error handling. 744 */ 745 if ((error || errno) && (pglob->gl_flags & GLOB_ERR)) 746 return GLOB_ABORTED; 747 748 return error; 749 } 750 751 752 /* 753 * Extend the gl_pathv member of a glob_t structure to accommodate a new item, 754 * add the new item, and update gl_pathc. 755 * 756 * This assumes the BSD realloc, which only copies the block when its size 757 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic 758 * behavior. 759 * 760 * Return 0 if new item added, error code if memory couldn't be allocated. 761 * 762 * Invariant of the glob_t structure: 763 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and 764 * gl_pathv points to (gl_offs + gl_pathc + 1) items. 765 */ 766 static int 767 globextend(const Char *path, glob_t *pglob, size_t *limit) 768 { 769 char **pathv; 770 size_t i, newsize, len; 771 char *copy; 772 const Char *p; 773 774 _DIAGASSERT(path != NULL); 775 _DIAGASSERT(pglob != NULL); 776 777 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); 778 pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) : 779 malloc(newsize); 780 if (pathv == NULL) 781 return GLOB_NOSPACE; 782 783 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { 784 /* first time around -- clear initial gl_offs items */ 785 pathv += pglob->gl_offs; 786 for (i = pglob->gl_offs + 1; --i > 0; ) 787 *--pathv = NULL; 788 } 789 pglob->gl_pathv = pathv; 790 791 for (p = path; *p++;) 792 continue; 793 len = (size_t)(p - path); 794 *limit += len; 795 if ((copy = malloc(len)) != NULL) { 796 if (g_Ctoc(path, copy, len)) { 797 free(copy); 798 return GLOB_ABORTED; 799 } 800 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; 801 } 802 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; 803 804 if ((pglob->gl_flags & GLOB_LIMIT) && (newsize + *limit) >= ARG_MAX) { 805 errno = 0; 806 return GLOB_NOSPACE; 807 } 808 809 return copy == NULL ? GLOB_NOSPACE : 0; 810 } 811 812 813 /* 814 * pattern matching function for filenames. Each occurrence of the * 815 * pattern causes a recursion level. 816 */ 817 static int 818 match(Char *name, Char *pat, Char *patend) 819 { 820 int ok, negate_range; 821 Char c, k; 822 823 _DIAGASSERT(name != NULL); 824 _DIAGASSERT(pat != NULL); 825 _DIAGASSERT(patend != NULL); 826 827 while (pat < patend) { 828 c = *pat++; 829 switch (c & M_MASK) { 830 case M_ALL: 831 if (pat == patend) 832 return 1; 833 do 834 if (match(name, pat, patend)) 835 return 1; 836 while (*name++ != EOS); 837 return 0; 838 case M_ONE: 839 if (*name++ == EOS) 840 return 0; 841 break; 842 case M_SET: 843 ok = 0; 844 if ((k = *name++) == EOS) 845 return 0; 846 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) 847 ++pat; 848 while (((c = *pat++) & M_MASK) != M_END) 849 if ((*pat & M_MASK) == M_RNG) { 850 if (c <= k && k <= pat[1]) 851 ok = 1; 852 pat += 2; 853 } else if (c == k) 854 ok = 1; 855 if (ok == negate_range) 856 return 0; 857 break; 858 default: 859 if (*name++ != c) 860 return 0; 861 break; 862 } 863 } 864 return *name == EOS; 865 } 866 867 /* Free allocated data belonging to a glob_t structure. */ 868 void 869 globfree(glob_t *pglob) 870 { 871 size_t i; 872 char **pp; 873 874 _DIAGASSERT(pglob != NULL); 875 876 if (pglob->gl_pathv != NULL) { 877 pp = pglob->gl_pathv + pglob->gl_offs; 878 for (i = pglob->gl_pathc; i--; ++pp) 879 if (*pp) 880 free(*pp); 881 free(pglob->gl_pathv); 882 pglob->gl_pathv = NULL; 883 pglob->gl_pathc = 0; 884 } 885 } 886 887 static DIR * 888 g_opendir(Char *str, glob_t *pglob) 889 { 890 char buf[MAXPATHLEN]; 891 892 _DIAGASSERT(str != NULL); 893 _DIAGASSERT(pglob != NULL); 894 895 if (!*str) 896 (void)strlcpy(buf, ".", sizeof(buf)); 897 else { 898 if (g_Ctoc(str, buf, sizeof(buf))) 899 return NULL; 900 } 901 902 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 903 return (*pglob->gl_opendir)(buf); 904 905 return opendir(buf); 906 } 907 908 static int 909 g_lstat(Char *fn, __gl_stat_t *sb, glob_t *pglob) 910 { 911 char buf[MAXPATHLEN]; 912 913 _DIAGASSERT(fn != NULL); 914 _DIAGASSERT(sb != NULL); 915 _DIAGASSERT(pglob != NULL); 916 917 if (g_Ctoc(fn, buf, sizeof(buf))) 918 return -1; 919 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 920 return (*pglob->gl_lstat)(buf, sb); 921 return lstat(buf, sb); 922 } 923 924 static int 925 g_stat(Char *fn, __gl_stat_t *sb, glob_t *pglob) 926 { 927 char buf[MAXPATHLEN]; 928 929 _DIAGASSERT(fn != NULL); 930 _DIAGASSERT(sb != NULL); 931 _DIAGASSERT(pglob != NULL); 932 933 if (g_Ctoc(fn, buf, sizeof(buf))) 934 return -1; 935 if (pglob->gl_flags & GLOB_ALTDIRFUNC) 936 return (*pglob->gl_stat)(buf, sb); 937 return stat(buf, sb); 938 } 939 940 static Char * 941 g_strchr(const Char *str, int ch) 942 { 943 944 _DIAGASSERT(str != NULL); 945 946 do { 947 if (*str == ch) 948 return __UNCONST(str); 949 } while (*str++); 950 return NULL; 951 } 952 953 static int 954 g_Ctoc(const Char *str, char *buf, size_t len) 955 { 956 char *dc; 957 958 _DIAGASSERT(str != NULL); 959 _DIAGASSERT(buf != NULL); 960 961 if (len == 0) 962 return 1; 963 964 for (dc = buf; len && (*dc++ = *str++) != EOS; len--) 965 continue; 966 967 return len == 0; 968 } 969 970 #ifdef DEBUG 971 static void 972 qprintf(const char *str, Char *s) 973 { 974 Char *p; 975 976 _DIAGASSERT(str != NULL); 977 _DIAGASSERT(s != NULL); 978 979 (void)printf("%s:\n", str); 980 for (p = s; *p; p++) 981 (void)printf("%c", CHAR(*p)); 982 (void)printf("\n"); 983 for (p = s; *p; p++) 984 (void)printf("%c", *p & M_PROTECT ? '"' : ' '); 985 (void)printf("\n"); 986 for (p = s; *p; p++) 987 (void)printf("%c", ismeta(*p) ? '_' : ' '); 988 (void)printf("\n"); 989 } 990 #endif 991