Replace the current implementations of ftw() and nftw() with the OpenBSD

implementations written by Todd C. Miller. These are cleaner, less buggy
and actively maintained.
This commit is contained in:
Tim J. Robbins 2004-08-24 13:00:55 +00:00
parent aaa7f2858e
commit e1bcce4f46
4 changed files with 251 additions and 281 deletions

View File

@ -1,107 +1,62 @@
/* $OpenBSD: ftw.h,v 1.1 2003/07/21 21:13:18 millert Exp $ */
/*
* Copyright (c) 2003 by Joel Baker.
* All rights reserved.
* Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*
* $FreeBSD$
*/
#ifndef _FTW_H
#define _FTW_H
#ifndef _FTW_H
#define _FTW_H
#include <sys/types.h>
#include <sys/stat.h>
__BEGIN_DECLS
/*
* Valid flags for the 3rd argument to the function that is passed as the
* second argument to ftw(3) and nftw(3). Say it three times fast!
*/
#define FTW_F 0 /* File. */
#define FTW_D 1 /* Directory. */
#define FTW_DNR 2 /* Directory without read permission. */
#define FTW_DP 3 /* Directory with subdirectories visited. */
#define FTW_NS 4 /* Unknown type; stat() failed. */
#define FTW_SL 5 /* Symbolic link. */
#define FTW_SLN 6 /* Sym link that names a nonexistent file. */
/* Enumerated values for 'flag' when calling [n]ftw */
enum {
FTW_D, /* Directories */
FTW_DNR, /* Unreadable directory */
FTW_F, /* Regular files */
FTW_SL, /* Symbolic link */
FTW_NS, /* stat(2) failed */
#if __XSI_VISIBLE /* X/Open */
/* Flags for nftw only */
FTW_DP, /* Directory, subdirs visited */
FTW_SLN, /* Dangling symlink */
#endif /* __XSI_VISIBLE */
};
#if __XSI_VISIBLE /* X/Open */
/* Enumerated values for 'flags' when calling nftw */
enum {
FTW_CHDIR = 1, /* Do a chdir(2) when entering a directory */
FTW_DEPTH = 2, /* Report files first (before directory) */
FTW_MOUNT = 4, /* Single filesystem */
FTW_PHYS = 8 /* Physical walk; ignore symlinks */
};
#define FTW_PHYS FTW_PHYS
#define FTW_MOUNT FTW_MOUNT
#define FTW_CHDIR FTW_CHDIR
#define FTW_DEPTH FTW_DEPTH
/* FTW struct for callbacks from nftw */
/*
* Flags for use as the 4th argument to nftw(3). These may be ORed together.
*/
#define FTW_PHYS 0x01 /* Physical walk, don't follow sym links. */
#define FTW_MOUNT 0x02 /* The walk does not cross a mount point. */
#define FTW_DEPTH 0x04 /* Subdirs visited before the dir itself. */
#define FTW_CHDIR 0x08 /* Change to a directory before reading it. */
struct FTW {
int base;
int level;
int base;
int level;
};
#endif /* __XSI_VISIBLE */
/* Typecasts for callback functions */
typedef int (*__ftw_func_t) \
(const char *file, const struct stat *status, int flag);
/* ftw: walk a directory tree, calling a function for each element */
extern int ftw (const char *dir, __ftw_func_t func, int descr);
#if __XSI_VISIBLE /* X/Open */
typedef int (*__nftw_func_t) \
(const char *file, const struct stat *status, int flag, struct FTW *detail);
/* nftw: walk a directory tree, calling a function for each element; much
* like ftw, but with behavior flags and minty freshness.
*/
extern int nftw (const char *dir, __nftw_func_t func, int descr, int flags);
#endif /* __XSI_VISIBLE */
__BEGIN_DECLS
int ftw(const char *, int (*)(const char *, const struct stat *, int), int);
int nftw(const char *, int (*)(const char *, const struct stat *, int,
struct FTW *), int, int);
__END_DECLS
#endif /* _FTW_H */
#endif /* !_FTW_H */

View File

@ -18,7 +18,7 @@ SRCS+= __xuname.c _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
getpeereid.c getprogname.c getpwent.c getttyent.c \
getusershell.c getvfsbyname.c glob.c \
initgroups.c isatty.c isinf.c isnan.c jrand48.c lcong48.c \
lockf.c lrand48.c mrand48.c nice.c \
lockf.c lrand48.c mrand48.c nftw.c nice.c \
nlist.c nrand48.c ntp_gettime.c opendir.c \
pause.c pmadvise.c popen.c posixshm.c pselect.c \
psignal.c pw_scan.c pwcache.c \

View File

