#define root and root's parent fts_level values in <fts.h>
[unix-history] / usr / src / lib / libc / gen / scandir.c
CommitLineData
bb0cfa24
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
d99e6414
KB
3 * All rights reserved.
4 *
269a7923 5 * %sccs.include.redist.c%
bb0cfa24
DF
6 */
7
2ce81398 8#if defined(LIBC_SCCS) && !defined(lint)
c5980113 9static char sccsid[] = "@(#)scandir.c 5.10 (Berkeley) %G%";
d99e6414 10#endif /* LIBC_SCCS and not lint */
455b164d 11
38cb3a9a
RC
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
8c6e64bc 16 * struct dirent (through namelist). Returns -1 if there were any errors.
38cb3a9a
RC
17 */
18
19#include <sys/types.h>
20#include <sys/stat.h>
8c6e64bc 21#include <dirent.h>
c5980113
DS
22#include <stdlib.h>
23#include <string.h>
38cb3a9a 24
c5453831
KM
25/*
26 * The DIRSIZ macro gives the minimum record length which will hold
27 * the directory entry. This requires the amount of space in struct dirent
28 * without the d_name field, plus enough space for the name with a terminating
29 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
30 */
31#undef DIRSIZ
32#define DIRSIZ(dp) \
33 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
34
c5980113 35int
38cb3a9a 36scandir(dirname, namelist, select, dcomp)
c5980113 37 const char *dirname;
f4775f4d 38 struct dirent ***namelist;
c5980113
DS
39 int (*select) __P((struct dirent *));
40 int (*dcomp) __P((const void *, const void *));
38cb3a9a 41{
8c6e64bc 42 register struct dirent *d, *p, **names;
c5980113 43 register size_t nitems;
38cb3a9a
RC
44 struct stat stb;
45 long arraysz;
46 DIR *dirp;
47
48 if ((dirp = opendir(dirname)) == NULL)
49 return(-1);
50 if (fstat(dirp->dd_fd, &stb) < 0)
51 return(-1);
52
53 /*
54 * estimate the array size by taking the size of the directory file
55 * and dividing it by a multiple of the minimum size entry.
56 */
57 arraysz = (stb.st_size / 24);
8c6e64bc 58 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
38cb3a9a
RC
59 if (names == NULL)
60 return(-1);
61
62 nitems = 0;
63 while ((d = readdir(dirp)) != NULL) {
64 if (select != NULL && !(*select)(d))
65 continue; /* just selected names */
66 /*
67 * Make a minimum size copy of the data
68 */
8c6e64bc 69 p = (struct dirent *)malloc(DIRSIZ(d));
38cb3a9a
RC
70 if (p == NULL)
71 return(-1);
72 p->d_ino = d->d_ino;
73 p->d_reclen = d->d_reclen;
74 p->d_namlen = d->d_namlen;
901dccca 75 bcopy(d->d_name, p->d_name, p->d_namlen + 1);
38cb3a9a
RC
76 /*
77 * Check to make sure the array has space left and
78 * realloc the maximum size.
79 */
80 if (++nitems >= arraysz) {
71120ea4
RC
81 if (fstat(dirp->dd_fd, &stb) < 0)
82 return(-1); /* just might have grown */
83 arraysz = stb.st_size / 12;
8c6e64bc
KM
84 names = (struct dirent **)realloc((char *)names,
85 arraysz * sizeof(struct dirent *));
38cb3a9a
RC
86 if (names == NULL)
87 return(-1);
88 }
89 names[nitems-1] = p;
90 }
91 closedir(dirp);
92 if (nitems && dcomp != NULL)
8c6e64bc 93 qsort(names, nitems, sizeof(struct dirent *), dcomp);
38cb3a9a
RC
94 *namelist = names;
95 return(nitems);
96}
97
98/*
99 * Alphabetic order comparison routine for those who want it.
100 */
c5980113 101int
38cb3a9a 102alphasort(d1, d2)
c5980113
DS
103 const void *d1;
104 const void *d2;
38cb3a9a 105{
8ac81353
KB
106 return(strcmp((*(struct dirent **)d1)->d_name,
107 (*(struct dirent **)d2)->d_name));
38cb3a9a 108}