1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 01/02/94";
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 #include <stdlib.h>
23 #include <string.h>
24
25 /*
26 * The DIRSIZ macro is the minimum record length which will hold the directory
27 * entry. This requires the amount of space in struct dirent without the
28 * d_name field, plus enough space for the name and a terminating nul byte
29 * (dp->d_namlen + 1), rounded up to a 4 byte boundary.
30 */
31 #undef DIRSIZ
32 #define DIRSIZ(dp) \
33 ((sizeof(struct dirent) - sizeof(dp)->d_name) + \
34 (((dp)->d_namlen + 1 + 3) &~ 3))
35
36 int
scandir(dirname,namelist,select,dcomp)37 scandir(dirname, namelist, select, dcomp)
38 const char *dirname;
39 struct dirent ***namelist;
40 int (*select) __P((struct dirent *));
41 int (*dcomp) __P((const void *, const void *));
42 {
43 register struct dirent *d, *p, **names;
44 register size_t nitems;
45 struct stat stb;
46 long arraysz;
47 DIR *dirp;
48
49 if ((dirp = opendir(dirname)) == NULL)
50 return(-1);
51 if (fstat(dirp->dd_fd, &stb) < 0)
52 return(-1);
53
54 /*
55 * estimate the array size by taking the size of the directory file
56 * and dividing it by a multiple of the minimum size entry.
57 */
58 arraysz = (stb.st_size / 24);
59 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
60 if (names == NULL)
61 return(-1);
62
63 nitems = 0;
64 while ((d = readdir(dirp)) != NULL) {
65 if (select != NULL && !(*select)(d))
66 continue; /* just selected names */
67 /*
68 * Make a minimum size copy of the data
69 */
70 p = (struct dirent *)malloc(DIRSIZ(d));
71 if (p == NULL)
72 return(-1);
73 p->d_ino = d->d_ino;
74 p->d_reclen = d->d_reclen;
75 p->d_namlen = d->d_namlen;
76 bcopy(d->d_name, p->d_name, p->d_namlen + 1);
77 /*
78 * Check to make sure the array has space left and
79 * realloc the maximum size.
80 */
81 if (++nitems >= arraysz) {
82 if (fstat(dirp->dd_fd, &stb) < 0)
83 return(-1); /* just might have grown */
84 arraysz = stb.st_size / 12;
85 names = (struct dirent **)realloc((char *)names,
86 arraysz * sizeof(struct dirent *));
87 if (names == NULL)
88 return(-1);
89 }
90 names[nitems-1] = p;
91 }
92 closedir(dirp);
93 if (nitems && dcomp != NULL)
94 qsort(names, nitems, sizeof(struct dirent *), dcomp);
95 *namelist = names;
96 return(nitems);
97 }
98
99 /*
100 * Alphabetic order comparison routine for those who want it.
101 */
102 int
alphasort(d1,d2)103 alphasort(d1, d2)
104 const void *d1;
105 const void *d2;
106 {
107 return(strcmp((*(struct dirent **)d1)->d_name,
108 (*(struct dirent **)d2)->d_name));
109 }
110