update from main archive 961203
[glibc.git] / io / ftw.c
blobb7983d4525543da461e94ee7815df1b2fab6caf3
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 not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <dirent.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <ftw.h>
30 #ifndef PATH_MAX
31 #define PATH_MAX 1024 /* XXX */
32 #endif
35 /* Traverse one level of a directory tree. */
37 static int
38 ftw_dir (DIR **dirs, int level, int descriptors, char *dir, size_t len,
39 int (*func) (const char *file, struct stat *status, int flag))
41 int got;
42 struct dirent dirbuf, *entry;
44 got = 0;
46 __set_errno (0);
48 while (__readdir_r (dirs[level], &dirbuf, &entry) >= 0)
50 struct stat s;
51 int flag, retval, newlev;
52 size_t namlen;
54 ++got;
56 if (entry->d_name[0] == '.'
57 && (entry->d_name[1] == '\0' ||
58 (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
60 __set_errno (0);
61 continue;
64 namlen = _D_EXACT_NAMLEN (entry);
66 if (namlen + len + 1 > PATH_MAX)
68 #ifdef ENAMETOOLONG
69 __set_errno (ENAMETOOLONG);
70 #else
71 __set_errno (ENOMEM);
72 #endif
73 return -1;
76 dir[len] = '/';
77 memcpy ((void *) (dir + len + 1), (void *) entry->d_name,
78 namlen + 1);
80 if (stat (dir, &s) < 0)
82 if (errno != EACCES && errno != ENOENT)
83 return -1;
84 flag = FTW_NS;
86 else if (S_ISDIR (s.st_mode))
88 newlev = (level + 1) % descriptors;
90 if (dirs[newlev] != NULL)
91 closedir (dirs[newlev]);
93 dirs[newlev] = opendir (dir);
94 if (dirs[newlev] != NULL)
95 flag = FTW_D;
96 else
98 if (errno != EACCES)
99 return -1;
100 flag = FTW_DNR;
103 else
104 flag = FTW_F;
106 retval = (*func) (dir, &s, flag);
108 if (flag == FTW_D)
110 if (retval == 0)
111 retval = ftw_dir (dirs, newlev, descriptors, dir,
112 namlen + len + 1, func);
113 if (dirs[newlev] != NULL)
115 int save;
117 save = errno;
118 closedir (dirs[newlev]);
119 __set_errno (save);
120 dirs[newlev] = NULL;
124 if (retval != 0)
125 return retval;
127 if (dirs[level] == NULL)
129 int skip;
131 dir[len] = '\0';
132 dirs[level] = opendir (dir);
133 if (dirs[level] == NULL)
134 return -1;
135 skip = got;
136 while (skip-- != 0)
138 __set_errno (0);
139 if (__readdir_r (dirs[level], &dirbuf, &entry) < 0)
140 return errno == 0 ? 0 : -1;
144 __set_errno (0);
147 return errno == 0 ? 0 : -1;
150 /* Call a function on every element in a directory tree. */
153 ftw (const char *dir,
154 int (*func) (const char *file, struct stat *status, int flag),
155 int descriptors)
157 DIR **dirs;
158 size_t len;
159 char buf[PATH_MAX + 1];
160 struct stat s;
161 int flag, retval;
162 int i;
164 if (descriptors <= 0)
165 descriptors = 1;
167 dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
168 i = descriptors;
169 while (i-- > 0)
170 dirs[i] = NULL;
172 if (stat (dir, &s) < 0)
174 if (errno != EACCES && errno != ENOENT)
175 return -1;
176 flag = FTW_NS;
178 else if (S_ISDIR (s.st_mode))
180 dirs[0] = opendir (dir);
181 if (dirs[0] != NULL)
182 flag = FTW_D;
183 else
185 if (errno != EACCES)
186 return -1;
187 flag = FTW_DNR;
190 else
191 flag = FTW_F;
193 len = strlen (dir);
194 memcpy ((void *) buf, (void *) dir, len + 1);
196 retval = (*func) (buf, &s, flag);
198 if (flag == FTW_D)
200 if (retval == 0)
201 retval = ftw_dir (dirs, 0, descriptors, buf, len, func);
202 if (dirs[0] != NULL)
204 int save;
206 save = errno;
207 closedir (dirs[0]);
208 __set_errno (save);
212 return retval;