master
1/**
2 * This file is part of the mingw-w64 runtime package.
3 * No warranty is given; refer to the file DISCLAIMER within this package.
4 */
5
6#include <stdlib.h>
7#include <unistd.h>
8#include <malloc.h>
9#include <string.h>
10#include <errno.h>
11#include <limits.h>
12#include <fcntl.h>
13#include <sys/param.h>
14#include <sys/stat.h>
15#include <dirent.h>
16#include <ftw.h>
17
18int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat);
19int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat);
20int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat);
21
22typedef struct dir_data_t {
23 DIR *h;
24 char *buf;
25} dir_data_t;
26
27typedef struct node_t {
28 struct node_t *l, *r;
29 unsigned int colored : 1;
30} node_t;
31
32typedef struct ctx_t {
33 node_t *objs;
34 dir_data_t **dirs;
35 char *buf;
36 struct FTW ftw;
37 int (*fcb) (const char *, const STRUCT_STAT *, int , struct FTW *);
38 size_t cur_dir, msz_dir, buf_sz;
39 int flags;
40 dev_t dev;
41} ctx_t;
42
43static int add_object (ctx_t *);
44static int do_dir (ctx_t *, STRUCT_STAT *, dir_data_t *);
45static int do_entity (ctx_t *, dir_data_t *, const char *, size_t);
46static int do_it (const char *, int, void *, int, int);
47
48static int open_directory (ctx_t *, dir_data_t *);
49
50static void
51prepare_for_insert (int forced, node_t **bp, node_t **pp1, node_t **pp2, int p1_c, int p2_c)
52{
53 node_t *p1, *p2, **rp, **lp, *b = *bp;
54
55 rp = &(*bp)->r;
56 lp = &(*bp)->l;
57
58 if (!forced && ((*lp) == NULL || (*lp)->colored == 0 || (*rp) == NULL || (*rp)->colored == 0))
59 return;
60
61 b->colored = 1;
62
63 if (*rp)
64 (*rp)->colored = 0;
65
66 if (*lp)
67 (*lp)->colored = 0;
68
69 if (!pp1 || (*pp1)->colored == 0)
70 return;
71
72 p1 = *pp1;
73 p2 = *pp2;
74
75 if ((p1_c > 0) == (p2_c > 0))
76 {
77 *pp2 = *pp1;
78 p1->colored = 0;
79 p2->colored = 1;
80 *(p1_c < 0 ? &p2->l : &p2->r) = (p1_c < 0 ? p1->r : p1->l);
81 *(p1_c < 0 ? &p1->r : &p1->l) = p2;
82 return;
83 }
84
85 b->colored = 0;
86 p1->colored = p2->colored = 1;
87 *(p1_c < 0 ? &p1->l : &p1->r) = (p1_c < 0 ? *rp : *lp);
88 *(p1_c < 0 ? rp : lp) = p1;
89 *(p1_c < 0 ? &p2->r : &p2->l) = (p1_c < 0 ? *lp : *rp);
90 *(p1_c < 0 ? lp : rp) = p2;
91 *pp2 = b;
92}
93
94static int
95add_object (ctx_t *ctx)
96{
97 node_t **bp, **np, *b, *n, **pp1 = NULL, **pp2 = NULL;
98 int c = 0, p1_c = 0, p2_c = 0;
99
100 if (ctx->objs)
101 ctx->objs->colored = 0;
102
103 np = bp = &ctx->objs;
104
105 if (ctx->objs != NULL)
106 {
107 c = 1;
108
109 do
110 {
111 b = *bp;
112 prepare_for_insert (0, bp, pp1, pp2, p1_c, p2_c);
113 np = &b->r;
114
115 if (*np == NULL)
116 break;
117
118 pp2 = pp1;
119 p2_c = p1_c;
120 pp1 = bp;
121 p1_c = 1;
122 bp = np;
123 }
124 while (*np != NULL);
125 }
126
127 if (!(n = (node_t *) malloc (sizeof (node_t))))
128 return -1;
129
130 *np = n;
131 n->l = n->r = NULL;
132 n->colored = 1;
133
134 if (np != bp)
135 prepare_for_insert (1, np, bp, pp1, c, p1_c);
136
137 return 0;
138}
139
140static int
141open_directory (ctx_t *ctx, dir_data_t *dirp)
142{
143 DIR *st;
144 struct dirent *d;
145 char *buf, *h;
146 size_t cur_sz, buf_sz, sz;
147 int sv_e, ret = 0;
148
149 if (ctx->dirs[ctx->cur_dir] != NULL)
150 {
151 if (!(buf = malloc (1024)))
152 return -1;
153
154 st = ctx->dirs[ctx->cur_dir]->h;
155
156 buf_sz = 1024;
157 cur_sz = 0;
158
159 while ((d = readdir (st)) != NULL)
160 {
161 sz = strlen (d->d_name);
162
163 if ((cur_sz + sz + 2) >= buf_sz)
164 {
165 buf_sz += ((2 * sz) < 1024 ? 1024 : (2 * sz));
166 if (!(h = (char *) realloc (buf, buf_sz)))
167 {
168 sv_e = errno;
169 free (buf);
170 errno = (sv_e);
171
172 return -1;
173 }
174
175 buf = h;
176 }
177
178 *((char *) memcpy (buf + cur_sz, d->d_name, sz) + sz) = 0;
179 cur_sz += sz + 1;
180 }
181
182 buf[cur_sz++] = 0;
183
184 ctx->dirs[ctx->cur_dir]->buf = realloc (buf, cur_sz);
185
186 if (ctx->dirs[ctx->cur_dir]->buf == NULL)
187 {
188 sv_e = errno;
189 free (buf);
190 errno = sv_e;
191 ret = -1;
192 }
193 else
194 {
195 closedir (st);
196
197 ctx->dirs[ctx->cur_dir]->h = NULL;
198 ctx->dirs[ctx->cur_dir] = NULL;
199 }
200 }
201
202 if (!ret)
203 {
204 dirp->h = opendir (ctx->buf);
205
206 if (dirp->h == NULL)
207 ret = -1;
208 else
209 {
210 dirp->buf = NULL;
211 ctx->dirs[ctx->cur_dir] = dirp;
212 ctx->cur_dir += 1;
213
214 if (ctx->cur_dir == ctx->msz_dir)
215 ctx->cur_dir = 0;
216 }
217 }
218
219 return ret;
220}
221
222
223static int
224do_entity (ctx_t *ctx, dir_data_t *dir, const char *name, size_t namlen)
225{
226 STRUCT_STAT st;
227 char *h;
228 size_t cnt_sz;
229 int ret = 0, flag = 0;
230
231 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
232 return 0;
233
234 cnt_sz = ctx->ftw.base + namlen + 2;
235
236 if (ctx->buf_sz < cnt_sz)
237 {
238 ctx->buf_sz = cnt_sz * 2;
239
240 if (!(h = (char *) realloc (ctx->buf, ctx->buf_sz)))
241 return -1;
242
243 ctx->buf = h;
244 }
245
246 *((char *) memcpy (ctx->buf + ctx->ftw.base, name, namlen) + namlen) = 0;
247
248 name = ctx->buf;
249
250 if (FUNC_STAT (name, &st) < 0)
251 {
252 if (errno != EACCES && errno != ENOENT)
253 ret = -1;
254 else
255 flag = FTW_NS;
256
257 if (!(ctx->flags & FTW_PHYS))
258 FUNC_STAT (name, &st);
259 }
260 else
261 flag = (S_ISDIR (st.st_mode) ? FTW_D : FTW_F);
262
263 if (!ret && (flag == FTW_NS || !(ctx->flags & FTW_MOUNT) || st.st_dev == ctx->dev))
264 {
265 if (flag == FTW_D)
266 {
267 if ((ctx->flags & FTW_PHYS) || !(ret = add_object (ctx)))
268 ret = do_dir (ctx, &st, dir);
269 }
270 else
271 ret = (*ctx->fcb) (ctx->buf, &st, flag, &ctx->ftw);
272 }
273
274 if ((ctx->flags & FTW_ACTIONRETVAL) && ret == FTW_SKIP_SUBTREE)
275 ret = 0;
276
277 return ret;
278}
279
280
281static int
282do_dir (ctx_t *ctx, STRUCT_STAT *st, __UNUSED_PARAM(dir_data_t *old_dir))
283{
284 dir_data_t dir;
285 struct dirent *d;
286 char *startp, *runp, *endp;
287 int sv_e, ret, previous_base = ctx->ftw.base;
288
289 if ((ret = open_directory (ctx, &dir)) != 0)
290 {
291 if (errno == EACCES)
292 ret = (*ctx->fcb) (ctx->buf, st, FTW_DNR, &ctx->ftw);
293
294 return ret;
295 }
296
297 if (!(ctx->flags & FTW_DEPTH) && (ret = (*ctx->fcb) (ctx->buf, st, FTW_D, &ctx->ftw)) != 0)
298 {
299 sv_e = errno;
300 closedir (dir.h);
301 errno = sv_e;
302
303 if (ctx->cur_dir-- == 0)
304 ctx->cur_dir = ctx->msz_dir - 1;
305
306 ctx->dirs[ctx->cur_dir] = NULL;
307
308 return ret;
309 }
310
311 ctx->ftw.level += 1;
312 startp = memchr (ctx->buf, 0, 1024);
313
314 if (startp[-1] != '/')
315 *startp++ = '/';
316
317 ctx->ftw.base = (startp - ctx->buf);
318
319 while (dir.h != NULL && (d = readdir (dir.h)) != NULL
320 && !(ret = do_entity (ctx, &dir, d->d_name, strlen (d->d_name))))
321 ;
322
323 if (dir.h != NULL)
324 {
325 sv_e = errno;
326 closedir (dir.h);
327 errno = sv_e;
328
329 if (ctx->cur_dir-- == 0)
330 ctx->cur_dir = ctx->msz_dir - 1;
331
332 ctx->dirs[ctx->cur_dir] = NULL;
333 }
334 else
335 {
336 runp = dir.buf;
337
338 while (!ret && *runp != 0)
339 {
340 endp = strchr (runp, 0);
341 ret = do_entity (ctx, &dir, runp, endp - runp);
342 runp = endp + 1;
343 }
344
345 sv_e = errno;
346 free (dir.buf);
347 errno = sv_e;
348 }
349
350 if ((ctx->flags & FTW_ACTIONRETVAL) && ret == FTW_SKIP_SIBLINGS)
351 ret = 0;
352
353 ctx->buf[ctx->ftw.base - 1] = 0;
354 ctx->ftw.level -= 1;
355 ctx->ftw.base = previous_base;
356
357 if (!ret && (ctx->flags & FTW_DEPTH))
358 ret = (*ctx->fcb) (ctx->buf, st, FTW_DP, &ctx->ftw);
359
360 return ret;
361}
362
363static void
364free_objs (node_t *r)
365{
366 if (r->l)
367 free_objs (r->l);
368
369 if (r->r)
370 free_objs (r->r);
371
372 free (r);
373}
374
375static int
376do_it (const char *dir, __UNUSED_PARAM(int is_nftw), void *fcb, int descriptors, int flags)
377{
378 struct ctx_t ctx;
379 STRUCT_STAT st;
380 int ret = 0;
381 int sv_e;
382 char *cp;
383
384 if (dir[0] == 0)
385 {
386 errno = (ENOENT);
387 return -1;
388 }
389
390 ctx.msz_dir = descriptors < 1 ? 1 : descriptors;
391 ctx.cur_dir = 0;
392 ctx.dirs = (dir_data_t **) alloca (ctx.msz_dir * sizeof (dir_data_t *));
393 memset (ctx.dirs, 0, ctx.msz_dir * sizeof (dir_data_t *));
394
395 ctx.buf_sz = 2 * strlen (dir);
396
397 if (ctx.buf_sz <= 1024)
398 ctx.buf_sz = 1024;
399
400 ctx.buf = (char *) malloc (ctx.buf_sz);
401
402 if (ctx.buf == NULL)
403 return -1;
404
405 cp = strcpy (ctx.buf, dir) + strlen (dir);
406
407 while (cp > (ctx.buf + 1) && cp[-1] == '/')
408 --cp;
409
410 *cp = 0;
411
412 while (cp > ctx.buf && cp[-1] != '/')
413 --cp;
414
415 ctx.ftw.level = 0;
416 ctx.ftw.base = cp - ctx.buf;
417 ctx.flags = flags;
418 ctx.fcb = (int (*) (const char *, const STRUCT_STAT *, int , struct FTW *)) fcb;
419 ctx.objs = NULL;
420
421 if (!ret)
422 {
423 if (FUNC_STAT (ctx.buf, &st) < 0)
424 ret = -1;
425 else if (S_ISDIR (st.st_mode))
426 {
427 ctx.dev = st.st_dev;
428
429 if (!(flags & FTW_PHYS))
430 ret = add_object (&ctx);
431
432 if (!ret)
433 ret = do_dir (&ctx, &st, NULL);
434 }
435 else
436 ret = (*ctx.fcb) (ctx.buf, &st, FTW_F, &ctx.ftw);
437
438 if ((flags & FTW_ACTIONRETVAL) && (ret == FTW_SKIP_SUBTREE || ret == FTW_SKIP_SIBLINGS))
439 ret = 0;
440 }
441
442 sv_e = errno;
443 if (ctx.objs)
444 free_objs (ctx.objs);
445 free (ctx.buf);
446 errno = (sv_e);
447
448 return ret;
449}
450
451int
452FUNC_FTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int), int descriptors);
453int
454FUNC_FTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int), int descriptors)
455{
456 return do_it (path, 0, fcb, descriptors, 0);
457}
458
459int
460FUNC_NFTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int , struct FTW *), int descriptors, int flags);
461int
462FUNC_NFTW (const char *path, int (*fcb) (const char *, const STRUCT_STAT *, int , struct FTW *), int descriptors, int flags)
463{
464 return do_it (path, 1, fcb, descriptors, flags);
465}