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