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