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