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 2004 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 "synonyms.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 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 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 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 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