xref: /illumos-gate/usr/src/lib/libc/port/regex/glob.c (revision 33e8313d)
1 /*
2  * Copyright (c) 2013 Gary Mills
3  */
4 /*	$OpenBSD: glob.c,v 1.39 2012/01/20 07:09:42 tedu Exp $ */
5 /*
6  * Copyright (c) 1989, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Guido van Rossum.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
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.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 /*
38  * glob(3) -- a superset of the one defined in POSIX 1003.2.
39  *
40  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
41  *
42  * Optional extra services, controlled by flags not defined by POSIX:
43  *
44  * GLOB_QUOTE:
45  *	Escaping convention: \ inhibits any special meaning the following
46  *	character might have (except \ at end of string is retained).
47  * GLOB_MAGCHAR:
48  *	Set in gl_flags if pattern contained a globbing character.
49  * GLOB_NOMAGIC:
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]
52  * GLOB_ALTDIRFUNC:
53  *	Use alternately specified directory access functions.
54  * GLOB_TILDE:
55  *	expand ~user/foo to the /home/dir/of/user/foo
56  * GLOB_BRACE:
57  *	expand {1,2}{a,b} to 1a 1b 2a 2b
58  * gl_matchc:
59  *	Number of matches in the current invocation of glob.
60  */
61 
62 #include "lint.h"
63 
64 #include <sys/param.h>
65 #include <sys/stat.h>
66 
67 #include <ctype.h>
68 #include <dirent.h>
69 #include <errno.h>
70 #include <glob.h>
71 #include <limits.h>
72 #include <pwd.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <unistd.h>
77 #include <wchar.h>
78 #include <wctype.h>
79 
80 /*
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".
85  */
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 */
93 }	old_glob_t;
94 
95 /*
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() .
100  */
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),
106     old_glob_t *);
107 extern void old_globfree(old_glob_t *);
108 
109 /*
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.
116  */
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 */
121 
122 #define	DOLLAR		'$'
123 #define	DOT		'.'
124 #define	EOS		'\0'
125 #define	LBRACKET	'['
126 #define	NOT		'!'
127 #define	QUESTION	'?'
128 #define	QUOTE		'\\'
129 #define	RANGE		'-'
130 #define	RBRACKET	']'
131 #define	SEP		'/'
132 #define	STAR		'*'
133 #define	TILDE		'~'
134 #define	UNDERSCORE	'_'
135 #define	LBRACE		'{'
136 #define	RBRACE		'}'
137 #define	SLASH		'/'
138 #define	COMMA		','
139 #define	COLON		':'
140 
141 #define	M_QUOTE		0x800000
142 #define	M_PROTECT	0x400000
143 
144 typedef struct wcat {
145 	wchar_t w_wc;
146 	uint_t w_at;
147 } wcat_t;
148 
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)
157 
158 #define	INITIAL			8	/* initial pathv allocation */
159 
160 #define	GLOB_LIMIT_MALLOC	65536
161 #define	GLOB_LIMIT_STAT		2048
162 #define	GLOB_LIMIT_READDIR	16384
163 
164 /* Limit of recursion during matching attempts. */
165 #define	GLOB_LIMIT_RECUR	64
166 
167 struct glob_lim {
168 	size_t	glim_malloc;
169 	size_t	glim_stat;
170 	size_t	glim_readdir;
171 };
172 
173 struct glob_path_stat {
174 	char		*gps_path;
175 	struct stat	*gps_stat;
176 };
177 
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 *,
196 		    struct stat *);
197 static
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);
204 
205 /*
206  * Extended glob() function, selected by #pragma redefine_extname
207  * in glob.h with the external name _glob_ext() .
208  */
209 int
210 _glob_ext(const char *pattern, int flags, int (*errfunc)(const char *, int),
211     glob_t *pglob)
212 {
213 	const char *patnext;
214 	int n;
215 	size_t patlen;
216 	wchar_t c;
217 	wcat_t *bufnext, *bufend, patbuf[MAXPATHLEN];
218 	struct glob_lim limit = { 0, 0, 0 };
219 
220 	if ((patlen = strnlen(pattern, PATH_MAX)) == PATH_MAX)
221 		return (GLOB_NOMATCH);
222 
223 	patnext = pattern;
224 	if (!(flags & GLOB_APPEND)) {
225 		pglob->gl_pathc = 0;
226 		pglob->gl_pathn = 0;
227 		pglob->gl_pathv = NULL;
228 		if ((flags & GLOB_KEEPSTAT) != 0)
229 			pglob->gl_statv = NULL;
230 		if (!(flags & GLOB_DOOFFS))
231 			pglob->gl_offs = 0;
232 	}
233 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
234 	pglob->gl_matchc = 0;
235 
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);
239 
240 	bufnext = patbuf;
241 	bufend = bufnext + MAXPATHLEN - 1;
242 	patlen += 1;
243 	if (flags & GLOB_NOESCAPE) {
244 		while (bufnext < bufend) {
245 			if ((n = mbtowc(&c, patnext, patlen)) > 0) {
246 				patnext += n;
247 				patlen -= n;
248 				bufnext->w_at = 0;
249 				(bufnext++)->w_wc = c;
250 			} else if (n == 0) {
251 				break;
252 			} else {
253 				return (GLOB_NOMATCH);
254 			}
255 		}
256 	} else {
257 		/* Protect the quoted characters. */
258 		while (bufnext < bufend) {
259 			if ((n = mbtowc(&c, patnext, patlen)) > 0) {
260 				patnext += n;
261 				patlen -= n;
262 				if (c == QUOTE) {
263 					n = mbtowc(&c, patnext, patlen);
264 					if (n < 0)
265 						return (GLOB_NOMATCH);
266 					if (n > 0) {
267 						patnext += n;
268 						patlen -= n;
269 					}
270 					if (n == 0)
271 						c = QUOTE;
272 					bufnext->w_at = M_PROTECT;
273 					(bufnext++)->w_wc = c;
274 				} else {
275 					bufnext->w_at = 0;
276 					(bufnext++)->w_wc = c;
277 				}
278 			} else if (n == 0) {
279 				break;
280 			} else {
281 				return (GLOB_NOMATCH);
282 			}
283 		}
284 	}
285 	bufnext->w_at = 0;
286 	bufnext->w_wc = EOS;
287 
288 	if (flags & GLOB_BRACE)
289 		return (globexp1(patbuf, pglob, &limit, errfunc));
290 	else
291 		return (glob0(patbuf, pglob, &limit, errfunc));
292 }
293 
294 /*
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
297  * characters
298  */
299 static int
300 globexp1(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
301     int (*errfunc)(const char *, int))
302 {
303 	const wcat_t *ptr = pattern;
304 
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));
309 
310 	if ((ptr = (const wcat_t *) g_strchr(ptr, LBRACE)) != NULL)
311 		return (globexp2(ptr, pattern, pglob, limitp, errfunc));
312 
313 	return (glob0(pattern, pglob, limitp, errfunc));
314 }
315 
316 
317 /*
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.
321  */
322 static int
323 globexp2(const wcat_t *ptr, const wcat_t *pattern, glob_t *pglob,
324     struct glob_lim *limitp, int (*errfunc)(const char *, int))
325 {
326 	int	i, rv;
327 	wcat_t   *lm, *ls;
328 	const wcat_t *pe, *pm, *pl;
329 	wcat_t    patbuf[MAXPATHLEN];
330 
331 	/* copy part up to the brace */
332 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
333 		;
334 	lm->w_at = 0;
335 	lm->w_wc = EOS;
336 	ls = lm;
337 
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++)
344 				;
345 			if (pe->w_wc == EOS) {
346 				/*
347 				 * We could not find a matching RBRACKET.
348 				 * Ignore and just look for RBRACE
349 				 */
350 				pe = pm;
351 			}
352 		} else if (pe->w_wc == LBRACE) {
353 			i++;
354 		} else if (pe->w_wc == RBRACE) {
355 			if (i == 0)
356 				break;
357 			i--;
358 		}
359 
360 	/* Non matching braces; just glob the pattern */
361 	if (i != 0 || pe->w_wc == EOS)
362 		return (glob0(patbuf, pglob, limitp, errfunc));
363 
364 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
365 		switch (pm->w_wc) {
366 		case LBRACKET:
367 			/* Ignore everything between [] */
368 			for (pl = pm++; pm->w_wc != RBRACKET && pm->w_wc != EOS;
369 			    pm++)
370 				;
371 			if (pm->w_wc == EOS) {
372 				/*
373 				 * We could not find a matching RBRACKET.
374 				 * Ignore and just look for RBRACE
375 				 */
376 				pm = pl;
377 			}
378 			break;
379 
380 		case LBRACE:
381 			i++;
382 			break;
383 
384 		case RBRACE:
385 			if (i) {
386 				i--;
387 				break;
388 			}
389 			/* FALLTHROUGH */
390 		case COMMA:
391 			if (i && pm->w_wc == COMMA)
392 				break;
393 			else {
394 				/* Append the current string */
395 				for (lm = ls; (pl < pm); *lm++ = *pl++)
396 					;
397 
398 				/*
399 				 * Append the rest of the pattern after the
400 				 * closing brace
401 				 */
402 				for (pl = pe + 1;
403 				    (*lm++ = *pl++).w_wc != EOS; /* */)
404 					;
405 
406 				/* Expand the current pattern */
407 				rv = globexp1(patbuf, pglob, limitp, errfunc);
408 				if (rv && rv != GLOB_NOMATCH)
409 					return (rv);
410 
411 				/* move after the comma, to the next string */
412 				pl = pm + 1;
413 			}
414 			break;
415 
416 		default:
417 			break;
418 		}
419 	}
420 	return (0);
421 }
422 
423 
424 
425 /*
426  * expand tilde from the passwd file.
427  */
428 static const wcat_t *
429 globtilde(const wcat_t *pattern, wcat_t *patbuf, size_t patbuf_len,
430     glob_t *pglob)
431 {
432 	struct passwd *pwd;
433 	char *h;
434 	const wcat_t *p;
435 	wcat_t *b, *eb, *q;
436 	int n;
437 	size_t lenh;
438 	wchar_t c;
439 
440 	if (pattern->w_wc != TILDE || !(pglob->gl_flags & GLOB_TILDE))
441 		return (pattern);
442 
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++)
447 		;
448 
449 	q->w_at = 0;
450 	q->w_wc = EOS;
451 
452 	/* What to do if patbuf is full? */
453 
454 	if (patbuf[0].w_wc == EOS) {
455 		/*
456 		 * handle a plain ~ or ~/ by expanding $HOME
457 		 * first and then trying the password file
458 		 */
459 		if (issetugid() != 0)
460 			return (pattern);
461 		if ((h = getenv("HOME")) == NULL) {
462 			if ((pwd = getpwuid(getuid())) == NULL)
463 				return (pattern);
464 			else
465 				h = pwd->pw_dir;
466 		}
467 	} else {
468 		/*
469 		 * Expand a ~user
470 		 */
471 		if ((pwd = getpwnam((char *)patbuf)) == NULL)
472 			return (pattern);
473 		else
474 			h = pwd->pw_dir;
475 	}
476 
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) {
481 			h += n;
482 			lenh -= n;
483 			b->w_at = 0;
484 			b->w_wc = c;
485 		} else if (n < 0) {
486 			return (pattern);
487 		} else {
488 			break;
489 		}
490 	}
491 
492 	/* Append the rest of the pattern */
493 	while (b < eb && (*b++ = *p++).w_wc != EOS)
494 		;
495 	b->w_at = 0;
496 	b->w_wc = EOS;
497 
498 	return (patbuf);
499 }
500 
501 static int
502 g_charclass(const wcat_t **patternp, wcat_t **bufnextp)
503 {
504 	const wcat_t *pattern = *patternp + 1;
505 	wcat_t *bufnext = *bufnextp;
506 	const wcat_t *colon;
507 	char cbuf[MB_LEN_MAX + 32];
508 	wctype_t cc;
509 	size_t len;
510 
511 	if ((colon = g_strchr(pattern, COLON)) == NULL ||
512 	    colon[1].w_wc != RBRACKET)
513 		return (1);	/* not a character class */
514 
515 	len = (size_t)(colon - pattern);
516 	if (len + MB_LEN_MAX + 1 > sizeof (cbuf))
517 		return (-1);	/* invalid character class */
518 	{
519 		wchar_t w;
520 		const wcat_t *s1 = pattern;
521 		char *s2 = cbuf;
522 		size_t n = len;
523 
524 		/* Copy the string. */
525 		while (n > 0) {
526 			w = (s1++)->w_wc;
527 			/* Character class names must be ASCII. */
528 			if (iswascii(w)) {
529 				n--;
530 				*s2++ = w;
531 			} else {
532 				return (-1);	/* invalid character class */
533 			}
534 		}
535 		*s2 = EOS;
536 	}
537 	if ((cc = wctype(cbuf)) == 0)
538 		return (-1);	/* invalid character class */
539 	bufnext->w_at = M_QUOTE;
540 	(bufnext++)->w_wc = M_CLASS;
541 	bufnext->w_at = 0;
542 	(bufnext++)->w_wc = cc;
543 	*bufnextp = bufnext;
544 	*patternp += len + 3;
545 
546 	return (0);
547 }
548 
549 /*
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.
555  */
556 static int
557 glob0(const wcat_t *pattern, glob_t *pglob, struct glob_lim *limitp,
558     int (*errfunc)(const char *, int))
559 {
560 	const wcat_t *qpatnext;
561 	int err, oldpathc;
562 	wchar_t c;
563 	int a;
564 	wcat_t *bufnext, patbuf[MAXPATHLEN];
565 
566 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
567 	oldpathc = pglob->gl_pathc;
568 	bufnext = patbuf;
569 
570 	/*
571 	 * We don't need to check for buffer overflow any more.
572 	 * The pattern has already been copied to an internal buffer.
573 	 */
574 	while ((a = qpatnext->w_at), (c = (qpatnext++)->w_wc) != EOS) {
575 		switch (c) {
576 		case LBRACKET:
577 			if (a != 0) {
578 				bufnext->w_at = a;
579 				(bufnext++)->w_wc = c;
580 				break;
581 			}
582 			a = qpatnext->w_at;
583 			c = qpatnext->w_wc;
584 			if (a == 0 && c == NOT)
585 				++qpatnext;
586 			if (qpatnext->w_wc == EOS ||
587 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
588 				bufnext->w_at = 0;
589 				(bufnext++)->w_wc = LBRACKET;
590 				if (a == 0 && c == NOT)
591 					--qpatnext;
592 				break;
593 			}
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;
599 			}
600 			a = qpatnext->w_at;
601 			c = (qpatnext++)->w_wc;
602 			do {
603 				if (a == 0 && c == LBRACKET &&
604 				    qpatnext->w_wc == COLON) {
605 					do {
606 						err = g_charclass(&qpatnext,
607 						    &bufnext);
608 						if (err)
609 							break;
610 						a = qpatnext->w_at;
611 						c = (qpatnext++)->w_wc;
612 					} while (a == 0 && c == LBRACKET &&
613 					    qpatnext->w_wc == COLON);
614 					if (err == -1 &&
615 					    !(pglob->gl_flags & GLOB_NOCHECK))
616 						return (GLOB_NOMATCH);
617 					if (a == 0 && c == RBRACKET)
618 						break;
619 				}
620 				bufnext->w_at = a;
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;
630 						bufnext->w_at = a;
631 						(bufnext++)->w_wc = c;
632 						qpatnext += 2;
633 					}
634 				}
635 				a = qpatnext->w_at;
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;
641 			break;
642 		case QUESTION:
643 			if (a != 0) {
644 				bufnext->w_at = a;
645 				(bufnext++)->w_wc = c;
646 				break;
647 			}
648 			pglob->gl_flags |= GLOB_MAGCHAR;
649 			bufnext->w_at = M_QUOTE;
650 			(bufnext++)->w_wc = M_ONE;
651 			break;
652 		case STAR:
653 			if (a != 0) {
654 				bufnext->w_at = a;
655 				(bufnext++)->w_wc = c;
656 				break;
657 			}
658 			pglob->gl_flags |= GLOB_MAGCHAR;
659 			/*
660 			 * collapse adjacent stars to one,
661 			 * to avoid exponential behavior
662 			 */
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;
668 			}
669 			break;
670 		default:
671 			bufnext->w_at = a;
672 			(bufnext++)->w_wc = c;
673 			break;
674 		}
675 	}
676 	bufnext->w_at = 0;
677 	bufnext->w_wc = EOS;
678 
679 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limitp, errfunc))
680 	    != 0)
681 		return (err);
682 
683 	/*
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.
688 	 */
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));
694 		else
695 			return (GLOB_NOMATCH);
696 	}
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;
701 			int i;
702 			int n = pglob->gl_pathc - oldpathc;
703 			int o = pglob->gl_offs + oldpathc;
704 
705 			if ((path_stat = calloc(n, sizeof (*path_stat))) ==
706 			    NULL)
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];
711 			}
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;
716 			}
717 			free(path_stat);
718 		} else {
719 			qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
720 			    pglob->gl_pathc - oldpathc, sizeof (char *),
721 			    compare);
722 		}
723 	}
724 	return (0);
725 }
726 
727 static int
728 compare(const void *p, const void *q)
729 {
730 	return (strcmp(*(char **)p, *(char **)q));
731 }
732 
733 static int
734 compare_gps(const void *_p, const void *_q)
735 {
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;
738 
739 	return (strcmp(p->gps_path, q->gps_path));
740 }
741 
742 static int
743 glob1(wcat_t *pattern, wcat_t *pattern_last, glob_t *pglob,
744     struct glob_lim *limitp, int (*errfunc)(const char *, int))
745 {
746 	wcat_t pathbuf[MAXPATHLEN];
747 
748 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
749 	if (pattern->w_wc == EOS)
750 		return (0);
751 	return (glob2(pathbuf, pathbuf+MAXPATHLEN-1,
752 	    pathbuf, pathbuf+MAXPATHLEN-1,
753 	    pattern, pattern_last, pglob, limitp, errfunc));
754 }
755 
756 /*
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
759  * meta characters.
760  */
761 static int
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))
765 {
766 	struct stat sb;
767 	wcat_t *p, *q;
768 	int anymeta;
769 
770 	/*
771 	 * Loop over pattern segments until end of pattern or until
772 	 * segment with meta character found.
773 	 */
774 	for (anymeta = 0; ; ) {
775 		if (pattern->w_wc == EOS) {		/* End of pattern? */
776 			pathend->w_at = 0;
777 			pathend->w_wc = EOS;
778 
779 			if ((pglob->gl_flags & GLOB_LIMIT) &&
780 			    limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
781 				errno = 0;
782 				pathend->w_at = 0;
783 				(pathend++)->w_wc = SEP;
784 				pathend->w_at = 0;
785 				pathend->w_wc = EOS;
786 				return (GLOB_NOSPACE);
787 			}
788 			if (g_lstat(pathbuf, &sb, pglob))
789 				return (0);
790 
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);
800 				pathend->w_at = 0;
801 				(pathend++)->w_wc = SEP;
802 				pathend->w_at = 0;
803 				pathend->w_wc = EOS;
804 			}
805 			++pglob->gl_matchc;
806 			return (globextend(pathbuf, pglob, limitp, &sb));
807 		}
808 
809 		/* Find end of next segment, copy tentatively to pathend. */
810 		q = pathend;
811 		p = pattern;
812 		while (p->w_wc != EOS && p->w_wc != SEP) {
813 			if (ismeta(*p))
814 				anymeta = 1;
815 			if (q+1 > pathend_last)
816 				return (GLOB_NOSPACE);
817 			*q++ = *p++;
818 		}
819 
820 		if (!anymeta) {		/* No expansion, do next segment. */
821 			pathend = q;
822 			pattern = p;
823 			while (pattern->w_wc == SEP) {
824 				if (pathend+1 > pathend_last)
825 					return (GLOB_NOSPACE);
826 				*pathend++ = *pattern++;
827 			}
828 		} else  {
829 			/* Need expansion, recurse. */
830 			return (glob3(pathbuf, pathbuf_last, pathend,
831 			    pathend_last, pattern, p, pattern_last,
832 			    pglob, limitp, errfunc));
833 		}
834 	}
835 	/* NOTREACHED */
836 }
837 
838 static int
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))
843 {
844 	struct dirent *dp;
845 	DIR *dirp;
846 	int err;
847 	char buf[MAXPATHLEN];
848 
849 	/*
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
853 	 * structures.
854 	 */
855 	struct dirent *(*readdirfunc)(void *);
856 
857 	if (pathend > pathend_last)
858 		return (GLOB_NOSPACE);
859 	pathend->w_at = 0;
860 	pathend->w_wc = EOS;
861 	errno = 0;
862 
863 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
864 		/* TODO: don't call for ENOENT or ENOTDIR? */
865 		if (errfunc) {
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);
871 		}
872 		return (0);
873 	}
874 
875 	err = 0;
876 
877 	/* Search directory for matching names. */
878 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
879 		readdirfunc = pglob->gl_readdir;
880 	else
881 		readdirfunc = (struct dirent *(*)(void *))readdir;
882 	while ((dp = (*readdirfunc)(dirp))) {
883 		char *sc;
884 		wcat_t *dc;
885 		int n;
886 		int lensc;
887 		wchar_t w;
888 
889 		if ((pglob->gl_flags & GLOB_LIMIT) &&
890 		    limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
891 			errno = 0;
892 			pathend->w_at = 0;
893 			(pathend++)->w_wc = SEP;
894 			pathend->w_at = 0;
895 			pathend->w_wc = EOS;
896 			err = GLOB_NOSPACE;
897 			break;
898 		}
899 
900 		/* Initial DOT must be matched literally. */
901 		if (dp->d_name[0] == DOT && pattern->w_wc != DOT)
902 			continue;
903 		dc = pathend;
904 		sc = dp->d_name;
905 		lensc = strlen(sc) + 1;
906 		while (dc < pathend_last) {
907 			if ((n = mbtowc(&w, sc, lensc)) <= 0) {
908 				sc += 1;
909 				lensc -= 1;
910 				dc->w_at = 0;
911 				dc->w_wc = EOS;
912 			} else {
913 				sc += n;
914 				lensc -= n;
915 				dc->w_at = 0;
916 				dc->w_wc = w;
917 			}
918 			dc++;
919 			if (n <= 0)
920 				break;
921 		}
922 		if (dc >= pathend_last) {
923 			dc->w_at = 0;
924 			dc->w_wc = EOS;
925 			err = GLOB_NOSPACE;
926 			break;
927 		}
928 		if (n < 0) {
929 			err = GLOB_NOMATCH;
930 			break;
931 		}
932 
933 		if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) {
934 			pathend->w_at = 0;
935 			pathend->w_wc = EOS;
936 			continue;
937 		}
938 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
939 		    restpattern, restpattern_last, pglob, limitp,
940 		    errfunc);
941 		if (err)
942 			break;
943 	}
944 
945 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
946 		(*pglob->gl_closedir)(dirp);
947 	else
948 		(void) closedir(dirp);
949 	return (err);
950 }
951 
952 
953 /*
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
957  * the number.
958  *
959  * Return 0 if new item added, error code if memory couldn't be allocated.
960  *
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.
964  */
965 static int
966 globextend(const wcat_t *path, glob_t *pglob, struct glob_lim *limitp,
967     struct stat *sb)
968 {
969 	char **pathv;
970 	ssize_t i;
971 	size_t allocn, newn, len;
972 	char *copy = NULL;
973 	const wcat_t *p;
974 	struct stat **statv;
975 	char junk[MB_LEN_MAX];
976 	int n;
977 
978 	allocn = pglob->gl_pathn;
979 	newn = 2 + pglob->gl_pathc + pglob->gl_offs;
980 
981 	if (newn <= allocn) {
982 		pathv = pglob->gl_pathv;
983 		if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0)
984 			statv = pglob->gl_statv;
985 	} else {
986 		if (allocn == 0)
987 			allocn = pglob->gl_offs + INITIAL;
988 		allocn *= 2;
989 		if (pglob->gl_offs >= INT_MAX ||
990 		    pglob->gl_pathc >= INT_MAX ||
991 		    allocn >= INT_MAX ||
992 		    SIZE_MAX / sizeof (*pathv) <= allocn ||
993 		    SIZE_MAX / sizeof (*statv) <= allocn) {
994 		nospace:
995 			for (i = pglob->gl_offs; i < (ssize_t)(newn - 2);
996 			    i++) {
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]);
1002 			}
1003 			if (pglob->gl_pathv) {
1004 				free(pglob->gl_pathv);
1005 				pglob->gl_pathv = NULL;
1006 			}
1007 			if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
1008 			    pglob->gl_statv) {
1009 				free(pglob->gl_statv);
1010 				pglob->gl_statv = NULL;
1011 			}
1012 			return (GLOB_NOSPACE);
1013 		}
1014 		limitp->glim_malloc += allocn * sizeof (*pathv);
1015 		pathv = realloc(pglob->gl_pathv, allocn * sizeof (*pathv));
1016 		if (pathv == NULL)
1017 			goto nospace;
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));
1022 			if (statv == NULL)
1023 				goto nospace;
1024 		}
1025 	}
1026 	pglob->gl_pathn = allocn;
1027 
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; )
1032 			*--pathv = NULL;
1033 	}
1034 	pglob->gl_pathv = pathv;
1035 
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; )
1041 				*--statv = NULL;
1042 		}
1043 		pglob->gl_statv = statv;
1044 		if (sb == NULL)
1045 			statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1046 		else {
1047 			limitp->glim_malloc += sizeof (**statv);
1048 			if ((statv[pglob->gl_offs + pglob->gl_pathc] =
1049 			    malloc(sizeof (**statv))) == NULL)
1050 				goto copy_error;
1051 			(void) memcpy(statv[pglob->gl_offs + pglob->gl_pathc],
1052 			    sb, sizeof (*sb));
1053 		}
1054 		statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
1055 	}
1056 
1057 	len = MB_LEN_MAX;
1058 	p = path;
1059 	while ((n = wctomb(junk, p->w_wc)) > 0) {
1060 		len += n;
1061 		if ((p++)->w_wc == EOS)
1062 			break;
1063 	}
1064 	if (n < 0)
1065 		return (GLOB_NOMATCH);
1066 
1067 	limitp->glim_malloc += len;
1068 	if ((copy = malloc(len)) != NULL) {
1069 		if (g_Ctoc(path, copy, len)) {
1070 			free(copy);
1071 			return (GLOB_NOSPACE);
1072 		}
1073 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1074 	}
1075 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1076 
1077 	if ((pglob->gl_flags & GLOB_LIMIT) &&
1078 	    limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
1079 		errno = 0;
1080 		return (GLOB_NOSPACE);
1081 	}
1082 	copy_error:
1083 	return (copy == NULL ? GLOB_NOSPACE : 0);
1084 }
1085 
1086 
1087 /*
1088  * pattern matching function for filenames.  Each occurrence of the *
1089  * pattern causes a recursion level.
1090  */
1091 static int
1092 match(wcat_t *name, wcat_t *pat, wcat_t *patend, int recur)
1093 {
1094 	int ok, negate_range;
1095 	wcat_t c, k;
1096 
1097 	if (recur-- == 0)
1098 		return (1);
1099 
1100 	while (pat < patend) {
1101 		c = *pat++;
1102 		switch (c.w_wc) {
1103 		case M_ALL:
1104 			if (c.w_at != M_QUOTE) {
1105 				k = *name++;
1106 				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1107 					return (0);
1108 				break;
1109 			}
1110 			while (pat < patend && pat->w_at == M_QUOTE &&
1111 			    pat->w_wc == M_ALL)
1112 				pat++;	/* eat consecutive '*' */
1113 			if (pat == patend)
1114 				return (1);
1115 			do {
1116 				if (match(name, pat, patend, recur))
1117 					return (1);
1118 			} while ((name++)->w_wc != EOS);
1119 			return (0);
1120 		case M_ONE:
1121 			if (c.w_at != M_QUOTE) {
1122 				k = *name++;
1123 				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1124 					return (0);
1125 				break;
1126 			}
1127 			if ((name++)->w_wc == EOS)
1128 				return (0);
1129 			break;
1130 		case M_SET:
1131 			if (c.w_at != M_QUOTE) {
1132 				k = *name++;
1133 				if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1134 					return (0);
1135 				break;
1136 			}
1137 			ok = 0;
1138 			if ((k = *name++).w_wc == EOS)
1139 				return (0);
1140 			if ((negate_range = (pat->w_at == M_QUOTE &&
1141 			    pat->w_wc == M_NOT)) != 0)
1142 				++pat;
1143 			while (((c = *pat++).w_at != M_QUOTE) ||
1144 			    c.w_wc != M_END) {
1145 				if (c.w_at == M_QUOTE && c.w_wc == M_CLASS) {
1146 					wcat_t cc;
1147 
1148 					cc.w_at = pat->w_at;
1149 					cc.w_wc = pat->w_wc;
1150 					if (iswctype(k.w_wc, cc.w_wc))
1151 						ok = 1;
1152 					++pat;
1153 				}
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)
1158 						ok = 1;
1159 					pat += 2;
1160 				} else if (c.w_wc == k.w_wc)
1161 					ok = 1;
1162 			}
1163 			if (ok == negate_range)
1164 				return (0);
1165 			break;
1166 		default:
1167 			k = *name++;
1168 			if (k.w_at != c.w_at || k.w_wc != c.w_wc)
1169 				return (0);
1170 			break;
1171 		}
1172 	}
1173 	return (name->w_wc == EOS);
1174 }
1175 
1176 /*
1177  * Extended globfree() function, selected by #pragma redefine_extname
1178  * in glob.h with the external name _globfree_ext() .
1179  */
1180 void
1181 _globfree_ext(glob_t *pglob)
1182 {
1183 	int i;
1184 	char **pp;
1185 
1186 	if (pglob->gl_pathv != NULL) {
1187 		pp = pglob->gl_pathv + pglob->gl_offs;
1188 		for (i = pglob->gl_pathc; i--; ++pp)
1189 			if (*pp)
1190 				free(*pp);
1191 		free(pglob->gl_pathv);
1192 		pglob->gl_pathv = NULL;
1193 	}
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]);
1199 		}
1200 		free(pglob->gl_statv);
1201 		pglob->gl_statv = NULL;
1202 	}
1203 }
1204 
1205 static DIR *
1206 g_opendir(wcat_t *str, glob_t *pglob)
1207 {
1208 	char buf[MAXPATHLEN];
1209 
1210 	if (str->w_wc == EOS)
1211 		(void) strlcpy(buf, ".", sizeof (buf));
1212 	else {
1213 		if (g_Ctoc(str, buf, sizeof (buf)))
1214 			return (NULL);
1215 	}
1216 
1217 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1218 		return ((*pglob->gl_opendir)(buf));
1219 
1220 	return (opendir(buf));
1221 }
1222 
1223 static int
1224 g_lstat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1225 {
1226 	char buf[MAXPATHLEN];
1227 
1228 	if (g_Ctoc(fn, buf, sizeof (buf)))
1229 		return (-1);
1230 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1231 		return ((*pglob->gl_lstat)(buf, sb));
1232 	return (lstat(buf, sb));
1233 }
1234 
1235 static int
1236 g_stat(wcat_t *fn, struct stat *sb, glob_t *pglob)
1237 {
1238 	char buf[MAXPATHLEN];
1239 
1240 	if (g_Ctoc(fn, buf, sizeof (buf)))
1241 		return (-1);
1242 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1243 		return ((*pglob->gl_stat)(buf, sb));
1244 	return (stat(buf, sb));
1245 }
1246 
1247 static wcat_t *
1248 g_strchr(const wcat_t *str, wchar_t ch)
1249 {
1250 	do {
1251 		if (str->w_at == 0 && str->w_wc == ch)
1252 			return ((wcat_t *)str);
1253 	} while ((str++)->w_wc != EOS);
1254 	return (NULL);
1255 }
1256 
1257 static int
1258 g_Ctoc(const wcat_t *str, char *buf, uint_t len)
1259 {
1260 	int n;
1261 	wchar_t w;
1262 
1263 	while (len >= MB_LEN_MAX) {
1264 		w = (str++)->w_wc;
1265 		if ((n = wctomb(buf, w)) > 0) {
1266 			len -= n;
1267 			buf += n;
1268 		}
1269 		if (n < 0)
1270 			break;
1271 		if (w == EOS)
1272 			return (0);
1273 	}
1274 	return (1);
1275 }
1276 
1277 #if defined(_LP64) || _FILE_OFFSET_BITS != 64
1278 
1279 /* glob() function with legacy glob structure */
1280 int
1281 old_glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
1282     old_glob_t *pglob)
1283 {
1284 
1285 	glob_t gl;
1286 	int rv;
1287 
1288 	flags &= GLOB_POSIX;
1289 
1290 	(void) memset(&gl, 0, sizeof (gl));
1291 
1292 	/*
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.
1296 	 */
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;
1302 
1303 	rv = _glob_ext(pattern, flags, errfunc, &gl);
1304 
1305 	/*
1306 	 * Copy all the members, new to old.  There's
1307 	 * really no point in micro-optimizing the copying.
1308 	 */
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;
1314 
1315 	return (rv);
1316 }
1317 
1318 /* globfree() function with legacy glob structure */
1319 void
1320 old_globfree(old_glob_t *pglob)
1321 {
1322 	glob_t gl;
1323 
1324 	(void) memset(&gl, 0, sizeof (gl));
1325 
1326 	/*
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.
1330 	 */
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;
1336 
1337 	_globfree_ext(&gl);
1338 
1339 	/*
1340 	 * Copy all the members, new to old.  There's
1341 	 * really no point in micro-optimizing the copying.
1342 	 */
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;
1348 
1349 }
1350 
1351 #endif	/* _LP64 || _FILE_OFFSET_BITS != 64 */
1352