blob: fd3d86c4c330284096eeb1e7c5d00670a5db9e34 [file] [log] [blame]
Darren Tucker6524d4f2005-11-10 17:02:21 +11001/* $OpenBSD: glob.c,v 1.25 2005/08/08 08:05:34 espie Exp $ */
Damien Miller3c027682001-03-14 11:39:45 +11002/*
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.
Damien Miller329638e2003-06-03 12:12:50 +100017 * 3. Neither the name of the University nor the names of its contributors
Damien Miller3c027682001-03-14 11:39:45 +110018 * 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
Darren Tucker7f24a0e2005-11-10 16:18:56 +110034/* OPENBSD ORIGINAL: lib/libc/gen/glob.c */
35
Damien Miller3c027682001-03-14 11:39:45 +110036#include "includes.h"
Damien Miller6645e7a2006-03-15 14:42:54 +110037#include <sys/types.h>
38#include <sys/stat.h>
39#include <dirent.h>
Damien Miller3c027682001-03-14 11:39:45 +110040#include <ctype.h>
41
Damien Miller79b332d2001-06-27 23:36:08 +100042static long
43get_arg_max(void)
Tim Riced9d5ba22001-03-19 20:46:50 -080044{
45#ifdef ARG_MAX
46 return(ARG_MAX);
47#elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX)
48 return(sysconf(_SC_ARG_MAX));
49#else
50 return(256); /* XXX: arbitrary */
51#endif
52}
53
Ben Lindstrom45b14db2001-03-17 01:15:38 +000054#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
55 !defined(GLOB_HAS_GL_MATCHC)
Damien Miller3c027682001-03-14 11:39:45 +110056
Damien Miller3c027682001-03-14 11:39:45 +110057/*
58 * glob(3) -- a superset of the one defined in POSIX 1003.2.
59 *
60 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
61 *
62 * Optional extra services, controlled by flags not defined by POSIX:
63 *
64 * GLOB_QUOTE:
65 * Escaping convention: \ inhibits any special meaning the following
66 * character might have (except \ at end of string is retained).
67 * GLOB_MAGCHAR:
68 * Set in gl_flags if pattern contained a globbing character.
69 * GLOB_NOMAGIC:
70 * Same as GLOB_NOCHECK, but it will only append pattern if it did
71 * not contain any magic characters. [Used in csh style globbing]
72 * GLOB_ALTDIRFUNC:
73 * Use alternately specified directory access functions.
74 * GLOB_TILDE:
75 * expand ~user/foo to the /home/dir/of/user/foo
76 * GLOB_BRACE:
77 * expand {1,2}{a,b} to 1a 1b 2a 2b
78 * gl_matchc:
79 * Number of matches in the current invocation of glob.
80 */
81
82
83#define DOLLAR '$'
84#define DOT '.'
85#define EOS '\0'
86#define LBRACKET '['
87#define NOT '!'
88#define QUESTION '?'
89#define QUOTE '\\'
90#define RANGE '-'
91#define RBRACKET ']'
92#define SEP '/'
93#define STAR '*'
Ben Lindstrom604de562002-07-04 18:20:51 +000094#undef TILDE /* Some platforms may already define it */
Damien Miller3c027682001-03-14 11:39:45 +110095#define TILDE '~'
96#define UNDERSCORE '_'
97#define LBRACE '{'
98#define RBRACE '}'
99#define SLASH '/'
100#define COMMA ','
101
102#ifndef DEBUG
103
104#define M_QUOTE 0x8000
105#define M_PROTECT 0x4000
106#define M_MASK 0xffff
107#define M_ASCII 0x00ff
108
109typedef u_short Char;
110
111#else
112
113#define M_QUOTE 0x80
114#define M_PROTECT 0x40
115#define M_MASK 0xff
116#define M_ASCII 0x7f
117
118typedef char Char;
119
120#endif
121
122
123#define CHAR(c) ((Char)((c)&M_ASCII))
124#define META(c) ((Char)((c)|M_QUOTE))
125#define M_ALL META('*')
126#define M_END META(']')
127#define M_NOT META('!')
128#define M_ONE META('?')
129#define M_RNG META('-')
130#define M_SET META('[')
131#define ismeta(c) (((c)&M_QUOTE) != 0)
132
133
Damien Miller71eb0c12002-09-11 10:29:11 +1000134static int compare(const void *, const void *);
135static int g_Ctoc(const Char *, char *, u_int);
136static int g_lstat(Char *, struct stat *, glob_t *);
137static DIR *g_opendir(Char *, glob_t *);
138static Char *g_strchr(Char *, int);
139static int g_stat(Char *, struct stat *, glob_t *);
140static int glob0(const Char *, glob_t *);
141static int glob1(Char *, Char *, glob_t *, size_t *);
142static int glob2(Char *, Char *, Char *, Char *, Char *, Char *,
143 glob_t *, size_t *);
144static int glob3(Char *, Char *, Char *, Char *, Char *, Char *,
145 Char *, Char *, glob_t *, size_t *);
146static int globextend(const Char *, glob_t *, size_t *);
Ben Lindstroma77d6412001-03-19 18:58:13 +0000147static const Char *
Damien Miller71eb0c12002-09-11 10:29:11 +1000148 globtilde(const Char *, Char *, size_t, glob_t *);
149static int globexp1(const Char *, glob_t *);
150static int globexp2(const Char *, const Char *, glob_t *, int *);
151static int match(Char *, Char *, Char *);
Damien Miller3c027682001-03-14 11:39:45 +1100152#ifdef DEBUG
Damien Miller71eb0c12002-09-11 10:29:11 +1000153static void qprintf(const char *, Char *);
Damien Miller3c027682001-03-14 11:39:45 +1100154#endif
155
156int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100157glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
158 glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100159{
160 const u_char *patnext;
161 int c;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000162 Char *bufnext, *bufend, patbuf[MAXPATHLEN];
Damien Miller3c027682001-03-14 11:39:45 +1100163
164 patnext = (u_char *) pattern;
165 if (!(flags & GLOB_APPEND)) {
166 pglob->gl_pathc = 0;
167 pglob->gl_pathv = NULL;
168 if (!(flags & GLOB_DOOFFS))
169 pglob->gl_offs = 0;
170 }
171 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
172 pglob->gl_errfunc = errfunc;
173 pglob->gl_matchc = 0;
174
175 bufnext = patbuf;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000176 bufend = bufnext + MAXPATHLEN - 1;
Damien Miller3c027682001-03-14 11:39:45 +1100177 if (flags & GLOB_NOESCAPE)
Damien Millerb68af622001-03-28 21:05:26 +1000178 while (bufnext < bufend && (c = *patnext++) != EOS)
179 *bufnext++ = c;
Damien Miller3c027682001-03-14 11:39:45 +1100180 else {
181 /* Protect the quoted characters. */
182 while (bufnext < bufend && (c = *patnext++) != EOS)
183 if (c == QUOTE) {
184 if ((c = *patnext++) == EOS) {
185 c = QUOTE;
186 --patnext;
187 }
188 *bufnext++ = c | M_PROTECT;
Damien Miller6e77a532001-04-14 00:22:33 +1000189 } else
Damien Miller3c027682001-03-14 11:39:45 +1100190 *bufnext++ = c;
191 }
192 *bufnext = EOS;
193
194 if (flags & GLOB_BRACE)
195 return globexp1(patbuf, pglob);
196 else
197 return glob0(patbuf, pglob);
198}
199
200/*
201 * Expand recursively a glob {} pattern. When there is no more expansion
202 * invoke the standard globbing routine to glob the rest of the magic
203 * characters
204 */
Damien Millerd8f72ca2001-03-30 10:23:17 +1000205static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100206globexp1(const Char *pattern, glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100207{
208 const Char* ptr = pattern;
209 int rv;
210
211 /* Protect a single {}, for find(1), like csh */
212 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
213 return glob0(pattern, pglob);
214
215 while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
216 if (!globexp2(ptr, pattern, pglob, &rv))
217 return rv;
218
219 return glob0(pattern, pglob);
220}
221
222
223/*
224 * Recursive brace globbing helper. Tries to expand a single brace.
225 * If it succeeds then it invokes globexp1 with the new pattern.
226 * If it fails then it tries to glob the rest of the pattern and returns.
227 */
Damien Millerd8f72ca2001-03-30 10:23:17 +1000228static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100229globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
Damien Miller3c027682001-03-14 11:39:45 +1100230{
231 int i;
232 Char *lm, *ls;
233 const Char *pe, *pm, *pl;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000234 Char patbuf[MAXPATHLEN];
Damien Miller3c027682001-03-14 11:39:45 +1100235
236 /* copy part up to the brace */
237 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
Damien Miller6e77a532001-04-14 00:22:33 +1000238 ;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000239 *lm = EOS;
Damien Miller3c027682001-03-14 11:39:45 +1100240 ls = lm;
241
242 /* Find the balanced brace */
243 for (i = 0, pe = ++ptr; *pe; pe++)
244 if (*pe == LBRACKET) {
245 /* Ignore everything between [] */
246 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
Damien Miller6e77a532001-04-14 00:22:33 +1000247 ;
Damien Miller3c027682001-03-14 11:39:45 +1100248 if (*pe == EOS) {
249 /*
250 * We could not find a matching RBRACKET.
251 * Ignore and just look for RBRACE
252 */
253 pe = pm;
254 }
Damien Miller6e77a532001-04-14 00:22:33 +1000255 } else if (*pe == LBRACE)
Damien Miller3c027682001-03-14 11:39:45 +1100256 i++;
257 else if (*pe == RBRACE) {
258 if (i == 0)
259 break;
260 i--;
261 }
262
263 /* Non matching braces; just glob the pattern */
264 if (i != 0 || *pe == EOS) {
265 *rv = glob0(patbuf, pglob);
266 return 0;
267 }
268
Damien Millerb68af622001-03-28 21:05:26 +1000269 for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
Damien Miller3c027682001-03-14 11:39:45 +1100270 switch (*pm) {
271 case LBRACKET:
272 /* Ignore everything between [] */
273 for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
Damien Miller6e77a532001-04-14 00:22:33 +1000274 ;
Damien Miller3c027682001-03-14 11:39:45 +1100275 if (*pm == EOS) {
276 /*
277 * We could not find a matching RBRACKET.
278 * Ignore and just look for RBRACE
279 */
280 pm = pl;
281 }
282 break;
283
284 case LBRACE:
285 i++;
286 break;
287
288 case RBRACE:
289 if (i) {
Damien Millerb68af622001-03-28 21:05:26 +1000290 i--;
291 break;
Damien Miller3c027682001-03-14 11:39:45 +1100292 }
293 /* FALLTHROUGH */
294 case COMMA:
295 if (i && *pm == COMMA)
296 break;
297 else {
298 /* Append the current string */
299 for (lm = ls; (pl < pm); *lm++ = *pl++)
Damien Miller6e77a532001-04-14 00:22:33 +1000300 ;
301
Damien Miller3c027682001-03-14 11:39:45 +1100302 /*
303 * Append the rest of the pattern after the
304 * closing brace
305 */
Damien Miller6e77a532001-04-14 00:22:33 +1000306 for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
307 ;
Damien Miller3c027682001-03-14 11:39:45 +1100308
309 /* Expand the current pattern */
310#ifdef DEBUG
311 qprintf("globexp2:", patbuf);
312#endif
313 *rv = globexp1(patbuf, pglob);
314
315 /* move after the comma, to the next string */
316 pl = pm + 1;
317 }
318 break;
319
320 default:
321 break;
322 }
Damien Millerb68af622001-03-28 21:05:26 +1000323 }
Damien Miller3c027682001-03-14 11:39:45 +1100324 *rv = 0;
325 return 0;
326}
327
328
329
330/*
331 * expand tilde from the passwd file.
332 */
333static const Char *
Darren Tucker6524d4f2005-11-10 17:02:21 +1100334globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100335{
336 struct passwd *pwd;
337 char *h;
338 const Char *p;
339 Char *b, *eb;
340
341 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
342 return pattern;
343
344 /* Copy up to the end of the string or / */
345 eb = &patbuf[patbuf_len - 1];
346 for (p = pattern + 1, h = (char *) patbuf;
347 h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
Damien Miller6e77a532001-04-14 00:22:33 +1000348 ;
Damien Miller3c027682001-03-14 11:39:45 +1100349
350 *h = EOS;
351
Damien Miller6e77a532001-04-14 00:22:33 +1000352#if 0
353 if (h == (char *)eb)
354 return what;
355#endif
356
Damien Miller3c027682001-03-14 11:39:45 +1100357 if (((char *) patbuf)[0] == EOS) {
358 /*
359 * handle a plain ~ or ~/ by expanding $HOME
360 * first and then trying the password file
361 */
362#if 0
363 if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
364#endif
365 if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
366 if ((pwd = getpwuid(getuid())) == NULL)
367 return pattern;
368 else
369 h = pwd->pw_dir;
370 }
Damien Miller6e77a532001-04-14 00:22:33 +1000371 } else {
Damien Miller3c027682001-03-14 11:39:45 +1100372 /*
373 * Expand a ~user
374 */
375 if ((pwd = getpwnam((char*) patbuf)) == NULL)
376 return pattern;
377 else
378 h = pwd->pw_dir;
379 }
380
381 /* Copy the home directory */
382 for (b = patbuf; b < eb && *h; *b++ = *h++)
Damien Miller6e77a532001-04-14 00:22:33 +1000383 ;
Damien Miller3c027682001-03-14 11:39:45 +1100384
385 /* Append the rest of the pattern */
386 while (b < eb && (*b++ = *p++) != EOS)
Damien Miller6e77a532001-04-14 00:22:33 +1000387 ;
Damien Miller3c027682001-03-14 11:39:45 +1100388 *b = EOS;
389
390 return patbuf;
391}
392
393
394/*
395 * The main glob() routine: compiles the pattern (optionally processing
396 * quotes), calls glob1() to do the real pattern matching, and finally
397 * sorts the list (unless unsorted operation is requested). Returns 0
398 * if things went well, nonzero if errors occurred. It is not an error
399 * to find no matches.
400 */
401static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100402glob0(const Char *pattern, glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100403{
404 const Char *qpatnext;
405 int c, err, oldpathc;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000406 Char *bufnext, patbuf[MAXPATHLEN];
Ben Lindstroma77d6412001-03-19 18:58:13 +0000407 size_t limit = 0;
Damien Miller3c027682001-03-14 11:39:45 +1100408
Damien Millerd8f72ca2001-03-30 10:23:17 +1000409 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
Damien Miller3c027682001-03-14 11:39:45 +1100410 oldpathc = pglob->gl_pathc;
411 bufnext = patbuf;
412
413 /* We don't need to check for buffer overflow any more. */
414 while ((c = *qpatnext++) != EOS) {
415 switch (c) {
416 case LBRACKET:
417 c = *qpatnext;
418 if (c == NOT)
419 ++qpatnext;
420 if (*qpatnext == EOS ||
421 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
422 *bufnext++ = LBRACKET;
423 if (c == NOT)
424 --qpatnext;
425 break;
426 }
427 *bufnext++ = M_SET;
428 if (c == NOT)
429 *bufnext++ = M_NOT;
430 c = *qpatnext++;
431 do {
432 *bufnext++ = CHAR(c);
433 if (*qpatnext == RANGE &&
434 (c = qpatnext[1]) != RBRACKET) {
435 *bufnext++ = M_RNG;
436 *bufnext++ = CHAR(c);
437 qpatnext += 2;
438 }
439 } while ((c = *qpatnext++) != RBRACKET);
440 pglob->gl_flags |= GLOB_MAGCHAR;
441 *bufnext++ = M_END;
442 break;
443 case QUESTION:
444 pglob->gl_flags |= GLOB_MAGCHAR;
445 *bufnext++ = M_ONE;
446 break;
447 case STAR:
448 pglob->gl_flags |= GLOB_MAGCHAR;
449 /* collapse adjacent stars to one,
450 * to avoid exponential behavior
451 */
452 if (bufnext == patbuf || bufnext[-1] != M_ALL)
Damien Millerb68af622001-03-28 21:05:26 +1000453 *bufnext++ = M_ALL;
Damien Miller3c027682001-03-14 11:39:45 +1100454 break;
455 default:
456 *bufnext++ = CHAR(c);
457 break;
458 }
459 }
460 *bufnext = EOS;
461#ifdef DEBUG
462 qprintf("glob0:", patbuf);
463#endif
464
Damien Millerd8f72ca2001-03-30 10:23:17 +1000465 if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
Damien Miller3c027682001-03-14 11:39:45 +1100466 return(err);
467
468 /*
469 * If there was no match we are going to append the pattern
470 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
471 * and the pattern did not contain any magic characters
472 * GLOB_NOMAGIC is there just for compatibility with csh.
473 */
474 if (pglob->gl_pathc == oldpathc) {
475 if ((pglob->gl_flags & GLOB_NOCHECK) ||
476 ((pglob->gl_flags & GLOB_NOMAGIC) &&
477 !(pglob->gl_flags & GLOB_MAGCHAR)))
Ben Lindstroma77d6412001-03-19 18:58:13 +0000478 return(globextend(pattern, pglob, &limit));
Damien Miller3c027682001-03-14 11:39:45 +1100479 else
480 return(GLOB_NOMATCH);
481 }
482 if (!(pglob->gl_flags & GLOB_NOSORT))
483 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
484 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
485 return(0);
486}
487
488static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100489compare(const void *p, const void *q)
Damien Miller3c027682001-03-14 11:39:45 +1100490{
491 return(strcmp(*(char **)p, *(char **)q));
492}
493
494static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100495glob1(Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
Damien Miller3c027682001-03-14 11:39:45 +1100496{
Damien Millerd8f72ca2001-03-30 10:23:17 +1000497 Char pathbuf[MAXPATHLEN];
Damien Miller3c027682001-03-14 11:39:45 +1100498
499 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
500 if (*pattern == EOS)
501 return(0);
Damien Millerd8f72ca2001-03-30 10:23:17 +1000502 return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
503 pathbuf, pathbuf+MAXPATHLEN-1,
504 pattern, pattern_last, pglob, limitp));
Damien Miller3c027682001-03-14 11:39:45 +1100505}
506
507/*
508 * The functions glob2 and glob3 are mutually recursive; there is one level
509 * of recursion for each segment in the pattern that contains one or more
510 * meta characters.
511 */
512static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100513glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
514 Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
Damien Miller3c027682001-03-14 11:39:45 +1100515{
516 struct stat sb;
517 Char *p, *q;
518 int anymeta;
519
520 /*
521 * Loop over pattern segments until end of pattern or until
522 * segment with meta character found.
523 */
524 for (anymeta = 0;;) {
525 if (*pattern == EOS) { /* End of pattern? */
526 *pathend = EOS;
527 if (g_lstat(pathbuf, &sb, pglob))
528 return(0);
529
530 if (((pglob->gl_flags & GLOB_MARK) &&
Damien Millerb68af622001-03-28 21:05:26 +1000531 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
532 (S_ISLNK(sb.st_mode) &&
Damien Miller3c027682001-03-14 11:39:45 +1100533 (g_stat(pathbuf, &sb, pglob) == 0) &&
534 S_ISDIR(sb.st_mode)))) {
Damien Millerd8f72ca2001-03-30 10:23:17 +1000535 if (pathend+1 > pathend_last)
536 return (1);
Damien Miller3c027682001-03-14 11:39:45 +1100537 *pathend++ = SEP;
538 *pathend = EOS;
539 }
540 ++pglob->gl_matchc;
Ben Lindstroma77d6412001-03-19 18:58:13 +0000541 return(globextend(pathbuf, pglob, limitp));
Damien Miller3c027682001-03-14 11:39:45 +1100542 }
543
544 /* Find end of next segment, copy tentatively to pathend. */
545 q = pathend;
546 p = pattern;
547 while (*p != EOS && *p != SEP) {
548 if (ismeta(*p))
549 anymeta = 1;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000550 if (q+1 > pathend_last)
551 return (1);
Damien Miller3c027682001-03-14 11:39:45 +1100552 *q++ = *p++;
553 }
554
555 if (!anymeta) { /* No expansion, do next segment. */
556 pathend = q;
557 pattern = p;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000558 while (*pattern == SEP) {
559 if (pathend+1 > pathend_last)
560 return (1);
Damien Miller3c027682001-03-14 11:39:45 +1100561 *pathend++ = *pattern++;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000562 }
Damien Millerb68af622001-03-28 21:05:26 +1000563 } else
564 /* Need expansion, recurse. */
Damien Millerd8f72ca2001-03-30 10:23:17 +1000565 return(glob3(pathbuf, pathbuf_last, pathend,
566 pathend_last, pattern, pattern_last,
567 p, pattern_last, pglob, limitp));
Damien Miller3c027682001-03-14 11:39:45 +1100568 }
569 /* NOTREACHED */
570}
571
572static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100573glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
574 Char *pattern, Char *pattern_last, Char *restpattern,
575 Char *restpattern_last, glob_t *pglob, size_t *limitp)
Damien Miller3c027682001-03-14 11:39:45 +1100576{
Darren Tucker6524d4f2005-11-10 17:02:21 +1100577 struct dirent *dp;
Damien Miller3c027682001-03-14 11:39:45 +1100578 DIR *dirp;
579 int err;
580 char buf[MAXPATHLEN];
581
582 /*
583 * The readdirfunc declaration can't be prototyped, because it is
584 * assigned, below, to two functions which are prototyped in glob.h
585 * and dirent.h as taking pointers to differently typed opaque
586 * structures.
587 */
Ben Lindstromaf4a6c32003-08-25 01:10:51 +0000588 struct dirent *(*readdirfunc)(void *);
Damien Miller3c027682001-03-14 11:39:45 +1100589
Damien Millerd8f72ca2001-03-30 10:23:17 +1000590 if (pathend > pathend_last)
591 return (1);
Damien Miller3c027682001-03-14 11:39:45 +1100592 *pathend = EOS;
593 errno = 0;
594
595 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
596 /* TODO: don't call for ENOENT or ENOTDIR? */
597 if (pglob->gl_errfunc) {
Damien Miller6e77a532001-04-14 00:22:33 +1000598 if (g_Ctoc(pathbuf, buf, sizeof(buf)))
Damien Millerb68af622001-03-28 21:05:26 +1000599 return(GLOB_ABORTED);
Damien Miller3c027682001-03-14 11:39:45 +1100600 if (pglob->gl_errfunc(buf, errno) ||
601 pglob->gl_flags & GLOB_ERR)
Damien Millerb68af622001-03-28 21:05:26 +1000602 return(GLOB_ABORTED);
Damien Miller3c027682001-03-14 11:39:45 +1100603 }
604 return(0);
605 }
606
607 err = 0;
608
609 /* Search directory for matching names. */
610 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
611 readdirfunc = pglob->gl_readdir;
612 else
Ben Lindstromaf4a6c32003-08-25 01:10:51 +0000613 readdirfunc = (struct dirent *(*)(void *))readdir;
Damien Miller3c027682001-03-14 11:39:45 +1100614 while ((dp = (*readdirfunc)(dirp))) {
Darren Tucker6524d4f2005-11-10 17:02:21 +1100615 u_char *sc;
616 Char *dc;
Damien Miller3c027682001-03-14 11:39:45 +1100617
618 /* Initial DOT must be matched literally. */
619 if (dp->d_name[0] == DOT && *pattern != DOT)
620 continue;
Damien Millerd8f72ca2001-03-30 10:23:17 +1000621 dc = pathend;
622 sc = (u_char *) dp->d_name;
623 while (dc < pathend_last && (*dc++ = *sc++) != EOS)
624 ;
625 if (dc >= pathend_last) {
626 *dc = EOS;
627 err = 1;
628 break;
629 }
630
Damien Miller3c027682001-03-14 11:39:45 +1100631 if (!match(pathend, pattern, restpattern)) {
632 *pathend = EOS;
633 continue;
634 }
Damien Millerd8f72ca2001-03-30 10:23:17 +1000635 err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
636 restpattern, restpattern_last, pglob, limitp);
Damien Miller3c027682001-03-14 11:39:45 +1100637 if (err)
638 break;
639 }
640
641 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
642 (*pglob->gl_closedir)(dirp);
643 else
644 closedir(dirp);
645 return(err);
646}
647
648
649/*
Damien Miller71eb0c12002-09-11 10:29:11 +1000650 * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
Damien Miller3c027682001-03-14 11:39:45 +1100651 * add the new item, and update gl_pathc.
652 *
653 * This assumes the BSD realloc, which only copies the block when its size
654 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
655 * behavior.
656 *
657 * Return 0 if new item added, error code if memory couldn't be allocated.
658 *
659 * Invariant of the glob_t structure:
660 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
661 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
662 */
663static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100664globextend(const Char *path, glob_t *pglob, size_t *limitp)
Damien Miller3c027682001-03-14 11:39:45 +1100665{
Darren Tucker6524d4f2005-11-10 17:02:21 +1100666 char **pathv;
667 int i;
Ben Lindstroma77d6412001-03-19 18:58:13 +0000668 u_int newsize, len;
Damien Miller3c027682001-03-14 11:39:45 +1100669 char *copy;
670 const Char *p;
671
672 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
Ben Lindstroma77d6412001-03-19 18:58:13 +0000673 pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
674 malloc(newsize);
Damien Miller3c027682001-03-14 11:39:45 +1100675 if (pathv == NULL) {
Ben Lindstrom11c78f82001-03-19 19:00:09 +0000676 if (pglob->gl_pathv) {
Damien Miller3c027682001-03-14 11:39:45 +1100677 free(pglob->gl_pathv);
Ben Lindstrom11c78f82001-03-19 19:00:09 +0000678 pglob->gl_pathv = NULL;
679 }
Damien Miller3c027682001-03-14 11:39:45 +1100680 return(GLOB_NOSPACE);
681 }
682
683 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
684 /* first time around -- clear initial gl_offs items */
685 pathv += pglob->gl_offs;
686 for (i = pglob->gl_offs; --i >= 0; )
687 *--pathv = NULL;
688 }
689 pglob->gl_pathv = pathv;
690
691 for (p = path; *p++;)
Damien Miller6e77a532001-04-14 00:22:33 +1000692 ;
Ben Lindstroma77d6412001-03-19 18:58:13 +0000693 len = (size_t)(p - path);
694 *limitp += len;
695 if ((copy = malloc(len)) != NULL) {
Damien Miller6e77a532001-04-14 00:22:33 +1000696 if (g_Ctoc(path, copy, len)) {
Damien Millerb68af622001-03-28 21:05:26 +1000697 free(copy);
698 return(GLOB_NOSPACE);
699 }
Damien Miller3c027682001-03-14 11:39:45 +1100700 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
701 }
702 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
Ben Lindstroma77d6412001-03-19 18:58:13 +0000703
704 if ((pglob->gl_flags & GLOB_LIMIT) &&
Tim Riced9d5ba22001-03-19 20:46:50 -0800705 newsize + *limitp >= (u_int) get_arg_max()) {
Ben Lindstroma77d6412001-03-19 18:58:13 +0000706 errno = 0;
707 return(GLOB_NOSPACE);
708 }
709
Damien Miller3c027682001-03-14 11:39:45 +1100710 return(copy == NULL ? GLOB_NOSPACE : 0);
711}
712
713
714/*
715 * pattern matching function for filenames. Each occurrence of the *
716 * pattern causes a recursion level.
717 */
718static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100719match(Char *name, Char *pat, Char *patend)
Damien Miller3c027682001-03-14 11:39:45 +1100720{
721 int ok, negate_range;
722 Char c, k;
723
724 while (pat < patend) {
725 c = *pat++;
726 switch (c & M_MASK) {
727 case M_ALL:
728 if (pat == patend)
729 return(1);
Darren Tucker6524d4f2005-11-10 17:02:21 +1100730 do {
Damien Miller3c027682001-03-14 11:39:45 +1100731 if (match(name, pat, patend))
732 return(1);
Darren Tucker6524d4f2005-11-10 17:02:21 +1100733 } while (*name++ != EOS);
Damien Miller3c027682001-03-14 11:39:45 +1100734 return(0);
735 case M_ONE:
736 if (*name++ == EOS)
737 return(0);
738 break;
739 case M_SET:
740 ok = 0;
741 if ((k = *name++) == EOS)
742 return(0);
743 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
744 ++pat;
745 while (((c = *pat++) & M_MASK) != M_END)
746 if ((*pat & M_MASK) == M_RNG) {
747 if (c <= k && k <= pat[1])
748 ok = 1;
749 pat += 2;
750 } else if (c == k)
751 ok = 1;
752 if (ok == negate_range)
753 return(0);
754 break;
755 default:
756 if (*name++ != c)
757 return(0);
758 break;
759 }
760 }
761 return(*name == EOS);
762}
763
764/* Free allocated data belonging to a glob_t structure. */
765void
Darren Tucker6524d4f2005-11-10 17:02:21 +1100766globfree(glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100767{
Darren Tucker6524d4f2005-11-10 17:02:21 +1100768 int i;
769 char **pp;
Damien Miller3c027682001-03-14 11:39:45 +1100770
771 if (pglob->gl_pathv != NULL) {
772 pp = pglob->gl_pathv + pglob->gl_offs;
773 for (i = pglob->gl_pathc; i--; ++pp)
774 if (*pp)
775 free(*pp);
776 free(pglob->gl_pathv);
Ben Lindstrom11c78f82001-03-19 19:00:09 +0000777 pglob->gl_pathv = NULL;
Damien Miller3c027682001-03-14 11:39:45 +1100778 }
779}
780
781static DIR *
Darren Tucker6524d4f2005-11-10 17:02:21 +1100782g_opendir(Char *str, glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100783{
784 char buf[MAXPATHLEN];
785
786 if (!*str)
Damien Miller71eb0c12002-09-11 10:29:11 +1000787 strlcpy(buf, ".", sizeof buf);
Damien Millerb68af622001-03-28 21:05:26 +1000788 else {
Damien Miller6e77a532001-04-14 00:22:33 +1000789 if (g_Ctoc(str, buf, sizeof(buf)))
Damien Millerb68af622001-03-28 21:05:26 +1000790 return(NULL);
791 }
Damien Miller3c027682001-03-14 11:39:45 +1100792
793 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
794 return((*pglob->gl_opendir)(buf));
795
796 return(opendir(buf));
797}
798
799static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100800g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100801{
802 char buf[MAXPATHLEN];
803
Damien Miller6e77a532001-04-14 00:22:33 +1000804 if (g_Ctoc(fn, buf, sizeof(buf)))
Damien Millerb68af622001-03-28 21:05:26 +1000805 return(-1);
Damien Miller3c027682001-03-14 11:39:45 +1100806 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
807 return((*pglob->gl_lstat)(buf, sb));
808 return(lstat(buf, sb));
809}
810
811static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100812g_stat(Char *fn, struct stat *sb, glob_t *pglob)
Damien Miller3c027682001-03-14 11:39:45 +1100813{
814 char buf[MAXPATHLEN];
815
Damien Miller6e77a532001-04-14 00:22:33 +1000816 if (g_Ctoc(fn, buf, sizeof(buf)))
Damien Millerb68af622001-03-28 21:05:26 +1000817 return(-1);
Damien Miller3c027682001-03-14 11:39:45 +1100818 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
819 return((*pglob->gl_stat)(buf, sb));
820 return(stat(buf, sb));
821}
822
823static Char *
Darren Tucker6524d4f2005-11-10 17:02:21 +1100824g_strchr(Char *str, int ch)
Damien Miller3c027682001-03-14 11:39:45 +1100825{
826 do {
827 if (*str == ch)
828 return (str);
829 } while (*str++);
830 return (NULL);
831}
832
Damien Millerb68af622001-03-28 21:05:26 +1000833static int
Darren Tucker6524d4f2005-11-10 17:02:21 +1100834g_Ctoc(const Char *str, char *buf, u_int len)
Damien Miller3c027682001-03-14 11:39:45 +1100835{
Damien Miller3c027682001-03-14 11:39:45 +1100836
Damien Miller6e77a532001-04-14 00:22:33 +1000837 while (len--) {
838 if ((*buf++ = *str++) == EOS)
839 return (0);
840 }
841 return (1);
Damien Miller3c027682001-03-14 11:39:45 +1100842}
843
844#ifdef DEBUG
845static void
Darren Tucker6524d4f2005-11-10 17:02:21 +1100846qprintf(const char *str, Char *s)
Damien Miller3c027682001-03-14 11:39:45 +1100847{
Darren Tucker6524d4f2005-11-10 17:02:21 +1100848 Char *p;
Damien Miller3c027682001-03-14 11:39:45 +1100849
850 (void)printf("%s:\n", str);
851 for (p = s; *p; p++)
852 (void)printf("%c", CHAR(*p));
853 (void)printf("\n");
854 for (p = s; *p; p++)
855 (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
856 (void)printf("\n");
857 for (p = s; *p; p++)
858 (void)printf("%c", ismeta(*p) ? '_' : ' ');
859 (void)printf("\n");
860}
861#endif
862
Ben Lindstrom45b14db2001-03-17 01:15:38 +0000863#endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
864 !defined(GLOB_HAS_GL_MATCHC) */
Damien Miller3c027682001-03-14 11:39:45 +1100865