1/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. 2This file is part of the GNU C Library. 3Contributed by Ian Lance Taylor (ian@airs.com). 4 5The GNU C Library is free software; you can redistribute it and/or 6modify it under the terms of the GNU Library General Public License as 7published by the Free Software Foundation; either version 2 of the 8License, or (at your option) any later version. 9 10The GNU C Library is distributed in the hope that it will be useful, 11but WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13Library General Public License for more details. 14 15You should have received a copy of the GNU Library General Public 16License along with the GNU C Library; see the file COPYING.LIB. If 17not, write to the Free Software Foundation, Inc., 59 Temple Place - 18Suite 330, Boston, MA 02111-1307, USA. 19 20Modified by Ian Lance Taylor for Taylor UUCP, June 1992, and October 1993. */ 21 22#include "uucp.h" 23 24#include "sysdep.h" 25 26#include <errno.h> 27 28#if HAVE_LIMITS_H 29#include <limits.h> 30#endif 31 32#if HAVE_SYS_PARAM_H 33#include <sys/param.h> 34#endif 35 36#if HAVE_OPENDIR 37#if HAVE_DIRENT_H 38#include <dirent.h> 39#else /* ! HAVE_DIRENT_H */ 40#include <sys/dir.h> 41#define dirent direct 42#endif /* ! HAVE_DIRENT_H */ 43#endif /* HAVE_OPENDIR */ 44 45#if HAVE_FTW_H 46#include <ftw.h> 47#endif 48 49#ifndef PATH_MAX 50#ifdef MAXPATHLEN 51#define PATH_MAX MAXPATHLEN 52#else 53#define PATH_MAX 1024 54#endif 55#endif 56 57/* Traverse one level of a directory tree. */ 58 59static int 60ftw_dir (dirs, level, descriptors, dir, len, func) 61 DIR **dirs; 62 int level; 63 int descriptors; 64 char *dir; 65 size_t len; 66 int (*func) P((const char *file, const struct stat *status, int flag)); 67{ 68 int got; 69 struct dirent *entry; 70 71 got = 0; 72 73 errno = 0; 74 75 while ((entry = readdir (dirs[level])) != NULL) 76 { 77 size_t namlen; 78 struct stat s; 79 int flag, ret, newlev = 0; 80 81 ++got; 82 83 namlen = strlen (entry->d_name); 84 if (entry->d_name[0] == '.' 85 && (namlen == 1 || 86 (namlen == 2 && entry->d_name[1] == '.'))) 87 { 88 errno = 0; 89 continue; 90 } 91 92 if (namlen + len + 1 > PATH_MAX) 93 { 94#ifdef ENAMETOOLONG 95 errno = ENAMETOOLONG; 96#else 97 errno = ENOMEM; 98#endif 99 return -1; 100 } 101 102 dir[len] = '/'; 103 memcpy ((dir + len + 1), entry->d_name, namlen + 1); 104 105 if (stat (dir, &s) < 0) 106 { 107 if (errno != EACCES) 108 return -1; 109 flag = FTW_NS; 110 } 111 else if (S_ISDIR (s.st_mode)) 112 { 113 newlev = (level + 1) % descriptors; 114 115 if (dirs[newlev] != NULL) 116 closedir (dirs[newlev]); 117 118 dirs[newlev] = opendir (dir); 119 if (dirs[newlev] != NULL) 120 flag = FTW_D; 121 else 122 { 123 if (errno != EACCES) 124 return -1; 125 flag = FTW_DNR; 126 } 127 } 128 else 129 flag = FTW_F; 130 131 ret = (*func) (dir, &s, flag); 132 133 if (flag == FTW_D) 134 { 135 if (ret == 0) 136 ret = ftw_dir (dirs, newlev, descriptors, dir, 137 namlen + len + 1, func); 138 if (dirs[newlev] != NULL) 139 { 140 int save; 141 142 save = errno; 143 closedir (dirs[newlev]); 144 errno = save; 145 dirs[newlev] = NULL; 146 } 147 } 148 149 if (ret != 0) 150 return ret; 151 152 if (dirs[level] == NULL) 153 { 154 int skip; 155 156 dir[len] = '\0'; 157 dirs[level] = opendir (dir); 158 if (dirs[level] == NULL) 159 return -1; 160 skip = got; 161 while (skip-- != 0) 162 { 163 errno = 0; 164 if (readdir (dirs[level]) == NULL) 165 return errno == 0 ? 0 : -1; 166 } 167 } 168 169 errno = 0; 170 } 171 172 return errno == 0 ? 0 : -1; 173} 174 175/* Call a function on every element in a directory tree. */ 176 177int 178ftw (dir, func, descriptors) 179 const char *dir; 180 int (*func) P((const char *file, const struct stat *status, int flag)); 181 int descriptors; 182{ 183 DIR **dirs; 184 int c; 185 DIR **p; 186 size_t len; 187 char buf[PATH_MAX + 1]; 188 struct stat s; 189 int flag, ret; 190 191 if (descriptors <= 0) 192 descriptors = 1; 193 194 dirs = (DIR **) malloc (descriptors * sizeof (DIR *)); 195 if (dirs == NULL) 196 return -1; 197 c = descriptors; 198 p = dirs; 199 while (c-- != 0) 200 *p++ = NULL; 201 202 len = strlen (dir); 203 memcpy (buf, dir, len + 1); 204 205 if (stat (dir, &s) < 0) 206 { 207 if (errno != EACCES) 208 { 209 free ((pointer) dirs); 210 return -1; 211 } 212 flag = FTW_NS; 213 } 214 else if (S_ISDIR (s.st_mode)) 215 { 216 dirs[0] = opendir (dir); 217 if (dirs[0] != NULL) 218 flag = FTW_D; 219 else 220 { 221 if (errno != EACCES) 222 { 223 free ((pointer) dirs); 224 return -1; 225 } 226 flag = FTW_DNR; 227 } 228 } 229 else 230 flag = FTW_F; 231 232 ret = (*func) (buf, &s, flag); 233 234 if (flag == FTW_D) 235 { 236 if (ret == 0) 237 { 238 if (len == 1 && *buf == '/') 239 len = 0; 240 ret = ftw_dir (dirs, 0, descriptors, buf, len, func); 241 } 242 if (dirs[0] != NULL) 243 { 244 int save; 245 246 save = errno; 247 closedir (dirs[0]); 248 errno = save; 249 } 250 } 251 252 free ((pointer) dirs); 253 return ret; 254} 255