1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: #include <dirent.h>
20: #include <stdlib.h>
21: #include <string.h>
22: #include <errno.h>
23: #include <bits/libc-lock.h>
24:
25: #ifndef SCANDIR
26: #define SCANDIR scandir
27: #define READDIR __readdir
28: #define DIRENT_TYPE struct dirent
29: #endif
30:
31: #ifndef SCANDIR_CANCEL
32: #define SCANDIR_CANCEL
33: struct scandir_cancel_struct
34: {
35: DIR *dp;
36: void *v;
37: size_t cnt;
38: };
39:
40: static void
41: cancel_handler (void *arg)
42: {
43: struct scandir_cancel_struct *cp = arg;
44: size_t i;
45: void **v = cp->v;
46:
47: for (i = 0; i < cp->cnt; ++i)
48: free (v[i]);
49: free (v);
50: (void) __closedir (cp->dp);
51: }
52: #endif
53:
54:
55: int
56: SCANDIR (dir, namelist, select, cmp)
57: const char *dir;
58: DIRENT_TYPE ***namelist;
59: int (*select) (const DIRENT_TYPE *);
60: int (*cmp) (const void *, const void *);
61: {
62: DIR *dp = __opendir (dir);
63: DIRENT_TYPE **v = NULL;
64: size_t vsize = 0;
65: struct scandir_cancel_struct c;
66: DIRENT_TYPE *d;
67: int save;
68:
69: if (dp == NULL)
70: return -1;
71:
72: save = errno;
73: __set_errno (0);
74:
75: c.dp = dp;
76: c.v = NULL;
77: c.cnt = 0;
78: __libc_cleanup_push (cancel_handler, &c);
79:
80: while ((d = READDIR (dp)) != NULL)
81: {
82: int use_it = select == NULL;
83:
84: if (! use_it)
85: {
86: use_it = select (d);
87:
88:
89:
90: __set_errno (0);
91: }
92:
93: if (use_it)
94: {
95: DIRENT_TYPE *vnew;
96: size_t dsize;
97:
98:
99: __set_errno (0);
100:
101: if (__builtin_expect (c.cnt == vsize, 0))
102: {
103: DIRENT_TYPE **new;
104: if (vsize == 0)
105: vsize = 10;
106: else
107: vsize *= 2;
108: new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v));
109: if (new == NULL)
110: break;
111: v = new;
112: c.v = (void *) v;
113: }
114:
115: dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
116: vnew = (DIRENT_TYPE *) malloc (dsize);
117: if (vnew == NULL)
118: break;
119:
120: v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
121: }
122: }
123:
124: if (__builtin_expect (errno, 0) != 0)
125: {
126: save = errno;
127:
128: while (c.cnt > 0)
129: free (v[--c.cnt]);
130: free (v);
131: c.cnt = -1;
132: }
133: else
134: {
135:
136: if (cmp != NULL)
137: qsort (v, c.cnt, sizeof (*v), cmp);
138:
139: *namelist = v;
140: }
141:
142: __libc_cleanup_pop (0);
143:
144: (void) __closedir (dp);
145: __set_errno (save);
146:
147: return c.cnt;
148: }