Fix an integer overflow in processing client connections.
[polipo.git] / fts_compat.c
blob7451e8152a889b9b8ee13c1503addb16009d38e5
1 /*
2 Copyright (c) 2003-2006 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
128 * Make the directory identified by the argument the current directory.
130 #ifdef MINGW
132 change_to_dir(DIR *dir)
134 errno = ENOSYS;
135 return -1;
137 #else
139 change_to_dir(DIR *dir)
141 return fchdir(dirfd(dir));
143 #endif
145 FTS*
146 fts_open(char * const *path_argv, int options,
147 int (*compar)(const FTSENT **, const FTSENT **))
149 FTS *fts;
150 DIR *dir;
151 char *cwd;
152 int rc;
154 if(options != FTS_LOGICAL || compar != NULL || path_argv[1] != NULL) {
155 errno = ENOSYS;
156 return NULL;
159 dir = opendir(path_argv[0]);
160 if(dir == NULL)
161 return NULL;
163 fts = calloc(sizeof(FTS), 1);
164 if(fts == NULL) {
165 int save = errno;
166 closedir(dir);
167 errno = save;
168 return NULL;
171 cwd = getcwd_a();
172 if(cwd == NULL) {
173 int save = errno;
174 free(fts);
175 closedir(dir);
176 errno = save;
177 return NULL;
180 rc = change_to_dir(dir);
181 if(rc < 0) {
182 int save = errno;
183 free(cwd);
184 free(fts);
185 closedir(dir);
186 errno = save;
187 return NULL;
190 fts->depth = 0;
191 fts->dir[0] = dir;
192 fts->cwd0 = cwd;
193 fts->cwd = strdup(path_argv[0]);
194 return fts;
198 fts_close(FTS *fts)
200 int save = 0;
201 int rc;
203 if(fts->ftsent.fts_path) {
204 free(fts->ftsent.fts_path);
205 fts->ftsent.fts_path = NULL;
208 if(fts->dname) {
209 free(fts->dname);
210 fts->dname = NULL;
213 rc = chdir(fts->cwd0);
214 if(rc < 0)
215 save = errno;
217 while(fts->depth >= 0) {
218 closedir(fts->dir[fts->depth]);
219 fts->depth--;
222 free(fts->cwd0);
223 if(fts->cwd) free(fts->cwd);
224 free(fts);
226 if(rc < 0) {
227 errno = save;
228 return -1;
230 return 0;
233 FTSENT *
234 fts_read(FTS *fts)
236 struct dirent *dirent;
237 int rc;
238 char *name;
239 char buf[1024];
241 if(fts->ftsent.fts_path) {
242 free(fts->ftsent.fts_path);
243 fts->ftsent.fts_path = NULL;
246 if(fts->dname) {
247 free(fts->dname);
248 fts->dname = NULL;
251 again:
252 dirent = readdir(fts->dir[fts->depth]);
253 if(dirent == NULL) {
254 char *newcwd = NULL;
255 closedir(fts->dir[fts->depth]);
256 fts->dir[fts->depth] = NULL;
257 fts->depth--;
258 if(fts->depth >= 0) {
259 fts->dname = basename_a(fts->cwd);
260 if(fts->dname == NULL)
261 goto error;
262 newcwd = dirname_a(fts->cwd);
263 if(newcwd == NULL)
264 goto error;
266 if(fts->cwd) free(fts->cwd);
267 fts->cwd = NULL;
268 if(fts->depth < 0)
269 return NULL;
270 rc = change_to_dir(fts->dir[fts->depth]);
271 if(rc < 0) {
272 free(newcwd);
273 goto error;
275 fts->cwd = newcwd;
276 name = fts->dname;
277 fts->ftsent.fts_info = FTS_DP;
278 goto done;
281 name = dirent->d_name;
283 again2:
284 rc = stat(name, &fts->stat);
285 if(rc < 0) {
286 fts->ftsent.fts_info = FTS_NS;
287 goto error2;
290 if(S_ISDIR(fts->stat.st_mode)) {
291 char *newcwd;
292 DIR *dir;
294 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
295 goto again;
297 if(fts->depth >= FTS_MAX_DEPTH) {
298 errno = ENFILE;
299 goto error;
301 dir = opendir(dirent->d_name);
302 if(dir == NULL) {
303 if(errno == EACCES) {
304 fts->ftsent.fts_info = FTS_DNR;
305 goto error2;
306 } else
307 goto error;
309 newcwd = mkfilename(fts->cwd, dirent->d_name);
310 rc = change_to_dir(dir);
311 if(rc < 0) {
312 free(newcwd);
313 goto error;
315 free(fts->cwd);
316 fts->cwd = newcwd;
317 fts->ftsent.fts_info = FTS_D;
318 fts->depth++;
319 fts->dir[fts->depth] = dir;
320 goto done;
321 } else if(S_ISREG(fts->stat.st_mode)) {
322 fts->ftsent.fts_info = FTS_F;
323 goto done;
324 #ifdef S_ISLNK
325 } else if(S_ISLNK(fts->stat.st_mode)) {
326 int rc;
327 rc = readlink(name, buf, 1024);
328 if(rc < 0)
329 goto error;
330 if(rc >= 1023) {
331 errno = ENAMETOOLONG;
332 goto error;
334 buf[rc] = '\0';
335 name = buf;
336 if(access(buf, F_OK) >= 0)
337 goto again2;
338 fts->ftsent.fts_info = FTS_SLNONE;
339 goto done;
340 #endif
341 } else {
342 fts->ftsent.fts_info = FTS_DEFAULT;
343 goto done;
346 done:
347 if(fts->cwd == NULL)
348 fts->cwd = getcwd_a();
349 if(fts->cwd == NULL) goto error;
350 fts->ftsent.fts_path = mkfilename(fts->cwd, name);
351 if(fts->ftsent.fts_path == NULL) goto error;
352 fts->ftsent.fts_accpath = name;
353 fts->ftsent.fts_statp = &fts->stat;
354 return &fts->ftsent;
356 error:
357 fts->ftsent.fts_info = FTS_ERR;
358 error2:
359 fts->ftsent.fts_errno = errno;
360 return &fts->ftsent;