This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / gnu / libexec / uucp / libunix / ftw.c
CommitLineData
78ed81a3 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., 675 Mass Ave,
18Cambridge, MA 02139, USA.
19
20Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */
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;
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 ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
238 if (dirs[0] != NULL)
239 {
240 int save;
241
242 save = errno;
243 closedir (dirs[0]);
244 errno = save;
245 }
246 }
247
248 free ((pointer) dirs);
249 return ret;
250}