update from main archive 961009
[glibc.git] / io / ftw.c
blobb8d745b8d3e52a5f92631281d73b18337cef956a
1 /* Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ian Lance Taylor (ian@airs.com).
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA. */
20 #include <ansidecl.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <dirent.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <ftw.h>
31 #ifndef PATH_MAX
32 #define PATH_MAX 1024 /* XXX */
33 #endif
36 /* Traverse one level of a directory tree. */
38 static int
39 DEFUN (ftw_dir, (dirs, level, descriptors, dir, len, func),
40 DIR **dirs AND int level AND int descriptors AND
41 char *dir AND size_t len AND
42 int EXFUN((*func), (CONST char *file, struct stat *status,
43 int flag)))
45 int got;
46 struct dirent *entry;
48 got = 0;
50 __set_errno (0);
52 while ((entry = readdir (dirs[level])) != NULL)
54 struct stat s;
55 int flag, retval, newlev;
56 size_t namlen;
58 ++got;
60 if (entry->d_name[0] == '.'
61 && (entry->d_name[1] == '\0' ||
62 (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
64 __set_errno (0);
65 continue;
68 namlen = _D_EXACT_NAMLEN (entry);
70 if (namlen + len + 1 > PATH_MAX)
72 #ifdef ENAMETOOLONG
73 __set_errno (ENAMETOOLONG);
74 #else
75 __set_errno (ENOMEM);
76 #endif
77 return -1;
80 dir[len] = '/';
81 memcpy ((PTR) (dir + len + 1), (PTR) entry->d_name,
82 namlen + 1);
84 if (stat (dir, &s) < 0)
86 if (errno != EACCES && errno != ENOENT)
87 return -1;
88 flag = FTW_NS;
90 else if (S_ISDIR (s.st_mode))
92 newlev = (level + 1) % descriptors;
94 if (dirs[newlev] != NULL)
95 closedir (dirs[newlev]);
97 dirs[newlev] = opendir (dir);
98 if (dirs[newlev] != NULL)
99 flag = FTW_D;
100 else
102 if (errno != EACCES)
103 return -1;
104 flag = FTW_DNR;
107 else
108 flag = FTW_F;
110 retval = (*func) (dir, &s, flag);
112 if (flag == FTW_D)
114 if (retval == 0)
115 retval = ftw_dir (dirs, newlev, descriptors, dir,
116 namlen + len + 1, func);
117 if (dirs[newlev] != NULL)
119 int save;
121 save = errno;
122 closedir (dirs[newlev]);
123 __set_errno (save);
124 dirs[newlev] = NULL;
128 if (retval != 0)
129 return retval;
131 if (dirs[level] == NULL)
133 int skip;
135 dir[len] = '\0';
136 dirs[level] = opendir (dir);
137 if (dirs[level] == NULL)
138 return -1;
139 skip = got;
140 while (skip-- != 0)
142 __set_errno (0);
143 if (readdir (dirs[level]) == NULL)
144 return errno == 0 ? 0 : -1;
148 __set_errno (0);
151 return errno == 0 ? 0 : -1;
154 /* Call a function on every element in a directory tree. */
157 DEFUN(ftw, (dir, func, descriptors),
158 CONST char *dir AND
159 int EXFUN((*func), (CONST char *file, struct stat *status,
160 int flag)) AND
161 int descriptors)
163 DIR **dirs;
164 size_t len;
165 char buf[PATH_MAX + 1];
166 struct stat s;
167 int flag, retval;
168 int i;
170 if (descriptors <= 0)
171 descriptors = 1;
173 dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
174 i = descriptors;
175 while (i-- > 0)
176 dirs[i] = NULL;
178 if (stat (dir, &s) < 0)
180 if (errno != EACCES && errno != ENOENT)
181 return -1;
182 flag = FTW_NS;
184 else if (S_ISDIR (s.st_mode))
186 dirs[0] = opendir (dir);
187 if (dirs[0] != NULL)
188 flag = FTW_D;
189 else
191 if (errno != EACCES)
192 return -1;
193 flag = FTW_DNR;
196 else
197 flag = FTW_F;
199 len = strlen (dir);
200 memcpy ((PTR) buf, (PTR) dir, len + 1);
202 retval = (*func) (buf, &s, flag);
204 if (flag == FTW_D)
206 if (retval == 0)
207 retval = ftw_dir (dirs, 0, descriptors, buf, len, func);
208 if (dirs[0] != NULL)
210 int save;
212 save = errno;
213 closedir (dirs[0]);
214 __set_errno (save);
218 return retval;