1 /* 2 * Copyright (c) 2003 by Joel Baker. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the Author nor the names of any contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/types.h> /* Because fts(3) says so */ 33 #include <sys/stat.h> 34 #include <fts.h> 35 36 #include <unistd.h> /* We want strcpy */ 37 38 #include <errno.h> /* Because errno is our friend */ 39 40 #include "ftw.h" 41 42 /* I like symbolic values - this is only used in this file. */ 43 44 enum __ftw_modes { 45 MODE_FTW, 46 MODE_NFTW 47 }; 48 49 /* Prototype this so that we can have it later */ 50 51 static int __ftw_core(const char *, void *, int, int, enum __ftw_modes); 52 53 /* 54 * The external function calls are really just wrappers around __ftw_core, 55 * since the work they do is 90% the same. 56 */ 57 58 int ftw (const char *dir, __ftw_func_t func, int descr) { 59 return __ftw_core(dir, func, descr, 0, MODE_FTW); 60 } 61 62 int nftw (const char *dir, __nftw_func_t func, int descr, int flags) { 63 return __ftw_core(dir, func, descr, flags, MODE_NFTW); 64 } 65 66 /* 67 typedef int (*__ftw_func_t) \ 68 (const char *file, const struct stat status, int flag); 69 typedef int (*__nftw_func_t) \ 70 (const char *file, const struct stat status, int flag, struct FTW detail); 71 */ 72 73 static int __ftw_core(const char *dir, void *func, int descr, int flags, 74 enum __ftw_modes mode) { 75 FTS *hierarchy; 76 FTSENT *entry; 77 int fts_options; 78 const char *paths[2]; 79 int ftw_flag, func_ret; 80 struct FTW ftw_st; 81 int skip_entry; 82 __ftw_func_t ftw_func; 83 __nftw_func_t nftw_func; 84 int saved_errno; 85 86 errno = 0; 87 88 /* We need at least one descriptor to call fts */ 89 90 if (descr < 1) { 91 errno = EINVAL; 92 return -1; 93 } 94 95 /* Decide which mode we're running in, and set the FTS options suitably. */ 96 97 if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */ 98 fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL; 99 fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR; 100 fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0; 101 } else { /* We must be in FTW mode. Nothing else makes sense. */ 102 fts_options = FTS_LOGICAL; 103 } 104 105 /* FTW gets a const char *, but FTS expects a null-term array of them. */ 106 107 paths[0] = dir; 108 paths[1] = NULL; 109 110 /* Open the file hierarchy. */ 111 112 if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) { 113 if (EACCES == errno) { 114 return 0; 115 } else { 116 return -1; 117 } 118 } 119 120 /* The main loop. Is it not nifty? Worship the loop. */ 121 122 while ((entry = fts_read(hierarchy))) { 123 skip_entry = 0; 124 125 switch (entry->fts_info) { 126 127 case FTS_D: 128 if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) { 129 ftw_flag = FTW_D; 130 } else { 131 skip_entry = 1; 132 } 133 break; 134 135 case FTS_DNR: 136 ftw_flag = FTW_DNR; 137 break; 138 139 case FTS_F: 140 ftw_flag = FTW_F; 141 break; 142 143 case FTS_SL: 144 ftw_flag = FTW_SL; 145 break; 146 147 case FTS_NS: 148 ftw_flag = FTW_NS; 149 break; 150 151 /* Values that should only occur in nftw mode */ 152 153 case FTS_SLNONE: 154 if (MODE_NFTW == mode) { 155 ftw_flag = FTW_SLN; 156 } else { 157 ftw_flag = FTW_SL; 158 } 159 break; 160 161 case FTS_DP: 162 if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) { 163 ftw_flag = FTW_D; 164 } else { 165 skip_entry = 1; 166 } 167 break; 168 169 default: 170 /* I'm not sure this is right, but we don't have a valid FTW 171 * type to call with, so cowardice seems the better part of 172 * guessing. 173 */ 174 175 skip_entry = 1; 176 } 177 178 if (MODE_FTW == mode) { 179 ftw_func = (__ftw_func_t) func; 180 func_ret = (*ftw_func) 181 (entry->fts_path, entry->fts_statp, ftw_flag); 182 } else if (MODE_NFTW == mode) { 183 ftw_st.base = (entry->fts_pathlen - entry->fts_namelen); 184 ftw_st.level = entry->fts_level; 185 186 nftw_func = (__nftw_func_t) func; 187 func_ret = (*nftw_func) 188 (entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st); 189 } 190 191 if (0 != func_ret) { 192 saved_errno = errno; 193 fts_close(hierarchy); 194 errno = saved_errno; 195 return func_ret; 196 } 197 } 198 199 /* The janitors will be upset if we don't clean up after ourselves. */ 200 201 saved_errno = errno; 202 fts_close(hierarchy); 203 if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */ 204 errno = saved_errno; 205 } 206 207 return errno ? -1 : 0; 208 } 209