diff options
-rw-r--r-- | include/Makefile | 3 | ||||
-rw-r--r-- | include/ftw.h | 107 | ||||
-rw-r--r-- | lib/libc/gen/Makefile.inc | 5 | ||||
-rw-r--r-- | lib/libc/gen/ftw.c | 208 |
4 files changed, 320 insertions, 3 deletions
diff --git a/include/Makefile b/include/Makefile index 130e226..28b5294 100644 --- a/include/Makefile +++ b/include/Makefile @@ -7,7 +7,8 @@ CLEANFILES= osreldate.h version vers.c SUBDIR= arpa protocols rpcsvc rpc INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h ctype.h db.h \ dirent.h dlfcn.h elf.h elf-hints.h err.h fmtmsg.h fnmatch.h fstab.h \ - fts.h getopt.h glob.h grp.h hesiod.h histedit.h ieeefp.h ifaddrs.h \ + fts.h ftw.h getopt.h glob.h grp.h \ + hesiod.h histedit.h ieeefp.h ifaddrs.h \ inttypes.h iso646.h kenv.h langinfo.h libgen.h limits.h link.h \ locale.h malloc.h memory.h monetary.h mpool.h ndbm.h netconfig.h \ netdb.h nl_types.h nlist.h nss.h nsswitch.h objformat.h paths.h \ diff --git a/include/ftw.h b/include/ftw.h new file mode 100644 index 0000000..e0cf085 --- /dev/null +++ b/include/ftw.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2003 by Joel Baker. + * All rights reserved. + * + * 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. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _FTW_H +#define _FTW_H + +#include <sys/stat.h> + +__BEGIN_DECLS + +/* 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 */ + +struct FTW { + 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 */ + +__END_DECLS + +#endif /* _FTW_H */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 01844e5..a7d164b 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -9,7 +9,8 @@ SRCS+= __xuname.c _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \ clock.c closedir.c confstr.c \ crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \ dlfcn.c dlfunc.c drand48.c erand48.c err.c errlst.c errno.c \ - exec.c fmtcheck.c fmtmsg.c fnmatch.c fpclassify.c fstab.c ftok.c fts.c \ + exec.c fmtcheck.c fmtmsg.c fnmatch.c \ + fpclassify.c fstab.c ftok.c fts.c ftw.c \ getbootfile.c getbsize.c \ getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \ gethostname.c getloadavg.c getlogin.c getmntinfo.c getnetgrent.c \ @@ -42,7 +43,7 @@ MAN+= alarm.3 arc4random.3 \ confstr.3 ctermid.3 daemon.3 devname.3 directory.3 dirname.3 \ dladdr.3 dlinfo.3 dllockinit.3 dlopen.3 \ err.3 exec.3 fmtcheck.3 fmtmsg.3 fnmatch.3 fpclassify.3 frexp.3 \ - ftok.3 fts.3 \ + ftok.3 fts.3 ftw.3 \ getbootfile.3 getbsize.3 getcap.3 getcontext.3 getcwd.3 \ getdiskbyname.3 getdomainname.3 getfsent.3 \ getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \ diff --git a/lib/libc/gen/ftw.c b/lib/libc/gen/ftw.c new file mode 100644 index 0000000..a13aa17 --- /dev/null +++ b/lib/libc/gen/ftw.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2003 by Joel Baker. + * All rights reserved. + * + * 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. + * + * 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> /* Because fts(3) says so */ +#include <sys/stat.h> +#include <fts.h> + +#include <unistd.h> /* We want strcpy */ + +#include <errno.h> /* Because errno is our friend */ + +#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, func, descr, 0, MODE_FTW); +} + +int nftw (const char *dir, __nftw_func_t func, int descr, int flags) { + return __ftw_core(dir, 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; + int skip_entry; + __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))) { + skip_entry = 0; + + switch (entry->fts_info) { + + case FTS_D: + if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) { + ftw_flag = FTW_D; + } else { + skip_entry = 1; + } + 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; + } else { + skip_entry = 1; + } + 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. + */ + + skip_entry = 1; + } + + 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; +} |