ftw.c revision 131661
1256325Sdteske/* 2256325Sdteske * Copyright (c) 2003 by Joel Baker. 3256325Sdteske * All rights reserved. 4256325Sdteske * 5256325Sdteske * Redistribution and use in source and binary forms, with or without 6256325Sdteske * modification, are permitted provided that the following conditions 7256325Sdteske * are met: 8256325Sdteske * 1. Redistributions of source code must retain the above copyright 9256325Sdteske * notice, this list of conditions and the following disclaimer. 10256325Sdteske * 2. Redistributions in binary form must reproduce the above copyright 11256325Sdteske * notice, this list of conditions and the following disclaimer in the 12256325Sdteske * documentation and/or other materials provided with the distribution. 13256325Sdteske * 3. Neither the name of the Author nor the names of any contributors 14256325Sdteske * may be used to endorse or promote products derived from this software 15256325Sdteske * without specific prior written permission. 16256325Sdteske * 17256325Sdteske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18256325Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19256325Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20256325Sdteske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21256325Sdteske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22256325Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23256325Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24256325Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25256325Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26256325Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27256325Sdteske * SUCH DAMAGE. 28256325Sdteske * 29256325Sdteske * $FreeBSD: head/lib/libc/gen/ftw.c 131661 2004-07-05 23:13:16Z das $ 30256325Sdteske */ 31256325Sdteske 32256325Sdteske#include <sys/types.h> /* Because fts(3) says so */ 33256325Sdteske#include <sys/stat.h> 34256325Sdteske#include <fts.h> 35256325Sdteske 36256325Sdteske#include <unistd.h> /* We want strcpy */ 37256325Sdteske 38256325Sdteske#include <errno.h> /* Because errno is our friend */ 39256325Sdteske 40256325Sdteske#include "ftw.h" 41256325Sdteske 42256325Sdteske/* I like symbolic values - this is only used in this file. */ 43256325Sdteske 44256325Sdteskeenum __ftw_modes { 45256325Sdteske MODE_FTW, 46256325Sdteske MODE_NFTW 47256325Sdteske}; 48256325Sdteske 49256325Sdteske/* Prototype this so that we can have it later */ 50256325Sdteske 51256325Sdteskestatic int __ftw_core(const char *, void *, int, int, enum __ftw_modes); 52256325Sdteske 53256325Sdteske/* 54256325Sdteske * The external function calls are really just wrappers around __ftw_core, 55256325Sdteske * since the work they do is 90% the same. 56256325Sdteske */ 57256325Sdteske 58256325Sdteskeint ftw (const char *dir, __ftw_func_t func, int descr) { 59256325Sdteske return __ftw_core(dir, func, descr, 0, MODE_FTW); 60256325Sdteske} 61256325Sdteske 62256325Sdteskeint nftw (const char *dir, __nftw_func_t func, int descr, int flags) { 63256325Sdteske return __ftw_core(dir, func, descr, flags, MODE_NFTW); 64256325Sdteske} 65256325Sdteske 66256325Sdteske/* 67256325Sdtesketypedef int (*__ftw_func_t) \ 68256325Sdteske (const char *file, const struct stat status, int flag); 69256325Sdtesketypedef int (*__nftw_func_t) \ 70256325Sdteske (const char *file, const struct stat status, int flag, struct FTW detail); 71256325Sdteske*/ 72256325Sdteske 73256325Sdteskestatic int __ftw_core(const char *dir, void *func, int descr, int flags, 74256325Sdteske enum __ftw_modes mode) { 75256325Sdteske FTS *hierarchy; 76256325Sdteske FTSENT *entry; 77256325Sdteske int fts_options; 78256325Sdteske const char *paths[2]; 79256325Sdteske int ftw_flag, func_ret; 80256325Sdteske struct FTW ftw_st; 81256325Sdteske int skip_entry; 82256325Sdteske __ftw_func_t ftw_func; 83256325Sdteske __nftw_func_t nftw_func; 84256325Sdteske int saved_errno; 85256325Sdteske 86256325Sdteske errno = 0; 87256325Sdteske 88256325Sdteske /* We need at least one descriptor to call fts */ 89256325Sdteske 90256325Sdteske if (descr < 1) { 91256325Sdteske errno = EINVAL; 92256325Sdteske return -1; 93256325Sdteske } 94256325Sdteske 95256325Sdteske /* Decide which mode we're running in, and set the FTS options suitably. */ 96256325Sdteske 97256325Sdteske if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */ 98256325Sdteske fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL; 99256325Sdteske fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR; 100256325Sdteske fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0; 101256325Sdteske } else { /* We must be in FTW mode. Nothing else makes sense. */ 102256325Sdteske fts_options = FTS_LOGICAL; 103256325Sdteske } 104256325Sdteske 105256325Sdteske /* FTW gets a const char *, but FTS expects a null-term array of them. */ 106256325Sdteske 107256325Sdteske paths[0] = dir; 108256325Sdteske paths[1] = NULL; 109256325Sdteske 110256325Sdteske /* Open the file hierarchy. */ 111256325Sdteske 112256325Sdteske if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) { 113256325Sdteske if (EACCES == errno) { 114256325Sdteske return 0; 115256325Sdteske } else { 116256325Sdteske return -1; 117256325Sdteske } 118256325Sdteske } 119256325Sdteske 120256325Sdteske /* The main loop. Is it not nifty? Worship the loop. */ 121256325Sdteske 122256325Sdteske while ((entry = fts_read(hierarchy))) { 123256325Sdteske skip_entry = 0; 124256325Sdteske 125256325Sdteske switch (entry->fts_info) { 126256325Sdteske 127256325Sdteske case FTS_D: 128256325Sdteske if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) { 129256325Sdteske ftw_flag = FTW_D; 130256325Sdteske } else { 131256325Sdteske skip_entry = 1; 132256325Sdteske } 133256325Sdteske break; 134256325Sdteske 135256325Sdteske case FTS_DNR: 136256325Sdteske ftw_flag = FTW_DNR; 137256325Sdteske break; 138256325Sdteske 139256325Sdteske case FTS_F: 140256325Sdteske ftw_flag = FTW_F; 141256325Sdteske break; 142256325Sdteske 143256325Sdteske case FTS_SL: 144256325Sdteske ftw_flag = FTW_SL; 145256325Sdteske break; 146256325Sdteske 147256325Sdteske case FTS_NS: 148256325Sdteske ftw_flag = FTW_NS; 149256325Sdteske break; 150256325Sdteske 151256325Sdteske /* Values that should only occur in nftw mode */ 152256325Sdteske 153256325Sdteske case FTS_SLNONE: 154256325Sdteske if (MODE_NFTW == mode) { 155256325Sdteske ftw_flag = FTW_SLN; 156256325Sdteske } else { 157256325Sdteske ftw_flag = FTW_SL; 158256325Sdteske } 159256325Sdteske break; 160256325Sdteske 161256325Sdteske case FTS_DP: 162256325Sdteske if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) { 163256325Sdteske ftw_flag = FTW_D; 164256325Sdteske } else { 165256325Sdteske skip_entry = 1; 166256325Sdteske } 167256325Sdteske break; 168256325Sdteske 169256325Sdteske default: 170256325Sdteske /* I'm not sure this is right, but we don't have a valid FTW 171256325Sdteske * type to call with, so cowardice seems the better part of 172256325Sdteske * guessing. 173256325Sdteske */ 174256325Sdteske 175256325Sdteske skip_entry = 1; 176256325Sdteske } 177256325Sdteske 178256325Sdteske if (MODE_FTW == mode) { 179256325Sdteske ftw_func = (__ftw_func_t) func; 180256325Sdteske func_ret = (*ftw_func) 181256325Sdteske (entry->fts_path, entry->fts_statp, ftw_flag); 182256325Sdteske } else if (MODE_NFTW == mode) { 183256325Sdteske ftw_st.base = (entry->fts_pathlen - entry->fts_namelen); 184256325Sdteske ftw_st.level = entry->fts_level; 185256325Sdteske 186256325Sdteske nftw_func = (__nftw_func_t) func; 187256325Sdteske func_ret = (*nftw_func) 188256325Sdteske (entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st); 189256325Sdteske } 190256325Sdteske 191256325Sdteske if (0 != func_ret) { 192256325Sdteske saved_errno = errno; 193256325Sdteske fts_close(hierarchy); 194256325Sdteske errno = saved_errno; 195256325Sdteske return func_ret; 196256325Sdteske } 197256325Sdteske } 198256325Sdteske 199256325Sdteske /* The janitors will be upset if we don't clean up after ourselves. */ 200256325Sdteske 201256325Sdteske saved_errno = errno; 202256325Sdteske fts_close(hierarchy); 203256325Sdteske if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */ 204256325Sdteske errno = saved_errno; 205256325Sdteske } 206256325Sdteske 207256325Sdteske return errno ? -1 : 0; 208256325Sdteske} 209256325Sdteske