4 * SPDX-License-Identifier: BSD-3-Clause
6 * Copyright (c) 1983, 1993
7 * The Regents of the University of California. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __SCCSID("@(#)scandir.c 8.3 (Berkeley) 1/2/94");
36 __FBSDID("$FreeBSD: head/lib/libc/gen/scandir.c 335898 2018-07-03 17:31:45Z jhb $");
39 * Scan the directory dirname calling select to make a list of selected
40 * directory entries then sort using qsort and compare routine dcomp.
41 * Returns the number of entries and a pointer to a list of pointers to
42 * struct dirent (through namelist). Returns -1 if there were any errors.
52 * The DIRSIZ macro gives the minimum record length which will hold
53 * the directory entry. This requires the amount of space in struct dirent
54 * without the d_name field, plus enough space for the name with a terminating
55 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
58 #ifdef _DIRENT_HAVE_D_NAMLEN
60 (offsetof (struct dirent, d_name) + (((dp)->d_namlen+1 + 3) &~ 3))
63 (offsetof (struct dirent, d_name) + ((strlen((dp)->d_name)+1 + 3) &~ 3))
68 scandir(const char *dirname
, struct dirent
***namelist
,
69 int (*select
)(const struct dirent
*), int (*dcomp
)(const struct dirent
**,
70 const struct dirent
**))
72 register struct dirent
*d
, *p
, **names
= NULL
;
73 register size_t arraysz
, numitems
;
76 if ((dirp
= opendir(dirname
)) == NULL
)
79 __lock_acquire_recursive(dirp
->dd_lock
);
83 arraysz
= 32; /* initial estimate of the array size */
84 names
= (struct dirent
**)malloc(arraysz
* sizeof(struct dirent
*));
88 while ((d
= readdir(dirp
)) != NULL
) {
89 if (select
!= NULL
&& !(*select
)(d
))
90 continue; /* just selected names */
92 * Make a minimum size copy of the data
94 p
= (struct dirent
*)malloc(DIRSIZ(d
));
99 p
->d_type
= d
->d_type
;
101 p
->d_reclen
= d
->d_reclen
;
102 #ifdef _DIRENT_HAVE_D_NAMLEN
103 p
->d_namlen
= d
->d_namlen
;
104 bcopy(d
->d_name
, p
->d_name
, p
->d_namlen
+ 1);
106 strcpy(p
->d_name
, d
->d_name
);
109 * Check to make sure the array has space left and
110 * realloc the maximum size.
112 if (numitems
>= arraysz
) {
113 struct dirent
**names2
;
115 names2
= reallocarray(names
, arraysz
,
116 2 * sizeof(struct dirent
*));
117 if (names2
== NULL
) {
124 names
[numitems
++] = p
;
127 if (numitems
&& dcomp
!= NULL
)
128 qsort(names
, numitems
, sizeof(struct dirent
*), (void *)dcomp
);
131 __lock_release_recursive(dirp
->dd_lock
);
137 free(names
[--numitems
]);
141 __lock_release_recursive(dirp
->dd_lock
);
147 * Alphabetic order comparison routine for those who want it.
148 * POSIX 2008 requires that alphasort() uses strcoll().
151 alphasort(const struct dirent
**d1
, const struct dirent
**d2
)
154 return (strcoll((*d1
)->d_name
, (*d2
)->d_name
));
157 #endif /* ! HAVE_OPENDIR */