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