recurse.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
recurse.c (2454B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <dirent.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include "../fs.h"
14 #include "../util.h"
15
16 int recurse_status = 0;
17
18 void
19 recurse(int dirfd, const char *name, void *data, struct recursor *r)
20 {
21 struct dirent *d;
22 struct history *new, *h;
23 struct stat st, dst;
24 DIR *dp;
25 int flags = 0, fd;
26 size_t pathlen = r->pathlen;
27
28 if (dirfd == AT_FDCWD)
29 pathlen = estrlcpy(r->path, name, sizeof(r->path));
30
31 if (r->follow == 'P' || (r->follow == 'H' && r->depth))
32 flags |= AT_SYMLINK_NOFOLLOW;
33
34 if (fstatat(dirfd, name, &st, flags) < 0) {
35 if (!(r->flags & SILENT)) {
36 weprintf("stat %s:", r->path);
37 recurse_status = 1;
38 }
39 return;
40 }
41 if (!S_ISDIR(st.st_mode)) {
42 r->fn(dirfd, name, &st, data, r);
43 return;
44 }
45
46 new = emalloc(sizeof(struct history));
47 new->prev = r->hist;
48 r->hist = new;
49 new->dev = st.st_dev;
50 new->ino = st.st_ino;
51
52 for (h = new->prev; h; h = h->prev)
53 if (h->ino == st.st_ino && h->dev == st.st_dev)
54 return;
55
56 if (!r->depth && (r->flags & DIRFIRST))
57 r->fn(dirfd, name, &st, data, r);
58
59 if (!r->maxdepth || r->depth + 1 < r->maxdepth) {
60 fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
61 if (fd < 0) {
62 weprintf("open %s:", r->path);
63 recurse_status = 1;
64 }
65 if (!(dp = fdopendir(fd))) {
66 if (!(r->flags & SILENT)) {
67 weprintf("fdopendir:");
68 recurse_status = 1;
69 }
70 return;
71 }
72 if (r->path[pathlen - 1] != '/')
73 r->path[pathlen++] = '/';
74 if (r->follow == 'H')
75 flags |= AT_SYMLINK_NOFOLLOW;
76 while ((d = readdir(dp))) {
77 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
78 continue;
79 r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen);
80 if (fstatat(fd, d->d_name, &dst, flags) < 0) {
81 if (!(r->flags & SILENT)) {
82 weprintf("stat %s:", r->path);
83 recurse_status = 1;
84 }
85 } else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) {
86 continue;
87 } else {
88 r->depth++;
89 r->fn(fd, d->d_name, &dst, data, r);
90 r->depth--;
91 }
92 }
93 r->path[pathlen - 1] = '\0';
94 r->pathlen = pathlen - 1;
95 closedir(dp);
96 }
97
98 if (!r->depth) {
99 if (!(r->flags & DIRFIRST))
100 r->fn(dirfd, name, &st, data, r);
101
102 while (r->hist) {
103 h = r->hist;
104 r->hist = r->hist->prev;
105 free(h);
106 }
107 }
108 }