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