1 #ifndef HAVE_OPENDIR 2 3 /* 4 * Copyright (c) 1983 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #if defined(LIBC_SCCS) && !defined(lint) 37 static char sccsid[] = "@(#)scandir.c 5.10 (Berkeley) 2/23/91"; 38 #endif /* LIBC_SCCS and not lint */ 39 40 /* 41 * Scan the directory dirname calling select to make a list of selected 42 * directory entries then sort using qsort and compare routine dcomp. 43 * Returns the number of entries and a pointer to a list of pointers to 44 * struct dirent (through namelist). Returns -1 if there were any errors. 45 */ 46 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <dirent.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <sys/lock.h> 53 54 /* 55 * The DIRSIZ macro gives the minimum record length which will hold 56 * the directory entry. This requires the amount of space in struct dirent 57 * without the d_name field, plus enough space for the name with a terminating 58 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. 59 */ 60 #undef DIRSIZ 61 #ifdef _DIRENT_HAVE_D_NAMLEN 62 #define DIRSIZ(dp) \ 63 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) 64 #else 65 #define DIRSIZ(dp) \ 66 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((strlen((dp)->d_name)+1 + 3) &~ 3)) 67 #endif 68 69 #ifndef __P 70 #define __P(args) () 71 #endif 72 73 int 74 _DEFUN(scandir, (dirname, namelist, select, dcomp), 75 const char *dirname _AND 76 struct dirent ***namelist _AND 77 int (*select) __P((struct dirent *)) _AND 78 int (*dcomp) __P((const void *, const void *))) 79 { 80 register struct dirent *d, *p, **names; 81 register size_t nitems; 82 struct stat stb; 83 long arraysz; 84 DIR *dirp; 85 86 if ((dirp = opendir(dirname)) == NULL) 87 return(-1); 88 #ifdef HAVE_DD_LOCK 89 __lock_acquire_recursive(dirp->dd_lock); 90 #endif 91 if (fstat(dirp->dd_fd, &stb) < 0) { 92 #ifdef HAVE_DD_LOCK 93 __lock_release_recursive(dirp->dd_lock); 94 #endif 95 return(-1); 96 } 97 98 /* 99 * estimate the array size by taking the size of the directory file 100 * and dividing it by a multiple of the minimum size entry. 101 */ 102 arraysz = (stb.st_size / 24); 103 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); 104 if (names == NULL) { 105 #ifdef HAVE_DD_LOCK 106 __lock_release_recursive(dirp->dd_lock); 107 #endif 108 return(-1); 109 } 110 111 nitems = 0; 112 while ((d = readdir(dirp)) != NULL) { 113 if (select != NULL && !(*select)(d)) 114 continue; /* just selected names */ 115 /* 116 * Make a minimum size copy of the data 117 */ 118 p = (struct dirent *)malloc(DIRSIZ(d)); 119 if (p == NULL) { 120 #ifdef HAVE_DD_LOCK 121 __lock_release_recursive(dirp->dd_lock); 122 #endif 123 return(-1); 124 } 125 p->d_ino = d->d_ino; 126 p->d_reclen = d->d_reclen; 127 #ifdef _DIRENT_HAVE_D_NAMLEN 128 p->d_namlen = d->d_namlen; 129 bcopy(d->d_name, p->d_name, p->d_namlen + 1); 130 #else 131 strcpy(p->d_name, d->d_name); 132 #endif 133 /* 134 * Check to make sure the array has space left and 135 * realloc the maximum size. 136 */ 137 if (++nitems >= arraysz) { 138 if (fstat(dirp->dd_fd, &stb) < 0) { 139 #ifdef HAVE_DD_LOCK 140 __lock_release_recursive(dirp->dd_lock); 141 #endif 142 return(-1); /* just might have grown */ 143 } 144 arraysz = stb.st_size / 12; 145 names = (struct dirent **)realloc((char *)names, 146 arraysz * sizeof(struct dirent *)); 147 if (names == NULL) { 148 #ifdef HAVE_DD_LOCK 149 __lock_release_recursive(dirp->dd_lock); 150 #endif 151 return(-1); 152 } 153 } 154 names[nitems-1] = p; 155 } 156 closedir(dirp); 157 if (nitems && dcomp != NULL) 158 qsort(names, nitems, sizeof(struct dirent *), dcomp); 159 *namelist = names; 160 #ifdef HAVE_DD_LOCK 161 __lock_release_recursive(dirp->dd_lock); 162 #endif 163 return(nitems); 164 } 165 166 /* 167 * Alphabetic order comparison routine for those who want it. 168 */ 169 int 170 _DEFUN(alphasort, (d1, d2), 171 const struct dirent **d1 _AND 172 const struct dirent **d2) 173 { 174 return(strcmp((*d1)->d_name, (*d2)->d_name)); 175 } 176 177 #endif /* ! HAVE_OPENDIR */ 178