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 #pragma ident "%Z%%M% %I% %E% SMI"
41
42 /*
43 * Based on usr/src/ucblib/libucb/port/gen/scandir.c
44 */
45
46 /*
47 * Scan the directory dirname calling select to make a list of selected
48 * directory entries then sort using qsort and compare routine dcomp.
49 * Returns the number of entries and a pointer to a list of pointers to
50 * struct direct (through namelist). Returns -1 if there were any errors.
51 */
52
53 #include <sys/feature_tests.h>
54
55 #pragma weak _scandir = scandir
56 #pragma weak _alphasort = alphasort
57 #if !defined(_LP64)
58 #pragma weak _scandir64 = scandir64
59 #pragma weak _alphasort64 = alphasort64
60 #endif
61
62 #include "lint.h"
63 #include <dirent.h>
64 #include <errno.h>
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <limits.h>
70
71
72 #if !defined(_LP64)
73 int
scandir64(const char * dirname,struct dirent64 * (* namelist[]),int (* select)(const struct dirent64 *),int (* dcomp)(const struct dirent64 **,const struct dirent64 **))74 scandir64(const char *dirname, struct dirent64 *(*namelist[]),
75 int (*select)(const struct dirent64 *),
76 int (*dcomp)(const struct dirent64 **, const struct dirent64 **))
77 {
78 struct dirent64 *d, *p, **names = NULL;
79 size_t nitems = 0;
80 size_t arraysz, entlen;
81 struct stat64 stb;
82 DIR *dirp;
83 u_longlong_t tmp_arraysz;
84
85 if ((dirp = opendir(dirname)) == NULL)
86 return (-1);
87 if (fstat64(dirp->dd_fd, &stb) < 0)
88 goto fail;
89
90 /*
91 * estimate the array size by taking the size of the directory file
92 * and dividing it by a multiple of the minimum size entry.
93 */
94 tmp_arraysz = stb.st_size / 24; /* 24 bytes on a 64-bit system */
95 if (tmp_arraysz > INT_MAX)
96 arraysz = INT_MAX;
97 else
98 arraysz = (size_t)tmp_arraysz;
99 names = malloc(arraysz * sizeof (struct dirent64 *));
100 if (names == NULL)
101 goto fail;
102
103 while ((d = readdir64(dirp)) != NULL) {
104 if (select != NULL && !(*select)(d))
105 continue; /* just selected names */
106
107 entlen = d->d_reclen;
108 /*
109 * Make a minimum size copy of the data
110 */
111 p = malloc(entlen);
112 if (p == NULL)
113 goto fail;
114 (void) memcpy(p, d, entlen);
115 /*
116 * Check to make sure the array has space left and
117 * realloc the maximum size.
118 */
119 if (nitems >= arraysz) {
120 struct dirent64 **tmp;
121 if (nitems == INT_MAX) {
122 /* overflow */
123 free(p);
124 errno = EOVERFLOW;
125 goto fail;
126 }
127 arraysz += 512; /* no science here */
128 tmp = realloc(names,
129 arraysz * sizeof (struct dirent64 *));
130 if (tmp == NULL) {
131 free(p);
132 goto fail;
133 }
134 names = tmp;
135 }
136 names[nitems++] = p;
137 }
138 (void) closedir(dirp);
139 if (nitems && dcomp != NULL)
140 qsort(names, nitems, sizeof (struct dirent64 *),
141 (int(*)(const void *, const void *))dcomp);
142 *namelist = names;
143
144 return ((int)nitems);
145
146 fail:
147 while (nitems != 0) {
148 free(names[--nitems]);
149 }
150 if (names)
151 free(names);
152 (void) closedir(dirp);
153 return (-1);
154 }
155 #endif
156
157
158 int
scandir(const char * dirname,struct dirent * (* namelist[]),int (* select)(const struct dirent *),int (* dcomp)(const struct dirent **,const struct dirent **))159 scandir(const char *dirname, struct dirent *(*namelist[]),
160 int (*select)(const struct dirent *),
161 int (*dcomp)(const struct dirent **, const struct dirent **))
162 {
163 struct dirent *d, *p, **names = NULL;
164 size_t nitems = 0;
165 size_t arraysz, entlen;
166 struct stat64 stb;
167 DIR *dirp;
168 u_longlong_t tmp_arraysz;
169
170 if ((dirp = opendir(dirname)) == NULL)
171 return (-1);
172 if (fstat64(dirp->dd_fd, &stb) < 0)
173 goto fail;
174
175 /*
176 * estimate the array size by taking the size of the directory file
177 * and dividing it by a multiple of the minimum size entry.
178 */
179 tmp_arraysz = stb.st_size / 24; /* 24 bytes on a 64-bit system */
180 if (tmp_arraysz > INT_MAX)
181 arraysz = INT_MAX;
182 else
183 arraysz = (size_t)tmp_arraysz;
184 names = malloc(arraysz * sizeof (struct dirent *));
185 if (names == NULL)
186 goto fail;
187
188 while ((d = readdir(dirp)) != NULL) {
189 if (select != NULL && !(*select)(d))
190 continue; /* just selected names */
191
192 entlen = d->d_reclen;
193 /*
194 * Make a minimum size copy of the data
195 */
196 p = malloc(entlen);
197 if (p == NULL)
198 goto fail;
199 (void) memcpy(p, d, entlen);
200 /*
201 * Check to make sure the array has space left and
202 * realloc the maximum size.
203 */
204 if (nitems >= arraysz) {
205 struct dirent **tmp;
206 if (nitems == INT_MAX) {
207 /* overflow */
208 free(p);
209 errno = EOVERFLOW;
210 goto fail;
211 }
212 arraysz += 512; /* no science here */
213 tmp = realloc(names,
214 arraysz * sizeof (struct dirent *));
215 if (tmp == NULL) {
216 free(p);
217 goto fail;
218 }
219 names = tmp;
220 }
221 names[nitems++] = p;
222 }
223 (void) closedir(dirp);
224 if (nitems && dcomp != NULL)
225 qsort(names, nitems, sizeof (struct dirent *),
226 (int(*)(const void *, const void *))dcomp);
227 *namelist = names;
228
229 return ((int)nitems);
230
231 fail:
232 while (nitems != 0) {
233 free(names[--nitems]);
234 }
235 if (names)
236 free(names);
237 (void) closedir(dirp);
238 return (-1);
239 }
240
241 /*
242 * Alphabetic order comparison routine for those who want it.
243 */
244 int
alphasort(const struct dirent ** d1,const struct dirent ** d2)245 alphasort(const struct dirent **d1, const struct dirent **d2)
246 {
247 return (strcoll((*d1)->d_name,
248 (*d2)->d_name));
249 }
250
251 #if !defined(_LP64)
252 int
alphasort64(const struct dirent64 ** d1,const struct dirent64 ** d2)253 alphasort64(const struct dirent64 **d1, const struct dirent64 **d2)
254 {
255 return (strcoll((*d1)->d_name,
256 (*d2)->d_name));
257 }
258 #endif
259