Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
2 | /* ftw() for DJGPP. |
||
3 | * |
||
4 | * Recursively descent the directory hierarchy rooted in DIR, |
||
5 | * calling FUNC for each object in the hierarchy. |
||
6 | * |
||
7 | * Copyright (c) 1995 Eli Zaretskii |
||
8 | * |
||
9 | * This software may be used freely as long as this copyright notice is |
||
10 | * left intact. There is no warranty on this software. |
||
11 | * |
||
12 | */ |
||
13 | |||
14 | #include |
||
15 | #include |
||
16 | #include |
||
17 | #include |
||
18 | #include |
||
19 | #include |
||
20 | #include |
||
21 | #include |
||
22 | #include |
||
23 | |||
24 | static int |
||
25 | walk_dir(char *path, int (*func)(const char *, struct stat *, int)) |
||
26 | { |
||
27 | DIR *dp; |
||
28 | struct dirent *de; |
||
29 | struct stat stbuf; |
||
30 | int flag; |
||
31 | int e = errno; |
||
32 | int pathlen = strlen(path); |
||
33 | |||
34 | if ((dp = opendir(path)) == 0) |
||
35 | return -1; |
||
36 | |||
37 | for (errno = 0; (de = readdir(dp)) != 0; errno = 0) |
||
38 | { |
||
39 | int func_result; |
||
40 | char lastc = de->d_name[de->d_namlen - 1]; |
||
41 | |||
42 | /* Skip `.' and `..' entries. Checking the last char is enough, |
||
43 | because readdir will never return a filename which ends with |
||
44 | a dot. */ |
||
45 | if (lastc == '.') |
||
46 | continue; |
||
47 | |||
48 | /* Append found name to directory path. */ |
||
49 | if (pathlen + de->d_namlen + 1 > FILENAME_MAX) |
||
50 | { |
||
51 | (void)closedir(dp); |
||
52 | errno = ENAMETOOLONG; |
||
53 | return -1; |
||
54 | } |
||
55 | if (path[pathlen-1] == '/' || path[pathlen-1] == '\\') |
||
56 | pathlen--; |
||
57 | path[pathlen] = '/'; |
||
58 | strcpy(path + pathlen + 1, de->d_name); |
||
59 | |||
60 | if (stat(path, &stbuf) < 0) |
||
61 | flag = FTW_NS; |
||
62 | else if (S_ISDIR(stbuf.st_mode)) |
||
63 | flag = FTW_D; |
||
64 | else if (S_ISLABEL(stbuf.st_mode)) |
||
65 | flag = FTW_VL; |
||
66 | else |
||
67 | flag = FTW_F; |
||
68 | |||
69 | /* Invoke FUNC() on this object. */ |
||
70 | errno = e; |
||
71 | if ((func_result = (*func)(path, &stbuf, flag)) != 0) |
||
72 | { |
||
73 | (void)closedir(dp); |
||
74 | return func_result; |
||
75 | } |
||
76 | |||
77 | /* If this is a directory, walk its siblings. */ |
||
78 | if (flag == FTW_D) |
||
79 | { |
||
80 | int subwalk_result; |
||
81 | |||
82 | errno = e; |
||
83 | if ((subwalk_result = walk_dir(path, func)) != 0) |
||
84 | { |
||
85 | (void)closedir(dp); |
||
86 | return subwalk_result; |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /* Erase D_NAME[] from PATH. */ |
||
91 | path[pathlen] = '\0'; |
||
92 | } |
||
93 | |||
94 | (void)closedir(dp); |
||
95 | if (errno == 0) /* normal case: this subtree exhausted */ |
||
96 | { |
||
97 | errno = e;/* restore errno from previous syscall */ |
||
98 | return 0; |
||
99 | } |
||
100 | else |
||
101 | return -1; /* with whatever errno was set by readdir() */ |
||
102 | } |
||
103 | |||
104 | int |
||
105 | ftw(const char *dir, int (*func)(const char *, struct stat *, int), |
||
106 | int ignored) |
||
107 | { |
||
108 | int flag; |
||
109 | unsigned char pathbuf[FILENAME_MAX]; |
||
110 | int dirattr; |
||
111 | int len; |
||
112 | int e = errno; |
||
113 | |||
114 | ignored = ignored; /* pacify -Wall */ |
||
115 | |||
116 | if (dir == 0 || func == 0) |
||
117 | { |
||
118 | errno = EFAULT; |
||
119 | return -1; |
||
120 | } |
||
121 | |||
122 | if (*dir == '\0') |
||
123 | { |
||
124 | errno = ENOENT; |
||
125 | return -1; |
||
126 | } |
||
127 | |||
128 | strcpy(pathbuf, dir); |
||
129 | len = strlen(pathbuf); |
||
130 | if (pathbuf[len-1] == ':') |
||
131 | { |
||
132 | pathbuf[len++] = '.'; |
||
133 | pathbuf[len] = '\0'; |
||
134 | } |
||
135 | |||
136 | /* Fail for non-directories. */ |
||
137 | errno = 0; |
||
138 | dirattr = _chmod(pathbuf, 0, 0); |
||
139 | if (errno == ENOENT) |
||
140 | return -1; |
||
141 | else if ((dirattr & 0x10) != 0x10) |
||
142 | { |
||
143 | errno = ENOTDIR; |
||
144 | return -1; |
||
145 | } |
||
146 | else |
||
147 | { |
||
148 | int func_result; |
||
149 | struct stat stbuf; |
||
150 | |||
151 | if (stat(pathbuf, &stbuf) < 0) |
||
152 | flag = FTW_NS; |
||
153 | else |
||
154 | flag = FTW_D; |
||
155 | errno = e; |
||
156 | if ((func_result = (*func)(pathbuf, &stbuf, flag)) != 0) |
||
157 | return func_result; |
||
158 | |||
159 | return walk_dir(pathbuf, func); |
||
160 | } |
||
161 | } |
||
162 | |||
163 | #ifdef TEST |
||
164 | |||
165 | #include |
||
166 | |||
167 | int |
||
168 | ftw_walker(const char *path, struct stat *sb, int flag) |
||
169 | { |
||
170 | char *base; |
||
171 | |||
172 | printf("%s:\t%u\t", path, sb->st_size); |
||
173 | if (S_ISLABEL(sb->st_mode)) |
||
174 | printf("V"); |
||
175 | if (S_ISDIR(sb->st_mode)) |
||
176 | printf("D"); |
||
177 | if (S_ISCHR(sb->st_mode)) |
||
178 | printf("C"); |
||
179 | if (sb->st_mode & S_IRUSR) |
||
180 | printf("r"); |
||
181 | if (sb->st_mode & S_IWUSR) |
||
182 | printf("w"); |
||
183 | if (sb->st_mode & S_IXUSR) |
||
184 | printf("x"); |
||
185 | |||
186 | if (flag == FTW_NS) |
||
187 | printf(" !!no_stat!!"); |
||
188 | printf("\n"); |
||
189 | |||
190 | base = strrchr(path, '/'); |
||
191 | if (base == 0) |
||
192 | base = strrchr(path, '\\'); |
||
193 | if (base == 0) |
||
194 | base = strrchr(path, ':'); |
||
195 | if (strcmp(base == 0 ? path : base + 1, "xxxxx") == 0) |
||
196 | return 8; |
||
197 | return 0; |
||
198 | } |
||
199 | |||
200 | int |
||
201 | main(int argc, char *argv[]) |
||
202 | { |
||
203 | if (argc > 1) |
||
204 | { |
||
205 | char msg[80]; |
||
206 | |||
207 | sprintf(msg, "file_tree_walk: %d", |
||
208 | ftw(argv[1], ftw_walker, 0)); |
||
209 | if (errno) |
||
210 | perror(msg); |
||
211 | else |
||
212 | puts(msg); |
||
213 | } |
||
214 | else |
||
215 | printf("Usage: %s dir\n", argv[0]); |
||
216 | |||
217 | return 0; |
||
218 | } |
||
219 | |||
220 | #endif>> |