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