11038
|
1 /* Copyright (C) 1992-1998, 2000, 2002, 2003, 2009 Free Software Foundation, Inc. |
|
2 This file is part of the GNU C Library. |
|
3 |
|
4 This program is free software; you can redistribute it and/or modify it |
|
5 under the terms of the GNU General Public License as published by the |
|
6 Free Software Foundation; either version 2, or (at your option) any |
|
7 later version. |
|
8 |
|
9 This program 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 |
|
12 GNU General Public License for more details. |
|
13 |
|
14 You should have received a copy of the GNU General Public License |
|
15 along with this program; if not, write to the Free Software Foundation, |
|
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
|
17 |
|
18 #include <config.h> |
|
19 |
|
20 #include <dirent.h> |
|
21 |
|
22 #include <stdlib.h> |
|
23 #include <string.h> |
|
24 #include <errno.h> |
|
25 #if _LIBC |
|
26 # include <bits/libc-lock.h> |
|
27 #endif |
|
28 |
|
29 #if ! defined __builtin_expect && __GNUC__ < 3 |
|
30 # define __builtin_expect(expr, expected) (expr) |
|
31 #endif |
|
32 |
|
33 #undef select |
|
34 |
|
35 #if _LIBC |
|
36 # ifndef SCANDIR |
|
37 # define SCANDIR scandir |
|
38 # define READDIR __readdir |
|
39 # define DIRENT_TYPE struct dirent |
|
40 # endif |
|
41 #else |
|
42 # define SCANDIR scandir |
|
43 # define READDIR readdir |
|
44 # define DIRENT_TYPE struct dirent |
|
45 # define __opendir opendir |
|
46 # define __closedir closedir |
|
47 # define __set_errno(val) errno = (val) |
|
48 #endif |
|
49 |
|
50 #ifndef SCANDIR_CANCEL |
|
51 # define SCANDIR_CANCEL |
|
52 struct scandir_cancel_struct |
|
53 { |
|
54 DIR *dp; |
|
55 void *v; |
|
56 size_t cnt; |
|
57 }; |
|
58 |
|
59 # if _LIBC |
|
60 static void |
|
61 cancel_handler (void *arg) |
|
62 { |
|
63 struct scandir_cancel_struct *cp = arg; |
|
64 size_t i; |
|
65 void **v = cp->v; |
|
66 |
|
67 for (i = 0; i < cp->cnt; ++i) |
|
68 free (v[i]); |
|
69 free (v); |
|
70 (void) __closedir (cp->dp); |
|
71 } |
|
72 # endif |
|
73 #endif |
|
74 |
|
75 |
|
76 int |
|
77 SCANDIR (const char *dir, |
|
78 DIRENT_TYPE ***namelist, |
|
79 int (*select) (const DIRENT_TYPE *), |
|
80 int (*cmp) (const DIRENT_TYPE **, const DIRENT_TYPE **)) |
|
81 { |
|
82 DIR *dp = __opendir (dir); |
|
83 DIRENT_TYPE **v = NULL; |
|
84 size_t vsize = 0; |
|
85 struct scandir_cancel_struct c; |
|
86 DIRENT_TYPE *d; |
|
87 int save; |
|
88 |
|
89 if (dp == NULL) |
|
90 return -1; |
|
91 |
|
92 save = errno; |
|
93 __set_errno (0); |
|
94 |
|
95 c.dp = dp; |
|
96 c.v = NULL; |
|
97 c.cnt = 0; |
|
98 #if _LIBC |
|
99 __libc_cleanup_push (cancel_handler, &c); |
|
100 #endif |
|
101 |
|
102 while ((d = READDIR (dp)) != NULL) |
|
103 { |
|
104 int use_it = select == NULL; |
|
105 |
|
106 if (! use_it) |
|
107 { |
|
108 use_it = select (d); |
|
109 /* The select function might have changed errno. It was |
|
110 zero before and it need to be again to make the latter |
|
111 tests work. */ |
|
112 __set_errno (0); |
|
113 } |
|
114 |
|
115 if (use_it) |
|
116 { |
|
117 DIRENT_TYPE *vnew; |
|
118 size_t dsize; |
|
119 |
|
120 /* Ignore errors from select or readdir */ |
|
121 __set_errno (0); |
|
122 |
|
123 if (__builtin_expect (c.cnt == vsize, 0)) |
|
124 { |
|
125 DIRENT_TYPE **new; |
|
126 if (vsize == 0) |
|
127 vsize = 10; |
|
128 else |
|
129 vsize *= 2; |
|
130 new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v)); |
|
131 if (new == NULL) |
|
132 break; |
|
133 v = new; |
|
134 c.v = (void *) v; |
|
135 } |
|
136 |
|
137 dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d; |
|
138 vnew = (DIRENT_TYPE *) malloc (dsize); |
|
139 if (vnew == NULL) |
|
140 break; |
|
141 |
|
142 v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize); |
|
143 } |
|
144 } |
|
145 |
|
146 if (__builtin_expect (errno, 0) != 0) |
|
147 { |
|
148 save = errno; |
|
149 |
|
150 while (c.cnt > 0) |
|
151 free (v[--c.cnt]); |
|
152 free (v); |
|
153 c.cnt = -1; |
|
154 } |
|
155 else |
|
156 { |
|
157 /* Sort the list if we have a comparison function to sort with. */ |
|
158 if (cmp != NULL) |
|
159 qsort (v, c.cnt, sizeof (*v), (int (*) (const void *, const void *)) cmp); |
|
160 |
|
161 *namelist = v; |
|
162 } |
|
163 |
|
164 #if _LIBC |
|
165 __libc_cleanup_pop (0); |
|
166 #endif |
|
167 |
|
168 (void) __closedir (dp); |
|
169 __set_errno (save); |
|
170 |
|
171 return c.cnt; |
|
172 } |