1 /** @file
2  * glob(3) -- a superset of the one defined in POSIX 1003.2.
3  *
4  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
5  *
6  * Optional extra services, controlled by flags not defined by POSIX:
7  *
8  * GLOB_MAGCHAR:
9  *  Set in gl_flags if pattern contained a globbing character.
10  * GLOB_NOMAGIC:
11  *  Same as GLOB_NOCHECK, but it will only append pattern if it did
12  *  not contain any magic characters.  [Used in csh style globbing]
13  * GLOB_ALTDIRFUNC:
14  *  Use alternately specified directory access functions.
15  * GLOB_TILDE:
16  *  expand ~user/foo to the /home/dir/of/user/foo
17  * GLOB_BRACE:
18  *  expand {1,2}{a,b} to 1a 1b 2a 2b
19  * GLOB_PERIOD:
20  *  allow metacharacters to match leading dots in filenames.
21  * GLOB_NO_DOTDIRS:
22  *  . and .. are hidden from wildcards, even if GLOB_PERIOD is set.
23  * gl_matchc:
24  *  Number of matches in the current invocation of glob.
25  *
26     Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
27     This program and the accompanying materials are licensed and made available under
28     the terms and conditions of the BSD License that accompanies this distribution.
29     The full text of the license may be found at
30     http://opensource.org/licenses/bsd-license.
31 
32     THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
33     WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
34 
35  * Copyright (c) 1989, 1993
36  *  The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Guido van Rossum.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64 
65     glob.c  8.3 (Berkeley) 10/13/93
66     NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp
67  */
68 #if defined(_MSC_VER)
69   #pragma warning ( disable : 4244 )
70   #pragma warning ( disable : 4018 )
71 #endif
72 
73 #include  <LibConfig.h>
74 
75 #include <sys/cdefs.h>
76 
77 #include <sys/param.h>
78 #include <sys/stat.h>
79 
80 #include <assert.h>
81 #include <ctype.h>
82 #include <dirent.h>
83 #include <errno.h>
84 #include <glob.h>
85 //#include <pwd.h>
86 #include <stdio.h>
87 #include <stddef.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <unistd.h>
91 #include <sys/fcntl.h>
92 
93 #ifdef HAVE_NBTOOL_CONFIG_H
94 #define NO_GETPW_R
95 #endif
96 
97 #define GLOB_LIMIT_MALLOC     65536
98 #define GLOB_LIMIT_STAT         128
99 #define GLOB_LIMIT_READDIR    16384
100 
101 #define GLOB_INDEX_MALLOC         0
102 #define GLOB_INDEX_STAT           1
103 #define GLOB_INDEX_READDIR        2
104 
105 /*
106  * XXX: For NetBSD 1.4.x compatibility. (kill me l8r)
107  */
108 #ifndef _DIAGASSERT
109 #define _DIAGASSERT(a)
110 #endif
111 
112 #define DOLLAR        '$'
113 #define DOT           '.'
114 #define EOS           '\0'
115 #define LBRACKET      '['
116 #define NOT           '!'
117 #define QUESTION      '?'
118 #define QUOTE         '\\'
119 #define RANGE         '-'
120 #define RBRACKET      ']'
121 #define SEP           '/'
122 #define STAR          '*'
123 #define TILDE         '~'
124 #define UNDERSCORE    '_'
125 #define LBRACE        '{'
126 #define RBRACE        '}'
127 #define SLASH         '/'
128 #define COMMA         ','
129 
130 #ifndef USE_8BIT_CHARS
131 
132 #define M_QUOTE       0x8000
133 #define M_PROTECT     0x4000
134 #define M_MASK        0xffff
135 #define M_ASCII       0x00ff
136 
137 typedef u_short Char;
138 
139 #else
140 
141 #define M_QUOTE       (Char)0x80
142 #define M_PROTECT     (Char)0x40
143 #define M_MASK        (Char)0xff
144 #define M_ASCII       (Char)0x7f
145 
146 typedef char Char;
147 
148 #endif
149 
150 
151 #define CHAR(c)       ((Char)((c)&M_ASCII))
152 #define META(c)       ((Char)((c)|M_QUOTE))
153 #define M_ALL         META('*')
154 #define M_END         META(']')
155 #define M_NOT         META('!')
156 #define M_ONE         META('?')
157 #define M_RNG         META('-')
158 #define M_SET         META('[')
159 #define ismeta(c)     (((c)&M_QUOTE) != 0)
160 
161 static int            compare(const void *, const void *);
162 static int            g_Ctoc(const Char *, char *, size_t);
163 static int            g_lstat(Char *, __gl_stat_t  *, glob_t *);
164 static DIR           *g_opendir(Char *, glob_t *);
165 static Char          *g_strchr(const Char *, int);
166 static int            g_stat(Char *, __gl_stat_t *, glob_t *);
167 static int            glob0(const Char *, glob_t *, size_t *);
168 static int            glob1(Char *, glob_t *, size_t *);
169 static int            glob2(Char *, Char *, Char *, Char *, glob_t *, size_t *);
170 static int            glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, size_t *);
171 static int            globextend(const Char *, glob_t *, size_t *);
172 static const Char    *globtilde(const Char *, Char *, size_t, glob_t *);
173 static int            globexp1(const Char *, glob_t *, size_t *);
174 static int            globexp2(const Char *, const Char *, glob_t *, int *, size_t *);
175 static int            match(Char *, Char *, Char *);
176 #ifdef DEBUG
177 static void           qprintf(const char *, Char *);
178 #endif
179 
180 int
glob(const char * pattern,int flags,int (* errfunc)(const char *,int),glob_t * pglob)181 glob(
182   const char *pattern,
183   int flags,
184   int (*errfunc)(const char *, int),
185   glob_t *pglob
186 )
187 {
188   const u_char *patnext;
189   int c;
190   Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
191   /* 0 = malloc(), 1 = stat(), 2 = readdir() */
192   size_t limit[] = { 0, 0, 0 };
193 
194   _DIAGASSERT(pattern != NULL);
195 
196   patnext = (const u_char *) pattern;
197   if (!(flags & GLOB_APPEND)) {
198     pglob->gl_pathc = 0;
199     pglob->gl_pathv = NULL;
200     if (!(flags & GLOB_DOOFFS))
201       pglob->gl_offs = 0;
202   }
203   pglob->gl_flags = flags & ~GLOB_MAGCHAR;
204   pglob->gl_errfunc = errfunc;
205   pglob->gl_matchc = 0;
206 
207   bufnext = patbuf;
208   bufend = bufnext + MAXPATHLEN;
209   if (flags & GLOB_NOESCAPE) {
210     while (bufnext < bufend && (c = *patnext++) != EOS)
211       *bufnext++ = c;
212   } else {
213     /* Protect the quoted characters. */
214     while (bufnext < bufend && (c = *patnext++) != EOS)
215       if (c == QUOTE) {
216         if ((c = *patnext++) == EOS) {
217           c = QUOTE;
218           --patnext;
219         }
220         *bufnext++ = c | M_PROTECT;
221       }
222       else
223         *bufnext++ = c;
224   }
225   *bufnext = EOS;
226 
227   if (flags & GLOB_BRACE)
228       return globexp1(patbuf, pglob, limit);
229   else
230       return glob0(patbuf, pglob, limit);
231 }
232 
233 /*
234  * Expand recursively a glob {} pattern. When there is no more expansion
235  * invoke the standard globbing routine to glob the rest of the magic
236  * characters
237  */
238 static int
globexp1(const Char * pattern,glob_t * pglob,size_t * limit)239 globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
240 {
241   const Char* ptr = pattern;
242   int rv;
243 
244   _DIAGASSERT(pattern != NULL);
245   _DIAGASSERT(pglob != NULL);
246 
247   /* Protect a single {}, for find(1), like csh */
248   if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
249     return glob0(pattern, pglob, limit);
250 
251   while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
252     if (!globexp2(ptr, pattern, pglob, &rv, limit))
253       return rv;
254 
255   return glob0(pattern, pglob, limit);
256 }
257 
258 
259 /*
260  * Recursive brace globbing helper. Tries to expand a single brace.
261  * If it succeeds then it invokes globexp1 with the new pattern.
262  * If it fails then it tries to glob the rest of the pattern and returns.
263  */
264 static int
globexp2(const Char * ptr,const Char * pattern,glob_t * pglob,int * rv,size_t * limit)265 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
266     size_t *limit)
267 {
268   int     i;
269   Char   *lm, *ls;
270   const Char *pe, *pm, *pl;
271   Char    patbuf[MAXPATHLEN + 1];
272 
273   _DIAGASSERT(ptr != NULL);
274   _DIAGASSERT(pattern != NULL);
275   _DIAGASSERT(pglob != NULL);
276   _DIAGASSERT(rv != NULL);
277 
278   /* copy part up to the brace */
279   for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
280     continue;
281   ls = lm;
282 
283   /* Find the balanced brace */
284   for (i = 0, pe = ++ptr; *pe; pe++)
285     if (*pe == LBRACKET) {
286       /* Ignore everything between [] */
287       for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
288         continue;
289       if (*pe == EOS) {
290         /*
291          * We could not find a matching RBRACKET.
292          * Ignore and just look for RBRACE
293          */
294         pe = pm;
295       }
296     }
297     else if (*pe == LBRACE)
298       i++;
299     else if (*pe == RBRACE) {
300       if (i == 0)
301         break;
302       i--;
303     }
304 
305   /* Non matching braces; just glob the pattern */
306   if (i != 0 || *pe == EOS) {
307     /*
308      * we use `pattern', not `patbuf' here so that that
309      * unbalanced braces are passed to the match
310      */
311     *rv = glob0(pattern, pglob, limit);
312     return 0;
313   }
314 
315   for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
316     switch (*pm) {
317     case LBRACKET:
318       /* Ignore everything between [] */
319       for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
320         continue;
321       if (*pm == EOS) {
322         /*
323          * We could not find a matching RBRACKET.
324          * Ignore and just look for RBRACE
325          */
326         pm = pl;
327       }
328       break;
329 
330     case LBRACE:
331       i++;
332       break;
333 
334     case RBRACE:
335       if (i) {
336         i--;
337         break;
338       }
339       /* FALLTHROUGH */
340     case COMMA:
341       if (i && *pm == COMMA)
342         break;
343       else {
344         /* Append the current string */
345         for (lm = ls; (pl < pm); *lm++ = *pl++)
346           continue;
347         /*
348          * Append the rest of the pattern after the
349          * closing brace
350          */
351         for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
352           continue;
353 
354         /* Expand the current pattern */
355 #ifdef DEBUG
356         qprintf("globexp2:", patbuf);
357 #endif
358         *rv = globexp1(patbuf, pglob, limit);
359 
360         /* move after the comma, to the next string */
361         pl = pm + 1;
362       }
363       break;
364 
365     default:
366       break;
367     }
368   }
369   *rv = 0;
370   return 0;
371 }
372 
373 
374 
375 /*
376  * expand tilde from the passwd file.
377  */
378 static const Char *
globtilde(const Char * pattern,Char * patbuf,size_t patsize,glob_t * pglob)379 globtilde(const Char *pattern, Char *patbuf, size_t patsize, glob_t *pglob)
380 {
381   const char *h;
382   const Char *p;
383   Char *b;
384   char *d;
385   Char *pend = &patbuf[patsize / sizeof(Char)];
386 
387   pend--;
388 
389   _DIAGASSERT(pattern != NULL);
390   _DIAGASSERT(patbuf != NULL);
391   _DIAGASSERT(pglob != NULL);
392 
393   if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
394     return pattern;
395 
396   /* Copy up to the end of the string or / */
397   for (p = pattern + 1, d = (char *)(void *)patbuf;
398        d < (char *)(void *)pend && *p && *p != SLASH;
399        *d++ = *p++)
400     continue;
401 
402   if (d == (char *)(void *)pend)
403     return NULL;
404 
405   *d = EOS;
406   d = (char *)(void *)patbuf;
407 
408   if (*d == EOS) {
409     /*
410      * handle a plain ~ or ~/ by expanding $HOME
411      * first and then trying the password file
412      */
413     if ((h = getenv("HOME")) == NULL) {
414       return pattern;
415     }
416   }
417   else {
418     /*
419      * Expand a ~user
420      */
421     return pattern;
422   }
423 
424   /* Copy the home directory */
425   for (b = patbuf; b < pend && *h; *b++ = *h++)
426     continue;
427 
428   if (b == pend)
429     return NULL;
430 
431   /* Append the rest of the pattern */
432   while (b < pend && (*b++ = *p++) != EOS)
433     continue;
434 
435   if (b == pend)
436     return NULL;
437 
438   return patbuf;
439 }
440 
441 
442 /*
443  * The main glob() routine: compiles the pattern (optionally processing
444  * quotes), calls glob1() to do the real pattern matching, and finally
445  * sorts the list (unless unsorted operation is requested).  Returns 0
446  * if things went well, nonzero if errors occurred.  It is not an error
447  * to find no matches.
448  */
449 static int
glob0(const Char * pattern,glob_t * pglob,size_t * limit)450 glob0(const Char *pattern, glob_t *pglob, size_t *limit)
451 {
452   const Char *qpatnext;
453   int c, error;
454   __gl_size_t oldpathc;
455   Char *bufnext, patbuf[MAXPATHLEN+1];
456 
457   _DIAGASSERT(pattern != NULL);
458   _DIAGASSERT(pglob != NULL);
459 
460   if ((qpatnext = globtilde(pattern, patbuf, sizeof(patbuf),
461       pglob)) == NULL)
462     return GLOB_ABEND;
463   oldpathc = pglob->gl_pathc;
464   bufnext = patbuf;
465 
466   /* We don't need to check for buffer overflow any more. */
467   while ((c = *qpatnext++) != EOS) {
468     switch (c) {
469     case LBRACKET:
470       c = *qpatnext;
471       if (c == NOT)
472         ++qpatnext;
473       if (*qpatnext == EOS ||
474           g_strchr(qpatnext+1, RBRACKET) == NULL) {
475         *bufnext++ = LBRACKET;
476         if (c == NOT)
477           --qpatnext;
478         break;
479       }
480       *bufnext++ = M_SET;
481       if (c == NOT)
482         *bufnext++ = M_NOT;
483       c = *qpatnext++;
484       do {
485         *bufnext++ = CHAR(c);
486         if (*qpatnext == RANGE &&
487             (c = qpatnext[1]) != RBRACKET) {
488           *bufnext++ = M_RNG;
489           *bufnext++ = CHAR(c);
490           qpatnext += 2;
491         }
492       } while ((c = *qpatnext++) != RBRACKET);
493       pglob->gl_flags |= GLOB_MAGCHAR;
494       *bufnext++ = M_END;
495       break;
496     case QUESTION:
497       pglob->gl_flags |= GLOB_MAGCHAR;
498       *bufnext++ = M_ONE;
499       break;
500     case STAR:
501       pglob->gl_flags |= GLOB_MAGCHAR;
502       /* collapse adjacent stars to one,
503        * to avoid exponential behavior
504        */
505       if (bufnext == patbuf || bufnext[-1] != M_ALL)
506         *bufnext++ = M_ALL;
507       break;
508     default:
509       *bufnext++ = CHAR(c);
510       break;
511     }
512   }
513   *bufnext = EOS;
514 #ifdef DEBUG
515   qprintf("glob0:", patbuf);
516 #endif
517 
518   if ((error = glob1(patbuf, pglob, limit)) != 0)
519     return error;
520 
521   if (pglob->gl_pathc == oldpathc) {
522     /*
523      * If there was no match we are going to append the pattern
524      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was
525      * specified and the pattern did not contain any magic
526      * characters GLOB_NOMAGIC is there just for compatibility
527      * with csh.
528      */
529     if ((pglob->gl_flags & GLOB_NOCHECK) ||
530         ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR))
531          == GLOB_NOMAGIC)) {
532       return globextend(pattern, pglob, limit);
533     } else {
534       return GLOB_NOMATCH;
535     }
536   } else if (!(pglob->gl_flags & GLOB_NOSORT)) {
537     qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
538         (size_t)pglob->gl_pathc - oldpathc, sizeof(char *),
539         compare);
540   }
541 
542   return 0;
543 }
544 
545 static int
compare(const void * p,const void * q)546 compare(const void *p, const void *q)
547 {
548 
549   _DIAGASSERT(p != NULL);
550   _DIAGASSERT(q != NULL);
551 
552   return strcoll(*(const char * const *)p, *(const char * const *)q);
553 }
554 
555 static int
glob1(Char * pattern,glob_t * pglob,size_t * limit)556 glob1(Char *pattern, glob_t *pglob, size_t *limit)
557 {
558   Char pathbuf[MAXPATHLEN+1];
559 
560   _DIAGASSERT(pattern != NULL);
561   _DIAGASSERT(pglob != NULL);
562 
563   /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
564   if (*pattern == EOS)
565     return 0;
566   /*
567    * we save one character so that we can use ptr >= limit,
568    * in the general case when we are appending non nul chars only.
569    */
570   return glob2(pathbuf, pathbuf,
571       pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1, pattern,
572       pglob, limit);
573 }
574 
575 /*
576  * The functions glob2 and glob3 are mutually recursive; there is one level
577  * of recursion for each segment in the pattern that contains one or more
578  * meta characters.
579  */
580 static int
glob2(Char * pathbuf,Char * pathend,Char * pathlim,Char * pattern,glob_t * pglob,size_t * limit)581 glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob,
582     size_t *limit)
583 {
584   __gl_stat_t sb;
585   Char *p, *q;
586   int anymeta;
587   Char *pend;
588   ptrdiff_t diff;
589 
590   _DIAGASSERT(pathbuf != NULL);
591   _DIAGASSERT(pathend != NULL);
592   _DIAGASSERT(pattern != NULL);
593   _DIAGASSERT(pglob != NULL);
594 
595   /*
596    * Loop over pattern segments until end of pattern or until
597    * segment with meta character found.
598    */
599   for (anymeta = 0;;) {
600     if (*pattern == EOS) {    /* End of pattern? */
601       *pathend = EOS;
602       if (g_lstat(pathbuf, &sb, pglob))
603         return 0;
604 
605       if ((pglob->gl_flags & GLOB_LIMIT) &&
606           limit[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) {
607         errno = 0;
608         *pathend++ = SEP;
609         *pathend = EOS;
610         return GLOB_NOSPACE;
611       }
612       if (((pglob->gl_flags & GLOB_MARK) &&
613           pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
614 //          (S_ISLNK(sb.st_mode) &&
615           (0 &&
616           (g_stat(pathbuf, &sb, pglob) == 0) &&
617           S_ISDIR(sb.st_mode)))) {
618         if (pathend >= pathlim)
619           return GLOB_ABORTED;
620         *pathend++ = SEP;
621         *pathend = EOS;
622       }
623       ++pglob->gl_matchc;
624       return globextend(pathbuf, pglob, limit);
625     }
626 
627     /* Find end of next segment, copy tentatively to pathend. */
628     q = pathend;
629     p = pattern;
630     while (*p != EOS && *p != SEP) {
631       if (ismeta(*p))
632         anymeta = 1;
633       if (q >= pathlim)
634         return GLOB_ABORTED;
635       *q++ = *p++;
636     }
637 
638                 /*
639      * No expansion, or path ends in slash-dot shash-dot-dot,
640      * do next segment.
641      */
642     if (pglob->gl_flags & GLOB_PERIOD) {
643       for (pend = pathend; pend > pathbuf && pend[-1] == '/';
644           pend--)
645         continue;
646       diff = pend - pathbuf;
647     } else {
648       /* XXX: GCC */
649       diff = 0;
650       pend = pathend;
651     }
652 
653                 if ((!anymeta) ||
654         ((pglob->gl_flags & GLOB_PERIOD) &&
655          (diff >= 1 && pend[-1] == DOT) &&
656          (diff >= 2 && (pend[-2] == SLASH || pend[-2] == DOT)) &&
657          (diff < 3 || pend[-3] == SLASH))) {
658       pathend = q;
659       pattern = p;
660       while (*pattern == SEP) {
661         if (pathend >= pathlim)
662           return GLOB_ABORTED;
663         *pathend++ = *pattern++;
664       }
665     } else      /* Need expansion, recurse. */
666       return glob3(pathbuf, pathend, pathlim, pattern, p,
667           pglob, limit);
668   }
669   /* NOTREACHED */
670 }
671 
672 static int
glob3(Char * pathbuf,Char * pathend,Char * pathlim,Char * pattern,Char * restpattern,glob_t * pglob,size_t * limit)673 glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern,
674     Char *restpattern, glob_t *pglob, size_t *limit)
675 {
676   struct dirent *dp;
677   DIR *dirp;
678   int error;
679   char buf[MAXPATHLEN];
680 
681   /*
682    * The readdirfunc declaration can't be prototyped, because it is
683    * assigned, below, to two functions which are prototyped in glob.h
684    * and dirent.h as taking pointers to differently typed opaque
685    * structures.
686    */
687   struct dirent *(*readdirfunc)(void *);
688 
689   _DIAGASSERT(pathbuf != NULL);
690   _DIAGASSERT(pathend != NULL);
691   _DIAGASSERT(pattern != NULL);
692   _DIAGASSERT(restpattern != NULL);
693   _DIAGASSERT(pglob != NULL);
694 
695   *pathend = EOS;
696   errno = 0;
697 
698   if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
699     if (pglob->gl_errfunc) {
700       if (g_Ctoc(pathbuf, buf, sizeof(buf)))
701         return GLOB_ABORTED;
702       if (pglob->gl_errfunc(buf, errno) ||
703           pglob->gl_flags & GLOB_ERR)
704         return GLOB_ABORTED;
705     }
706     /*
707      * Posix/XOpen: glob should return when it encounters a
708      * directory that it cannot open or read
709      * XXX: Should we ignore ENOTDIR and ENOENT though?
710      * I think that Posix had in mind EPERM...
711      */
712     if (pglob->gl_flags & GLOB_ERR)
713       return GLOB_ABORTED;
714 
715     return 0;
716   }
717 
718   error = 0;
719 
720   /* Search directory for matching names. */
721   if (pglob->gl_flags & GLOB_ALTDIRFUNC)
722     readdirfunc = pglob->gl_readdir;
723   else
724     readdirfunc = (struct dirent *(*)(void *)) readdir;
725   while ((dp = (*readdirfunc)(dirp)) != NULL) {
726     u_char *sc;
727     Char *dc;
728 
729     if ((pglob->gl_flags & GLOB_LIMIT) &&
730         limit[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) {
731       errno = 0;
732       *pathend++ = SEP;
733       *pathend = EOS;
734       return GLOB_NOSPACE;
735     }
736 
737     /*
738      * Initial DOT must be matched literally, unless we have
739      * GLOB_PERIOD set.
740      */
741     if ((pglob->gl_flags & GLOB_PERIOD) == 0)
742       if (dp->FileName[0] == DOT && *pattern != DOT)
743         continue;
744     /*
745      * If GLOB_NO_DOTDIRS is set, . and .. vanish.
746      */
747     if ((pglob->gl_flags & GLOB_NO_DOTDIRS) &&
748         (dp->FileName[0] == DOT) &&
749         ((dp->FileName[1] == EOS) ||
750          ((dp->FileName[1] == DOT) && (dp->FileName[2] == EOS))))
751       continue;
752     /*
753      * The resulting string contains EOS, so we can
754      * use the pathlim character, if it is the nul
755      */
756     for (sc = (u_char *) dp->FileName, dc = pathend;
757          dc <= pathlim && (*dc++ = *sc++) != EOS;)
758       continue;
759 
760     /*
761      * Have we filled the buffer without seeing EOS?
762      */
763     if (dc > pathlim && *pathlim != EOS) {
764       /*
765        * Abort when requested by caller, otherwise
766        * reset pathend back to last SEP and continue
767        * with next dir entry.
768        */
769       if (pglob->gl_flags & GLOB_ERR) {
770         error = GLOB_ABORTED;
771         break;
772       }
773       else {
774         *pathend = EOS;
775         continue;
776       }
777     }
778 
779     if (!match(pathend, pattern, restpattern)) {
780       *pathend = EOS;
781       continue;
782     }
783     error = glob2(pathbuf, --dc, pathlim, restpattern, pglob,
784         limit);
785     if (error)
786       break;
787   }
788 
789   if (pglob->gl_flags & GLOB_ALTDIRFUNC)
790     (*pglob->gl_closedir)(dirp);
791   else
792     closedir(dirp);
793 
794   /*
795    * Again Posix X/Open issue with regards to error handling.
796    */
797   if ((error || errno) && (pglob->gl_flags & GLOB_ERR))
798     return GLOB_ABORTED;
799 
800   return error;
801 }
802 
803 
804 /*
805  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
806  * add the new item, and update gl_pathc.
807  *
808  * This assumes the BSD realloc, which only copies the block when its size
809  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
810  * behavior.
811  *
812  * Return 0 if new item added, error code if memory couldn't be allocated.
813  *
814  * Invariant of the glob_t structure:
815  *  Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
816  *  gl_pathv points to (gl_offs + gl_pathc + 1) items.
817  */
818 static int
globextend(const Char * path,glob_t * pglob,size_t * limit)819 globextend(const Char *path, glob_t *pglob, size_t *limit)
820 {
821   char **pathv;
822   size_t i, newsize, len;
823   char *copy;
824   const Char *p;
825 
826   _DIAGASSERT(path != NULL);
827   _DIAGASSERT(pglob != NULL);
828 
829   newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
830   pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) :
831       malloc(newsize);
832   if (pathv == NULL)
833     return GLOB_NOSPACE;
834 
835   if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
836     /* first time around -- clear initial gl_offs items */
837     pathv += pglob->gl_offs;
838     for (i = pglob->gl_offs + 1; --i > 0; )
839       *--pathv = NULL;
840   }
841   pglob->gl_pathv = pathv;
842 
843   for (p = path; *p++;)
844     continue;
845   len = (size_t)(p - path);
846   limit[GLOB_INDEX_MALLOC] += len;
847   if ((copy = malloc(len)) != NULL) {
848     if (g_Ctoc(path, copy, len)) {
849       free(copy);
850       return GLOB_ABORTED;
851     }
852     pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
853   }
854   pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
855 
856   if ((pglob->gl_flags & GLOB_LIMIT) &&
857       (newsize + limit[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) {
858     errno = 0;
859     return GLOB_NOSPACE;
860   }
861 
862   return copy == NULL ? GLOB_NOSPACE : 0;
863 }
864 
865 
866 /*
867  * pattern matching function for filenames.  Each occurrence of the *
868  * pattern causes a recursion level.
869  */
870 static int
match(Char * name,Char * pat,Char * patend)871 match(Char *name, Char *pat, Char *patend)
872 {
873   int ok, negate_range;
874   Char c, k;
875 
876   _DIAGASSERT(name != NULL);
877   _DIAGASSERT(pat != NULL);
878   _DIAGASSERT(patend != NULL);
879 
880   while (pat < patend) {
881     c = *pat++;
882     switch (c & M_MASK) {
883     case M_ALL:
884       if (pat == patend)
885         return 1;
886       do
887           if (match(name, pat, patend))
888             return 1;
889       while (*name++ != EOS);
890       return 0;
891     case M_ONE:
892       if (*name++ == EOS)
893         return 0;
894       break;
895     case M_SET:
896       ok = 0;
897       if ((k = *name++) == EOS)
898         return 0;
899       if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
900         ++pat;
901       while (((c = *pat++) & M_MASK) != M_END)
902         if ((*pat & M_MASK) == M_RNG) {
903           if (c <= k && k <= pat[1])
904             ok = 1;
905           pat += 2;
906         } else if (c == k)
907           ok = 1;
908       if (ok == negate_range)
909         return 0;
910       break;
911     default:
912       if (*name++ != c)
913         return 0;
914       break;
915     }
916   }
917   return *name == EOS;
918 }
919 
920 /* Free allocated data belonging to a glob_t structure. */
921 void
globfree(glob_t * pglob)922 globfree(glob_t *pglob)
923 {
924   size_t i;
925   char **pp;
926 
927   _DIAGASSERT(pglob != NULL);
928 
929   if (pglob->gl_pathv != NULL) {
930     pp = pglob->gl_pathv + pglob->gl_offs;
931     for (i = pglob->gl_pathc; i--; ++pp)
932       if (*pp)
933         free(*pp);
934     free(pglob->gl_pathv);
935     pglob->gl_pathv = NULL;
936     pglob->gl_pathc = 0;
937   }
938 }
939 
940 static DIR *
g_opendir(Char * str,glob_t * pglob)941 g_opendir(Char *str, glob_t *pglob)
942 {
943   char buf[MAXPATHLEN];
944 
945   _DIAGASSERT(str != NULL);
946   _DIAGASSERT(pglob != NULL);
947 
948   if (!*str)
949     (void)strlcpy(buf, ".", sizeof(buf));
950   else {
951     if (g_Ctoc(str, buf, sizeof(buf)))
952       return NULL;
953   }
954 
955   if (pglob->gl_flags & GLOB_ALTDIRFUNC)
956     return (*pglob->gl_opendir)(buf);
957 
958   return opendir(buf);
959 }
960 
961 static int
g_lstat(Char * fn,__gl_stat_t * sb,glob_t * pglob)962 g_lstat(Char *fn, __gl_stat_t *sb, glob_t *pglob)
963 {
964   char buf[MAXPATHLEN];
965 
966   _DIAGASSERT(fn != NULL);
967   _DIAGASSERT(sb != NULL);
968   _DIAGASSERT(pglob != NULL);
969 
970   if (g_Ctoc(fn, buf, sizeof(buf)))
971     return -1;
972   if (pglob->gl_flags & GLOB_ALTDIRFUNC)
973     return (*pglob->gl_lstat)(buf, sb);
974   return lstat(buf, sb);
975 }
976 
977 static int
g_stat(Char * fn,__gl_stat_t * sb,glob_t * pglob)978 g_stat(Char *fn, __gl_stat_t *sb, glob_t *pglob)
979 {
980   char buf[MAXPATHLEN];
981 
982   _DIAGASSERT(fn != NULL);
983   _DIAGASSERT(sb != NULL);
984   _DIAGASSERT(pglob != NULL);
985 
986   if (g_Ctoc(fn, buf, sizeof(buf)))
987     return -1;
988   if (pglob->gl_flags & GLOB_ALTDIRFUNC)
989     return (*pglob->gl_stat)(buf, sb);
990   return stat(buf, sb);
991 }
992 
993 static Char *
g_strchr(const Char * str,int ch)994 g_strchr(const Char *str, int ch)
995 {
996 
997   _DIAGASSERT(str != NULL);
998 
999   do {
1000     if (*str == ch)
1001       return __UNCONST(str);
1002   } while (*str++);
1003   return NULL;
1004 }
1005 
1006 static int
g_Ctoc(const Char * str,char * buf,size_t len)1007 g_Ctoc(const Char *str, char *buf, size_t len)
1008 {
1009   char *dc;
1010 
1011   _DIAGASSERT(str != NULL);
1012   _DIAGASSERT(buf != NULL);
1013 
1014   if (len == 0)
1015     return 1;
1016 
1017   for (dc = buf; len && (*dc++ = *str++) != EOS; len--)
1018     continue;
1019 
1020   return len == 0;
1021 }
1022 
1023 #ifdef DEBUG
1024 static void
qprintf(const char * str,Char * s)1025 qprintf(const char *str, Char *s)
1026 {
1027   Char *p;
1028 
1029   _DIAGASSERT(str != NULL);
1030   _DIAGASSERT(s != NULL);
1031 
1032   (void)printf("%s:\n", str);
1033   for (p = s; *p; p++)
1034     (void)printf("%c", CHAR(*p));
1035   (void)printf("\n");
1036   for (p = s; *p; p++)
1037     (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
1038   (void)printf("\n");
1039   for (p = s; *p; p++)
1040     (void)printf("%c", ismeta(*p) ? '_' : ' ');
1041   (void)printf("\n");
1042 }
1043 #endif
1044