@ -1,200 +1,98 @@
/* $OpenBSD: ftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $ */
/*
* Copyright (c) 2003 by Joel Baker.
* All rights reserved.
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Author nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <sys/types.h> /* Because fts(3) says so */
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$OpenBSD: ftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $";
#endif /* LIBC_SCCS and not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
#include <limits.h>
#include <unistd.h> /* We want strcpy */
int
ftw(const char *path, int (*fn)(const char *, const struct stat *, int),
int nfds)
{
char * const paths[2] = { (char *)path, NULL };
FTSENT *cur;
FTS *ftsp;
int error = 0, fnflag, sverrno;
#include <errno.h> /* Because errno is our friend */
/* XXX - nfds is currently unused */
if (nfds < 1 || nfds > OPEN_MAX) {
errno = EINVAL;
return (-1);
}
#include "ftw.h"
/* I like symbolic values - this is only used in this file. */
enum __ftw_modes {
MODE_FTW,
MODE_NFTW
};
/* Prototype this so that we can have it later */
static int __ftw_core(const char *, void (*)(), int, int, enum __ftw_modes);
/*
* The external function calls are really just wrappers around __ftw_core,
* since the work they do is 90% the same.
*/
int ftw (const char *dir, __ftw_func_t func, int descr) {
return __ftw_core(dir, (void (*)())func, descr, 0, MODE_FTW);
}
int nftw (const char *dir, __nftw_func_t func, int descr, int flags) {
return __ftw_core(dir, (void (*)())func, descr, flags, MODE_NFTW);
}
/*
typedef int (*__ftw_func_t) \
(const char *file, const struct stat status, int flag);
typedef int (*__nftw_func_t) \
(const char *file, const struct stat status, int flag, struct FTW detail);
*/
static int __ftw_core(const char *dir, void (*func)(), int descr, int flags,
enum __ftw_modes mode) {
FTS *hierarchy;
FTSENT *entry;
int fts_options;
const char *paths[2];
int ftw_flag, func_ret;
struct FTW ftw_st;
__ftw_func_t ftw_func;
__nftw_func_t nftw_func;
int saved_errno;
errno = 0;
/* We need at least one descriptor to call fts */
if (descr < 1) {
errno = EINVAL;
return -1;
}
/* Decide which mode we're running in, and set the FTS options suitably. */
if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */
fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL;
fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR;
fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0;
} else { /* We must be in FTW mode. Nothing else makes sense. */
fts_options = FTS_LOGICAL;
}
/* FTW gets a const char *, but FTS expects a null-term array of them. */
paths[0] = dir;
paths[1] = NULL;
/* Open the file hierarchy. */
if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) {
if (EACCES == errno) {
return 0;
} else {
return -1;
}
}
/* The main loop. Is it not nifty? Worship the loop. */
while ((entry = fts_read(hierarchy))) {
switch (entry->fts_info) {
case FTS_D:
if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) {
ftw_flag = FTW_D;
}
break;
case FTS_DNR:
ftw_flag = FTW_DNR;
break;
case FTS_F:
ftw_flag = FTW_F;
break;
case FTS_SL:
ftw_flag = FTW_SL;
break;
case FTS_NS:
ftw_flag = FTW_NS;
break;
/* Values that should only occur in nftw mode */
case FTS_SLNONE:
if (MODE_NFTW == mode) {
ftw_flag = FTW_SLN;
} else {
ftw_flag = FTW_SL;
}
break;
case FTS_DP:
if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) {
ftw_flag = FTW_D;
}
break;
default:
/* I'm not sure this is right, but we don't have a valid FTW
* type to call with, so cowardice seems the better part of
* guessing.
*/
break;
}
if (MODE_FTW == mode) {
ftw_func = (__ftw_func_t) func;
func_ret = (*ftw_func)
(entry->fts_path, entry->fts_statp, ftw_flag);
} else if (MODE_NFTW == mode) {
ftw_st.base = (entry->fts_pathlen - entry->fts_namelen);
ftw_st.level = entry->fts_level;
nftw_func = (__nftw_func_t) func;
func_ret = (*nftw_func)
(entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st);
}
if (0 != func_ret) {
saved_errno = errno;
fts_close(hierarchy);
errno = saved_errno;
return func_ret;
}
}
/* The janitors will be upset if we don't clean up after ourselves. */
saved_errno = errno;
fts_close(hierarchy);
if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */
errno = saved_errno;
}
return errno ? -1 : 0;
ftsp = fts_open(paths, FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
fnflag = FTW_D;
break;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
/* we only visit in preorder */
continue;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
case FTS_SLNONE:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_DC:
errno = ELOOP;
/* FALLTHROUGH */
default:
error = -1;
goto done;
}
error = fn(cur->fts_path, cur->fts_statp, fnflag);
if (error != 0)
break;
}
done:
sverrno = errno;
if (fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}

117
lib/libc/gen/nftw.c Normal file
View File

@ -0,0 +1,117 @@
/* $OpenBSD: nftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $ */
/*
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$OpenBSD: nftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $";
#endif /* LIBC_SCCS and not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
#include <limits.h>
int
nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
struct FTW *), int nfds, int ftwflags)
{
char * const paths[2] = { (char *)path, NULL };
struct FTW ftw;
FTSENT *cur;
FTS *ftsp;
int error = 0, ftsflags, fnflag, postorder, sverrno;
/* XXX - nfds is currently unused */
if (nfds < 1 || nfds > OPEN_MAX) {
errno = EINVAL;
return (-1);
}
ftsflags = FTS_COMFOLLOW;
if (!(ftwflags & FTW_CHDIR))
ftsflags |= FTS_NOCHDIR;
if (ftwflags & FTW_MOUNT)
ftsflags |= FTS_XDEV;
if (ftwflags & FTW_PHYS)
ftsflags |= FTS_PHYSICAL;
else
ftsflags |= FTS_LOGICAL;
postorder = (ftwflags & FTW_DEPTH) != 0;
ftsp = fts_open(paths, ftsflags, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
if (postorder)
continue;
fnflag = FTW_D;
break;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
if (!postorder)
continue;
fnflag = FTW_DP;
break;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_SLNONE:
fnflag = FTW_SLN;
break;
case FTS_DC:
errno = ELOOP;
/* FALLTHROUGH */
default:
error = -1;
goto done;
}
ftw.base = cur->fts_pathlen - cur->fts_namelen;
ftw.level = cur->fts_level;
error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
if (error != 0)
break;
}
done:
sverrno = errno;
if (fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}