ftw.c revision 131661
1131661Sdas/* 2131661Sdas * Copyright (c) 2003 by Joel Baker. 3131661Sdas * All rights reserved. 4131661Sdas * 5131661Sdas * Redistribution and use in source and binary forms, with or without 6131661Sdas * modification, are permitted provided that the following conditions 7131661Sdas * are met: 8131661Sdas * 1. Redistributions of source code must retain the above copyright 9131661Sdas * notice, this list of conditions and the following disclaimer. 10131661Sdas * 2. Redistributions in binary form must reproduce the above copyright 11131661Sdas * notice, this list of conditions and the following disclaimer in the 12131661Sdas * documentation and/or other materials provided with the distribution. 13131661Sdas * 3. Neither the name of the Author nor the names of any contributors 14131661Sdas * may be used to endorse or promote products derived from this software 15131661Sdas * without specific prior written permission. 16131661Sdas * 17131661Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18131661Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19131661Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20131661Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21131661Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22131661Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23131661Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24131661Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25131661Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26131661Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27131661Sdas * SUCH DAMAGE. 28131661Sdas * 29131661Sdas * $FreeBSD: head/lib/libc/gen/ftw.c 131661 2004-07-05 23:13:16Z das $ 30131661Sdas */ 31131661Sdas 32131661Sdas#include <sys/types.h> /* Because fts(3) says so */ 33131661Sdas#include <sys/stat.h> 34131661Sdas#include <fts.h> 35131661Sdas 36131661Sdas#include <unistd.h> /* We want strcpy */ 37131661Sdas 38131661Sdas#include <errno.h> /* Because errno is our friend */ 39131661Sdas 40131661Sdas#include "ftw.h" 41131661Sdas 42131661Sdas/* I like symbolic values - this is only used in this file. */ 43131661Sdas 44131661Sdasenum __ftw_modes { 45131661Sdas MODE_FTW, 46131661Sdas MODE_NFTW 47131661Sdas}; 48131661Sdas 49131661Sdas/* Prototype this so that we can have it later */ 50131661Sdas 51131661Sdasstatic int __ftw_core(const char *, void *, int, int, enum __ftw_modes); 52131661Sdas 53131661Sdas/* 54131661Sdas * The external function calls are really just wrappers around __ftw_core, 55131661Sdas * since the work they do is 90% the same. 56131661Sdas */ 57131661Sdas 58131661Sdasint ftw (const char *dir, __ftw_func_t func, int descr) { 59131661Sdas return __ftw_core(dir, func, descr, 0, MODE_FTW); 60131661Sdas} 61131661Sdas 62131661Sdasint nftw (const char *dir, __nftw_func_t func, int descr, int flags) { 63131661Sdas return __ftw_core(dir, func, descr, flags, MODE_NFTW); 64131661Sdas} 65131661Sdas 66131661Sdas/* 67131661Sdastypedef int (*__ftw_func_t) \ 68131661Sdas (const char *file, const struct stat status, int flag); 69131661Sdastypedef int (*__nftw_func_t) \ 70131661Sdas (const char *file, const struct stat status, int flag, struct FTW detail); 71131661Sdas*/ 72131661Sdas 73131661Sdasstatic int __ftw_core(const char *dir, void *func, int descr, int flags, 74131661Sdas enum __ftw_modes mode) { 75131661Sdas FTS *hierarchy; 76131661Sdas FTSENT *entry; 77131661Sdas int fts_options; 78131661Sdas const char *paths[2]; 79131661Sdas int ftw_flag, func_ret; 80131661Sdas struct FTW ftw_st; 81131661Sdas int skip_entry; 82131661Sdas __ftw_func_t ftw_func; 83131661Sdas __nftw_func_t nftw_func; 84131661Sdas int saved_errno; 85131661Sdas 86131661Sdas errno = 0; 87131661Sdas 88131661Sdas /* We need at least one descriptor to call fts */ 89131661Sdas 90131661Sdas if (descr < 1) { 91131661Sdas errno = EINVAL; 92131661Sdas return -1; 93131661Sdas } 94131661Sdas 95131661Sdas /* Decide which mode we're running in, and set the FTS options suitably. */ 96131661Sdas 97131661Sdas if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */ 98131661Sdas fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL; 99131661Sdas fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR; 100131661Sdas fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0; 101131661Sdas } else { /* We must be in FTW mode. Nothing else makes sense. */ 102131661Sdas fts_options = FTS_LOGICAL; 103131661Sdas } 104131661Sdas 105131661Sdas /* FTW gets a const char *, but FTS expects a null-term array of them. */ 106131661Sdas 107131661Sdas paths[0] = dir; 108131661Sdas paths[1] = NULL; 109131661Sdas 110131661Sdas /* Open the file hierarchy. */ 111131661Sdas 112131661Sdas if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) { 113131661Sdas if (EACCES == errno) { 114131661Sdas return 0; 115131661Sdas } else { 116131661Sdas return -1; 117131661Sdas } 118131661Sdas } 119131661Sdas 120131661Sdas /* The main loop. Is it not nifty? Worship the loop. */ 121131661Sdas 122131661Sdas while ((entry = fts_read(hierarchy))) { 123131661Sdas skip_entry = 0; 124131661Sdas 125131661Sdas switch (entry->fts_info) { 126131661Sdas 127131661Sdas case FTS_D: 128131661Sdas if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) { 129131661Sdas ftw_flag = FTW_D; 130131661Sdas } else { 131131661Sdas skip_entry = 1; 132131661Sdas } 133131661Sdas break; 134131661Sdas 135131661Sdas case FTS_DNR: 136131661Sdas ftw_flag = FTW_DNR; 137131661Sdas break; 138131661Sdas 139131661Sdas case FTS_F: 140131661Sdas ftw_flag = FTW_F; 141131661Sdas break; 142131661Sdas 143131661Sdas case FTS_SL: 144131661Sdas ftw_flag = FTW_SL; 145131661Sdas break; 146131661Sdas 147131661Sdas case FTS_NS: 148131661Sdas ftw_flag = FTW_NS; 149131661Sdas break; 150131661Sdas 151131661Sdas /* Values that should only occur in nftw mode */ 152131661Sdas 153131661Sdas case FTS_SLNONE: 154131661Sdas if (MODE_NFTW == mode) { 155131661Sdas ftw_flag = FTW_SLN; 156131661Sdas } else { 157131661Sdas ftw_flag = FTW_SL; 158131661Sdas } 159131661Sdas break; 160131661Sdas 161131661Sdas case FTS_DP: 162131661Sdas if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) { 163131661Sdas ftw_flag = FTW_D; 164131661Sdas } else { 165131661Sdas skip_entry = 1; 166131661Sdas } 167131661Sdas break; 168131661Sdas 169131661Sdas default: 170131661Sdas /* I'm not sure this is right, but we don't have a valid FTW 171131661Sdas * type to call with, so cowardice seems the better part of 172131661Sdas * guessing. 173131661Sdas */ 174131661Sdas 175131661Sdas skip_entry = 1; 176131661Sdas } 177131661Sdas 178131661Sdas if (MODE_FTW == mode) { 179131661Sdas ftw_func = (__ftw_func_t) func; 180131661Sdas func_ret = (*ftw_func) 181131661Sdas (entry->fts_path, entry->fts_statp, ftw_flag); 182131661Sdas } else if (MODE_NFTW == mode) { 183131661Sdas ftw_st.base = (entry->fts_pathlen - entry->fts_namelen); 184131661Sdas ftw_st.level = entry->fts_level; 185131661Sdas 186131661Sdas nftw_func = (__nftw_func_t) func; 187131661Sdas func_ret = (*nftw_func) 188131661Sdas (entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st); 189131661Sdas } 190131661Sdas 191131661Sdas if (0 != func_ret) { 192131661Sdas saved_errno = errno; 193131661Sdas fts_close(hierarchy); 194131661Sdas errno = saved_errno; 195131661Sdas return func_ret; 196131661Sdas } 197131661Sdas } 198131661Sdas 199131661Sdas /* The janitors will be upset if we don't clean up after ourselves. */ 200131661Sdas 201131661Sdas saved_errno = errno; 202131661Sdas fts_close(hierarchy); 203131661Sdas if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */ 204131661Sdas errno = saved_errno; 205131661Sdas } 206131661Sdas 207131661Sdas return errno ? -1 : 0; 208131661Sdas} 209