2 * Copyright (c) 2013 Gary Mills
4 /* $OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
6 * Copyright (c) 1989, 1993
7 * The Regents of the University of California. All rights reserved.
9 * This code is derived from software contributed to Berkeley by
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. 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.
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
38 * glob(3) -- a superset of the one defined in POSIX 1003.2.
40 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
42 * Optional extra services, controlled by flags not defined by POSIX:
45 * Escaping convention: \ inhibits any special meaning the following
46 * character might have (except \ at end of string is retained).
48 * Set in gl_flags if pattern contained a globbing character.
50 * Same as GLOB_NOCHECK, but it will only append pattern if it did
51 * not contain any magic characters. [Used in csh style globbing]
53 * Use alternately specified directory access functions.
55 * expand ~user/foo to the /home/dir/of/user/foo
57 * expand {1,2}{a,b} to 1a 1b 2a 2b
59 * Number of matches in the current invocation of glob.
64 #include <sys/param.h>
81 * This is the legacy glob_t prior to illumos enhancement 1097,
82 * used when old programs call the old libc glob functions.
83 * (New programs call the _glob_ext, _globfree_ext functions.)
84 * This struct should be considered "carved in stone".
86 typedef struct old_glob
{
87 size_t gl_pathc
; /* Count of paths matched by pattern */
88 char **gl_pathv
; /* List of matched pathnames */
89 size_t gl_offs
; /* # of slots reserved in gl_pathv */
90 /* following are internal to the implementation */
91 char **gl_pathp
; /* gl_pathv + gl_offs */
92 int gl_pathn
; /* # of elements allocated */
96 * For old programs, the external names need to be the old names:
97 * glob() and globfree() . We've redefined those already to
98 * _glob_ext() and _globfree_ext() . Now redefine old_glob()
99 * and old_globfree() to glob() and globfree() .
101 #ifdef __PRAGMA_REDEFINE_EXTNAME
102 #pragma redefine_extname old_glob glob
103 #pragma redefine_extname old_globfree globfree
104 #endif /* __PRAGMA_REDEFINE_EXTNAME */
105 extern int old_glob(const char *, int, int (*)(const char *, int),
107 extern void old_globfree(old_glob_t
*);
110 * The various extensions to glob(3C) allow for stat and dirent structures to
111 * show up whose size may change in a largefile environment. If libc defines
112 * _FILE_OFFSET_BITS to be 64 that is the key to indicate that we're building
113 * the LFS version of this file. As such, we rename the public functions here,
114 * _glob_ext() and _globfree_ext() to have a 64 suffix. When building the LFS
115 * version, we do not include the old versions.
117 #if !defined(_LP64) && _FILE_OFFSET_BITS == 64
118 #define _glob_ext _glob_ext64
119 #define _globfree_ext _globfree_ext64
120 #endif /* !_LP64 && _FILE_OFFSET_BITS == 64 */
134 #define UNDERSCORE '_'
141 #define M_QUOTE 0x800000
142 #define M_PROTECT 0x400000
144 typedef struct wcat
{
149 #define M_ALL '*' /* Plus M_QUOTE */
150 #define M_END ']' /* Plus M_QUOTE */
151 #define M_NOT '!' /* Plus M_QUOTE */
152 #define M_ONE '?' /* Plus M_QUOTE */
153 #define M_RNG '-' /* Plus M_QUOTE */
154 #define M_SET '[' /* Plus M_QUOTE */
155 #define M_CLASS ':' /* Plus M_QUOTE */
156 #define ismeta(c) (((c).w_at&M_QUOTE) != 0)
158 #define INITIAL 8 /* initial pathv allocation */
160 #define GLOB_LIMIT_MALLOC 65536
161 #define GLOB_LIMIT_STAT 2048
162 #define GLOB_LIMIT_READDIR 16384
164 /* Limit of recursion during matching attempts. */
165 #define GLOB_LIMIT_RECUR 64
173 struct glob_path_stat
{
175 struct stat
*gps_stat
;
178 static int compare(const void *, const void *);
179 static int compare_gps(const void *, const void *);
180 static int g_Ctoc(const wcat_t
*, char *, uint_t
);
181 static int g_lstat(wcat_t
*, struct stat
*, glob_t
*);
182 static DIR *g_opendir(wcat_t
*, glob_t
*);
183 static wcat_t
*g_strchr(const wcat_t
*, wchar_t);
184 static int g_stat(wcat_t
*, struct stat
*, glob_t
*);
185 static int glob0(const wcat_t
*, glob_t
*, struct glob_lim
*,
186 int (*)(const char *, int));
187 static int glob1(wcat_t
*, wcat_t
*, glob_t
*, struct glob_lim
*,
188 int (*)(const char *, int));
189 static int glob2(wcat_t
*, wcat_t
*, wcat_t
*, wcat_t
*, wcat_t
*,
190 wcat_t
*, glob_t
*, struct glob_lim
*,
191 int (*)(const char *, int));
192 static int glob3(wcat_t
*, wcat_t
*, wcat_t
*, wcat_t
*, wcat_t
*,
193 wcat_t
*, wcat_t
*, glob_t
*, struct glob_lim
*,
194 int (*)(const char *, int));
195 static int globextend(const wcat_t
*, glob_t
*, struct glob_lim
*,
198 const wcat_t
*globtilde(const wcat_t
*, wcat_t
*, size_t, glob_t
*);
199 static int globexp1(const wcat_t
*, glob_t
*, struct glob_lim
*,
200 int (*)(const char *, int));
201 static int globexp2(const wcat_t
*, const wcat_t
*, glob_t
*,
202 struct glob_lim
*, int (*)(const char *, int));
203 static int match(wcat_t
*, wcat_t
*, wcat_t
*, int);
206 * Extended glob() function, selected by #pragma redefine_extname
207 * in glob.h with the external name _glob_ext() .
210 _glob_ext(const char *pattern
, int flags
, int (*errfunc
)(const char *, int),
217 wcat_t
*bufnext
, *bufend
, patbuf
[MAXPATHLEN
];
218 struct glob_lim limit
= { 0, 0, 0 };
220 if ((patlen
= strnlen(pattern
, PATH_MAX
)) == PATH_MAX
)
221 return (GLOB_NOMATCH
);
224 if (!(flags
& GLOB_APPEND
)) {
227 pglob
->gl_pathv
= NULL
;
228 if ((flags
& GLOB_KEEPSTAT
) != 0)
229 pglob
->gl_statv
= NULL
;
230 if (!(flags
& GLOB_DOOFFS
))
233 pglob
->gl_flags
= flags
& ~GLOB_MAGCHAR
;
234 pglob
->gl_matchc
= 0;
236 if (pglob
->gl_offs
>= INT_MAX
|| pglob
->gl_pathc
>= INT_MAX
||
237 pglob
->gl_pathc
>= INT_MAX
- pglob
->gl_offs
- 1)
238 return (GLOB_NOSPACE
);
241 bufend
= bufnext
+ MAXPATHLEN
- 1;
243 if (flags
& GLOB_NOESCAPE
) {
244 while (bufnext
< bufend
) {
245 if ((n
= mbtowc(&c
, patnext
, patlen
)) > 0) {
249 (bufnext
++)->w_wc
= c
;
253 return (GLOB_NOMATCH
);
257 /* Protect the quoted characters. */
258 while (bufnext
< bufend
) {
259 if ((n
= mbtowc(&c
, patnext
, patlen
)) > 0) {
263 n
= mbtowc(&c
, patnext
, patlen
);
265 return (GLOB_NOMATCH
);
272 bufnext
->w_at
= M_PROTECT
;
273 (bufnext
++)->w_wc
= c
;
276 (bufnext
++)->w_wc
= c
;
281 return (GLOB_NOMATCH
);
288 if (flags
& GLOB_BRACE
)
289 return (globexp1(patbuf
, pglob
, &limit
, errfunc
));
291 return (glob0(patbuf
, pglob
, &limit
, errfunc
));
295 * Expand recursively a glob {} pattern. When there is no more expansion
296 * invoke the standard globbing routine to glob the rest of the magic
300 globexp1(const wcat_t
*pattern
, glob_t
*pglob
, struct glob_lim
*limitp
,
301 int (*errfunc
)(const char *, int))
303 const wcat_t
*ptr
= pattern
;
305 /* Protect a single {}, for find(1), like csh */
306 if (pattern
[0].w_wc
== LBRACE
&& pattern
[1].w_wc
== RBRACE
&&
307 pattern
[2].w_wc
== EOS
)
308 return (glob0(pattern
, pglob
, limitp
, errfunc
));
310 if ((ptr
= (const wcat_t
*) g_strchr(ptr
, LBRACE
)) != NULL
)
311 return (globexp2(ptr
, pattern
, pglob
, limitp
, errfunc
));
313 return (glob0(pattern
, pglob
, limitp
, errfunc
));
318 * Recursive brace globbing helper. Tries to expand a single brace.
319 * If it succeeds then it invokes globexp1 with the new pattern.
320 * If it fails then it tries to glob the rest of the pattern and returns.
323 globexp2(const wcat_t
*ptr
, const wcat_t
*pattern
, glob_t
*pglob
,
324 struct glob_lim
*limitp
, int (*errfunc
)(const char *, int))
328 const wcat_t
*pe
, *pm
, *pl
;
329 wcat_t patbuf
[MAXPATHLEN
];
331 /* copy part up to the brace */
332 for (lm
= patbuf
, pm
= pattern
; pm
!= ptr
; *lm
++ = *pm
++)
338 /* Find the balanced brace */
339 for (i
= 0, pe
= ++ptr
; pe
->w_wc
!= EOS
; pe
++)
340 if (pe
->w_wc
== LBRACKET
) {
341 /* Ignore everything between [] */
342 for (pm
= pe
++; pe
->w_wc
!= RBRACKET
&&
343 pe
->w_wc
!= EOS
; pe
++)
345 if (pe
->w_wc
== EOS
) {
347 * We could not find a matching RBRACKET.
348 * Ignore and just look for RBRACE
352 } else if (pe
->w_wc
== LBRACE
) {
354 } else if (pe
->w_wc
== RBRACE
) {
360 /* Non matching braces; just glob the pattern */
361 if (i
!= 0 || pe
->w_wc
== EOS
)
362 return (glob0(patbuf
, pglob
, limitp
, errfunc
));
364 for (i
= 0, pl
= pm
= ptr
; pm
<= pe
; pm
++) {
367 /* Ignore everything between [] */
368 for (pl
= pm
++; pm
->w_wc
!= RBRACKET
&& pm
->w_wc
!= EOS
;
371 if (pm
->w_wc
== EOS
) {
373 * We could not find a matching RBRACKET.
374 * Ignore and just look for RBRACE
391 if (i
&& pm
->w_wc
== COMMA
)
394 /* Append the current string */
395 for (lm
= ls
; (pl
< pm
); *lm
++ = *pl
++)
399 * Append the rest of the pattern after the
403 (*lm
++ = *pl
++).w_wc
!= EOS
; /* */)
406 /* Expand the current pattern */
407 rv
= globexp1(patbuf
, pglob
, limitp
, errfunc
);
408 if (rv
&& rv
!= GLOB_NOMATCH
)
411 /* move after the comma, to the next string */
426 * expand tilde from the passwd file.
428 static const wcat_t
*
429 globtilde(const wcat_t
*pattern
, wcat_t
*patbuf
, size_t patbuf_len
,
440 if (pattern
->w_wc
!= TILDE
|| !(pglob
->gl_flags
& GLOB_TILDE
))
443 /* Copy up to the end of the string or / */
444 eb
= &patbuf
[patbuf_len
- 1];
445 for (p
= pattern
+ 1, q
= patbuf
;
446 q
< eb
&& p
->w_wc
!= EOS
&& p
->w_wc
!= SLASH
; *q
++ = *p
++)
452 /* What to do if patbuf is full? */
454 if (patbuf
[0].w_wc
== EOS
) {
456 * handle a plain ~ or ~/ by expanding $HOME
457 * first and then trying the password file
459 if (issetugid() != 0)
461 if ((h
= getenv("HOME")) == NULL
) {
462 if ((pwd
= getpwuid(getuid())) == NULL
)
471 if ((pwd
= getpwnam((char *)patbuf
)) == NULL
)
477 /* Copy the home directory */
478 lenh
= strlen(h
) + 1;
479 for (b
= patbuf
; b
< eb
&& *h
!= EOS
; b
++) {
480 if ((n
= mbtowc(&c
, h
, lenh
)) > 0) {
492 /* Append the rest of the pattern */
493 while (b
< eb
&& (*b
++ = *p
++).w_wc
!= EOS
)
502 g_charclass(const wcat_t
**patternp
, wcat_t
**bufnextp
)
504 const wcat_t
*pattern
= *patternp
+ 1;
505 wcat_t
*bufnext
= *bufnextp
;
507 char cbuf
[MB_LEN_MAX
+ 32];
511 if ((colon
= g_strchr(pattern
, COLON
)) == NULL
||
512 colon
[1].w_wc
!= RBRACKET
)
513 return (1); /* not a character class */
515 len
= (size_t)(colon
- pattern
);
516 if (len
+ MB_LEN_MAX
+ 1 > sizeof (cbuf
))
517 return (-1); /* invalid character class */
520 const wcat_t
*s1
= pattern
;
524 /* Copy the string. */
527 /* Character class names must be ASCII. */
532 return (-1); /* invalid character class */
537 if ((cc
= wctype(cbuf
)) == 0)
538 return (-1); /* invalid character class */
539 bufnext
->w_at
= M_QUOTE
;
540 (bufnext
++)->w_wc
= M_CLASS
;
542 (bufnext
++)->w_wc
= cc
;
544 *patternp
+= len
+ 3;
550 * The main glob() routine: compiles the pattern (optionally processing
551 * quotes), calls glob1() to do the real pattern matching, and finally
552 * sorts the list (unless unsorted operation is requested). Returns 0
553 * if things went well, nonzero if errors occurred. It is not an error
554 * to find no matches.
557 glob0(const wcat_t
*pattern
, glob_t
*pglob
, struct glob_lim
*limitp
,
558 int (*errfunc
)(const char *, int))
560 const wcat_t
*qpatnext
;
564 wcat_t
*bufnext
, patbuf
[MAXPATHLEN
];
566 qpatnext
= globtilde(pattern
, patbuf
, MAXPATHLEN
, pglob
);
567 oldpathc
= pglob
->gl_pathc
;
571 * We don't need to check for buffer overflow any more.
572 * The pattern has already been copied to an internal buffer.
574 while ((a
= qpatnext
->w_at
), (c
= (qpatnext
++)->w_wc
) != EOS
) {
579 (bufnext
++)->w_wc
= c
;
584 if (a
== 0 && c
== NOT
)
586 if (qpatnext
->w_wc
== EOS
||
587 g_strchr(qpatnext
+1, RBRACKET
) == NULL
) {
589 (bufnext
++)->w_wc
= LBRACKET
;
590 if (a
== 0 && c
== NOT
)
594 bufnext
->w_at
= M_QUOTE
;
595 (bufnext
++)->w_wc
= M_SET
;
596 if (a
== 0 && c
== NOT
) {
597 bufnext
->w_at
= M_QUOTE
;
598 (bufnext
++)->w_wc
= M_NOT
;
601 c
= (qpatnext
++)->w_wc
;
603 if (a
== 0 && c
== LBRACKET
&&
604 qpatnext
->w_wc
== COLON
) {
606 err
= g_charclass(&qpatnext
,
611 c
= (qpatnext
++)->w_wc
;
612 } while (a
== 0 && c
== LBRACKET
&&
613 qpatnext
->w_wc
== COLON
);
615 !(pglob
->gl_flags
& GLOB_NOCHECK
))
616 return (GLOB_NOMATCH
);
617 if (a
== 0 && c
== RBRACKET
)
621 (bufnext
++)->w_wc
= c
;
622 if (qpatnext
->w_at
== 0 &&
623 qpatnext
->w_wc
== RANGE
) {
624 a
= qpatnext
[1].w_at
;
625 c
= qpatnext
[1].w_wc
;
626 if (qpatnext
[1].w_at
!= 0 ||
627 qpatnext
[1].w_wc
!= RBRACKET
) {
628 bufnext
->w_at
= M_QUOTE
;
629 (bufnext
++)->w_wc
= M_RNG
;
631 (bufnext
++)->w_wc
= c
;
636 c
= (qpatnext
++)->w_wc
;
637 } while (a
!= 0 || c
!= RBRACKET
);
638 pglob
->gl_flags
|= GLOB_MAGCHAR
;
639 bufnext
->w_at
= M_QUOTE
;
640 (bufnext
++)->w_wc
= M_END
;
645 (bufnext
++)->w_wc
= c
;
648 pglob
->gl_flags
|= GLOB_MAGCHAR
;
649 bufnext
->w_at
= M_QUOTE
;
650 (bufnext
++)->w_wc
= M_ONE
;
655 (bufnext
++)->w_wc
= c
;
658 pglob
->gl_flags
|= GLOB_MAGCHAR
;
660 * collapse adjacent stars to one,
661 * to avoid exponential behavior
663 if (bufnext
== patbuf
||
664 bufnext
[-1].w_at
!= M_QUOTE
||
665 bufnext
[-1].w_wc
!= M_ALL
) {
666 bufnext
->w_at
= M_QUOTE
;
667 (bufnext
++)->w_wc
= M_ALL
;
672 (bufnext
++)->w_wc
= c
;
679 if ((err
= glob1(patbuf
, patbuf
+MAXPATHLEN
-1, pglob
, limitp
, errfunc
))
684 * If there was no match we are going to append the pattern
685 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
686 * and the pattern did not contain any magic characters
687 * GLOB_NOMAGIC is there just for compatibility with csh.
689 if (pglob
->gl_pathc
== oldpathc
) {
690 if ((pglob
->gl_flags
& GLOB_NOCHECK
) ||
691 ((pglob
->gl_flags
& GLOB_NOMAGIC
) &&
692 !(pglob
->gl_flags
& GLOB_MAGCHAR
)))
693 return (globextend(pattern
, pglob
, limitp
, NULL
));
695 return (GLOB_NOMATCH
);
697 if (!(pglob
->gl_flags
& GLOB_NOSORT
)) {
698 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
)) {
699 /* Keep the paths and stat info synced during sort */
700 struct glob_path_stat
*path_stat
;
702 int n
= pglob
->gl_pathc
- oldpathc
;
703 int o
= pglob
->gl_offs
+ oldpathc
;
705 if ((path_stat
= calloc(n
, sizeof (*path_stat
))) ==
707 return (GLOB_NOSPACE
);
708 for (i
= 0; i
< n
; i
++) {
709 path_stat
[i
].gps_path
= pglob
->gl_pathv
[o
+ i
];
710 path_stat
[i
].gps_stat
= pglob
->gl_statv
[o
+ i
];
712 qsort(path_stat
, n
, sizeof (*path_stat
), compare_gps
);
713 for (i
= 0; i
< n
; i
++) {
714 pglob
->gl_pathv
[o
+ i
] = path_stat
[i
].gps_path
;
715 pglob
->gl_statv
[o
+ i
] = path_stat
[i
].gps_stat
;
719 qsort(pglob
->gl_pathv
+ pglob
->gl_offs
+ oldpathc
,
720 pglob
->gl_pathc
- oldpathc
, sizeof (char *),
728 compare(const void *p
, const void *q
)
730 return (strcmp(*(char **)p
, *(char **)q
));
734 compare_gps(const void *_p
, const void *_q
)
736 const struct glob_path_stat
*p
= (const struct glob_path_stat
*)_p
;
737 const struct glob_path_stat
*q
= (const struct glob_path_stat
*)_q
;
739 return (strcmp(p
->gps_path
, q
->gps_path
));
743 glob1(wcat_t
*pattern
, wcat_t
*pattern_last
, glob_t
*pglob
,
744 struct glob_lim
*limitp
, int (*errfunc
)(const char *, int))
746 wcat_t pathbuf
[MAXPATHLEN
];
748 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
749 if (pattern
->w_wc
== EOS
)
751 return (glob2(pathbuf
, pathbuf
+MAXPATHLEN
-1,
752 pathbuf
, pathbuf
+MAXPATHLEN
-1,
753 pattern
, pattern_last
, pglob
, limitp
, errfunc
));
757 * The functions glob2 and glob3 are mutually recursive; there is one level
758 * of recursion for each segment in the pattern that contains one or more
762 glob2(wcat_t
*pathbuf
, wcat_t
*pathbuf_last
, wcat_t
*pathend
,
763 wcat_t
*pathend_last
, wcat_t
*pattern
, wcat_t
*pattern_last
,
764 glob_t
*pglob
, struct glob_lim
*limitp
, int (*errfunc
)(const char *, int))
771 * Loop over pattern segments until end of pattern or until
772 * segment with meta character found.
774 for (anymeta
= 0; ; ) {
775 if (pattern
->w_wc
== EOS
) { /* End of pattern? */
779 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
780 limitp
->glim_stat
++ >= GLOB_LIMIT_STAT
) {
783 (pathend
++)->w_wc
= SEP
;
786 return (GLOB_NOSPACE
);
788 if (g_lstat(pathbuf
, &sb
, pglob
))
791 if (((pglob
->gl_flags
& GLOB_MARK
) &&
792 (pathend
[-1].w_at
!= 0 ||
793 pathend
[-1].w_wc
!= SEP
)) &&
794 (S_ISDIR(sb
.st_mode
) ||
795 (S_ISLNK(sb
.st_mode
) &&
796 (g_stat(pathbuf
, &sb
, pglob
) == 0) &&
797 S_ISDIR(sb
.st_mode
)))) {
798 if (pathend
+1 > pathend_last
)
799 return (GLOB_NOSPACE
);
801 (pathend
++)->w_wc
= SEP
;
806 return (globextend(pathbuf
, pglob
, limitp
, &sb
));
809 /* Find end of next segment, copy tentatively to pathend. */
812 while (p
->w_wc
!= EOS
&& p
->w_wc
!= SEP
) {
815 if (q
+1 > pathend_last
)
816 return (GLOB_NOSPACE
);
820 if (!anymeta
) { /* No expansion, do next segment. */
823 while (pattern
->w_wc
== SEP
) {
824 if (pathend
+1 > pathend_last
)
825 return (GLOB_NOSPACE
);
826 *pathend
++ = *pattern
++;
829 /* Need expansion, recurse. */
830 return (glob3(pathbuf
, pathbuf_last
, pathend
,
831 pathend_last
, pattern
, p
, pattern_last
,
832 pglob
, limitp
, errfunc
));
839 glob3(wcat_t
*pathbuf
, wcat_t
*pathbuf_last
, wcat_t
*pathend
,
840 wcat_t
*pathend_last
, wcat_t
*pattern
, wcat_t
*restpattern
,
841 wcat_t
*restpattern_last
, glob_t
*pglob
, struct glob_lim
*limitp
,
842 int (*errfunc
)(const char *, int))
847 char buf
[MAXPATHLEN
];
850 * The readdirfunc declaration can't be prototyped, because it is
851 * assigned, below, to two functions which are prototyped in glob.h
852 * and dirent.h as taking pointers to differently typed opaque
855 struct dirent
*(*readdirfunc
)(void *);
857 if (pathend
> pathend_last
)
858 return (GLOB_NOSPACE
);
863 if ((dirp
= g_opendir(pathbuf
, pglob
)) == NULL
) {
864 /* TODO: don't call for ENOENT or ENOTDIR? */
866 if (g_Ctoc(pathbuf
, buf
, sizeof (buf
)))
867 return (GLOB_ABORTED
);
868 if (errfunc(buf
, errno
) ||
869 pglob
->gl_flags
& GLOB_ERR
)
870 return (GLOB_ABORTED
);
877 /* Search directory for matching names. */
878 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
879 readdirfunc
= pglob
->gl_readdir
;
881 readdirfunc
= (struct dirent
*(*)(void *))readdir
;
882 while ((dp
= (*readdirfunc
)(dirp
))) {
889 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
890 limitp
->glim_readdir
++ >= GLOB_LIMIT_READDIR
) {
893 (pathend
++)->w_wc
= SEP
;
900 /* Initial DOT must be matched literally. */
901 if (dp
->d_name
[0] == DOT
&& pattern
->w_wc
!= DOT
)
905 lensc
= strlen(sc
) + 1;
906 while (dc
< pathend_last
) {
907 if ((n
= mbtowc(&w
, sc
, lensc
)) <= 0) {
922 if (dc
>= pathend_last
) {
933 if (!match(pathend
, pattern
, restpattern
, GLOB_LIMIT_RECUR
)) {
938 err
= glob2(pathbuf
, pathbuf_last
, --dc
, pathend_last
,
939 restpattern
, restpattern_last
, pglob
, limitp
,
945 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
946 (*pglob
->gl_closedir
)(dirp
);
948 (void) closedir(dirp
);
954 * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
955 * add the new item, and update gl_pathc. Avoids excessive reallocation
956 * by doubling the number of elements each time. Uses gl_pathn to contain
959 * Return 0 if new item added, error code if memory couldn't be allocated.
961 * Invariant of the glob_t structure:
962 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
963 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
966 globextend(const wcat_t
*path
, glob_t
*pglob
, struct glob_lim
*limitp
,
971 size_t allocn
, newn
, len
;
975 char junk
[MB_LEN_MAX
];
978 allocn
= pglob
->gl_pathn
;
979 newn
= 2 + pglob
->gl_pathc
+ pglob
->gl_offs
;
981 if (newn
<= allocn
) {
982 pathv
= pglob
->gl_pathv
;
983 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
) != 0)
984 statv
= pglob
->gl_statv
;
987 allocn
= pglob
->gl_offs
+ INITIAL
;
989 if (pglob
->gl_offs
>= INT_MAX
||
990 pglob
->gl_pathc
>= INT_MAX
||
992 SIZE_MAX
/ sizeof (*pathv
) <= allocn
||
993 SIZE_MAX
/ sizeof (*statv
) <= allocn
) {
995 for (i
= pglob
->gl_offs
; i
< (ssize_t
)(newn
- 2);
997 if (pglob
->gl_pathv
&& pglob
->gl_pathv
[i
])
998 free(pglob
->gl_pathv
[i
]);
999 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
) != 0 &&
1000 pglob
->gl_statv
&& pglob
->gl_statv
[i
])
1001 free(pglob
->gl_statv
[i
]);
1003 if (pglob
->gl_pathv
) {
1004 free(pglob
->gl_pathv
);
1005 pglob
->gl_pathv
= NULL
;
1007 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
) != 0 &&
1009 free(pglob
->gl_statv
);
1010 pglob
->gl_statv
= NULL
;
1012 return (GLOB_NOSPACE
);
1014 limitp
->glim_malloc
+= allocn
* sizeof (*pathv
);
1015 pathv
= realloc(pglob
->gl_pathv
, allocn
* sizeof (*pathv
));
1018 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
) != 0) {
1019 limitp
->glim_malloc
+= allocn
* sizeof (*statv
);
1020 statv
= realloc(pglob
->gl_statv
,
1021 allocn
* sizeof (*statv
));
1026 pglob
->gl_pathn
= allocn
;
1028 if (pglob
->gl_pathv
== NULL
&& pglob
->gl_offs
> 0) {
1029 /* first time around -- clear initial gl_offs items */
1030 pathv
+= pglob
->gl_offs
;
1031 for (i
= pglob
->gl_offs
; --i
>= 0; )
1034 pglob
->gl_pathv
= pathv
;
1036 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
) != 0) {
1037 if (pglob
->gl_statv
== NULL
&& pglob
->gl_offs
> 0) {
1038 /* first time around -- clear initial gl_offs items */
1039 statv
+= pglob
->gl_offs
;
1040 for (i
= pglob
->gl_offs
; --i
>= 0; )
1043 pglob
->gl_statv
= statv
;
1045 statv
[pglob
->gl_offs
+ pglob
->gl_pathc
] = NULL
;
1047 limitp
->glim_malloc
+= sizeof (**statv
);
1048 if ((statv
[pglob
->gl_offs
+ pglob
->gl_pathc
] =
1049 malloc(sizeof (**statv
))) == NULL
)
1051 (void) memcpy(statv
[pglob
->gl_offs
+ pglob
->gl_pathc
],
1054 statv
[pglob
->gl_offs
+ pglob
->gl_pathc
+ 1] = NULL
;
1059 while ((n
= wctomb(junk
, p
->w_wc
)) > 0) {
1061 if ((p
++)->w_wc
== EOS
)
1065 return (GLOB_NOMATCH
);
1067 limitp
->glim_malloc
+= len
;
1068 if ((copy
= malloc(len
)) != NULL
) {
1069 if (g_Ctoc(path
, copy
, len
)) {
1071 return (GLOB_NOSPACE
);
1073 pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
++] = copy
;
1075 pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
] = NULL
;
1077 if ((pglob
->gl_flags
& GLOB_LIMIT
) &&
1078 limitp
->glim_malloc
>= GLOB_LIMIT_MALLOC
) {
1080 return (GLOB_NOSPACE
);
1083 return (copy
== NULL
? GLOB_NOSPACE
: 0);
1088 * pattern matching function for filenames. Each occurrence of the *
1089 * pattern causes a recursion level.
1092 match(wcat_t
*name
, wcat_t
*pat
, wcat_t
*patend
, int recur
)
1094 int ok
, negate_range
;
1100 while (pat
< patend
) {
1104 if (c
.w_at
!= M_QUOTE
) {
1106 if (k
.w_at
!= c
.w_at
|| k
.w_wc
!= c
.w_wc
)
1110 while (pat
< patend
&& pat
->w_at
== M_QUOTE
&&
1112 pat
++; /* eat consecutive '*' */
1116 if (match(name
, pat
, patend
, recur
))
1118 } while ((name
++)->w_wc
!= EOS
);
1121 if (c
.w_at
!= M_QUOTE
) {
1123 if (k
.w_at
!= c
.w_at
|| k
.w_wc
!= c
.w_wc
)
1127 if ((name
++)->w_wc
== EOS
)
1131 if (c
.w_at
!= M_QUOTE
) {
1133 if (k
.w_at
!= c
.w_at
|| k
.w_wc
!= c
.w_wc
)
1138 if ((k
= *name
++).w_wc
== EOS
)
1140 if ((negate_range
= (pat
->w_at
== M_QUOTE
&&
1141 pat
->w_wc
== M_NOT
)) != 0)
1143 while (((c
= *pat
++).w_at
!= M_QUOTE
) ||
1145 if (c
.w_at
== M_QUOTE
&& c
.w_wc
== M_CLASS
) {
1148 cc
.w_at
= pat
->w_at
;
1149 cc
.w_wc
= pat
->w_wc
;
1150 if (iswctype(k
.w_wc
, cc
.w_wc
))
1154 if (pat
->w_at
== M_QUOTE
&&
1155 pat
->w_wc
== M_RNG
) {
1156 if (c
.w_wc
<= k
.w_wc
&&
1157 k
.w_wc
<= pat
[1].w_wc
)
1160 } else if (c
.w_wc
== k
.w_wc
)
1163 if (ok
== negate_range
)
1168 if (k
.w_at
!= c
.w_at
|| k
.w_wc
!= c
.w_wc
)
1173 return (name
->w_wc
== EOS
);
1177 * Extended globfree() function, selected by #pragma redefine_extname
1178 * in glob.h with the external name _globfree_ext() .
1181 _globfree_ext(glob_t
*pglob
)
1186 if (pglob
->gl_pathv
!= NULL
) {
1187 pp
= pglob
->gl_pathv
+ pglob
->gl_offs
;
1188 for (i
= pglob
->gl_pathc
; i
--; ++pp
)
1191 free(pglob
->gl_pathv
);
1192 pglob
->gl_pathv
= NULL
;
1194 if ((pglob
->gl_flags
& GLOB_KEEPSTAT
) != 0 &&
1195 pglob
->gl_statv
!= NULL
) {
1196 for (i
= 0; i
< pglob
->gl_pathc
; i
++) {
1197 if (pglob
->gl_statv
[i
] != NULL
)
1198 free(pglob
->gl_statv
[i
]);
1200 free(pglob
->gl_statv
);
1201 pglob
->gl_statv
= NULL
;
1206 g_opendir(wcat_t
*str
, glob_t
*pglob
)
1208 char buf
[MAXPATHLEN
];
1210 if (str
->w_wc
== EOS
)
1211 (void) strlcpy(buf
, ".", sizeof (buf
));
1213 if (g_Ctoc(str
, buf
, sizeof (buf
)))
1217 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1218 return ((*pglob
->gl_opendir
)(buf
));
1220 return (opendir(buf
));
1224 g_lstat(wcat_t
*fn
, struct stat
*sb
, glob_t
*pglob
)
1226 char buf
[MAXPATHLEN
];
1228 if (g_Ctoc(fn
, buf
, sizeof (buf
)))
1230 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1231 return ((*pglob
->gl_lstat
)(buf
, sb
));
1232 return (lstat(buf
, sb
));
1236 g_stat(wcat_t
*fn
, struct stat
*sb
, glob_t
*pglob
)
1238 char buf
[MAXPATHLEN
];
1240 if (g_Ctoc(fn
, buf
, sizeof (buf
)))
1242 if (pglob
->gl_flags
& GLOB_ALTDIRFUNC
)
1243 return ((*pglob
->gl_stat
)(buf
, sb
));
1244 return (stat(buf
, sb
));
1248 g_strchr(const wcat_t
*str
, wchar_t ch
)
1251 if (str
->w_at
== 0 && str
->w_wc
== ch
)
1252 return ((wcat_t
*)str
);
1253 } while ((str
++)->w_wc
!= EOS
);
1258 g_Ctoc(const wcat_t
*str
, char *buf
, uint_t len
)
1263 while (len
>= MB_LEN_MAX
) {
1265 if ((n
= wctomb(buf
, w
)) > 0) {
1277 #if defined(_LP64) || _FILE_OFFSET_BITS != 64
1279 /* glob() function with legacy glob structure */
1281 old_glob(const char *pattern
, int flags
, int (*errfunc
)(const char *, int),
1288 flags
&= GLOB_POSIX
;
1290 (void) memset(&gl
, 0, sizeof (gl
));
1293 * Copy all the members, old to new. There's
1294 * really no point in micro-optimizing the copying.
1295 * Other members are set to zero.
1297 gl
.gl_pathc
= pglob
->gl_pathc
;
1298 gl
.gl_pathv
= pglob
->gl_pathv
;
1299 gl
.gl_offs
= pglob
->gl_offs
;
1300 gl
.gl_pathp
= pglob
->gl_pathp
;
1301 gl
.gl_pathn
= pglob
->gl_pathn
;
1303 rv
= _glob_ext(pattern
, flags
, errfunc
, &gl
);
1306 * Copy all the members, new to old. There's
1307 * really no point in micro-optimizing the copying.
1309 pglob
->gl_pathc
= gl
.gl_pathc
;
1310 pglob
->gl_pathv
= gl
.gl_pathv
;
1311 pglob
->gl_offs
= gl
.gl_offs
;
1312 pglob
->gl_pathp
= gl
.gl_pathp
;
1313 pglob
->gl_pathn
= gl
.gl_pathn
;
1318 /* globfree() function with legacy glob structure */
1320 old_globfree(old_glob_t
*pglob
)
1324 (void) memset(&gl
, 0, sizeof (gl
));
1327 * Copy all the members, old to new. There's
1328 * really no point in micro-optimizing the copying.
1329 * Other members are set to zero.
1331 gl
.gl_pathc
= pglob
->gl_pathc
;
1332 gl
.gl_pathv
= pglob
->gl_pathv
;
1333 gl
.gl_offs
= pglob
->gl_offs
;
1334 gl
.gl_pathp
= pglob
->gl_pathp
;
1335 gl
.gl_pathn
= pglob
->gl_pathn
;
1340 * Copy all the members, new to old. There's
1341 * really no point in micro-optimizing the copying.
1343 pglob
->gl_pathc
= gl
.gl_pathc
;
1344 pglob
->gl_pathv
= gl
.gl_pathv
;
1345 pglob
->gl_offs
= gl
.gl_offs
;
1346 pglob
->gl_pathp
= gl
.gl_pathp
;
1347 pglob
->gl_pathn
= gl
.gl_pathn
;
1351 #endif /* _LP64 || _FILE_OFFSET_BITS != 64 */