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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 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 /*LINTLIBRARY*/ 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/types.h> 52 #include <sys/stat.h> 53 #include <sys/dir.h> 54 #include <errno.h> 55 #include <limits.h> 56 #include <stdlib.h> 57 #include <string.h> 58 59 /* 60 * The macro DIRSIZ(dp) gives an amount of space required to represent 61 * a directory entry. For any directory entry dp->d_reclen >= DIRSIZ(dp). 62 * Specific filesystem types may use this use this macro to construct the value 63 * for d_reclen. 64 */ 65 #undef DIRSIZ 66 #define DIRSIZ(dp) \ 67 ((sizeof (struct direct) - sizeof ((dp)->d_name) + \ 68 (strlen((dp)->d_name)+1) + 3) & ~3) 69 70 #if !defined(_LP64) 71 int 72 scandir64(char *dirname, struct direct64 *(*namelist[]), 73 int (*select)(struct direct64 *), 74 int (*dcomp)(struct direct64 **, struct direct64 **)) 75 { 76 struct direct64 *d, *p, **names; 77 int nitems; 78 char *cp1, *cp2; 79 struct stat64 stb; 80 long arraysz; 81 DIR *dirp; 82 83 if ((dirp = opendir(dirname)) == NULL) 84 return (-1); 85 if (fstat64(dirp->dd_fd, &stb) < 0) 86 return (-1); 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 arraysz = (stb.st_size / 24); 93 names = (struct direct64 **)malloc(arraysz * 94 sizeof (struct direct64 *)); 95 if (names == NULL) 96 return (-1); 97 98 nitems = 0; 99 while ((d = readdir64(dirp)) != NULL) { 100 if (select != NULL && !(*select)(d)) 101 continue; /* just selected names */ 102 /* 103 * Make a minimum size copy of the data 104 */ 105 p = (struct direct64 *)malloc(DIRSIZ64(d)); 106 if (p == NULL) 107 return (-1); 108 p->d_ino = d->d_ino; 109 p->d_reclen = d->d_reclen; 110 p->d_namlen = d->d_namlen; 111 for (cp1 = p->d_name, cp2 = d->d_name; *cp1++ = *cp2++; ) 112 ; 113 /* 114 * Check to make sure the array has space left and 115 * realloc the maximum size. 116 */ 117 if (++nitems >= arraysz) { 118 if (fstat64(dirp->dd_fd, &stb) < 0) 119 return (-1); /* just might have grown */ 120 arraysz = stb.st_size / 12; 121 names = (struct direct64 **)realloc((char *)names, 122 arraysz * sizeof (struct direct64 *)); 123 if (names == NULL) 124 return (-1); 125 } 126 names[nitems-1] = p; 127 } 128 (void) closedir(dirp); 129 if (nitems && dcomp != NULL) 130 qsort(names, nitems, sizeof (struct direct64 *), 131 (int(*)(const void *, const void *)) dcomp); 132 *namelist = names; 133 return (nitems); 134 } 135 #endif 136 137 138 int 139 scandir(char *dirname, struct direct *(*namelist[]), 140 int (*select)(struct direct *), 141 int (*dcomp)(struct direct **, struct direct **)) 142 { 143 struct direct *d, *p, **names; 144 int nitems; 145 char *cp1, *cp2; 146 struct stat64 stb; 147 long arraysz; 148 DIR *dirp; 149 150 if ((dirp = opendir(dirname)) == NULL) 151 return (-1); 152 if (fstat64(dirp->dd_fd, &stb) < 0) 153 return (-1); 154 /* 155 * estimate the array size by taking the size of the directory file 156 * and dividing it by a multiple of the minimum size entry. 157 */ 158 if (stb.st_size > SSIZE_MAX) { 159 errno = EOVERFLOW; 160 return (-1); 161 } 162 arraysz = (stb.st_size / 24); 163 164 names = (struct direct **)malloc(arraysz * sizeof (struct direct *)); 165 if (names == NULL) 166 return (-1); 167 168 nitems = 0; 169 while ((d = readdir(dirp)) != NULL) { 170 if (select != NULL && !(*select)(d)) 171 continue; /* just selected names */ 172 /* 173 * Make a minimum size copy of the data 174 */ 175 p = (struct direct *)malloc(DIRSIZ(d)); 176 if (p == NULL) 177 return (-1); 178 p->d_ino = d->d_ino; 179 p->d_reclen = d->d_reclen; 180 p->d_namlen = d->d_namlen; 181 for (cp1 = p->d_name, cp2 = d->d_name; *cp1++ = *cp2++; ) 182 ; 183 /* 184 * Check to make sure the array has space left and 185 * realloc the maximum size. 186 */ 187 if (++nitems >= arraysz) { 188 if (fstat64(dirp->dd_fd, &stb) < 0) 189 return (-1); /* just might have grown */ 190 arraysz = stb.st_size / 12; 191 names = (struct direct **)realloc((char *)names, 192 arraysz * sizeof (struct direct *)); 193 if (names == NULL) 194 return (-1); 195 } 196 names[nitems-1] = p; 197 } 198 (void) closedir(dirp); 199 if (nitems && dcomp != NULL) 200 qsort(names, nitems, sizeof (struct direct *), 201 (int(*)(const void *, const void *)) dcomp); 202 *namelist = names; 203 return (nitems); 204 } 205 206 /* 207 * Alphabetic order comparison routine for those who want it. 208 */ 209 int 210 alphasort(struct direct **d1, struct direct **d2) 211 { 212 return (strcmp((*d1)->d_name, (*d2)->d_name)); 213 } 214 215 #if !defined(_LP64) 216 int 217 alphasort64(struct direct64 **d1, struct direct64 **d2) 218 { 219 return (strcmp((*d1)->d_name, (*d2)->d_name)); 220 } 221 #endif 222