xref: /haiku/src/system/libroot/posix/musl/misc/nftw.c (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
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