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