1*9b2434d2SAugustin Cavalier #include <ftw.h>
2*9b2434d2SAugustin Cavalier #include <dirent.h>
3*9b2434d2SAugustin Cavalier #include <fcntl.h>
4*9b2434d2SAugustin Cavalier #include <sys/stat.h>
5*9b2434d2SAugustin Cavalier #include <errno.h>
6*9b2434d2SAugustin Cavalier #include <unistd.h>
7*9b2434d2SAugustin Cavalier #include <string.h>
8*9b2434d2SAugustin Cavalier #include <limits.h>
9*9b2434d2SAugustin Cavalier #include <pthread.h>
10*9b2434d2SAugustin Cavalier
11*9b2434d2SAugustin Cavalier struct history
12*9b2434d2SAugustin Cavalier {
13*9b2434d2SAugustin Cavalier struct history *chain;
14*9b2434d2SAugustin Cavalier dev_t dev;
15*9b2434d2SAugustin Cavalier ino_t ino;
16*9b2434d2SAugustin Cavalier int level;
17*9b2434d2SAugustin Cavalier int base;
18*9b2434d2SAugustin Cavalier };
19*9b2434d2SAugustin Cavalier
20*9b2434d2SAugustin Cavalier #undef dirfd
21*9b2434d2SAugustin Cavalier #define dirfd(d) (*(int *)d)
22*9b2434d2SAugustin Cavalier
do_nftw(char * path,int (* fn)(const char *,const struct stat *,int,struct FTW *),int fd_limit,int flags,struct history * h)23*9b2434d2SAugustin Cavalier static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags, struct history *h)
24*9b2434d2SAugustin Cavalier {
25*9b2434d2SAugustin Cavalier size_t l = strlen(path), j = l && path[l-1]=='/' ? l-1 : l;
26*9b2434d2SAugustin Cavalier struct stat st;
27*9b2434d2SAugustin Cavalier struct history new;
28*9b2434d2SAugustin Cavalier int type;
29*9b2434d2SAugustin Cavalier int r;
30*9b2434d2SAugustin Cavalier int dfd;
31*9b2434d2SAugustin Cavalier int err;
32*9b2434d2SAugustin Cavalier struct FTW lev;
33*9b2434d2SAugustin Cavalier
34*9b2434d2SAugustin Cavalier if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
35*9b2434d2SAugustin Cavalier if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
36*9b2434d2SAugustin Cavalier type = FTW_SLN;
37*9b2434d2SAugustin Cavalier else if (errno != EACCES) return -1;
38*9b2434d2SAugustin Cavalier else type = FTW_NS;
39*9b2434d2SAugustin Cavalier } else if (S_ISDIR(st.st_mode)) {
40*9b2434d2SAugustin Cavalier if (flags & FTW_DEPTH) type = FTW_DP;
41*9b2434d2SAugustin Cavalier else type = FTW_D;
42*9b2434d2SAugustin Cavalier } else if (S_ISLNK(st.st_mode)) {
43*9b2434d2SAugustin Cavalier if (flags & FTW_PHYS) type = FTW_SL;
44*9b2434d2SAugustin Cavalier else type = FTW_SLN;
45*9b2434d2SAugustin Cavalier } else {
46*9b2434d2SAugustin Cavalier type = FTW_F;
47*9b2434d2SAugustin Cavalier }
48*9b2434d2SAugustin Cavalier
49*9b2434d2SAugustin Cavalier if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
50*9b2434d2SAugustin Cavalier return 0;
51*9b2434d2SAugustin Cavalier
52*9b2434d2SAugustin Cavalier new.chain = h;
53*9b2434d2SAugustin Cavalier new.dev = st.st_dev;
54*9b2434d2SAugustin Cavalier new.ino = st.st_ino;
55*9b2434d2SAugustin Cavalier new.level = h ? h->level+1 : 0;
56*9b2434d2SAugustin Cavalier new.base = j+1;
57*9b2434d2SAugustin Cavalier
58*9b2434d2SAugustin Cavalier lev.level = new.level;
59*9b2434d2SAugustin Cavalier if (h) {
60*9b2434d2SAugustin Cavalier lev.base = h->base;
61*9b2434d2SAugustin Cavalier } else {
62*9b2434d2SAugustin Cavalier size_t k;
63*9b2434d2SAugustin Cavalier for (k=j; k && path[k]=='/'; k--);
64*9b2434d2SAugustin Cavalier for (; k && path[k-1]!='/'; k--);
65*9b2434d2SAugustin Cavalier lev.base = k;
66*9b2434d2SAugustin Cavalier }
67*9b2434d2SAugustin Cavalier
68*9b2434d2SAugustin Cavalier if (type == FTW_D || type == FTW_DP) {
69*9b2434d2SAugustin Cavalier dfd = open(path, O_RDONLY);
70*9b2434d2SAugustin Cavalier err = errno;
71*9b2434d2SAugustin Cavalier if (dfd < 0 && err == EACCES) type = FTW_DNR;
72*9b2434d2SAugustin Cavalier if (!fd_limit) close(dfd);
73*9b2434d2SAugustin Cavalier }
74*9b2434d2SAugustin Cavalier
75*9b2434d2SAugustin Cavalier if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
76*9b2434d2SAugustin Cavalier return r;
77*9b2434d2SAugustin Cavalier
78*9b2434d2SAugustin Cavalier for (; h; h = h->chain)
79*9b2434d2SAugustin Cavalier if (h->dev == st.st_dev && h->ino == st.st_ino)
80*9b2434d2SAugustin Cavalier return 0;
81*9b2434d2SAugustin Cavalier
82*9b2434d2SAugustin Cavalier if ((type == FTW_D || type == FTW_DP) && fd_limit) {
83*9b2434d2SAugustin Cavalier if (dfd < 0) {
84*9b2434d2SAugustin Cavalier errno = err;
85*9b2434d2SAugustin Cavalier return -1;
86*9b2434d2SAugustin Cavalier }
87*9b2434d2SAugustin Cavalier {
88*9b2434d2SAugustin Cavalier DIR *d = fdopendir(dfd);
89*9b2434d2SAugustin Cavalier if (d) {
90*9b2434d2SAugustin Cavalier struct dirent *de;
91*9b2434d2SAugustin Cavalier while ((de = readdir(d))) {
92*9b2434d2SAugustin Cavalier if (de->d_name[0] == '.'
93*9b2434d2SAugustin Cavalier && (!de->d_name[1]
94*9b2434d2SAugustin Cavalier || (de->d_name[1]=='.'
95*9b2434d2SAugustin Cavalier && !de->d_name[2]))) continue;
96*9b2434d2SAugustin Cavalier if (strlen(de->d_name) >= PATH_MAX-l) {
97*9b2434d2SAugustin Cavalier errno = ENAMETOOLONG;
98*9b2434d2SAugustin Cavalier closedir(d);
99*9b2434d2SAugustin Cavalier return -1;
100*9b2434d2SAugustin Cavalier }
101*9b2434d2SAugustin Cavalier path[j]='/';
102*9b2434d2SAugustin Cavalier strcpy(path+j+1, de->d_name);
103*9b2434d2SAugustin Cavalier if ((r=do_nftw(path, fn, fd_limit-1, flags, &new))) {
104*9b2434d2SAugustin Cavalier closedir(d);
105*9b2434d2SAugustin Cavalier return r;
106*9b2434d2SAugustin Cavalier }
107*9b2434d2SAugustin Cavalier }
108*9b2434d2SAugustin Cavalier closedir(d);
109*9b2434d2SAugustin Cavalier } else {
110*9b2434d2SAugustin Cavalier close(dfd);
111*9b2434d2SAugustin Cavalier return -1;
112*9b2434d2SAugustin Cavalier }
113*9b2434d2SAugustin Cavalier }
114*9b2434d2SAugustin Cavalier }
115*9b2434d2SAugustin Cavalier
116*9b2434d2SAugustin Cavalier path[l] = 0;
117*9b2434d2SAugustin Cavalier if ((flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
118*9b2434d2SAugustin Cavalier return r;
119*9b2434d2SAugustin Cavalier
120*9b2434d2SAugustin Cavalier return 0;
121*9b2434d2SAugustin Cavalier }
122*9b2434d2SAugustin Cavalier
nftw(const char * path,int (* fn)(const char *,const struct stat *,int,struct FTW *),int fd_limit,int flags)123*9b2434d2SAugustin Cavalier int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags)
124*9b2434d2SAugustin Cavalier {
125*9b2434d2SAugustin Cavalier int r, cs;
126*9b2434d2SAugustin Cavalier size_t l;
127*9b2434d2SAugustin Cavalier char pathbuf[PATH_MAX+1];
128*9b2434d2SAugustin Cavalier
129*9b2434d2SAugustin Cavalier if (fd_limit <= 0) return 0;
130*9b2434d2SAugustin Cavalier
131*9b2434d2SAugustin Cavalier l = strlen(path);
132*9b2434d2SAugustin Cavalier if (l > PATH_MAX) {
133*9b2434d2SAugustin Cavalier errno = ENAMETOOLONG;
134*9b2434d2SAugustin Cavalier return -1;
135*9b2434d2SAugustin Cavalier }
136*9b2434d2SAugustin Cavalier memcpy(pathbuf, path, l+1);
137*9b2434d2SAugustin Cavalier
138*9b2434d2SAugustin Cavalier pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
139*9b2434d2SAugustin Cavalier r = do_nftw(pathbuf, fn, fd_limit, flags, NULL);
140*9b2434d2SAugustin Cavalier pthread_setcancelstate(cs, 0);
141*9b2434d2SAugustin Cavalier return r;
142*9b2434d2SAugustin Cavalier }
143