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