This source file includes following definitions.
- readdir_result_type
- convert_dirent
- convert_dirent64
- glob_lstat
- size_add_wrapv
- glob_use_alloca
- prefix_array
- next_brace_sub
- __glob
- libc_hidden_ver
- prefix_array
- glob_in_dir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #ifndef _LIBC
19
20
21
22 # define _GL_ARG_NONNULL(params)
23
24 # include <libc-config.h>
25
26 #endif
27
28 #include <glob.h>
29
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <stdbool.h>
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <assert.h>
37 #include <unistd.h>
38
39 #if defined _WIN32 && ! defined __CYGWIN__
40 # define WINDOWS32
41 #endif
42
43 #ifndef WINDOWS32
44 # include <pwd.h>
45 #endif
46
47 #include <errno.h>
48 #include <dirent.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <alloca.h>
52
53 #ifdef _LIBC
54 # undef strdup
55 # define strdup(str) __strdup (str)
56 # define sysconf(id) __sysconf (id)
57 # define closedir(dir) __closedir (dir)
58 # define opendir(name) __opendir (name)
59 # define readdir(str) __readdir64 (str)
60 # define getpwnam_r(name, bufp, buf, len, res) \
61 __getpwnam_r (name, bufp, buf, len, res)
62 # define FLEXIBLE_ARRAY_MEMBER
63 # ifndef struct_stat
64 # define struct_stat struct stat
65 # endif
66 # ifndef struct_stat64
67 # define struct_stat64 struct stat64
68 # endif
69 # ifndef GLOB_LSTAT
70 # define GLOB_LSTAT gl_lstat
71 # endif
72 # ifndef GLOB_STAT64
73 # define GLOB_STAT64 __stat64
74 # endif
75 # ifndef GLOB_LSTAT64
76 # define GLOB_LSTAT64 __lstat64
77 # endif
78 # include <shlib-compat.h>
79 #else
80 # define __glob glob
81 # define __getlogin_r(buf, len) getlogin_r (buf, len)
82 # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
83 # ifndef __MVS__
84 # define __alloca alloca
85 # endif
86 # define __readdir readdir
87 # define COMPILE_GLOB64
88 # define struct_stat struct stat
89 # define struct_stat64 struct stat
90 # define GLOB_LSTAT gl_lstat
91 # define GLOB_STAT64 stat
92 # define GLOB_LSTAT64 lstat
93 #endif
94
95 #include <fnmatch.h>
96
97 #include <flexmember.h>
98 #include <glob_internal.h>
99 #include <scratch_buffer.h>
100
101 static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
102
103
104
105 typedef uint_fast32_t dirent_type;
106
107 #if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
108
109
110 # undef DT_UNKNOWN
111 # undef DT_DIR
112 # undef DT_LNK
113 # define DT_UNKNOWN 0
114 # define DT_DIR 1
115 # define DT_LNK 2
116 #endif
117
118
119
120 struct readdir_result
121 {
122 const char *name;
123 #if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
124 dirent_type type;
125 #endif
126 };
127
128
129 static dirent_type
130 readdir_result_type (struct readdir_result d)
131 {
132 #if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
133 # define D_TYPE_TO_RESULT(source) (source)->d_type,
134 return d.type;
135 #else
136 # define D_TYPE_TO_RESULT(source)
137 return DT_UNKNOWN;
138 #endif
139 }
140
141
142
143 #define READDIR_RESULT_INITIALIZER(source) \
144 { \
145 source->d_name, \
146 D_TYPE_TO_RESULT (source) \
147 }
148
149
150
151 #ifndef GL_READDIR
152 # define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream))
153 #endif
154
155
156
157
158 static struct readdir_result
159 convert_dirent (const struct dirent *source)
160 {
161 if (source == NULL)
162 {
163 struct readdir_result result = { NULL, };
164 return result;
165 }
166 struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
167 return result;
168 }
169
170 #ifndef COMPILE_GLOB64
171
172
173 static struct readdir_result
174 convert_dirent64 (const struct dirent64 *source)
175 {
176 if (source == NULL)
177 {
178 struct readdir_result result = { NULL, };
179 return result;
180 }
181 struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
182 return result;
183 }
184 #endif
185
186 #ifndef _LIBC
187
188
189
190
191
192 # ifdef GNULIB_defined_opendir
193 # undef opendir
194 # endif
195 # ifdef GNULIB_defined_closedir
196 # undef closedir
197 # endif
198
199
200 # define __libc_use_alloca(n) false
201 # define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
202 # define extend_alloca_account(buf, len, newlen, avar) \
203 ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
204 #endif
205
206 static int
207 glob_lstat (glob_t *pglob, int flags, const char *fullname)
208 {
209
210
211 union
212 {
213 struct_stat st;
214 struct_stat64 st64;
215 } ust;
216 return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
217 ? pglob->GLOB_LSTAT (fullname, &ust.st)
218 : GLOB_LSTAT64 (fullname, &ust.st64));
219 }
220
221
222
223
224
225 static bool
226 size_add_wrapv (size_t a, size_t b, size_t *r)
227 {
228 #if 7 <= __GNUC__ && !defined __ICC
229 return __builtin_add_overflow (a, b, r);
230 #else
231 *r = a + b;
232 return *r < a;
233 #endif
234 }
235
236 static bool
237 glob_use_alloca (size_t alloca_used, size_t len)
238 {
239 size_t size;
240 return (!size_add_wrapv (alloca_used, len, &size)
241 && __libc_use_alloca (size));
242 }
243
244 static int glob_in_dir (const char *pattern, const char *directory,
245 int flags, int (*errfunc) (const char *, int),
246 glob_t *pglob, size_t alloca_used);
247 static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
248 static int collated_compare (const void *, const void *) __THROWNL;
249
250
251
252
253 static bool
254 is_dir (char const *filename, int flags, glob_t const *pglob)
255 {
256 struct_stat st;
257 struct_stat64 st64;
258 return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
259 ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode)
260 : GLOB_STAT64 (filename, &st64) == 0 && S_ISDIR (st64.st_mode));
261 }
262
263
264 static const char *
265 next_brace_sub (const char *cp, int flags)
266 {
267 size_t depth = 0;
268 while (*cp != '\0')
269 if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
270 {
271 if (*++cp == '\0')
272 break;
273 ++cp;
274 }
275 else
276 {
277 if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
278 break;
279
280 if (*cp++ == '{')
281 depth++;
282 }
283
284 return *cp != '\0' ? cp : NULL;
285 }
286
287 #ifndef GLOB_ATTRIBUTE
288 # define GLOB_ATTRIBUTE
289 #endif
290
291
292
293
294
295
296
297
298
299 int
300 GLOB_ATTRIBUTE
301 __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
302 glob_t *pglob)
303 {
304 const char *filename;
305 char *dirname = NULL;
306 size_t dirlen;
307 int status;
308 size_t oldcount;
309 int meta;
310 int dirname_modified;
311 int malloc_dirname = 0;
312 glob_t dirs;
313 int retval = 0;
314 size_t alloca_used = 0;
315
316 if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
317 {
318 __set_errno (EINVAL);
319 return -1;
320 }
321
322
323
324 if (pattern[0] && pattern[strlen (pattern) - 1] == '/')
325 flags |= GLOB_ONLYDIR;
326
327 if (!(flags & GLOB_DOOFFS))
328
329
330 pglob->gl_offs = 0;
331
332 if (!(flags & GLOB_APPEND))
333 {
334 pglob->gl_pathc = 0;
335 if (!(flags & GLOB_DOOFFS))
336 pglob->gl_pathv = NULL;
337 else
338 {
339 size_t i;
340
341 if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *))
342 return GLOB_NOSPACE;
343
344 pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
345 * sizeof (char *));
346 if (pglob->gl_pathv == NULL)
347 return GLOB_NOSPACE;
348
349 for (i = 0; i <= pglob->gl_offs; ++i)
350 pglob->gl_pathv[i] = NULL;
351 }
352 }
353
354 if (flags & GLOB_BRACE)
355 {
356 const char *begin;
357
358 if (flags & GLOB_NOESCAPE)
359 begin = strchr (pattern, '{');
360 else
361 {
362 begin = pattern;
363 while (1)
364 {
365 if (*begin == '\0')
366 {
367 begin = NULL;
368 break;
369 }
370
371 if (*begin == '\\' && begin[1] != '\0')
372 ++begin;
373 else if (*begin == '{')
374 break;
375
376 ++begin;
377 }
378 }
379
380 if (begin != NULL)
381 {
382
383
384 size_t firstc;
385 char *alt_start;
386 const char *p;
387 const char *next;
388 const char *rest;
389 size_t rest_len;
390 char *onealt;
391 size_t pattern_len = strlen (pattern) - 1;
392 int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
393 if (alloca_onealt)
394 onealt = alloca_account (pattern_len, alloca_used);
395 else
396 {
397 onealt = malloc (pattern_len);
398 if (onealt == NULL)
399 return GLOB_NOSPACE;
400 }
401
402
403 alt_start = mempcpy (onealt, pattern, begin - pattern);
404
405
406
407 next = next_brace_sub (begin + 1, flags);
408 if (next == NULL)
409 {
410
411 illegal_brace:
412 if (__glibc_unlikely (!alloca_onealt))
413 free (onealt);
414 flags &= ~GLOB_BRACE;
415 goto no_brace;
416 }
417
418
419 rest = next;
420 while (*rest != '}')
421 {
422 rest = next_brace_sub (rest + 1, flags);
423 if (rest == NULL)
424
425 goto illegal_brace;
426 }
427
428
429 rest_len = strlen (++rest) + 1;
430
431
432
433
434
435
436 firstc = pglob->gl_pathc;
437
438 p = begin + 1;
439 while (1)
440 {
441 int result;
442
443
444 mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
445
446 result = __glob (onealt,
447 ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
448 | GLOB_APPEND),
449 errfunc, pglob);
450
451
452 if (result && result != GLOB_NOMATCH)
453 {
454 if (__glibc_unlikely (!alloca_onealt))
455 free (onealt);
456 if (!(flags & GLOB_APPEND))
457 {
458 globfree (pglob);
459 pglob->gl_pathc = 0;
460 }
461 return result;
462 }
463
464 if (*next == '}')
465
466 break;
467
468 p = next + 1;
469 next = next_brace_sub (p, flags);
470 assert (next != NULL);
471 }
472
473 if (__glibc_unlikely (!alloca_onealt))
474 free (onealt);
475
476 if (pglob->gl_pathc != firstc)
477
478 return 0;
479 else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
480 return GLOB_NOMATCH;
481 }
482 }
483
484 no_brace:
485 oldcount = pglob->gl_pathc + pglob->gl_offs;
486
487
488 filename = strrchr (pattern, '/');
489
490 #if defined __MSDOS__ || defined WINDOWS32
491
492
493
494
495 if (filename == NULL)
496 filename = strchr (pattern, ':');
497 #endif
498
499 dirname_modified = 0;
500 if (filename == NULL)
501 {
502
503
504 if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
505 {
506 dirname = (char *) pattern;
507 dirlen = strlen (pattern);
508
509
510
511
512 filename = NULL;
513 }
514 else
515 {
516 if (__glibc_unlikely (pattern[0] == '\0'))
517 {
518 dirs.gl_pathv = NULL;
519 goto no_matches;
520 }
521
522 filename = pattern;
523 dirname = (char *) ".";
524 dirlen = 0;
525 }
526 }
527 else if (filename == pattern
528 || (filename == pattern + 1 && pattern[0] == '\\'
529 && (flags & GLOB_NOESCAPE) == 0))
530 {
531
532 dirname = (char *) "/";
533 dirlen = 1;
534 ++filename;
535 }
536 else
537 {
538 char *newp;
539 dirlen = filename - pattern;
540 #if defined __MSDOS__ || defined WINDOWS32
541 if (*filename == ':'
542 || (filename > pattern + 1 && filename[-1] == ':'))
543 {
544 char *drive_spec;
545
546 ++dirlen;
547 drive_spec = __alloca (dirlen + 1);
548 *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
549
550
551 if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
552 return GLOB_NOMATCH;
553
554
555
556 }
557 #endif
558
559 if (glob_use_alloca (alloca_used, dirlen + 1))
560 newp = alloca_account (dirlen + 1, alloca_used);
561 else
562 {
563 newp = malloc (dirlen + 1);
564 if (newp == NULL)
565 return GLOB_NOSPACE;
566 malloc_dirname = 1;
567 }
568 *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
569 dirname = newp;
570 ++filename;
571
572 #if defined __MSDOS__ || defined WINDOWS32
573 bool drive_root = (dirlen > 1
574 && (dirname[dirlen - 1] == ':'
575 || (dirlen > 2 && dirname[dirlen - 2] == ':'
576 && dirname[dirlen - 1] == '/')));
577 #else
578 bool drive_root = false;
579 #endif
580
581 if (filename[0] == '\0' && dirlen > 1 && !drive_root)
582
583 {
584 int orig_flags = flags;
585 if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
586 {
587
588
589 char *p = (char *) &dirname[dirlen - 1];
590
591 while (p > dirname && p[-1] == '\\') --p;
592 if ((&dirname[dirlen] - p) & 1)
593 {
594 *(char *) &dirname[--dirlen] = '\0';
595 flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
596 }
597 }
598 int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
599 if (val == 0)
600 pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
601 | (flags & GLOB_MARK));
602 else if (val == GLOB_NOMATCH && flags != orig_flags)
603 {
604
605 dirs.gl_pathv = NULL;
606 flags = orig_flags;
607 oldcount = pglob->gl_pathc + pglob->gl_offs;
608 goto no_matches;
609 }
610 retval = val;
611 goto out;
612 }
613 }
614
615 if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
616 {
617 if (dirname[1] == '\0' || dirname[1] == '/'
618 || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\'
619 && (dirname[2] == '\0' || dirname[2] == '/')))
620 {
621
622 char *home_dir = getenv ("HOME");
623 int malloc_home_dir = 0;
624 if (home_dir == NULL || home_dir[0] == '\0')
625 {
626 #ifdef WINDOWS32
627
628
629 const char *home_drive = getenv ("HOMEDRIVE");
630 const char *home_path = getenv ("HOMEPATH");
631
632 if (home_drive != NULL && home_path != NULL)
633 {
634 size_t home_drive_len = strlen (home_drive);
635 size_t home_path_len = strlen (home_path);
636 char *mem = alloca (home_drive_len + home_path_len + 1);
637
638 memcpy (mem, home_drive, home_drive_len);
639 memcpy (mem + home_drive_len, home_path, home_path_len + 1);
640 home_dir = mem;
641 }
642 else
643 home_dir = "c:/users/default";
644 #else
645 int err;
646 struct passwd *p;
647 struct passwd pwbuf;
648 struct scratch_buffer s;
649 scratch_buffer_init (&s);
650 while (true)
651 {
652 p = NULL;
653 err = __getlogin_r (s.data, s.length);
654 if (err == 0)
655 {
656 # if defined HAVE_GETPWNAM_R || defined _LIBC
657 size_t ssize = strlen (s.data) + 1;
658 char *sdata = s.data;
659 err = getpwnam_r (sdata, &pwbuf, sdata + ssize,
660 s.length - ssize, &p);
661 # else
662 p = getpwnam (s.data);
663 if (p == NULL)
664 err = errno;
665 # endif
666 }
667 if (err != ERANGE)
668 break;
669 if (!scratch_buffer_grow (&s))
670 {
671 retval = GLOB_NOSPACE;
672 goto out;
673 }
674 }
675 if (err == 0)
676 {
677 home_dir = strdup (p->pw_dir);
678 malloc_home_dir = 1;
679 }
680 scratch_buffer_free (&s);
681 if (err == 0 && home_dir == NULL)
682 {
683 retval = GLOB_NOSPACE;
684 goto out;
685 }
686 #endif
687 }
688 if (home_dir == NULL || home_dir[0] == '\0')
689 {
690 if (__glibc_unlikely (malloc_home_dir))
691 free (home_dir);
692 if (flags & GLOB_TILDE_CHECK)
693 {
694 retval = GLOB_NOMATCH;
695 goto out;
696 }
697 else
698 {
699 home_dir = (char *) "~";
700 malloc_home_dir = 0;
701 }
702 }
703
704 if (dirname[1] == '\0')
705 {
706 if (__glibc_unlikely (malloc_dirname))
707 free (dirname);
708
709 dirname = home_dir;
710 dirlen = strlen (dirname);
711 malloc_dirname = malloc_home_dir;
712 }
713 else
714 {
715 char *newp;
716 size_t home_len = strlen (home_dir);
717 int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
718 if (use_alloca)
719 newp = alloca_account (home_len + dirlen, alloca_used);
720 else
721 {
722 newp = malloc (home_len + dirlen);
723 if (newp == NULL)
724 {
725 if (__glibc_unlikely (malloc_home_dir))
726 free (home_dir);
727 retval = GLOB_NOSPACE;
728 goto out;
729 }
730 }
731
732 mempcpy (mempcpy (newp, home_dir, home_len),
733 &dirname[1], dirlen);
734
735 if (__glibc_unlikely (malloc_dirname))
736 free (dirname);
737
738 dirname = newp;
739 dirlen += home_len - 1;
740 malloc_dirname = !use_alloca;
741
742 if (__glibc_unlikely (malloc_home_dir))
743 free (home_dir);
744 }
745 dirname_modified = 1;
746 }
747 else
748 {
749 #ifndef WINDOWS32
750
751
752 char *end_name = strchr (dirname, '/');
753 char *user_name;
754 int malloc_user_name = 0;
755 char *unescape = NULL;
756
757 if (!(flags & GLOB_NOESCAPE))
758 {
759 if (end_name == NULL)
760 {
761 unescape = strchr (dirname, '\\');
762 if (unescape)
763 end_name = strchr (unescape, '\0');
764 }
765 else
766 unescape = memchr (dirname, '\\', end_name - dirname);
767 }
768 if (end_name == NULL)
769 user_name = dirname + 1;
770 else
771 {
772 char *newp;
773 if (glob_use_alloca (alloca_used, end_name - dirname))
774 newp = alloca_account (end_name - dirname, alloca_used);
775 else
776 {
777 newp = malloc (end_name - dirname);
778 if (newp == NULL)
779 {
780 retval = GLOB_NOSPACE;
781 goto out;
782 }
783 malloc_user_name = 1;
784 }
785 if (unescape != NULL)
786 {
787 char *p = mempcpy (newp, dirname + 1,
788 unescape - dirname - 1);
789 char *q = unescape;
790 while (q != end_name)
791 {
792 if (*q == '\\')
793 {
794 if (q + 1 == end_name)
795 {
796
797
798
799 if (filename == NULL)
800 *p++ = '\\';
801 break;
802 }
803 ++q;
804 }
805 *p++ = *q++;
806 }
807 *p = '\0';
808 }
809 else
810 *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
811 = '\0';
812 user_name = newp;
813 }
814
815
816 {
817 struct passwd *p;
818 struct scratch_buffer pwtmpbuf;
819 scratch_buffer_init (&pwtmpbuf);
820
821 # if defined HAVE_GETPWNAM_R || defined _LIBC
822 struct passwd pwbuf;
823
824 while (getpwnam_r (user_name, &pwbuf,
825 pwtmpbuf.data, pwtmpbuf.length, &p)
826 == ERANGE)
827 {
828 if (!scratch_buffer_grow (&pwtmpbuf))
829 {
830 retval = GLOB_NOSPACE;
831 goto out;
832 }
833 }
834 # else
835 p = getpwnam (user_name);
836 # endif
837
838 if (__glibc_unlikely (malloc_user_name))
839 free (user_name);
840
841
842 if (p != NULL)
843 {
844 size_t home_len = strlen (p->pw_dir);
845 size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
846
847 char *prev_dirname =
848 (__glibc_unlikely (malloc_dirname) ? dirname : NULL);
849 char *d;
850
851 malloc_dirname = 0;
852
853 if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
854 dirname = alloca_account (home_len + rest_len + 1,
855 alloca_used);
856 else
857 {
858 dirname = malloc (home_len + rest_len + 1);
859 if (dirname == NULL)
860 {
861 free (prev_dirname);
862 scratch_buffer_free (&pwtmpbuf);
863 retval = GLOB_NOSPACE;
864 goto out;
865 }
866 malloc_dirname = 1;
867 }
868 d = mempcpy (dirname, p->pw_dir, home_len);
869 if (end_name != NULL)
870 d = mempcpy (d, end_name, rest_len);
871 *d = '\0';
872
873 free (prev_dirname);
874
875 dirlen = home_len + rest_len;
876 dirname_modified = 1;
877 }
878 else
879 {
880 if (flags & GLOB_TILDE_CHECK)
881 {
882
883
884 retval = GLOB_NOMATCH;
885 goto out;
886 }
887 }
888 scratch_buffer_free (&pwtmpbuf);
889 }
890 #else
891
892
893
894
895
896
897
898
899
900 if (flags & GLOB_TILDE_CHECK)
901 {
902 retval = GLOB_NOMATCH;
903 goto out;
904 }
905 #endif
906 }
907 }
908
909
910
911 if (filename == NULL)
912 {
913 size_t newcount = pglob->gl_pathc + pglob->gl_offs;
914 char **new_gl_pathv;
915
916 if (newcount > SIZE_MAX / sizeof (char *) - 2)
917 {
918 nospace:
919 free (pglob->gl_pathv);
920 pglob->gl_pathv = NULL;
921 pglob->gl_pathc = 0;
922 retval = GLOB_NOSPACE;
923 goto out;
924 }
925
926 new_gl_pathv = realloc (pglob->gl_pathv,
927 (newcount + 2) * sizeof (char *));
928 if (new_gl_pathv == NULL)
929 goto nospace;
930 pglob->gl_pathv = new_gl_pathv;
931
932 if (flags & GLOB_MARK && is_dir (dirname, flags, pglob))
933 {
934 char *p;
935 pglob->gl_pathv[newcount] = malloc (dirlen + 2);
936 if (pglob->gl_pathv[newcount] == NULL)
937 goto nospace;
938 p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
939 p[0] = '/';
940 p[1] = '\0';
941 if (__glibc_unlikely (malloc_dirname))
942 free (dirname);
943 }
944 else
945 {
946 if (__glibc_unlikely (malloc_dirname))
947 pglob->gl_pathv[newcount] = dirname;
948 else
949 {
950 pglob->gl_pathv[newcount] = strdup (dirname);
951 if (pglob->gl_pathv[newcount] == NULL)
952 goto nospace;
953 }
954 }
955 pglob->gl_pathv[++newcount] = NULL;
956 ++pglob->gl_pathc;
957 pglob->gl_flags = flags;
958
959 return 0;
960 }
961
962 meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
963
964
965
966
967
968 if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET))
969 {
970
971
972
973 size_t i;
974
975 if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\')
976 {
977
978
979 char *p = (char *) &dirname[dirlen - 1];
980
981 while (p > dirname && p[-1] == '\\') --p;
982 if ((&dirname[dirlen] - p) & 1)
983 *(char *) &dirname[--dirlen] = '\0';
984 }
985
986 if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0))
987 {
988
989
990 dirs.gl_opendir = pglob->gl_opendir;
991 dirs.gl_readdir = pglob->gl_readdir;
992 dirs.gl_closedir = pglob->gl_closedir;
993 dirs.gl_stat = pglob->gl_stat;
994 dirs.gl_lstat = pglob->gl_lstat;
995 }
996
997 status = __glob (dirname,
998 ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC))
999 | GLOB_NOSORT | GLOB_ONLYDIR),
1000 errfunc, &dirs);
1001 if (status != 0)
1002 {
1003 if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
1004 {
1005 retval = status;
1006 goto out;
1007 }
1008 goto no_matches;
1009 }
1010
1011
1012
1013
1014 for (i = 0; i < dirs.gl_pathc; ++i)
1015 {
1016 size_t old_pathc;
1017
1018 old_pathc = pglob->gl_pathc;
1019 status = glob_in_dir (filename, dirs.gl_pathv[i],
1020 ((flags | GLOB_APPEND)
1021 & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
1022 errfunc, pglob, alloca_used);
1023 if (status == GLOB_NOMATCH)
1024
1025 continue;
1026
1027 if (status != 0)
1028 {
1029 globfree (&dirs);
1030 globfree (pglob);
1031 pglob->gl_pathc = 0;
1032 retval = status;
1033 goto out;
1034 }
1035
1036
1037 if (prefix_array (dirs.gl_pathv[i],
1038 &pglob->gl_pathv[old_pathc + pglob->gl_offs],
1039 pglob->gl_pathc - old_pathc))
1040 {
1041 globfree (&dirs);
1042 globfree (pglob);
1043 pglob->gl_pathc = 0;
1044 retval = GLOB_NOSPACE;
1045 goto out;
1046 }
1047 }
1048
1049 flags |= GLOB_MAGCHAR;
1050
1051
1052
1053
1054 if (pglob->gl_pathc + pglob->gl_offs == oldcount)
1055 {
1056 no_matches:
1057
1058 if (flags & GLOB_NOCHECK)
1059 {
1060 size_t newcount = pglob->gl_pathc + pglob->gl_offs;
1061 char **new_gl_pathv;
1062
1063 if (newcount > SIZE_MAX / sizeof (char *) - 2)
1064 {
1065 nospace2:
1066 globfree (&dirs);
1067 retval = GLOB_NOSPACE;
1068 goto out;
1069 }
1070
1071 new_gl_pathv = realloc (pglob->gl_pathv,
1072 (newcount + 2) * sizeof (char *));
1073 if (new_gl_pathv == NULL)
1074 goto nospace2;
1075 pglob->gl_pathv = new_gl_pathv;
1076
1077 pglob->gl_pathv[newcount] = strdup (pattern);
1078 if (pglob->gl_pathv[newcount] == NULL)
1079 {
1080 globfree (&dirs);
1081 globfree (pglob);
1082 pglob->gl_pathc = 0;
1083 retval = GLOB_NOSPACE;
1084 goto out;
1085 }
1086
1087 ++pglob->gl_pathc;
1088 ++newcount;
1089
1090 pglob->gl_pathv[newcount] = NULL;
1091 pglob->gl_flags = flags;
1092 }
1093 else
1094 {
1095 globfree (&dirs);
1096 retval = GLOB_NOMATCH;
1097 goto out;
1098 }
1099 }
1100
1101 globfree (&dirs);
1102 }
1103 else
1104 {
1105 size_t old_pathc = pglob->gl_pathc;
1106 int orig_flags = flags;
1107
1108 if (meta & GLOBPAT_BACKSLASH)
1109 {
1110 char *p = strchr (dirname, '\\'), *q;
1111
1112
1113
1114 q = p;
1115 do
1116 {
1117 if (*p == '\\')
1118 {
1119 *q = *++p;
1120 --dirlen;
1121 }
1122 else
1123 *q = *p;
1124 ++q;
1125 }
1126 while (*p++ != '\0');
1127 dirname_modified = 1;
1128 }
1129 if (dirname_modified)
1130 flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
1131 status = glob_in_dir (filename, dirname, flags, errfunc, pglob,
1132 alloca_used);
1133 if (status != 0)
1134 {
1135 if (status == GLOB_NOMATCH && flags != orig_flags
1136 && pglob->gl_pathc + pglob->gl_offs == oldcount)
1137 {
1138
1139 dirs.gl_pathv = NULL;
1140 flags = orig_flags;
1141 goto no_matches;
1142 }
1143 retval = status;
1144 goto out;
1145 }
1146
1147 if (dirlen > 0)
1148 {
1149
1150 if (prefix_array (dirname,
1151 &pglob->gl_pathv[old_pathc + pglob->gl_offs],
1152 pglob->gl_pathc - old_pathc))
1153 {
1154 globfree (pglob);
1155 pglob->gl_pathc = 0;
1156 retval = GLOB_NOSPACE;
1157 goto out;
1158 }
1159 }
1160 }
1161
1162 if (flags & GLOB_MARK)
1163 {
1164
1165 size_t i;
1166
1167 for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
1168 if (is_dir (pglob->gl_pathv[i], flags, pglob))
1169 {
1170 size_t len = strlen (pglob->gl_pathv[i]) + 2;
1171 char *new = realloc (pglob->gl_pathv[i], len);
1172 if (new == NULL)
1173 {
1174 globfree (pglob);
1175 pglob->gl_pathc = 0;
1176 retval = GLOB_NOSPACE;
1177 goto out;
1178 }
1179 strcpy (&new[len - 2], "/");
1180 pglob->gl_pathv[i] = new;
1181 }
1182 }
1183
1184 if (!(flags & GLOB_NOSORT))
1185 {
1186
1187 qsort (&pglob->gl_pathv[oldcount],
1188 pglob->gl_pathc + pglob->gl_offs - oldcount,
1189 sizeof (char *), collated_compare);
1190 }
1191
1192 out:
1193 if (__glibc_unlikely (malloc_dirname))
1194 free (dirname);
1195
1196 return retval;
1197 }
1198 #if defined _LIBC && !defined __glob
1199 versioned_symbol (libc, __glob, glob, GLIBC_2_27);
1200 libc_hidden_ver (__glob, glob)
1201 #endif
1202
1203
1204
1205 static int
1206 collated_compare (const void *a, const void *b)
1207 {
1208 char *const *ps1 = a; char *s1 = *ps1;
1209 char *const *ps2 = b; char *s2 = *ps2;
1210
1211 if (s1 == s2)
1212 return 0;
1213 if (s1 == NULL)
1214 return 1;
1215 if (s2 == NULL)
1216 return -1;
1217 return strcoll (s1, s2);
1218 }
1219
1220
1221
1222
1223
1224
1225 static int
1226 prefix_array (const char *dirname, char **array, size_t n)
1227 {
1228 size_t i;
1229 size_t dirlen = strlen (dirname);
1230 char dirsep_char = '/';
1231
1232 if (dirlen == 1 && dirname[0] == '/')
1233
1234
1235 dirlen = 0;
1236
1237 #if defined __MSDOS__ || defined WINDOWS32
1238 if (dirlen > 1)
1239 {
1240 if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
1241
1242 --dirlen;
1243 else if (dirname[dirlen - 1] == ':')
1244 {
1245
1246 --dirlen;
1247 dirsep_char = ':';
1248 }
1249 }
1250 #endif
1251
1252 for (i = 0; i < n; ++i)
1253 {
1254 size_t eltlen = strlen (array[i]) + 1;
1255 char *new = malloc (dirlen + 1 + eltlen);
1256 if (new == NULL)
1257 {
1258 while (i > 0)
1259 free (array[--i]);
1260 return 1;
1261 }
1262
1263 {
1264 char *endp = mempcpy (new, dirname, dirlen);
1265 *endp++ = dirsep_char;
1266 mempcpy (endp, array[i], eltlen);
1267 }
1268 free (array[i]);
1269 array[i] = new;
1270 }
1271
1272 return 0;
1273 }
1274
1275
1276
1277
1278
1279 static int
1280 glob_in_dir (const char *pattern, const char *directory, int flags,
1281 int (*errfunc) (const char *, int),
1282 glob_t *pglob, size_t alloca_used)
1283 {
1284 size_t dirlen = strlen (directory);
1285 void *stream = NULL;
1286 # define GLOBNAMES_MEMBERS(nnames) \
1287 struct globnames *next; size_t count; char *name[nnames];
1288 struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
1289 struct { GLOBNAMES_MEMBERS (64) } init_names_buf;
1290 struct globnames *init_names = (struct globnames *) &init_names_buf;
1291 struct globnames *names = init_names;
1292 struct globnames *names_alloca = init_names;
1293 size_t nfound = 0;
1294 size_t cur = 0;
1295 int meta;
1296 int save;
1297 int result;
1298
1299 alloca_used += sizeof init_names_buf;
1300
1301 init_names->next = NULL;
1302 init_names->count = ((sizeof init_names_buf
1303 - offsetof (struct globnames, name))
1304 / sizeof init_names->name[0]);
1305
1306 meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
1307 if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
1308 {
1309
1310
1311
1312 flags |= GLOB_NOCHECK;
1313 }
1314 else if (meta == GLOBPAT_NONE)
1315 {
1316 size_t patlen = strlen (pattern);
1317 size_t fullsize;
1318 bool alloca_fullname
1319 = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
1320 && glob_use_alloca (alloca_used, fullsize));
1321 char *fullname;
1322 if (alloca_fullname)
1323 fullname = alloca_account (fullsize, alloca_used);
1324 else
1325 {
1326 fullname = malloc (fullsize);
1327 if (fullname == NULL)
1328 return GLOB_NOSPACE;
1329 }
1330
1331 mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
1332 "/", 1),
1333 pattern, patlen + 1);
1334 if (glob_lstat (pglob, flags, fullname) == 0
1335 || errno == EOVERFLOW)
1336
1337
1338 flags |= GLOB_NOCHECK;
1339
1340 if (__glibc_unlikely (!alloca_fullname))
1341 free (fullname);
1342 }
1343 else
1344 {
1345 stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
1346 ? (*pglob->gl_opendir) (directory)
1347 : opendir (directory));
1348 if (stream == NULL)
1349 {
1350 if (errno != ENOTDIR
1351 && ((errfunc != NULL && (*errfunc) (directory, errno))
1352 || (flags & GLOB_ERR)))
1353 return GLOB_ABORTED;
1354 }
1355 else
1356 {
1357 int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
1358 | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
1359 flags |= GLOB_MAGCHAR;
1360
1361 while (1)
1362 {
1363 struct readdir_result d;
1364 {
1365 if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
1366 d = convert_dirent (GL_READDIR (pglob, stream));
1367 else
1368 {
1369 #ifdef COMPILE_GLOB64
1370 d = convert_dirent (__readdir (stream));
1371 #else
1372 d = convert_dirent64 (__readdir64 (stream));
1373 #endif
1374 }
1375 }
1376 if (d.name == NULL)
1377 break;
1378
1379
1380
1381 if (flags & GLOB_ONLYDIR)
1382 switch (readdir_result_type (d))
1383 {
1384 case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
1385 default: continue;
1386 }
1387
1388 if (fnmatch (pattern, d.name, fnm_flags) == 0)
1389 {
1390 if (cur == names->count)
1391 {
1392 struct globnames *newnames;
1393 size_t count = names->count * 2;
1394 size_t nameoff = offsetof (struct globnames, name);
1395 size_t size = FLEXSIZEOF (struct globnames, name,
1396 count * sizeof (char *));
1397 if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
1398 < names->count)
1399 goto memory_error;
1400 if (glob_use_alloca (alloca_used, size))
1401 newnames = names_alloca
1402 = alloca_account (size, alloca_used);
1403 else if ((newnames = malloc (size))
1404 == NULL)
1405 goto memory_error;
1406 newnames->count = count;
1407 newnames->next = names;
1408 names = newnames;
1409 cur = 0;
1410 }
1411 names->name[cur] = strdup (d.name);
1412 if (names->name[cur] == NULL)
1413 goto memory_error;
1414 ++cur;
1415 ++nfound;
1416 if (SIZE_MAX - pglob->gl_offs <= nfound)
1417 goto memory_error;
1418 }
1419 }
1420 }
1421 }
1422
1423 if (nfound == 0 && (flags & GLOB_NOCHECK))
1424 {
1425 size_t len = strlen (pattern);
1426 nfound = 1;
1427 names->name[cur] = malloc (len + 1);
1428 if (names->name[cur] == NULL)
1429 goto memory_error;
1430 *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
1431 }
1432
1433 result = GLOB_NOMATCH;
1434 if (nfound != 0)
1435 {
1436 char **new_gl_pathv;
1437 result = 0;
1438
1439 if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
1440 < pglob->gl_offs + nfound + 1)
1441 goto memory_error;
1442
1443 new_gl_pathv
1444 = realloc (pglob->gl_pathv,
1445 (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
1446 * sizeof (char *));
1447
1448 if (new_gl_pathv == NULL)
1449 {
1450 memory_error:
1451 while (1)
1452 {
1453 struct globnames *old = names;
1454 for (size_t i = 0; i < cur; ++i)
1455 free (names->name[i]);
1456 names = names->next;
1457
1458
1459
1460
1461 if (names == NULL)
1462 {
1463 assert (old == init_names);
1464 break;
1465 }
1466 cur = names->count;
1467 if (old == names_alloca)
1468 names_alloca = names;
1469 else
1470 free (old);
1471 }
1472 result = GLOB_NOSPACE;
1473 }
1474 else
1475 {
1476 while (1)
1477 {
1478 struct globnames *old = names;
1479 for (size_t i = 0; i < cur; ++i)
1480 new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
1481 = names->name[i];
1482 names = names->next;
1483
1484
1485
1486
1487 if (names == NULL)
1488 {
1489 assert (old == init_names);
1490 break;
1491 }
1492 cur = names->count;
1493 if (old == names_alloca)
1494 names_alloca = names;
1495 else
1496 free (old);
1497 }
1498
1499 pglob->gl_pathv = new_gl_pathv;
1500
1501 pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1502
1503 pglob->gl_flags = flags;
1504 }
1505 }
1506
1507 if (stream != NULL)
1508 {
1509 save = errno;
1510 if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
1511 (*pglob->gl_closedir) (stream);
1512 else
1513 closedir (stream);
1514 __set_errno (save);
1515 }
1516
1517 return result;
1518 }