~ubuntu-branches/ubuntu/oneiric/sudo/oneiric-updates

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