Import polipo--devel--0--base-0.
[polipo.git] / fts_compat.c
blob2aa984d5d5f1cbf230d8c7ef8c04adfbd65af443
1 /*
2 Copyright (c) 2003 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
23 /* This file implements just enough of the fts family of functions
24 to make Polipo happy. */
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33 #include <string.h>
35 #include "fts_compat.h"
37 static char *
38 getcwd_a()
40 char buf[256];
41 char *ret;
42 ret = getcwd(buf, 256);
43 if(ret == NULL)
44 return NULL;
45 return strdup(buf);
48 static char *
49 mkfilename(const char *path, char *filename)
51 int n = strlen(path);
52 char *buf = malloc(n + 1 + strlen(filename) + 1);
53 if(buf == NULL)
54 return NULL;
55 memcpy(buf, path, n);
56 if(buf[n - 1] != '/')
57 buf[n++] = '/';
58 strcpy(buf + n, filename);
59 return buf;
62 static int
63 split(const char *path, int *slash_return, int *dlen, int *blen)
65 int len; int slash;
66 len = strlen(path);
67 while(len > 0 && path[len - 1] == '/')
68 len--;
69 if(len == 0)
70 return -1;
71 slash = len - 1;
72 while(slash >= 0 && path[slash] != '/')
73 slash--;
75 if(slash_return) *slash_return = slash;
76 if(dlen) *dlen = slash + 1;
77 if(blen) *blen = len - slash - 1;
78 return 1;
81 static char *
82 basename_a(const char *path)
84 int blen, slash;
85 char *b;
86 int rc;
88 rc = split(path, &slash, NULL, &blen);
89 if(rc < 0 || blen == 0)
90 return NULL;
92 b = malloc(blen + 1);
93 if(b == NULL)
94 return NULL;
95 memcpy(b, path + slash + 1, blen);
96 b[blen] = '\0';
97 return b;
100 static char *
101 dirname_a(const char *path)
103 int dlen;
104 int rc;
105 char *d;
107 rc = split(path, NULL, &dlen, NULL);
108 if(rc < 0)
109 return NULL;
111 d = malloc(dlen + 1);
112 if(d == NULL)
113 return NULL;
114 memcpy(d, path, dlen);
115 d[dlen] = '\0';
116 return d;
119 #if defined(__svr4__) || defined(SVR4)
120 static int
121 dirfd(DIR *dir)
123 return dir->dd_fd;
125 #endif
127 FTS*
128 fts_open(char * const *path_argv, int options,
129 int (*compar)(const FTSENT **, const FTSENT **))
131 FTS *fts;
132 DIR *dir;
133 char *cwd;
134 int rc;
136 if(options != FTS_LOGICAL || compar != NULL || path_argv[1] != NULL) {
137 errno = ENOSYS;
138 return NULL;
141 dir = opendir(path_argv[0]);
142 if(dir == NULL)
143 return NULL;
145 fts = calloc(sizeof(FTS), 1);
146 if(fts == NULL) {
147 int save = errno;
148 closedir(dir);
149 errno = save;
150 return NULL;
153 cwd = getcwd_a();
154 if(cwd == NULL) {
155 int save = errno;
156 free(fts);
157 closedir(dir);
158 errno = save;
159 return NULL;
162 rc = fchdir(dirfd(dir));
163 if(rc < 0) {
164 int save = errno;
165 free(cwd);
166 free(fts);
167 closedir(dir);
168 errno = save;
169 return NULL;
172 fts->depth = 0;
173 fts->dir[0] = dir;
174 fts->cwd0 = cwd;
175 fts->cwd = strdup(path_argv[0]);
176 return fts;
180 fts_close(FTS *fts)
182 int save = 0;
183 int rc;
185 if(fts->ftsent.fts_path) {
186 free(fts->ftsent.fts_path);
187 fts->ftsent.fts_path = NULL;
190 if(fts->dname) {
191 free(fts->dname);
192 fts->dname = NULL;
195 rc = chdir(fts->cwd0);
196 if(rc < 0)
197 save = errno;
199 while(fts->depth >= 0) {
200 closedir(fts->dir[fts->depth]);
201 fts->depth--;
204 free(fts->cwd0);
205 if(fts->cwd) free(fts->cwd);
206 free(fts);
208 if(rc < 0) {
209 errno = save;
210 return -1;
212 return 0;
215 FTSENT *
216 fts_read(FTS *fts)
218 struct dirent *dirent;
219 int rc;
220 char *name;
221 char buf[1024];
223 if(fts->ftsent.fts_path) {
224 free(fts->ftsent.fts_path);
225 fts->ftsent.fts_path = NULL;
228 if(fts->dname) {
229 free(fts->dname);
230 fts->dname = NULL;
233 again:
234 dirent = readdir(fts->dir[fts->depth]);
235 if(dirent == NULL) {
236 char *newcwd = NULL;
237 closedir(fts->dir[fts->depth]);
238 fts->dir[fts->depth] = NULL;
239 fts->depth--;
240 if(fts->depth >= 0) {
241 fts->dname = basename_a(fts->cwd);
242 if(fts->dname == NULL)
243 goto error;
244 newcwd = dirname_a(fts->cwd);
245 if(newcwd == NULL)
246 goto error;
248 if(fts->cwd) free(fts->cwd);
249 fts->cwd = NULL;
250 if(fts->depth < 0)
251 return NULL;
252 rc = fchdir(dirfd(fts->dir[fts->depth]));
253 if(rc < 0) {
254 free(newcwd);
255 goto error;
257 fts->cwd = newcwd;
258 name = fts->dname;
259 fts->ftsent.fts_info = FTS_DP;
260 goto done;
263 name = dirent->d_name;
265 again2:
266 rc = stat(name, &fts->stat);
267 if(rc < 0) {
268 fts->ftsent.fts_info = FTS_NS;
269 goto error2;
272 if(S_ISDIR(fts->stat.st_mode)) {
273 char *newcwd;
274 DIR *dir;
276 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
277 goto again;
279 if(fts->depth >= FTS_MAX_DEPTH) {
280 errno = ENFILE;
281 goto error;
283 dir = opendir(dirent->d_name);
284 if(dir == NULL) {
285 if(errno == EACCES) {
286 fts->ftsent.fts_info = FTS_DNR;
287 goto error2;
288 } else
289 goto error;
291 newcwd = mkfilename(fts->cwd, dirent->d_name);
292 rc = fchdir(dirfd(dir));
293 if(rc < 0) {
294 free(newcwd);
295 goto error;
297 free(fts->cwd);
298 fts->cwd = newcwd;
299 fts->ftsent.fts_info = FTS_D;
300 fts->depth++;
301 fts->dir[fts->depth] = dir;
302 goto done;
303 } else if(S_ISREG(fts->stat.st_mode)) {
304 fts->ftsent.fts_info = FTS_F;
305 goto done;
306 } else if(S_ISLNK(fts->stat.st_mode)) {
307 int rc;
308 rc = readlink(name, buf, 1024);
309 if(rc < 0)
310 goto error;
311 if(rc >= 1023) {
312 errno = ENAMETOOLONG;
313 goto error;
315 buf[rc] = '\0';
316 name = buf;
317 if(access(buf, F_OK) >= 0)
318 goto again2;
319 fts->ftsent.fts_info = FTS_SLNONE;
320 goto done;
321 } else {
322 fts->ftsent.fts_info = FTS_DEFAULT;
323 goto done;
326 done:
327 if(fts->cwd == NULL)
328 fts->cwd = getcwd_a();
329 if(fts->cwd == NULL) goto error;
330 fts->ftsent.fts_path = mkfilename(fts->cwd, name);
331 if(fts->ftsent.fts_path == NULL) goto error;
332 fts->ftsent.fts_accpath = name;
333 fts->ftsent.fts_statp = &fts->stat;
334 return &fts->ftsent;
336 error:
337 fts->ftsent.fts_info = FTS_ERR;
338 error2:
339 fts->ftsent.fts_errno = errno;
340 return &fts->ftsent;