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