fts.c revision 1.26
1/*	$NetBSD: fts.c,v 1.26 2005/10/22 20:55:13 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1990, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#if HAVE_NBTOOL_CONFIG_H
33#include "nbtool_config.h"
34#endif
35
36#include <sys/cdefs.h>
37#if defined(LIBC_SCCS) && !defined(lint)
38#if 0
39static char sccsid[] = "@(#)fts.c	8.6 (Berkeley) 8/14/94";
40#else
41__RCSID("$NetBSD: fts.c,v 1.26 2005/10/22 20:55:13 christos Exp $");
42#endif
43#endif /* LIBC_SCCS and not lint */
44
45#include "namespace.h"
46#include <sys/param.h>
47#include <sys/stat.h>
48
49#include <assert.h>
50#include <dirent.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <fts.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#if ! HAVE_NBTOOL_CONFIG_H
59#define HAVE_STRUCT_DIRENT_D_NAMLEN 1
60#endif
61
62static FTSENT	*fts_alloc __P((FTS *, const char *, size_t));
63static FTSENT	*fts_build __P((FTS *, int));
64static void	 fts_lfree __P((FTSENT *));
65static void	 fts_load __P((FTS *, FTSENT *));
66static size_t	 fts_maxarglen __P((char * const *));
67static size_t	 fts_pow2 __P((size_t));
68static int	 fts_palloc __P((FTS *, size_t));
69static void	 fts_padjust __P((FTS *, FTSENT *));
70static FTSENT	*fts_sort __P((FTS *, FTSENT *, size_t));
71static u_short	 fts_stat __P((FTS *, FTSENT *, int));
72static int	 fts_safe_changedir __P((const FTS *, const FTSENT *, int,
73    const char *));
74
75#define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
76
77#define	CLR(opt)	(sp->fts_options &= ~(opt))
78#define	ISSET(opt)	(sp->fts_options & (opt))
79#define	SET(opt)	(sp->fts_options |= (opt))
80
81#define	CHDIR(sp, path)	(!ISSET(FTS_NOCHDIR) && chdir(path))
82#define	FCHDIR(sp, fd)	(!ISSET(FTS_NOCHDIR) && fchdir(fd))
83
84/* fts_build flags */
85#define	BCHILD		1		/* fts_children */
86#define	BNAMES		2		/* fts_children, names only */
87#define	BREAD		3		/* fts_read */
88
89#ifndef DTF_HIDEW
90#undef FTS_WHITEOUT
91#endif
92
93FTS *
94fts_open(argv, options, compar)
95	char * const *argv;
96	int options;
97	int (*compar) __P((const FTSENT **, const FTSENT **));
98{
99	FTS *sp;
100	FTSENT *p, *root;
101	size_t nitems;
102	FTSENT *parent, *tmp = NULL;	/* pacify gcc */
103	size_t len;
104
105	_DIAGASSERT(argv != NULL);
106
107	/* Options check. */
108	if (options & ~FTS_OPTIONMASK) {
109		errno = EINVAL;
110		return (NULL);
111	}
112
113	/* Allocate/initialize the stream */
114	if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
115		return (NULL);
116	memset(sp, 0, sizeof(FTS));
117	sp->fts_compar = compar;
118	sp->fts_options = options;
119
120	/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
121	if (ISSET(FTS_LOGICAL))
122		SET(FTS_NOCHDIR);
123
124	/*
125	 * Start out with 1K of path space, and enough, in any case,
126	 * to hold the user's paths.
127	 */
128	if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
129		goto mem1;
130
131	/* Allocate/initialize root's parent. */
132	if ((parent = fts_alloc(sp, "", 0)) == NULL)
133		goto mem2;
134	parent->fts_level = FTS_ROOTPARENTLEVEL;
135
136	/* Allocate/initialize root(s). */
137	for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
138		/* Don't allow zero-length paths. */
139		if ((len = strlen(*argv)) == 0) {
140			errno = ENOENT;
141			goto mem3;
142		}
143
144		if ((p = fts_alloc(sp, *argv, len)) == NULL)
145			goto mem3;
146		p->fts_level = FTS_ROOTLEVEL;
147		p->fts_parent = parent;
148		p->fts_accpath = p->fts_name;
149		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
150
151		/* Command-line "." and ".." are real directories. */
152		if (p->fts_info == FTS_DOT)
153			p->fts_info = FTS_D;
154
155		/*
156		 * If comparison routine supplied, traverse in sorted
157		 * order; otherwise traverse in the order specified.
158		 */
159		if (compar) {
160			p->fts_link = root;
161			root = p;
162		} else {
163			p->fts_link = NULL;
164			if (root == NULL)
165				tmp = root = p;
166			else {
167				tmp->fts_link = p;
168				tmp = p;
169			}
170		}
171	}
172	if (compar && nitems > 1)
173		root = fts_sort(sp, root, nitems);
174
175	/*
176	 * Allocate a dummy pointer and make fts_read think that we've just
177	 * finished the node before the root(s); set p->fts_info to FTS_INIT
178	 * so that everything about the "current" node is ignored.
179	 */
180	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
181		goto mem3;
182	sp->fts_cur->fts_link = root;
183	sp->fts_cur->fts_info = FTS_INIT;
184
185	/*
186	 * If using chdir(2), grab a file descriptor pointing to dot to insure
187	 * that we can get back here; this could be avoided for some paths,
188	 * but almost certainly not worth the effort.  Slashes, symbolic links,
189	 * and ".." are all fairly nasty problems.  Note, if we can't get the
190	 * descriptor we run anyway, just more slowly.
191	 */
192	if (!ISSET(FTS_NOCHDIR)) {
193		if ((sp->fts_rfd = open(".", O_RDONLY, 0)) == -1)
194			SET(FTS_NOCHDIR);
195		else if (fcntl(sp->fts_rfd, F_SETFD, FD_CLOEXEC) == -1) {
196			close(sp->fts_rfd);
197			SET(FTS_NOCHDIR);
198		}
199	}
200
201	return (sp);
202
203mem3:	fts_lfree(root);
204	free(parent);
205mem2:	free(sp->fts_path);
206mem1:	free(sp);
207	return (NULL);
208}
209
210static void
211fts_load(sp, p)
212	FTS *sp;
213	FTSENT *p;
214{
215	size_t len;
216	char *cp;
217
218	_DIAGASSERT(sp != NULL);
219	_DIAGASSERT(p != NULL);
220
221	/*
222	 * Load the stream structure for the next traversal.  Since we don't
223	 * actually enter the directory until after the preorder visit, set
224	 * the fts_accpath field specially so the chdir gets done to the right
225	 * place and the user can access the first node.  From fts_open it's
226	 * known that the path will fit.
227	 */
228	len = p->fts_pathlen = p->fts_namelen;
229	memmove(sp->fts_path, p->fts_name, len + 1);
230	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
231		len = strlen(++cp);
232		memmove(p->fts_name, cp, len + 1);
233		p->fts_namelen = len;
234	}
235	p->fts_accpath = p->fts_path = sp->fts_path;
236	sp->fts_dev = p->fts_dev;
237}
238
239int
240fts_close(sp)
241	FTS *sp;
242{
243	FTSENT *freep, *p;
244	int saved_errno = 0;
245
246	_DIAGASSERT(sp != NULL);
247
248	/*
249	 * This still works if we haven't read anything -- the dummy structure
250	 * points to the root list, so we step through to the end of the root
251	 * list which has a valid parent pointer.
252	 */
253	if (sp->fts_cur) {
254		if (ISSET(FTS_SYMFOLLOW))
255			(void)close(sp->fts_cur->fts_symfd);
256		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
257			freep = p;
258			p = p->fts_link ? p->fts_link : p->fts_parent;
259			free(freep);
260		}
261		free(p);
262	}
263
264	/* Free up child linked list, sort array, path buffer. */
265	if (sp->fts_child)
266		fts_lfree(sp->fts_child);
267	if (sp->fts_array)
268		free(sp->fts_array);
269	free(sp->fts_path);
270
271	/* Return to original directory, save errno if necessary. */
272	if (!ISSET(FTS_NOCHDIR)) {
273		if (fchdir(sp->fts_rfd))
274			saved_errno = errno;
275		(void)close(sp->fts_rfd);
276	}
277
278	/* Free up the stream pointer. */
279	free(sp);
280	/* ISSET() is illegal after this, since the macro touches sp */
281
282	/* Set errno and return. */
283	if (saved_errno) {
284		errno = saved_errno;
285		return (-1);
286	}
287	return (0);
288}
289
290/*
291 * Special case of "/" at the end of the path so that slashes aren't
292 * appended which would cause paths to be written as "....//foo".
293 */
294#define	NAPPEND(p)							\
295	(p->fts_path[p->fts_pathlen - 1] == '/'				\
296	    ? p->fts_pathlen - 1 : p->fts_pathlen)
297
298FTSENT *
299fts_read(sp)
300	FTS *sp;
301{
302	FTSENT *p, *tmp;
303	int instr;
304	char *t;
305	int saved_errno;
306
307	_DIAGASSERT(sp != NULL);
308
309	/* If finished or unrecoverable error, return NULL. */
310	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
311		return (NULL);
312
313	/* Set current node pointer. */
314	p = sp->fts_cur;
315
316	/* Save and zero out user instructions. */
317	instr = p->fts_instr;
318	p->fts_instr = FTS_NOINSTR;
319
320	/* Any type of file may be re-visited; re-stat and re-turn. */
321	if (instr == FTS_AGAIN) {
322		p->fts_info = fts_stat(sp, p, 0);
323		return (p);
324	}
325
326	/*
327	 * Following a symlink -- SLNONE test allows application to see
328	 * SLNONE and recover.  If indirecting through a symlink, have
329	 * keep a pointer to current location.  If unable to get that
330	 * pointer, follow fails.
331	 */
332	if (instr == FTS_FOLLOW &&
333	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
334		p->fts_info = fts_stat(sp, p, 1);
335		if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
336			if ((p->fts_symfd = open(".", O_RDONLY, 0)) == -1) {
337				p->fts_errno = errno;
338				p->fts_info = FTS_ERR;
339			} else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
340				p->fts_errno = errno;
341				p->fts_info = FTS_ERR;
342				close(p->fts_symfd);
343			} else
344				p->fts_flags |= FTS_SYMFOLLOW;
345		}
346		return (p);
347	}
348
349	/* Directory in pre-order. */
350	if (p->fts_info == FTS_D) {
351		/* If skipped or crossed mount point, do post-order visit. */
352		if (instr == FTS_SKIP ||
353		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
354			if (p->fts_flags & FTS_SYMFOLLOW)
355				(void)close(p->fts_symfd);
356			if (sp->fts_child) {
357				fts_lfree(sp->fts_child);
358				sp->fts_child = NULL;
359			}
360			p->fts_info = FTS_DP;
361			return (p);
362		}
363
364		/* Rebuild if only read the names and now traversing. */
365		if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
366			CLR(FTS_NAMEONLY);
367			fts_lfree(sp->fts_child);
368			sp->fts_child = NULL;
369		}
370
371		/*
372		 * Cd to the subdirectory.
373		 *
374		 * If have already read and now fail to chdir, whack the list
375		 * to make the names come out right, and set the parent errno
376		 * so the application will eventually get an error condition.
377		 * Set the FTS_DONTCHDIR flag so that when we logically change
378		 * directories back to the parent we don't do a chdir.
379		 *
380		 * If haven't read do so.  If the read fails, fts_build sets
381		 * FTS_STOP or the fts_info field of the node.
382		 */
383		if (sp->fts_child) {
384			if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
385				p->fts_errno = errno;
386				p->fts_flags |= FTS_DONTCHDIR;
387				for (p = sp->fts_child; p; p = p->fts_link)
388					p->fts_accpath =
389					    p->fts_parent->fts_accpath;
390			}
391		} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
392			if (ISSET(FTS_STOP))
393				return (NULL);
394			return (p);
395		}
396		p = sp->fts_child;
397		sp->fts_child = NULL;
398		goto name;
399	}
400
401	/* Move to the next node on this level. */
402next:	tmp = p;
403	if ((p = p->fts_link) != NULL) {
404		free(tmp);
405
406		/*
407		 * If reached the top, return to the original directory, and
408		 * load the paths for the next root.
409		 */
410		if (p->fts_level == FTS_ROOTLEVEL) {
411			if (FCHDIR(sp, sp->fts_rfd)) {
412				SET(FTS_STOP);
413				return (NULL);
414			}
415			fts_load(sp, p);
416			return (sp->fts_cur = p);
417		}
418
419		/*
420		 * User may have called fts_set on the node.  If skipped,
421		 * ignore.  If followed, get a file descriptor so we can
422		 * get back if necessary.
423		 */
424		if (p->fts_instr == FTS_SKIP)
425			goto next;
426		if (p->fts_instr == FTS_FOLLOW) {
427			p->fts_info = fts_stat(sp, p, 1);
428			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
429				if ((p->fts_symfd =
430				    open(".", O_RDONLY, 0)) == -1) {
431					p->fts_errno = errno;
432					p->fts_info = FTS_ERR;
433				} else if (fcntl(p->fts_symfd, F_SETFD, FD_CLOEXEC) == -1) {
434					p->fts_errno = errno;
435					p->fts_info = FTS_ERR;
436					close(p->fts_symfd);
437				} else
438					p->fts_flags |= FTS_SYMFOLLOW;
439			}
440			p->fts_instr = FTS_NOINSTR;
441		}
442
443name:		t = sp->fts_path + NAPPEND(p->fts_parent);
444		*t++ = '/';
445		memmove(t, p->fts_name, (size_t)(p->fts_namelen + 1));
446		return (sp->fts_cur = p);
447	}
448
449	/* Move up to the parent node. */
450	p = tmp->fts_parent;
451	free(tmp);
452
453	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
454		/*
455		 * Done; free everything up and set errno to 0 so the user
456		 * can distinguish between error and EOF.
457		 */
458		free(p);
459		errno = 0;
460		return (sp->fts_cur = NULL);
461	}
462
463	/* Nul terminate the pathname. */
464	sp->fts_path[p->fts_pathlen] = '\0';
465
466	/*
467	 * Return to the parent directory.  If at a root node or came through
468	 * a symlink, go back through the file descriptor.  Otherwise, cd up
469	 * one directory.
470	 */
471	if (p->fts_level == FTS_ROOTLEVEL) {
472		if (FCHDIR(sp, sp->fts_rfd)) {
473			SET(FTS_STOP);
474			return (NULL);
475		}
476	} else if (p->fts_flags & FTS_SYMFOLLOW) {
477		if (FCHDIR(sp, p->fts_symfd)) {
478			saved_errno = errno;
479			(void)close(p->fts_symfd);
480			errno = saved_errno;
481			SET(FTS_STOP);
482			return (NULL);
483		}
484		(void)close(p->fts_symfd);
485	} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
486	    fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
487		SET(FTS_STOP);
488		return (NULL);
489	}
490	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
491	return (sp->fts_cur = p);
492}
493
494/*
495 * Fts_set takes the stream as an argument although it's not used in this
496 * implementation; it would be necessary if anyone wanted to add global
497 * semantics to fts using fts_set.  An error return is allowed for similar
498 * reasons.
499 */
500/* ARGSUSED */
501int
502fts_set(sp, p, instr)
503	FTS *sp;
504	FTSENT *p;
505	int instr;
506{
507
508	_DIAGASSERT(sp != NULL);
509	_DIAGASSERT(p != NULL);
510
511	if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
512	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
513		errno = EINVAL;
514		return (1);
515	}
516	p->fts_instr = instr;
517	return (0);
518}
519
520FTSENT *
521fts_children(sp, instr)
522	FTS *sp;
523	int instr;
524{
525	FTSENT *p;
526	int fd;
527
528	_DIAGASSERT(sp != NULL);
529
530	if (instr && instr != FTS_NAMEONLY) {
531		errno = EINVAL;
532		return (NULL);
533	}
534
535	/* Set current node pointer. */
536	p = sp->fts_cur;
537
538	/*
539	 * Errno set to 0 so user can distinguish empty directory from
540	 * an error.
541	 */
542	errno = 0;
543
544	/* Fatal errors stop here. */
545	if (ISSET(FTS_STOP))
546		return (NULL);
547
548	/* Return logical hierarchy of user's arguments. */
549	if (p->fts_info == FTS_INIT)
550		return (p->fts_link);
551
552	/*
553	 * If not a directory being visited in pre-order, stop here.  Could
554	 * allow FTS_DNR, assuming the user has fixed the problem, but the
555	 * same effect is available with FTS_AGAIN.
556	 */
557	if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
558		return (NULL);
559
560	/* Free up any previous child list. */
561	if (sp->fts_child)
562		fts_lfree(sp->fts_child);
563
564	if (instr == FTS_NAMEONLY) {
565		SET(FTS_NAMEONLY);
566		instr = BNAMES;
567	} else
568		instr = BCHILD;
569
570	/*
571	 * If using chdir on a relative path and called BEFORE fts_read does
572	 * its chdir to the root of a traversal, we can lose -- we need to
573	 * chdir into the subdirectory, and we don't know where the current
574	 * directory is, so we can't get back so that the upcoming chdir by
575	 * fts_read will work.
576	 */
577	if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
578	    ISSET(FTS_NOCHDIR))
579		return (sp->fts_child = fts_build(sp, instr));
580
581	if ((fd = open(".", O_RDONLY, 0)) == -1)
582		return (sp->fts_child = NULL);
583	sp->fts_child = fts_build(sp, instr);
584	if (fchdir(fd)) {
585		(void)close(fd);
586		return (NULL);
587	}
588	(void)close(fd);
589	return (sp->fts_child);
590}
591
592/*
593 * This is the tricky part -- do not casually change *anything* in here.  The
594 * idea is to build the linked list of entries that are used by fts_children
595 * and fts_read.  There are lots of special cases.
596 *
597 * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
598 * set and it's a physical walk (so that symbolic links can't be directories),
599 * we can do things quickly.  First, if it's a 4.4BSD file system, the type
600 * of the file is in the directory entry.  Otherwise, we assume that the number
601 * of subdirectories in a node is equal to the number of links to the parent.
602 * The former skips all stat calls.  The latter skips stat calls in any leaf
603 * directories and for any files after the subdirectories in the directory have
604 * been found, cutting the stat calls by about 2/3.
605 */
606static FTSENT *
607fts_build(sp, type)
608	FTS *sp;
609	int type;
610{
611	struct dirent *dp;
612	FTSENT *p, *head;
613	size_t nitems;
614	FTSENT *cur, *tail;
615	DIR *dirp;
616	int adjust, cderrno, descend, len, level, nlinks, saved_errno, nostat;
617	size_t maxlen;
618#ifdef FTS_WHITEOUT
619	int oflag;
620#endif
621	char *cp = NULL;	/* pacify gcc */
622
623	_DIAGASSERT(sp != NULL);
624
625	/* Set current node pointer. */
626	cur = sp->fts_cur;
627
628	/*
629	 * Open the directory for reading.  If this fails, we're done.
630	 * If being called from fts_read, set the fts_info field.
631	 */
632#ifdef FTS_WHITEOUT
633	if (ISSET(FTS_WHITEOUT))
634		oflag = DTF_NODUP|DTF_REWIND;
635	else
636		oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
637#else
638#define __opendir2(path, flag) opendir(path)
639#endif
640	if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
641		if (type == BREAD) {
642			cur->fts_info = FTS_DNR;
643			cur->fts_errno = errno;
644		}
645		return (NULL);
646	}
647
648	/*
649	 * Nlinks is the number of possible entries of type directory in the
650	 * directory if we're cheating on stat calls, 0 if we're not doing
651	 * any stat calls at all, -1 if we're doing stats on everything.
652	 */
653	if (type == BNAMES) {
654		nlinks = 0;
655		nostat = 1;
656	} else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
657		nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
658		nostat = 1;
659	} else {
660		nlinks = -1;
661		nostat = 0;
662	}
663
664#ifdef notdef
665	(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
666	(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
667	    ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
668#endif
669	/*
670	 * If we're going to need to stat anything or we want to descend
671	 * and stay in the directory, chdir.  If this fails we keep going,
672	 * but set a flag so we don't chdir after the post-order visit.
673	 * We won't be able to stat anything, but we can still return the
674	 * names themselves.  Note, that since fts_read won't be able to
675	 * chdir into the directory, it will have to return different path
676	 * names than before, i.e. "a/b" instead of "b".  Since the node
677	 * has already been visited in pre-order, have to wait until the
678	 * post-order visit to return the error.  There is a special case
679	 * here, if there was nothing to stat then it's not an error to
680	 * not be able to stat.  This is all fairly nasty.  If a program
681	 * needed sorted entries or stat information, they had better be
682	 * checking FTS_NS on the returned nodes.
683	 */
684	cderrno = 0;
685	if (nlinks || type == BREAD) {
686		if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
687			if (nlinks && type == BREAD)
688				cur->fts_errno = errno;
689			cur->fts_flags |= FTS_DONTCHDIR;
690			descend = 0;
691			cderrno = errno;
692		} else
693			descend = 1;
694	} else
695		descend = 0;
696
697	/*
698	 * Figure out the max file name length that can be stored in the
699	 * current path -- the inner loop allocates more path as necessary.
700	 * We really wouldn't have to do the maxlen calculations here, we
701	 * could do them in fts_read before returning the path, but it's a
702	 * lot easier here since the length is part of the dirent structure.
703	 *
704	 * If not changing directories set a pointer so that can just append
705	 * each new name into the path.
706	 */
707	len = NAPPEND(cur);
708	if (ISSET(FTS_NOCHDIR)) {
709		cp = sp->fts_path + len;
710		*cp++ = '/';
711	}
712	len++;
713	maxlen = sp->fts_pathlen - len;
714
715	level = cur->fts_level + 1;
716
717	/* Read the directory, attaching each entry to the `link' pointer. */
718	adjust = 0;
719	for (head = tail = NULL, nitems = 0; (dp = readdir(dirp)) != NULL;) {
720		size_t dlen;
721
722		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
723			continue;
724
725#if HAVE_STRUCT_DIRENT_D_NAMLEN
726		dlen = dp->d_namlen;
727#else
728		dlen = strlen(dp->d_name);
729#endif
730		if ((p = fts_alloc(sp, dp->d_name, dlen)) == NULL)
731			goto mem1;
732		if (dlen >= maxlen) {	/* include space for NUL */
733			if (fts_palloc(sp, len + dlen + 1)) {
734				/*
735				 * No more memory for path or structures.  Save
736				 * errno, free up the current structure and the
737				 * structures already allocated.
738				 */
739mem1:				saved_errno = errno;
740				if (p)
741					free(p);
742				fts_lfree(head);
743				(void)closedir(dirp);
744				errno = saved_errno;
745				cur->fts_info = FTS_ERR;
746				SET(FTS_STOP);
747				return (NULL);
748			}
749			adjust = 1;
750			if (ISSET(FTS_NOCHDIR))
751				cp = sp->fts_path + len;
752			maxlen = sp->fts_pathlen - len;
753		}
754
755		p->fts_pathlen = len + dlen;
756		p->fts_parent = sp->fts_cur;
757		p->fts_level = level;
758
759#ifdef FTS_WHITEOUT
760		if (dp->d_type == DT_WHT)
761			p->fts_flags |= FTS_ISW;
762#endif
763
764		if (cderrno) {
765			if (nlinks) {
766				p->fts_info = FTS_NS;
767				p->fts_errno = cderrno;
768			} else
769				p->fts_info = FTS_NSOK;
770			p->fts_accpath = cur->fts_accpath;
771		} else if (nlinks == 0
772#ifdef DT_DIR
773		    || (nostat &&
774		    dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
775#endif
776		    ) {
777			p->fts_accpath =
778			    ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
779			p->fts_info = FTS_NSOK;
780		} else {
781			/* Build a file name for fts_stat to stat. */
782			if (ISSET(FTS_NOCHDIR)) {
783				p->fts_accpath = p->fts_path;
784				memmove(cp, p->fts_name,
785				        (size_t)(p->fts_namelen + 1));
786			} else
787				p->fts_accpath = p->fts_name;
788			/* Stat it. */
789			p->fts_info = fts_stat(sp, p, 0);
790
791			/* Decrement link count if applicable. */
792			if (nlinks > 0 && (p->fts_info == FTS_D ||
793			    p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
794				--nlinks;
795		}
796
797		/* We walk in directory order so "ls -f" doesn't get upset. */
798		p->fts_link = NULL;
799		if (head == NULL)
800			head = tail = p;
801		else {
802			tail->fts_link = p;
803			tail = p;
804		}
805		++nitems;
806	}
807	(void)closedir(dirp);
808
809	/*
810	 * If had to realloc the path, adjust the addresses for the rest
811	 * of the tree.
812	 */
813	if (adjust)
814		fts_padjust(sp, head);
815
816	/*
817	 * If not changing directories, reset the path back to original
818	 * state.
819	 */
820	if (ISSET(FTS_NOCHDIR)) {
821		if (cp - 1 > sp->fts_path)
822			--cp;
823		*cp = '\0';
824	}
825
826	/*
827	 * If descended after called from fts_children or after called from
828	 * fts_read and nothing found, get back.  At the root level we use
829	 * the saved fd; if one of fts_open()'s arguments is a relative path
830	 * to an empty directory, we wind up here with no other way back.  If
831	 * can't get back, we're done.
832	 */
833	if (descend && (type == BCHILD || !nitems) &&
834	    (cur->fts_level == FTS_ROOTLEVEL ?
835	    FCHDIR(sp, sp->fts_rfd) :
836	    fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
837		cur->fts_info = FTS_ERR;
838		SET(FTS_STOP);
839		return (NULL);
840	}
841
842	/* If didn't find anything, return NULL. */
843	if (!nitems) {
844		if (type == BREAD)
845			cur->fts_info = FTS_DP;
846		return (NULL);
847	}
848
849	/* Sort the entries. */
850	if (sp->fts_compar && nitems > 1)
851		head = fts_sort(sp, head, nitems);
852	return (head);
853}
854
855static u_short
856fts_stat(sp, p, follow)
857	FTS *sp;
858	FTSENT *p;
859	int follow;
860{
861	FTSENT *t;
862	dev_t dev;
863	__fts_ino_t ino;
864	__fts_stat_t *sbp, sb;
865	int saved_errno;
866
867	_DIAGASSERT(sp != NULL);
868	_DIAGASSERT(p != NULL);
869
870	/* If user needs stat info, stat buffer already allocated. */
871	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
872
873#ifdef FTS_WHITEOUT
874	/* check for whiteout */
875	if (p->fts_flags & FTS_ISW) {
876		if (sbp != &sb) {
877			memset(sbp, '\0', sizeof (*sbp));
878			sbp->st_mode = S_IFWHT;
879		}
880		return (FTS_W);
881	}
882#endif
883
884	/*
885	 * If doing a logical walk, or application requested FTS_FOLLOW, do
886	 * a stat(2).  If that fails, check for a non-existent symlink.  If
887	 * fail, set the errno from the stat call.
888	 */
889	if (ISSET(FTS_LOGICAL) || follow) {
890		if (stat(p->fts_accpath, sbp)) {
891			saved_errno = errno;
892			if (!lstat(p->fts_accpath, sbp)) {
893				errno = 0;
894				return (FTS_SLNONE);
895			}
896			p->fts_errno = saved_errno;
897			goto err;
898		}
899	} else if (lstat(p->fts_accpath, sbp)) {
900		p->fts_errno = errno;
901err:		memset(sbp, 0, sizeof(*sbp));
902		return (FTS_NS);
903	}
904
905	if (S_ISDIR(sbp->st_mode)) {
906		/*
907		 * Set the device/inode.  Used to find cycles and check for
908		 * crossing mount points.  Also remember the link count, used
909		 * in fts_build to limit the number of stat calls.  It is
910		 * understood that these fields are only referenced if fts_info
911		 * is set to FTS_D.
912		 */
913		dev = p->fts_dev = sbp->st_dev;
914		ino = p->fts_ino = sbp->st_ino;
915		p->fts_nlink = sbp->st_nlink;
916
917		if (ISDOT(p->fts_name))
918			return (FTS_DOT);
919
920		/*
921		 * Cycle detection is done by brute force when the directory
922		 * is first encountered.  If the tree gets deep enough or the
923		 * number of symbolic links to directories is high enough,
924		 * something faster might be worthwhile.
925		 */
926		for (t = p->fts_parent;
927		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
928			if (ino == t->fts_ino && dev == t->fts_dev) {
929				p->fts_cycle = t;
930				return (FTS_DC);
931			}
932		return (FTS_D);
933	}
934	if (S_ISLNK(sbp->st_mode))
935		return (FTS_SL);
936	if (S_ISREG(sbp->st_mode))
937		return (FTS_F);
938	return (FTS_DEFAULT);
939}
940
941static FTSENT *
942fts_sort(sp, head, nitems)
943	FTS *sp;
944	FTSENT *head;
945	size_t nitems;
946{
947	FTSENT **ap, *p;
948
949	_DIAGASSERT(sp != NULL);
950	_DIAGASSERT(head != NULL);
951
952	/*
953	 * Construct an array of pointers to the structures and call qsort(3).
954	 * Reassemble the array in the order returned by qsort.  If unable to
955	 * sort for memory reasons, return the directory entries in their
956	 * current order.  Allocate enough space for the current needs plus
957	 * 40 so don't realloc one entry at a time.
958	 */
959	if (nitems > sp->fts_nitems) {
960		FTSENT **new;
961
962		new = realloc(sp->fts_array, sizeof(FTSENT *) * (nitems + 40));
963		if (new == 0)
964			return (head);
965		sp->fts_array = new;
966		sp->fts_nitems = nitems + 40;
967	}
968	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
969		*ap++ = p;
970	qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *),
971		(int (*) __P((const void *, const void *)))sp->fts_compar);
972	for (head = *(ap = sp->fts_array); --nitems; ++ap)
973		ap[0]->fts_link = ap[1];
974	ap[0]->fts_link = NULL;
975	return (head);
976}
977
978static FTSENT *
979fts_alloc(sp, name, namelen)
980	FTS *sp;
981	const char *name;
982	size_t namelen;
983{
984	FTSENT *p;
985	size_t len;
986
987	_DIAGASSERT(sp != NULL);
988	_DIAGASSERT(name != NULL);
989
990#if defined(ALIGNBYTES) && defined(ALIGN)
991	/*
992	 * The file name is a variable length array and no stat structure is
993	 * necessary if the user has set the nostat bit.  Allocate the FTSENT
994	 * structure, the file name and the stat structure in one chunk, but
995	 * be careful that the stat structure is reasonably aligned.  Since the
996	 * fts_name field is declared to be of size 1, the fts_name pointer is
997	 * namelen + 2 before the first possible address of the stat structure.
998	 */
999	len = sizeof(FTSENT) + namelen;
1000	if (!ISSET(FTS_NOSTAT))
1001		len += sizeof(*(p->fts_statp)) + ALIGNBYTES;
1002	if ((p = malloc(len)) == NULL)
1003		return (NULL);
1004
1005	if (!ISSET(FTS_NOSTAT))
1006		p->fts_statp =
1007		    (__fts_stat_t *)ALIGN((u_long)(p->fts_name + namelen + 2));
1008#else
1009	if ((p = malloc(sizeof(FTSENT) + namelen)) == NULL)
1010		return (NULL);
1011
1012	if (!ISSET(FTS_NOSTAT))
1013		if ((p->fts_statp = malloc(sizeof(*(p->fts_statp)))) == NULL) {
1014			free(p);
1015			return (NULL);
1016		}
1017#endif
1018
1019	/* Copy the name plus the trailing NULL. */
1020	memmove(p->fts_name, name, namelen + 1);
1021
1022	p->fts_namelen = namelen;
1023	p->fts_path = sp->fts_path;
1024	p->fts_errno = 0;
1025	p->fts_flags = 0;
1026	p->fts_instr = FTS_NOINSTR;
1027	p->fts_number = 0;
1028	p->fts_pointer = NULL;
1029	return (p);
1030}
1031
1032static void
1033fts_lfree(head)
1034	FTSENT *head;
1035{
1036	FTSENT *p;
1037
1038	/* XXX: head may be NULL ? */
1039
1040	/* Free a linked list of structures. */
1041	while ((p = head) != NULL) {
1042		head = head->fts_link;
1043
1044#if !defined(ALIGNBYTES) || !defined(ALIGN)
1045		if (p->fts_statp)
1046			free(p->fts_statp);
1047#endif
1048		free(p);
1049	}
1050}
1051
1052static size_t
1053fts_pow2(x)
1054	size_t x;
1055{
1056
1057	x--;
1058	x |= x>>1;
1059	x |= x>>2;
1060	x |= x>>4;
1061	x |= x>>8;
1062	x |= x>>16;
1063#if LONG_BIT > 32
1064	x |= x>>32;
1065#endif
1066#if LONG_BIT > 64
1067	x |= x>>64;
1068#endif
1069	x++;
1070	return (x);
1071}
1072
1073/*
1074 * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
1075 * Most systems will allow creation of paths much longer than MAXPATHLEN, even
1076 * though the kernel won't resolve them.  Round up the new size to a power of 2,
1077 * so we don't realloc the path 2 bytes at a time.
1078 */
1079static int
1080fts_palloc(sp, size)
1081	FTS *sp;
1082	size_t size;
1083{
1084	char *new;
1085
1086	_DIAGASSERT(sp != NULL);
1087
1088#if 1
1089	/* Protect against fts_pathlen overflow. */
1090	if (size > USHRT_MAX + 1) {
1091		errno = ENOMEM;
1092		return (1);
1093	}
1094#endif
1095	size = fts_pow2(size);
1096	new = realloc(sp->fts_path, size);
1097	if (new == 0)
1098		return (1);
1099	sp->fts_path = new;
1100	sp->fts_pathlen = size;
1101	return (0);
1102}
1103
1104/*
1105 * When the path is realloc'd, have to fix all of the pointers in structures
1106 * already returned.
1107 */
1108static void
1109fts_padjust(sp, head)
1110	FTS *sp;
1111	FTSENT *head;
1112{
1113	FTSENT *p;
1114	char *addr;
1115
1116	_DIAGASSERT(sp != NULL);
1117
1118#define	ADJUST(p) do {							\
1119	if ((p)->fts_accpath != (p)->fts_name)				\
1120		(p)->fts_accpath =					\
1121		    addr + ((p)->fts_accpath - (p)->fts_path);		\
1122	(p)->fts_path = addr;						\
1123} while (/*CONSTCOND*/0)
1124
1125	addr = sp->fts_path;
1126
1127	/* Adjust the current set of children. */
1128	for (p = sp->fts_child; p; p = p->fts_link)
1129		ADJUST(p);
1130
1131	/* Adjust the rest of the tree, including the current level. */
1132	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1133		ADJUST(p);
1134		p = p->fts_link ? p->fts_link : p->fts_parent;
1135	}
1136}
1137
1138static size_t
1139fts_maxarglen(argv)
1140	char * const *argv;
1141{
1142	size_t len, max;
1143
1144	_DIAGASSERT(argv != NULL);
1145
1146	for (max = 0; *argv; ++argv)
1147		if ((len = strlen(*argv)) > max)
1148			max = len;
1149	return (max + 1);
1150}
1151
1152/*
1153 * Change to dir specified by fd or p->fts_accpath without getting
1154 * tricked by someone changing the world out from underneath us.
1155 * Assumes p->fts_dev and p->fts_ino are filled in.
1156 */
1157static int
1158fts_safe_changedir(sp, p, fd, path)
1159	const FTS *sp;
1160	const FTSENT *p;
1161	int fd;
1162	const char *path;
1163{
1164	int oldfd = fd, ret = -1;
1165	__fts_stat_t sb;
1166
1167	if (ISSET(FTS_NOCHDIR))
1168		return 0;
1169
1170	if (oldfd < 0 && (fd = open(path, O_RDONLY)) == -1)
1171		return -1;
1172
1173	if (fstat(fd, &sb) == -1)
1174		goto bail;
1175
1176	if (sb.st_ino != p->fts_ino || sb.st_dev != p->fts_dev) {
1177		errno = ENOENT;
1178		goto bail;
1179	}
1180
1181	ret = fchdir(fd);
1182
1183bail:
1184	if (oldfd < 0) {
1185		int save_errno = errno;
1186		(void)close(fd);
1187		errno = save_errno;
1188	}
1189	return ret;
1190}
1191