1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)scandir.c 5.8 (Berkeley) 06/23/90"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 /* 13 * Scan the directory dirname calling select to make a list of selected 14 * directory entries then sort using qsort and compare routine dcomp. 15 * Returns the number of entries and a pointer to a list of pointers to 16 * struct dirent (through namelist). Returns -1 if there were any errors. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <dirent.h> 22 23 /* 24 * The DIRSIZ macro gives the minimum record length which will hold 25 * the directory entry. This requires the amount of space in struct dirent 26 * without the d_name field, plus enough space for the name with a terminating 27 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. 28 */ 29 #undef DIRSIZ 30 #define DIRSIZ(dp) \ 31 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) 32 33 scandir(dirname, namelist, select, dcomp) 34 char *dirname; 35 struct dirent ***namelist; 36 int (*select)(), (*dcomp)(); 37 { 38 register struct dirent *d, *p, **names; 39 register int nitems; 40 struct stat stb; 41 long arraysz; 42 DIR *dirp; 43 44 if ((dirp = opendir(dirname)) == NULL) 45 return(-1); 46 if (fstat(dirp->dd_fd, &stb) < 0) 47 return(-1); 48 49 /* 50 * estimate the array size by taking the size of the directory file 51 * and dividing it by a multiple of the minimum size entry. 52 */ 53 arraysz = (stb.st_size / 24); 54 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); 55 if (names == NULL) 56 return(-1); 57 58 nitems = 0; 59 while ((d = readdir(dirp)) != NULL) { 60 if (select != NULL && !(*select)(d)) 61 continue; /* just selected names */ 62 /* 63 * Make a minimum size copy of the data 64 */ 65 p = (struct dirent *)malloc(DIRSIZ(d)); 66 if (p == NULL) 67 return(-1); 68 p->d_ino = d->d_ino; 69 p->d_reclen = d->d_reclen; 70 p->d_namlen = d->d_namlen; 71 bcopy(d->d_name, p->d_name, p->d_namlen + 1); 72 /* 73 * Check to make sure the array has space left and 74 * realloc the maximum size. 75 */ 76 if (++nitems >= arraysz) { 77 if (fstat(dirp->dd_fd, &stb) < 0) 78 return(-1); /* just might have grown */ 79 arraysz = stb.st_size / 12; 80 names = (struct dirent **)realloc((char *)names, 81 arraysz * sizeof(struct dirent *)); 82 if (names == NULL) 83 return(-1); 84 } 85 names[nitems-1] = p; 86 } 87 closedir(dirp); 88 if (nitems && dcomp != NULL) 89 qsort(names, nitems, sizeof(struct dirent *), dcomp); 90 *namelist = names; 91 return(nitems); 92 } 93 94 /* 95 * Alphabetic order comparison routine for those who want it. 96 */ 97 alphasort(d1, d2) 98 struct dirent **d1, **d2; 99 { 100 return(strcmp((*d1)->d_name, (*d2)->d_name)); 101 } 102