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