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
_glob_ext(const char * pattern,int flags,int (* errfunc)(const char *,int),glob_t * pglob)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
globexp1(const wcat_t * pattern,glob_t * pglob,struct glob_lim * limitp,int (* errfunc)(const char *,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
globexp2(const wcat_t * ptr,const wcat_t * pattern,glob_t * pglob,struct glob_lim * limitp,int (* errfunc)(const char *,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 *
globtilde(const wcat_t * pattern,wcat_t * patbuf,size_t patbuf_len,glob_t * pglob)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
g_charclass(const wcat_t ** patternp,wcat_t ** bufnextp)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
glob0(const wcat_t * pattern,glob_t * pglob,struct glob_lim * limitp,int (* errfunc)(const char *,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
compare(const void * p,const void * q)728 compare(const void *p, const void *q)
729 {
730 return (strcmp(*(char **)p, *(char **)q));
731 }
732
733 static int
compare_gps(const void * _p,const void * _q)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
glob1(wcat_t * pattern,wcat_t * pattern_last,glob_t * pglob,struct glob_lim * limitp,int (* errfunc)(const char *,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
glob2(wcat_t * pathbuf,wcat_t * pathbuf_last,wcat_t * pathend,wcat_t * pathend_last,wcat_t * pattern,wcat_t * pattern_last,glob_t * pglob,struct glob_lim * limitp,int (* errfunc)(const char *,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
glob3(wcat_t * pathbuf,wcat_t * pathbuf_last,wcat_t * pathend,wcat_t * pathend_last,wcat_t * pattern,wcat_t * restpattern,wcat_t * restpattern_last,glob_t * pglob,struct glob_lim * limitp,int (* errfunc)(const char *,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
globextend(const wcat_t * path,glob_t * pglob,struct glob_lim * limitp,struct stat * sb)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
match(wcat_t * name,wcat_t * pat,wcat_t * patend,int recur)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
_globfree_ext(glob_t * pglob)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 *
g_opendir(wcat_t * str,glob_t * pglob)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
g_lstat(wcat_t * fn,struct stat * sb,glob_t * pglob)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
g_stat(wcat_t * fn,struct stat * sb,glob_t * pglob)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 *
g_strchr(const wcat_t * str,wchar_t ch)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
g_Ctoc(const wcat_t * str,char * buf,uint_t len)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
old_glob(const char * pattern,int flags,int (* errfunc)(const char *,int),old_glob_t * pglob)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
old_globfree(old_glob_t * pglob)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