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