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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 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 /* 41 * Based on usr/src/ucblib/libucb/port/gen/scandir.c 42 */ 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/feature_tests.h> 52 53 #pragma weak _scandir = scandir 54 #pragma weak _alphasort = alphasort 55 #if !defined(_LP64) 56 #pragma weak _scandir64 = scandir64 57 #pragma weak _alphasort64 = alphasort64 58 #endif 59 60 #include "lint.h" 61 #include <dirent.h> 62 #include <errno.h> 63 #include <sys/types.h> 64 #include <sys/stat.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <limits.h> 68 69 70 #if !defined(_LP64) 71 int 72 scandir64(const char *dirname, struct dirent64 *(*namelist[]), 73 int (*select)(const struct dirent64 *), 74 int (*dcomp)(const struct dirent64 **, const struct dirent64 **)) 75 { 76 struct dirent64 *d, *p, **names = NULL; 77 size_t nitems = 0; 78 size_t arraysz, entlen; 79 struct stat64 stb; 80 DIR *dirp; 81 u_longlong_t tmp_arraysz; 82 83 if ((dirp = opendir(dirname)) == NULL) 84 return (-1); 85 if (fstat64(dirp->dd_fd, &stb) < 0) 86 goto fail; 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 tmp_arraysz = stb.st_size / 24; /* 24 bytes on a 64-bit system */ 93 if (tmp_arraysz > INT_MAX) 94 arraysz = INT_MAX; 95 else 96 arraysz = (size_t)tmp_arraysz; 97 names = malloc(arraysz * sizeof (struct dirent64 *)); 98 if (names == NULL) 99 goto fail; 100 101 while ((d = readdir64(dirp)) != NULL) { 102 if (select != NULL && !(*select)(d)) 103 continue; /* just selected names */ 104 105 entlen = d->d_reclen; 106 /* 107 * Make a minimum size copy of the data 108 */ 109 p = malloc(entlen); 110 if (p == NULL) 111 goto fail; 112 (void) memcpy(p, d, entlen); 113 /* 114 * Check to make sure the array has space left and 115 * realloc the maximum size. 116 */ 117 if (nitems >= arraysz) { 118 struct dirent64 **tmp; 119 if (nitems == INT_MAX) { 120 /* overflow */ 121 free(p); 122 errno = EOVERFLOW; 123 goto fail; 124 } 125 arraysz += 512; /* no science here */ 126 tmp = realloc(names, 127 arraysz * sizeof (struct dirent64 *)); 128 if (tmp == NULL) { 129 free(p); 130 goto fail; 131 } 132 names = tmp; 133 } 134 names[nitems++] = p; 135 } 136 (void) closedir(dirp); 137 if (nitems && dcomp != NULL) 138 qsort(names, nitems, sizeof (struct dirent64 *), 139 (int(*)(const void *, const void *))dcomp); 140 *namelist = names; 141 142 return ((int)nitems); 143 144 fail: 145 while (nitems != 0) { 146 free(names[--nitems]); 147 } 148 if (names) 149 free(names); 150 (void) closedir(dirp); 151 return (-1); 152 } 153 #endif 154 155 156 int 157 scandir(const char *dirname, struct dirent *(*namelist[]), 158 int (*select)(const struct dirent *), 159 int (*dcomp)(const struct dirent **, const struct dirent **)) 160 { 161 struct dirent *d, *p, **names = NULL; 162 size_t nitems = 0; 163 size_t arraysz, entlen; 164 struct stat64 stb; 165 DIR *dirp; 166 u_longlong_t tmp_arraysz; 167 168 if ((dirp = opendir(dirname)) == NULL) 169 return (-1); 170 if (fstat64(dirp->dd_fd, &stb) < 0) 171 goto fail; 172 173 /* 174 * estimate the array size by taking the size of the directory file 175 * and dividing it by a multiple of the minimum size entry. 176 */ 177 tmp_arraysz = stb.st_size / 24; /* 24 bytes on a 64-bit system */ 178 if (tmp_arraysz > INT_MAX) 179 arraysz = INT_MAX; 180 else 181 arraysz = (size_t)tmp_arraysz; 182 names = malloc(arraysz * sizeof (struct dirent *)); 183 if (names == NULL) 184 goto fail; 185 186 while ((d = readdir(dirp)) != NULL) { 187 if (select != NULL && !(*select)(d)) 188 continue; /* just selected names */ 189 190 entlen = d->d_reclen; 191 /* 192 * Make a minimum size copy of the data 193 */ 194 p = malloc(entlen); 195 if (p == NULL) 196 goto fail; 197 (void) memcpy(p, d, entlen); 198 /* 199 * Check to make sure the array has space left and 200 * realloc the maximum size. 201 */ 202 if (nitems >= arraysz) { 203 struct dirent **tmp; 204 if (nitems == INT_MAX) { 205 /* overflow */ 206 free(p); 207 errno = EOVERFLOW; 208 goto fail; 209 } 210 arraysz += 512; /* no science here */ 211 tmp = realloc(names, 212 arraysz * sizeof (struct dirent *)); 213 if (tmp == NULL) { 214 free(p); 215 goto fail; 216 } 217 names = tmp; 218 } 219 names[nitems++] = p; 220 } 221 (void) closedir(dirp); 222 if (nitems && dcomp != NULL) 223 qsort(names, nitems, sizeof (struct dirent *), 224 (int(*)(const void *, const void *))dcomp); 225 *namelist = names; 226 227 return ((int)nitems); 228 229 fail: 230 while (nitems != 0) { 231 free(names[--nitems]); 232 } 233 if (names) 234 free(names); 235 (void) closedir(dirp); 236 return (-1); 237 } 238 239 /* 240 * Alphabetic order comparison routine for those who want it. 241 */ 242 int 243 alphasort(const struct dirent **d1, const struct dirent **d2) 244 { 245 return (strcoll((*d1)->d_name, 246 (*d2)->d_name)); 247 } 248 249 #if !defined(_LP64) 250 int 251 alphasort64(const struct dirent64 **d1, const struct dirent64 **d2) 252 { 253 return (strcoll((*d1)->d_name, 254 (*d2)->d_name)); 255 } 256 #endif 257