18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 458f0484fSRodney W. Grimes * Copyright (c) 1983, 1993 558f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 658f0484fSRodney W. Grimes * 758f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 858f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 958f0484fSRodney W. Grimes * are met: 1058f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1158f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1258f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1358f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1458f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 1658f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1758f0484fSRodney W. Grimes * without specific prior written permission. 1858f0484fSRodney W. Grimes * 1958f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2058f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2158f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2258f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2358f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2458f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2558f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2658f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2758f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2858f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2958f0484fSRodney W. Grimes * SUCH DAMAGE. 3058f0484fSRodney W. Grimes */ 3158f0484fSRodney W. Grimes 32b231cb39SDavid E. O'Brien #include <sys/cdefs.h> 33c1920558SJohn Baldwin __SCCSID("@(#)scandir.c 8.3 (Berkeley) 1/2/94"); 34b231cb39SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3558f0484fSRodney W. Grimes 3658f0484fSRodney W. Grimes /* 3758f0484fSRodney W. Grimes * Scan the directory dirname calling select to make a list of selected 3858f0484fSRodney W. Grimes * directory entries then sort using qsort and compare routine dcomp. 3958f0484fSRodney W. Grimes * Returns the number of entries and a pointer to a list of pointers to 4058f0484fSRodney W. Grimes * struct dirent (through namelist). Returns -1 if there were any errors. 4158f0484fSRodney W. Grimes */ 4258f0484fSRodney W. Grimes 43d201fe46SDaniel Eischen #include "namespace.h" 4458f0484fSRodney W. Grimes #include <dirent.h> 45*9fb8e8eeSKonstantin Belousov #include <fcntl.h> 4658f0484fSRodney W. Grimes #include <stdlib.h> 4758f0484fSRodney W. Grimes #include <string.h> 48*9fb8e8eeSKonstantin Belousov #include <unistd.h> 49d201fe46SDaniel Eischen #include "un-namespace.h" 5058f0484fSRodney W. Grimes 5146cdc140SDavid Chisnall #ifdef I_AM_SCANDIR_B 5246cdc140SDavid Chisnall #include "block_abi.h" 5346cdc140SDavid Chisnall #define SELECT(x) CALL_BLOCK(select, x) 5446cdc140SDavid Chisnall #ifndef __BLOCKS__ 55cc321ccdSKonstantin Belousov void qsort_b(void *, size_t, size_t, void *); 5646cdc140SDavid Chisnall #endif 5746cdc140SDavid Chisnall #else 5846cdc140SDavid Chisnall #define SELECT(x) select(x) 5946cdc140SDavid Chisnall #endif 6046cdc140SDavid Chisnall 61d10af81dSJohn Baldwin #ifdef I_AM_SCANDIR_B 62d10af81dSJohn Baldwin typedef DECLARE_BLOCK(int, select_block, const struct dirent *); 63d10af81dSJohn Baldwin typedef DECLARE_BLOCK(int, dcomp_block, const struct dirent **, 64d10af81dSJohn Baldwin const struct dirent **); 65d10af81dSJohn Baldwin #else 66f5636f88SKonstantin Belousov static int alphasort_thunk(void *thunk, const void *p1, const void *p2); 67992bcb37SMateusz Guzik #endif 68f5636f88SKonstantin Belousov 69cb6e97f4SKonstantin Belousov static int 7046cdc140SDavid Chisnall #ifdef I_AM_SCANDIR_B 71cb6e97f4SKonstantin Belousov scandir_b_dirp(DIR *dirp, struct dirent ***namelist, select_block select, 72d10af81dSJohn Baldwin dcomp_block dcomp) 7346cdc140SDavid Chisnall #else 74cb6e97f4SKonstantin Belousov scandir_dirp(DIR *dirp, struct dirent ***namelist, 754176dd52SKonstantin Belousov int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **, 764176dd52SKonstantin Belousov const struct dirent **)) 7746cdc140SDavid Chisnall #endif 7858f0484fSRodney W. Grimes { 79b231cb39SDavid E. O'Brien struct dirent *d, *p, **names = NULL; 805f2bd3bdSPedro F. Giffuni size_t arraysz, numitems; 8158f0484fSRodney W. Grimes 820a8ff54eSConrad Meyer numitems = 0; 8318798c64SDavid Schultz arraysz = 32; /* initial estimate of the array size */ 8458f0484fSRodney W. Grimes names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); 8558f0484fSRodney W. Grimes if (names == NULL) 8629595ffdSJulian Elischer goto fail; 8758f0484fSRodney W. Grimes 8858f0484fSRodney W. Grimes while ((d = readdir(dirp)) != NULL) { 8946cdc140SDavid Chisnall if (select != NULL && !SELECT(d)) 9058f0484fSRodney W. Grimes continue; /* just selected names */ 9158f0484fSRodney W. Grimes /* 9258f0484fSRodney W. Grimes * Make a minimum size copy of the data 9358f0484fSRodney W. Grimes */ 9469921123SKonstantin Belousov p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d)); 9558f0484fSRodney W. Grimes if (p == NULL) 9629595ffdSJulian Elischer goto fail; 97e169c667SPoul-Henning Kamp p->d_fileno = d->d_fileno; 98e169c667SPoul-Henning Kamp p->d_type = d->d_type; 9958f0484fSRodney W. Grimes p->d_reclen = d->d_reclen; 10058f0484fSRodney W. Grimes p->d_namlen = d->d_namlen; 10158f0484fSRodney W. Grimes bcopy(d->d_name, p->d_name, p->d_namlen + 1); 10258f0484fSRodney W. Grimes /* 10358f0484fSRodney W. Grimes * Check to make sure the array has space left and 10458f0484fSRodney W. Grimes * realloc the maximum size. 10558f0484fSRodney W. Grimes */ 10656362c6fSPedro F. Giffuni if (numitems >= arraysz) { 10729595ffdSJulian Elischer struct dirent **names2; 10829595ffdSJulian Elischer 1099f36610fSPedro F. Giffuni names2 = reallocarray(names, arraysz, 1109f36610fSPedro F. Giffuni 2 * sizeof(struct dirent *)); 11129595ffdSJulian Elischer if (names2 == NULL) { 11229595ffdSJulian Elischer free(p); 11329595ffdSJulian Elischer goto fail; 11458f0484fSRodney W. Grimes } 11529595ffdSJulian Elischer names = names2; 11618798c64SDavid Schultz arraysz *= 2; 11729595ffdSJulian Elischer } 11856362c6fSPedro F. Giffuni names[numitems++] = p; 11958f0484fSRodney W. Grimes } 12058f0484fSRodney W. Grimes closedir(dirp); 12156362c6fSPedro F. Giffuni if (numitems && dcomp != NULL) 12246cdc140SDavid Chisnall #ifdef I_AM_SCANDIR_B 12356362c6fSPedro F. Giffuni qsort_b(names, numitems, sizeof(struct dirent *), (void*)dcomp); 12446cdc140SDavid Chisnall #else 12556362c6fSPedro F. Giffuni qsort_r(names, numitems, sizeof(struct dirent *), 126f5636f88SKonstantin Belousov &dcomp, alphasort_thunk); 12746cdc140SDavid Chisnall #endif 12858f0484fSRodney W. Grimes *namelist = names; 12956362c6fSPedro F. Giffuni return (numitems); 13029595ffdSJulian Elischer 13129595ffdSJulian Elischer fail: 13256362c6fSPedro F. Giffuni while (numitems > 0) 13356362c6fSPedro F. Giffuni free(names[--numitems]); 13429595ffdSJulian Elischer free(names); 13529595ffdSJulian Elischer closedir(dirp); 1364176dd52SKonstantin Belousov return (-1); 13758f0484fSRodney W. Grimes } 13858f0484fSRodney W. Grimes 139cb6e97f4SKonstantin Belousov int 140cb6e97f4SKonstantin Belousov #ifdef I_AM_SCANDIR_B 141cb6e97f4SKonstantin Belousov scandir_b(const char *dirname, struct dirent ***namelist, select_block select, 142cb6e97f4SKonstantin Belousov dcomp_block dcomp) 143cb6e97f4SKonstantin Belousov #else 144cb6e97f4SKonstantin Belousov scandir(const char *dirname, struct dirent ***namelist, 145cb6e97f4SKonstantin Belousov int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **, 146cb6e97f4SKonstantin Belousov const struct dirent **)) 147cb6e97f4SKonstantin Belousov #endif 148cb6e97f4SKonstantin Belousov { 149cb6e97f4SKonstantin Belousov DIR *dirp; 150cb6e97f4SKonstantin Belousov 151cb6e97f4SKonstantin Belousov dirp = opendir(dirname); 152cb6e97f4SKonstantin Belousov if (dirp == NULL) 153cb6e97f4SKonstantin Belousov return (-1); 154cb6e97f4SKonstantin Belousov return ( 155cb6e97f4SKonstantin Belousov #ifdef I_AM_SCANDIR_B 156cb6e97f4SKonstantin Belousov scandir_b_dirp 157cb6e97f4SKonstantin Belousov #else 158cb6e97f4SKonstantin Belousov scandir_dirp 159cb6e97f4SKonstantin Belousov #endif 160cb6e97f4SKonstantin Belousov (dirp, namelist, select, dcomp)); 161cb6e97f4SKonstantin Belousov } 162cb6e97f4SKonstantin Belousov 163cc321ccdSKonstantin Belousov #ifndef I_AM_SCANDIR_B 164*9fb8e8eeSKonstantin Belousov int 165*9fb8e8eeSKonstantin Belousov scandirat(int dirfd, const char *dirname, struct dirent ***namelist, 166*9fb8e8eeSKonstantin Belousov int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **, 167*9fb8e8eeSKonstantin Belousov const struct dirent **)) 168*9fb8e8eeSKonstantin Belousov { 169*9fb8e8eeSKonstantin Belousov DIR *dirp; 170*9fb8e8eeSKonstantin Belousov int fd; 171*9fb8e8eeSKonstantin Belousov 172*9fb8e8eeSKonstantin Belousov fd = _openat(dirfd, dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC); 173*9fb8e8eeSKonstantin Belousov if (fd == -1) 174*9fb8e8eeSKonstantin Belousov return (-1); 175*9fb8e8eeSKonstantin Belousov dirp = fdopendir(fd); 176*9fb8e8eeSKonstantin Belousov if (dirp == NULL) { 177*9fb8e8eeSKonstantin Belousov _close(fd); 178*9fb8e8eeSKonstantin Belousov return (-1); 179*9fb8e8eeSKonstantin Belousov } 180*9fb8e8eeSKonstantin Belousov return (scandir_dirp(dirp, namelist, select, dcomp)); 181*9fb8e8eeSKonstantin Belousov } 182*9fb8e8eeSKonstantin Belousov 18358f0484fSRodney W. Grimes /* 18458f0484fSRodney W. Grimes * Alphabetic order comparison routine for those who want it. 1855fc5e42aSAndrey A. Chernov * POSIX 2008 requires that alphasort() uses strcoll(). 18658f0484fSRodney W. Grimes */ 18758f0484fSRodney W. Grimes int 1884176dd52SKonstantin Belousov alphasort(const struct dirent **d1, const struct dirent **d2) 18958f0484fSRodney W. Grimes { 1904176dd52SKonstantin Belousov 191dcdafd0eSAndrey A. Chernov return (strcoll((*d1)->d_name, (*d2)->d_name)); 19258f0484fSRodney W. Grimes } 193f5636f88SKonstantin Belousov 194f5636f88SKonstantin Belousov static int 195f5636f88SKonstantin Belousov alphasort_thunk(void *thunk, const void *p1, const void *p2) 196f5636f88SKonstantin Belousov { 197f5636f88SKonstantin Belousov int (*dc)(const struct dirent **, const struct dirent **); 198f5636f88SKonstantin Belousov 199f5636f88SKonstantin Belousov dc = *(int (**)(const struct dirent **, const struct dirent **))thunk; 200f5636f88SKonstantin Belousov return (dc((const struct dirent **)p1, (const struct dirent **)p2)); 201f5636f88SKonstantin Belousov } 202cc321ccdSKonstantin Belousov #endif 203