1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 /*
41 * Based on usr/src/ucblib/libucb/port/gen/scandir.c
42 */
43
44 /*
45 * Scan the directory dirname calling select to make a list of selected
46 * directory entries then sort using qsort and compare routine dcomp.
47 * Returns the number of entries and a pointer to a list of pointers to
48 * struct direct (through namelist). Returns -1 if there were any errors.
49 */
50
51 #include <sys/feature_tests.h>
52
53 #pragma weak _scandir = scandir
54 #pragma weak _alphasort = alphasort
55 #if !defined(_LP64)
56 #pragma weak _scandir64 = scandir64
57 #pragma weak _alphasort64 = alphasort64
58 #endif
59
60 #include "lint.h"
61 #include <dirent.h>
62 #include <errno.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <limits.h>
68
69
70 #if !defined(_LP64)
71 int
scandir64(const char * dirname,struct dirent64 * (* namelist[]),int (* select)(const struct dirent64 *),int (* dcomp)(const struct dirent64 **,const struct dirent64 **))72 scandir64(const char *dirname, struct dirent64 *(*namelist[]),
73 int (*select)(const struct dirent64 *),
74 int (*dcomp)(const struct dirent64 **, const struct dirent64 **))
75 {
76 struct dirent64 *d, *p, **names = NULL;
77 size_t nitems = 0;
78 size_t arraysz, entlen;
79 struct stat64 stb;
80 DIR *dirp;
81 u_longlong_t tmp_arraysz;
82
83 if ((dirp = opendir(dirname)) == NULL)
84 return (-1);
85 if (fstat64(dirp->dd_fd, &stb) < 0)
86 goto fail;
87
88 /*
89 * estimate the array size by taking the size of the directory file
90 * and dividing it by a multiple of the minimum size entry.
91 */
92 tmp_arraysz = stb.st_size / 24; /* 24 bytes on a 64-bit system */
93 if (tmp_arraysz > INT_MAX)
94 arraysz = INT_MAX;
95 else
96 arraysz = (size_t)tmp_arraysz;
97 names = malloc(arraysz * sizeof (struct dirent64 *));
98 if (names == NULL)
99 goto fail;
100
101 while ((d = readdir64(dirp)) != NULL) {
102 if (select != NULL && !(*select)(d))
103 continue; /* just selected names */
104
105 entlen = d->d_reclen;
106 /*
107 * Make a minimum size copy of the data
108 */
109 p = malloc(entlen);
110 if (p == NULL)
111 goto fail;
112 (void) memcpy(p, d, entlen);
113 /*
114 * Check to make sure the array has space left and
115 * realloc the maximum size.
116 */
117 if (nitems >= arraysz) {
118 struct dirent64 **tmp;
119 if (nitems == INT_MAX) {
120 /* overflow */
121 free(p);
122 errno = EOVERFLOW;
123 goto fail;
124 }
125 arraysz += 512; /* no science here */
126 tmp = realloc(names,
127 arraysz * sizeof (struct dirent64 *));
128 if (tmp == NULL) {
129 free(p);
130 goto fail;
131 }
132 names = tmp;
133 }
134 names[nitems++] = p;
135 }
136 (void) closedir(dirp);
137 if (nitems && dcomp != NULL)
138 qsort(names, nitems, sizeof (struct dirent64 *),
139 (int(*)(const void *, const void *))dcomp);
140 *namelist = names;
141
142 return ((int)nitems);
143
144 fail:
145 while (nitems != 0) {
146 free(names[--nitems]);
147 }
148 if (names)
149 free(names);
150 (void) closedir(dirp);
151 return (-1);
152 }
153 #endif
154
155
156 int
scandir(const char * dirname,struct dirent * (* namelist[]),int (* select)(const struct dirent *),int (* dcomp)(const struct dirent **,const struct dirent **))157 scandir(const char *dirname, struct dirent *(*namelist[]),
158 int (*select)(const struct dirent *),
159 int (*dcomp)(const struct dirent **, const struct dirent **))
160 {
161 struct dirent *d, *p, **names = NULL;
162 size_t nitems = 0;
163 size_t arraysz, entlen;
164 struct stat64 stb;
165 DIR *dirp;
166 u_longlong_t tmp_arraysz;
167
168 if ((dirp = opendir(dirname)) == NULL)
169 return (-1);
170 if (fstat64(dirp->dd_fd, &stb) < 0)
171 goto fail;
172
173 /*
174 * estimate the array size by taking the size of the directory file
175 * and dividing it by a multiple of the minimum size entry.
176 */
177 tmp_arraysz = stb.st_size / 24; /* 24 bytes on a 64-bit system */
178 if (tmp_arraysz > INT_MAX)
179 arraysz = INT_MAX;
180 else
181 arraysz = (size_t)tmp_arraysz;
182 names = malloc(arraysz * sizeof (struct dirent *));
183 if (names == NULL)
184 goto fail;
185
186 while ((d = readdir(dirp)) != NULL) {
187 if (select != NULL && !(*select)(d))
188 continue; /* just selected names */
189
190 entlen = d->d_reclen;
191 /*
192 * Make a minimum size copy of the data
193 */
194 p = malloc(entlen);
195 if (p == NULL)
196 goto fail;
197 (void) memcpy(p, d, entlen);
198 /*
199 * Check to make sure the array has space left and
200 * realloc the maximum size.
201 */
202 if (nitems >= arraysz) {
203 struct dirent **tmp;
204 if (nitems == INT_MAX) {
205 /* overflow */
206 free(p);
207 errno = EOVERFLOW;
208 goto fail;
209 }
210 arraysz += 512; /* no science here */
211 tmp = realloc(names,
212 arraysz * sizeof (struct dirent *));
213 if (tmp == NULL) {
214 free(p);
215 goto fail;
216 }
217 names = tmp;
218 }
219 names[nitems++] = p;
220 }
221 (void) closedir(dirp);
222 if (nitems && dcomp != NULL)
223 qsort(names, nitems, sizeof (struct dirent *),
224 (int(*)(const void *, const void *))dcomp);
225 *namelist = names;
226
227 return ((int)nitems);
228
229 fail:
230 while (nitems != 0) {
231 free(names[--nitems]);
232 }
233 if (names)
234 free(names);
235 (void) closedir(dirp);
236 return (-1);
237 }
238
239 /*
240 * Alphabetic order comparison routine for those who want it.
241 */
242 int
alphasort(const struct dirent ** d1,const struct dirent ** d2)243 alphasort(const struct dirent **d1, const struct dirent **d2)
244 {
245 return (strcoll((*d1)->d_name,
246 (*d2)->d_name));
247 }
248
249 #if !defined(_LP64)
250 int
alphasort64(const struct dirent64 ** d1,const struct dirent64 ** d2)251 alphasort64(const struct dirent64 **d1, const struct dirent64 **d2)
252 {
253 return (strcoll((*d1)->d_name,
254 (*d2)->d_name));
255 }
256 #endif
257