Sun Dec 17 15:56:35 1995 Miles Bader <miles@gnu.ai.mit.edu>
[glibc.git] / io / ftw.c
blob7b264e032e2a2fdf554ff76c297a2a3bcbb9f0ec
1 /* Copyright (C) 1992, 1995 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 errno = 0;
52 while ((entry = readdir (dirs[level])) != NULL)
54 struct stat s;
55 int flag, retval, newlev;
57 ++got;
59 if (entry->d_name[0] == '.'
60 && (entry->d_namlen == 1 ||
61 (entry->d_namlen == 2 && entry->d_name[1] == '.')))
63 errno = 0;
64 continue;
67 if (entry->d_namlen + len + 1 > PATH_MAX)
69 #ifdef ENAMETOOLONG
70 errno = ENAMETOOLONG;
71 #else
72 errno = ENOMEM;
73 #endif
74 return -1;
77 dir[len] = '/';
78 memcpy ((PTR) (dir + len + 1), (PTR) entry->d_name,
79 entry->d_namlen + 1);
81 if (stat (dir, &s) < 0)
83 if (errno != EACCES && errno != ENOENT)
84 return -1;
85 flag = FTW_NS;
87 else if (S_ISDIR (s.st_mode))
89 newlev = (level + 1) % descriptors;
91 if (dirs[newlev] != NULL)
92 closedir (dirs[newlev]);
94 dirs[newlev] = opendir (dir);
95 if (dirs[newlev] != NULL)
96 flag = FTW_D;
97 else
99 if (errno != EACCES)
100 return -1;
101 flag = FTW_DNR;
104 else
105 flag = FTW_F;
107 retval = (*func) (dir, &s, flag);
109 if (flag == FTW_D)
111 if (retval == 0)
112 retval = ftw_dir (dirs, newlev, descriptors, dir,
113 entry->d_namlen + len + 1, func);
114 if (dirs[newlev] != NULL)
116 int save;
118 save = errno;
119 closedir (dirs[newlev]);
120 errno = save;
121 dirs[newlev] = NULL;
125 if (retval != 0)
126 return retval;
128 if (dirs[level] == NULL)
130 int skip;
132 dir[len] = '\0';
133 dirs[level] = opendir (dir);
134 if (dirs[level] == NULL)
135 return -1;
136 skip = got;
137 while (skip-- != 0)
139 errno = 0;
140 if (readdir (dirs[level]) == NULL)
141 return errno == 0 ? 0 : -1;
145 errno = 0;
148 return errno == 0 ? 0 : -1;
151 /* Call a function on every element in a directory tree. */
154 DEFUN(ftw, (dir, func, descriptors),
155 CONST char *dir AND
156 int EXFUN((*func), (CONST char *file, struct stat *status,
157 int flag)) AND
158 int descriptors)
160 DIR **dirs;
161 size_t len;
162 char buf[PATH_MAX + 1];
163 struct stat s;
164 int flag, retval;
165 int i;
167 if (descriptors <= 0)
168 descriptors = 1;
170 dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
171 i = descriptors;
172 while (i-- > 0)
173 dirs[i] = NULL;
175 if (stat (dir, &s) < 0)
177 if (errno != EACCES && errno != ENOENT)
178 return -1;
179 flag = FTW_NS;
181 else if (S_ISDIR (s.st_mode))
183 dirs[0] = opendir (dir);
184 if (dirs[0] != NULL)
185 flag = FTW_D;
186 else
188 if (errno != EACCES)
189 return -1;
190 flag = FTW_DNR;
193 else
194 flag = FTW_F;
196 len = strlen (dir);
197 memcpy ((PTR) buf, (PTR) dir, len + 1);
199 retval = (*func) (buf, &s, flag);
201 if (flag == FTW_D)
203 if (retval == 0)
204 retval = ftw_dir (dirs, 0, descriptors, buf, len, func);
205 if (dirs[0] != NULL)
207 int save;
209 save = errno;
210 closedir (dirs[0]);
211 errno = save;
215 return retval;