diff options
| author | Warner Losh <imp@FreeBSD.org> | 1997-08-29 22:56:41 +0000 |
|---|---|---|
| committer | Warner Losh <imp@FreeBSD.org> | 1997-08-29 22:56:41 +0000 |
| commit | 9a91f1cc2588e491d54c2bec2b83184f4ce49749 (patch) | |
| tree | 98886385ad661ae085949c24e37064b2212eb2f6 /lib/libc | |
| parent | e90cdb54db07d4986b1c9b10caf695861f862490 (diff) | |
Notes
Diffstat (limited to 'lib/libc')
| -rw-r--r-- | lib/libc/gen/fts-compat.c | 84 | ||||
| -rw-r--r-- | lib/libc/gen/fts.c | 84 |
2 files changed, 128 insertions, 40 deletions
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c index e53270725c60..938dcb58c82a 100644 --- a/lib/libc/gen/fts-compat.c +++ b/lib/libc/gen/fts-compat.c @@ -1,3 +1,5 @@ +/* $OpenBSD: fts.c,v 1.9 1997/08/02 00:13:49 millert Exp $ */ + /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -55,11 +57,13 @@ static void fts_padjust __P((FTS *, void *)); static int fts_palloc __P((FTS *, size_t)); static FTSENT *fts_sort __P((FTS *, FTSENT *, int)); static u_short fts_stat __P((FTS *, FTSENT *, int)); +static int fts_safe_changedir __P((FTS *, FTSENT *, int)); -#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])) ) +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) -#define ISSET(opt) (sp->fts_options & opt) -#define SET(opt) (sp->fts_options |= opt) +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) @@ -73,7 +77,7 @@ FTS * fts_open(argv, options, compar) char * const *argv; register int options; - int (*compar)(); + int (*compar) __P((const FTSENT **, const FTSENT **)); { register FTS *sp; register FTSENT *p, *root; @@ -249,12 +253,12 @@ fts_close(sp) } /* - * Special case a root of "/" so that slashes aren't appended which would - * cause paths to be written as "//foo". + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". */ #define NAPPEND(p) \ - (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ - p->fts_path[0] == '/' ? 0 : p->fts_pathlen) + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) FTSENT * fts_read(sp) @@ -304,7 +308,7 @@ fts_read(sp) if (p->fts_info == FTS_D) { /* If skipped or crossed mount point, do post-order visit. */ if (instr == FTS_SKIP || - (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev) ) { + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { if (p->fts_flags & FTS_SYMFOLLOW) (void)close(p->fts_symfd); if (sp->fts_child) { @@ -316,8 +320,8 @@ fts_read(sp) } /* Rebuild if only read the names and now traversing. */ - if (sp->fts_child && sp->fts_options & FTS_NAMEONLY) { - sp->fts_options &= ~FTS_NAMEONLY; + if (sp->fts_child && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); fts_lfree(sp->fts_child); sp->fts_child = NULL; } @@ -335,7 +339,7 @@ fts_read(sp) * FTS_STOP or the fts_info field of the node. */ if (sp->fts_child) { - if (CHDIR(sp, p->fts_accpath)) { + if (fts_safe_changedir(sp, p, -1)) { p->fts_errno = errno; p->fts_flags |= FTS_DONTCHDIR; for (p = sp->fts_child; p; p = p->fts_link) @@ -354,7 +358,7 @@ fts_read(sp) /* Move to the next node on this level. */ next: tmp = p; - if ( (p = p->fts_link) ) { + if ((p = p->fts_link)) { free(tmp); /* @@ -362,7 +366,7 @@ next: tmp = p; * load the paths for the next root. */ if (p->fts_level == FTS_ROOTLEVEL) { - if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { + if (FCHDIR(sp, sp->fts_rfd)) { SET(FTS_STOP); return (NULL); } @@ -418,7 +422,7 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent); * one directory. */ if (p->fts_level == FTS_ROOTLEVEL) { - if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { + if (FCHDIR(sp, sp->fts_rfd)) { SET(FTS_STOP); return (NULL); } @@ -506,7 +510,7 @@ fts_children(sp, instr) fts_lfree(sp->fts_child); if (instr == FTS_NAMEONLY) { - sp->fts_options |= FTS_NAMEONLY; + SET(FTS_NAMEONLY); instr = BNAMES; } else instr = BCHILD; @@ -616,12 +620,14 @@ fts_build(sp, type) */ cderrno = 0; if (nlinks || type == BREAD) - if (FCHDIR(sp, dirfd(dirp))) { + if (fts_safe_changedir(sp, cur, dirfd(dirp))) { if (nlinks && type == BREAD) cur->fts_errno = errno; cur->fts_flags |= FTS_DONTCHDIR; descend = 0; cderrno = errno; + (void)closedir(dirp); + dirp = NULL; } else descend = 1; else @@ -648,7 +654,7 @@ fts_build(sp, type) /* Read the directory, attaching each entry to the `link' pointer. */ adjaddr = NULL; - for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)); ) { + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -726,7 +732,8 @@ mem1: saved_errno = errno; } ++nitems; } - (void)closedir(dirp); + if (dirp) + (void)closedir(dirp); /* * If had to realloc the path, adjust the addresses for the rest @@ -933,7 +940,7 @@ fts_lfree(head) register FTSENT *p; /* Free a linked list of structures. */ - while ( (p = head) ) { + while ((p = head)) { head = head->fts_link; free(p); } @@ -993,3 +1000,40 @@ fts_maxarglen(argv) max = len; return (max); } + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(sp, p, fd) + FTS *sp; + FTSENT *p; + int fd; +{ + int ret, oerrno, newfd; + struct stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = open(p->fts_accpath, O_RDONLY, 0)) < 0) + return (-1); + if (fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)close(newfd); + errno = oerrno; + return (ret); +} diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index e53270725c60..938dcb58c82a 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -1,3 +1,5 @@ +/* $OpenBSD: fts.c,v 1.9 1997/08/02 00:13:49 millert Exp $ */ + /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -55,11 +57,13 @@ static void fts_padjust __P((FTS *, void *)); static int fts_palloc __P((FTS *, size_t)); static FTSENT *fts_sort __P((FTS *, FTSENT *, int)); static u_short fts_stat __P((FTS *, FTSENT *, int)); +static int fts_safe_changedir __P((FTS *, FTSENT *, int)); -#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])) ) +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) -#define ISSET(opt) (sp->fts_options & opt) -#define SET(opt) (sp->fts_options |= opt) +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) #define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path)) #define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) @@ -73,7 +77,7 @@ FTS * fts_open(argv, options, compar) char * const *argv; register int options; - int (*compar)(); + int (*compar) __P((const FTSENT **, const FTSENT **)); { register FTS *sp; register FTSENT *p, *root; @@ -249,12 +253,12 @@ fts_close(sp) } /* - * Special case a root of "/" so that slashes aren't appended which would - * cause paths to be written as "//foo". + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". */ #define NAPPEND(p) \ - (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \ - p->fts_path[0] == '/' ? 0 : p->fts_pathlen) + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) FTSENT * fts_read(sp) @@ -304,7 +308,7 @@ fts_read(sp) if (p->fts_info == FTS_D) { /* If skipped or crossed mount point, do post-order visit. */ if (instr == FTS_SKIP || - (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev) ) { + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { if (p->fts_flags & FTS_SYMFOLLOW) (void)close(p->fts_symfd); if (sp->fts_child) { @@ -316,8 +320,8 @@ fts_read(sp) } /* Rebuild if only read the names and now traversing. */ - if (sp->fts_child && sp->fts_options & FTS_NAMEONLY) { - sp->fts_options &= ~FTS_NAMEONLY; + if (sp->fts_child && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); fts_lfree(sp->fts_child); sp->fts_child = NULL; } @@ -335,7 +339,7 @@ fts_read(sp) * FTS_STOP or the fts_info field of the node. */ if (sp->fts_child) { - if (CHDIR(sp, p->fts_accpath)) { + if (fts_safe_changedir(sp, p, -1)) { p->fts_errno = errno; p->fts_flags |= FTS_DONTCHDIR; for (p = sp->fts_child; p; p = p->fts_link) @@ -354,7 +358,7 @@ fts_read(sp) /* Move to the next node on this level. */ next: tmp = p; - if ( (p = p->fts_link) ) { + if ((p = p->fts_link)) { free(tmp); /* @@ -362,7 +366,7 @@ next: tmp = p; * load the paths for the next root. */ if (p->fts_level == FTS_ROOTLEVEL) { - if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { + if (FCHDIR(sp, sp->fts_rfd)) { SET(FTS_STOP); return (NULL); } @@ -418,7 +422,7 @@ name: t = sp->fts_path + NAPPEND(p->fts_parent); * one directory. */ if (p->fts_level == FTS_ROOTLEVEL) { - if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) { + if (FCHDIR(sp, sp->fts_rfd)) { SET(FTS_STOP); return (NULL); } @@ -506,7 +510,7 @@ fts_children(sp, instr) fts_lfree(sp->fts_child); if (instr == FTS_NAMEONLY) { - sp->fts_options |= FTS_NAMEONLY; + SET(FTS_NAMEONLY); instr = BNAMES; } else instr = BCHILD; @@ -616,12 +620,14 @@ fts_build(sp, type) */ cderrno = 0; if (nlinks || type == BREAD) - if (FCHDIR(sp, dirfd(dirp))) { + if (fts_safe_changedir(sp, cur, dirfd(dirp))) { if (nlinks && type == BREAD) cur->fts_errno = errno; cur->fts_flags |= FTS_DONTCHDIR; descend = 0; cderrno = errno; + (void)closedir(dirp); + dirp = NULL; } else descend = 1; else @@ -648,7 +654,7 @@ fts_build(sp, type) /* Read the directory, attaching each entry to the `link' pointer. */ adjaddr = NULL; - for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)); ) { + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -726,7 +732,8 @@ mem1: saved_errno = errno; } ++nitems; } - (void)closedir(dirp); + if (dirp) + (void)closedir(dirp); /* * If had to realloc the path, adjust the addresses for the rest @@ -933,7 +940,7 @@ fts_lfree(head) register FTSENT *p; /* Free a linked list of structures. */ - while ( (p = head) ) { + while ((p = head)) { head = head->fts_link; free(p); } @@ -993,3 +1000,40 @@ fts_maxarglen(argv) max = len; return (max); } + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(sp, p, fd) + FTS *sp; + FTSENT *p; + int fd; +{ + int ret, oerrno, newfd; + struct stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = open(p->fts_accpath, O_RDONLY, 0)) < 0) + return (-1); + if (fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)close(newfd); + errno = oerrno; + return (ret); +} |
