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