]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 1992-2014 Free Software Foundation, Inc. |
c55fbd1e UD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU Lesser General Public | |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
8 | ||
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Lesser General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
c55fbd1e | 17 | |
8e49df1d RM |
18 | /* We need to avoid the header declaration of scandir64, because |
19 | the types don't match scandir and then the compiler will | |
20 | complain about the mismatch when we do the alias below. */ | |
21 | #define scandirat64 __renamed_scandirat64 | |
22 | ||
c55fbd1e | 23 | #include <dirent.h> |
8e49df1d RM |
24 | |
25 | #undef scandirat64 | |
26 | ||
c55fbd1e UD |
27 | #include <stdlib.h> |
28 | #include <string.h> | |
29 | #include <errno.h> | |
30 | #include <bits/libc-lock.h> | |
31 | ||
32 | #ifndef SCANDIRAT | |
33 | # define SCANDIRAT scandirat | |
34 | # define READDIR __readdir | |
35 | # define DIRENT_TYPE struct dirent | |
36 | #endif | |
37 | ||
38 | #ifndef SKIP_SCANDIR_CANCEL | |
39 | void | |
40 | __scandir_cancel_handler (void *arg) | |
41 | { | |
42 | struct scandir_cancel_struct *cp = arg; | |
43 | size_t i; | |
44 | void **v = cp->v; | |
45 | ||
46 | for (i = 0; i < cp->cnt; ++i) | |
47 | free (v[i]); | |
48 | free (v); | |
49 | (void) __closedir (cp->dp); | |
50 | } | |
51 | #endif | |
52 | ||
53 | ||
54 | int | |
55 | SCANDIRAT (dfd, dir, namelist, select, cmp) | |
56 | int dfd; | |
57 | const char *dir; | |
58 | DIRENT_TYPE ***namelist; | |
59 | int (*select) (const DIRENT_TYPE *); | |
60 | int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **); | |
61 | { | |
62 | DIR *dp = __opendirat (dfd, dir); | |
63 | DIRENT_TYPE **v = NULL; | |
64 | size_t vsize = 0; | |
65 | struct scandir_cancel_struct c; | |
66 | DIRENT_TYPE *d; | |
67 | int save; | |
68 | ||
69 | if (dp == NULL) | |
70 | return -1; | |
71 | ||
72 | save = errno; | |
73 | __set_errno (0); | |
74 | ||
75 | c.dp = dp; | |
76 | c.v = NULL; | |
77 | c.cnt = 0; | |
78 | __libc_cleanup_push (__scandir_cancel_handler, &c); | |
79 | ||
80 | while ((d = READDIR (dp)) != NULL) | |
81 | { | |
82 | int use_it = select == NULL; | |
83 | ||
84 | if (! use_it) | |
85 | { | |
86 | use_it = select (d); | |
87 | /* The select function might have changed errno. It was | |
88 | zero before and it need to be again to make the latter | |
89 | tests work. */ | |
90 | __set_errno (0); | |
91 | } | |
92 | ||
93 | if (use_it) | |
94 | { | |
95 | DIRENT_TYPE *vnew; | |
96 | size_t dsize; | |
97 | ||
98 | /* Ignore errors from select or readdir */ | |
99 | __set_errno (0); | |
100 | ||
a1ffb40e | 101 | if (__glibc_unlikely (c.cnt == vsize)) |
c55fbd1e UD |
102 | { |
103 | DIRENT_TYPE **new; | |
104 | if (vsize == 0) | |
105 | vsize = 10; | |
106 | else | |
107 | vsize *= 2; | |
108 | new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v)); | |
109 | if (new == NULL) | |
110 | break; | |
111 | v = new; | |
112 | c.v = (void *) v; | |
113 | } | |
114 | ||
115 | dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d; | |
116 | vnew = (DIRENT_TYPE *) malloc (dsize); | |
117 | if (vnew == NULL) | |
118 | break; | |
119 | ||
120 | v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize); | |
121 | } | |
122 | } | |
123 | ||
124 | if (__builtin_expect (errno, 0) != 0) | |
125 | { | |
126 | save = errno; | |
127 | ||
128 | while (c.cnt > 0) | |
129 | free (v[--c.cnt]); | |
130 | free (v); | |
131 | c.cnt = -1; | |
132 | } | |
133 | else | |
134 | { | |
135 | /* Sort the list if we have a comparison function to sort with. */ | |
136 | if (cmp != NULL) | |
137 | qsort (v, c.cnt, sizeof (*v), | |
138 | (int (*) (const void *, const void *)) cmp); | |
139 | ||
140 | *namelist = v; | |
141 | } | |
142 | ||
143 | __libc_cleanup_pop (0); | |
144 | ||
145 | (void) __closedir (dp); | |
146 | __set_errno (save); | |
147 | ||
148 | return c.cnt; | |
149 | } | |
14d96785 | 150 | libc_hidden_def (SCANDIRAT) |
8e49df1d RM |
151 | |
152 | #ifdef _DIRENT_MATCHES_DIRENT64 | |
153 | weak_alias (scandirat, scandirat64) | |
154 | #endif |