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 __ftw_func_t ftw_func; 82 __nftw_func_t nftw_func; 83 int saved_errno; 84 85 errno = 0; 86 87 /* We need at least one descriptor to call fts */ 88 89 if (descr < 1) { 90 errno = EINVAL; 91 return -1; 92 } 93 94 /* Decide which mode we're running in, and set the FTS options suitably. */ 95 96 if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */ 97 fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL; 98 fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR; 99 fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0; 100 } else { /* We must be in FTW mode. Nothing else makes sense. */ 101 fts_options = FTS_LOGICAL; 102 } 103 104 /* FTW gets a const char *, but FTS expects a null-term array of them. */ 105 106 paths[0] = dir; 107 paths[1] = NULL; 108 109 /* Open the file hierarchy. */ 110 111 if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) { 112 if (EACCES == errno) { 113 return 0; 114 } else { 115 return -1; 116 } 117 } 118 119 /* The main loop. Is it not nifty? Worship the loop. */ 120 121 while ((entry = fts_read(hierarchy))) { 122 switch (entry->fts_info) { 123 124 case FTS_D: 125 if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) { 126 ftw_flag = FTW_D; 127 } 128 break; 129 130 case FTS_DNR: 131 ftw_flag = FTW_DNR; 132 break; 133 134 case FTS_F: 135 ftw_flag = FTW_F; 136 break; 137 138 case FTS_SL: 139 ftw_flag = FTW_SL; 140 break; 141 142 case FTS_NS: 143 ftw_flag = FTW_NS; 144 break; 145 146 /* Values that should only occur in nftw mode */ 147 148 case FTS_SLNONE: 149 if (MODE_NFTW == mode) { 150 ftw_flag = FTW_SLN; 151 } else { 152 ftw_flag = FTW_SL; 153 } 154 break; 155 156 case FTS_DP: 157 if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) { 158 ftw_flag = FTW_D; 159 } 160 break; 161 162 default: 163 /* I'm not sure this is right, but we don't have a valid FTW 164 * type to call with, so cowardice seems the better part of 165 * guessing. 166 */ 167 break; 168 } 169 170 if (MODE_FTW == mode) { 171 ftw_func = (__ftw_func_t) func; 172 func_ret = (*ftw_func) 173 (entry->fts_path, entry->fts_statp, ftw_flag); 174 } else if (MODE_NFTW == mode) { 175 ftw_st.base = (entry->fts_pathlen - entry->fts_namelen); 176 ftw_st.level = entry->fts_level; 177 178 nftw_func = (__nftw_func_t) func; 179 func_ret = (*nftw_func) 180 (entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st); 181 } 182 183 if (0 != func_ret) { 184 saved_errno = errno; 185 fts_close(hierarchy); 186 errno = saved_errno; 187 return func_ret; 188 } 189 } 190 191 /* The janitors will be upset if we don't clean up after ourselves. */ 192 193 saved_errno = errno; 194 fts_close(hierarchy); 195 if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */ 196 errno = saved_errno; 197 } 198 199 return errno ? -1 : 0; 200 } 201