12818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes/*	$OpenBSD: fts.c,v 1.48 2014/11/20 04:14:15 guenther Exp $	*/
264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*-
464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Copyright (c) 1990, 1993, 1994
564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *	The Regents of the University of California.  All rights reserved.
664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *
764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Redistribution and use in source and binary forms, with or without
864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * modification, are permitted provided that the following conditions
964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * are met:
1064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 1. Redistributions of source code must retain the above copyright
1164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *    notice, this list of conditions and the following disclaimer.
1264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 2. Redistributions in binary form must reproduce the above copyright
1364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *    notice, this list of conditions and the following disclaimer in the
1464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *    documentation and/or other materials provided with the distribution.
1564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * 3. Neither the name of the University nor the names of its contributors
1664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *    may be used to endorse or promote products derived from this software
1764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *    without specific prior written permission.
1864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *
1964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * SUCH DAMAGE.
3064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
3164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
3264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <sys/param.h>
3364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <sys/stat.h>
3464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
35705910094d07ddfc5a3b7a4baab58b0a94bcc691George Burgess IV#include <assert.h>
3664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <dirent.h>
3764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <errno.h>
3864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <fcntl.h>
3964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <fts.h>
40ec67cded1d2969b5ba21028f0dd1560827947f3dElliott Hughes#include <limits.h>
4164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <stdlib.h>
4264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <string.h>
4364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#include <unistd.h>
4464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
4564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT	*fts_alloc(FTS *, char *, size_t);
4664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT	*fts_build(FTS *, int);
4764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void	 fts_lfree(FTSENT *);
4864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void	 fts_load(FTS *, FTSENT *);
4964ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic size_t	 fts_maxarglen(char * const *);
5064ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void	 fts_padjust(FTS *, FTSENT *);
5164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int	 fts_palloc(FTS *, size_t);
5264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT	*fts_sort(FTS *, FTSENT *, int);
532818279ace22fb854b00e668c224492c4dd072a4Elliott Hughesstatic u_short	 fts_stat(FTS *, FTSENT *, int, int);
5464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int	 fts_safe_changedir(FTS *, FTSENT *, int, char *);
5564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
56c20de902875dcaebde0ccd0b7a8351598f254d4cCalin Juravle#define ALIGNBYTES (sizeof(uintptr_t) - 1)
57c20de902875dcaebde0ccd0b7a8351598f254d4cCalin Juravle#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
582818279ace22fb854b00e668c224492c4dd072a4Elliott Hughesvoid* reallocarray(void*, size_t, size_t);
59c20de902875dcaebde0ccd0b7a8351598f254d4cCalin Juravle
6064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
6164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
6264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	CLR(opt)	(sp->fts_options &= ~(opt))
6364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	ISSET(opt)	(sp->fts_options & (opt))
6464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	SET(opt)	(sp->fts_options |= (opt))
6564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
6664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	FCHDIR(sp, fd)	(!ISSET(FTS_NOCHDIR) && fchdir(fd))
6764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
6864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* fts_build flags */
6964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	BCHILD		1		/* fts_children */
7064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	BNAMES		2		/* fts_children, names only */
7164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	BREAD		3		/* fts_read */
7264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
7364ceac3f493e3063a289aec4a12c74787be974e4Colin CrossFTS *
7464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_open(char * const *argv, int options,
7564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross    int (*compar)(const FTSENT **, const FTSENT **))
7664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
7764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTS *sp;
7864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p, *root;
7964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int nitems;
8064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *parent, *tmp;
8164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	size_t len;
8264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
8364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Options check. */
8464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (options & ~FTS_OPTIONMASK) {
8564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = EINVAL;
8664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
8764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
8864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
8964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Allocate/initialize the stream */
9064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((sp = calloc(1, sizeof(FTS))) == NULL)
9164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
9264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_compar = compar;
9364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_options = options;
9464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
9564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
9664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (ISSET(FTS_LOGICAL))
9764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		SET(FTS_NOCHDIR);
9864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
9964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
10064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Start out with 1K of path space, and enough, in any case,
10164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * to hold the user's paths.
10264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
103ec67cded1d2969b5ba21028f0dd1560827947f3dElliott Hughes	if (fts_palloc(sp, MAX(fts_maxarglen(argv), PATH_MAX)))
10464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		goto mem1;
10564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
10664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Allocate/initialize root's parent. */
10764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((parent = fts_alloc(sp, "", 0)) == NULL)
10864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		goto mem2;
10964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	parent->fts_level = FTS_ROOTPARENTLEVEL;
11064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
11164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Allocate/initialize root(s). */
11264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
11364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/* Don't allow zero-length paths. */
11464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if ((len = strlen(*argv)) == 0) {
11564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			errno = ENOENT;
11664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			goto mem3;
11764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
11864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
11964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if ((p = fts_alloc(sp, *argv, len)) == NULL)
12064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			goto mem3;
12164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_level = FTS_ROOTLEVEL;
12264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_parent = parent;
12364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_accpath = p->fts_name;
1242818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
12564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
12664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/* Command-line "." and ".." are real directories. */
12764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (p->fts_info == FTS_DOT)
12864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_info = FTS_D;
12964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
13064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
13164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * If comparison routine supplied, traverse in sorted
13264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * order; otherwise traverse in the order specified.
13364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
13464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (compar) {
13564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_link = root;
13664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			root = p;
13764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		} else {
13864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_link = NULL;
13964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (root == NULL)
14064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				tmp = root = p;
14164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			else {
14264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				tmp->fts_link = p;
14364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				tmp = p;
14464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
14564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
14664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
14764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (compar && nitems > 1)
14864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		root = fts_sort(sp, root, nitems);
14964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
15064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
15164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Allocate a dummy pointer and make fts_read think that we've just
15264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * finished the node before the root(s); set p->fts_info to FTS_INIT
15364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * so that everything about the "current" node is ignored.
15464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
15564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
15664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		goto mem3;
15764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_cur->fts_link = root;
15864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_cur->fts_info = FTS_INIT;
15964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
16064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
16164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If using chdir(2), grab a file descriptor pointing to dot to ensure
16264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * that we can get back here; this could be avoided for some paths,
16364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * but almost certainly not worth the effort.  Slashes, symbolic links,
16464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * and ".." are all fairly nasty problems.  Note, if we can't get the
16564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * descriptor we run anyway, just more slowly.
16664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
16764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
16864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		SET(FTS_NOCHDIR);
16964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
17064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (nitems == 0)
17164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		free(parent);
17264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
17364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (sp);
17464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
17564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem3:	fts_lfree(root);
17664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	free(parent);
17764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem2:	free(sp->fts_path);
17864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem1:	free(sp);
17964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (NULL);
18064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
18164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
18264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void
18364ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_load(FTS *sp, FTSENT *p)
18464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
18564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	size_t len;
18664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	char *cp;
18764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
18864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
18964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Load the stream structure for the next traversal.  Since we don't
19064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * actually enter the directory until after the preorder visit, set
19164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * the fts_accpath field specially so the chdir gets done to the right
19264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * place and the user can access the first node.  From fts_open it's
19364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * known that the path will fit.
19464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
19564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	len = p->fts_pathlen = p->fts_namelen;
19664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	memmove(sp->fts_path, p->fts_name, len + 1);
19764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
19864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		len = strlen(++cp);
19964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		memmove(p->fts_name, cp, len + 1);
20064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_namelen = len;
20164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
20264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_accpath = p->fts_path = sp->fts_path;
20364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_dev = p->fts_dev;
20464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
20564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
20664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossint
20764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_close(FTS *sp)
20864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
20964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *freep, *p;
21064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int rfd, error = 0;
21164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
21264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
21364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * This still works if we haven't read anything -- the dummy structure
21464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * points to the root list, so we step through to the end of the root
21564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * list which has a valid parent pointer.
21664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
21764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_cur) {
21864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
21964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			freep = p;
22064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p = p->fts_link ? p->fts_link : p->fts_parent;
22164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			free(freep);
22264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
22364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		free(p);
22464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
22564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
22664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Stash the original directory fd if needed. */
22764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd;
22864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
22964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Free up child linked list, sort array, path buffer, stream ptr.*/
23064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_child)
23164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		fts_lfree(sp->fts_child);
23264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_array)
23364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		free(sp->fts_array);
23464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	free(sp->fts_path);
23564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	free(sp);
23664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
23764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Return to original directory, checking for error. */
23864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (rfd != -1) {
23964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		int saved_errno;
24064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		error = fchdir(rfd);
24164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		saved_errno = errno;
24264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		(void)close(rfd);
24364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = saved_errno;
24464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
24564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
24664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (error);
24764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
24864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
24964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*
25064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Special case of "/" at the end of the path so that slashes aren't
25164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * appended which would cause paths to be written as "....//foo".
25264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
25364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	NAPPEND(p)							\
25464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	(p->fts_path[p->fts_pathlen - 1] == '/'				\
25564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    ? p->fts_pathlen - 1 : p->fts_pathlen)
25664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
25764ceac3f493e3063a289aec4a12c74787be974e4Colin CrossFTSENT *
25864ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_read(FTS *sp)
25964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
26064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p, *tmp;
26164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int instr;
26264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	char *t;
26364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int saved_errno;
26464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
26564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* If finished or unrecoverable error, return NULL. */
26664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
26764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
26864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
26964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Set current node pointer. */
27064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p = sp->fts_cur;
27164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
27264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Save and zero out user instructions. */
27364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	instr = p->fts_instr;
27464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_instr = FTS_NOINSTR;
27564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
27664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Any type of file may be re-visited; re-stat and re-turn. */
27764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (instr == FTS_AGAIN) {
2782818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		p->fts_info = fts_stat(sp, p, 0, -1);
27964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (p);
28064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
28164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
28264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
28364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Following a symlink -- SLNONE test allows application to see
28464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * SLNONE and recover.  If indirecting through a symlink, have
28564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * keep a pointer to current location.  If unable to get that
28664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * pointer, follow fails.
28764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
28864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (instr == FTS_FOLLOW &&
28964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
2902818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		p->fts_info = fts_stat(sp, p, 1, -1);
29164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
29264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
29364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_errno = errno;
29464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_info = FTS_ERR;
29564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			} else
29664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_flags |= FTS_SYMFOLLOW;
29764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
29864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (p);
29964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
30064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
30164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Directory in pre-order. */
30264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_info == FTS_D) {
30364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/* If skipped or crossed mount point, do post-order visit. */
30464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (instr == FTS_SKIP ||
30564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
30664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (p->fts_flags & FTS_SYMFOLLOW)
30764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				(void)close(p->fts_symfd);
30864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (sp->fts_child) {
30964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				fts_lfree(sp->fts_child);
31064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				sp->fts_child = NULL;
31164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
31264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_info = FTS_DP;
31364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (p);
31464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
31564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
31664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/* Rebuild if only read the names and now traversing. */
31764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (sp->fts_child && ISSET(FTS_NAMEONLY)) {
31864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			CLR(FTS_NAMEONLY);
31964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			fts_lfree(sp->fts_child);
32064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			sp->fts_child = NULL;
32164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
32264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
32364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
32464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * Cd to the subdirectory.
32564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 *
32664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * If have already read and now fail to chdir, whack the list
32764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * to make the names come out right, and set the parent errno
32864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * so the application will eventually get an error condition.
32964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * Set the FTS_DONTCHDIR flag so that when we logically change
33064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * directories back to the parent we don't do a chdir.
33164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 *
33264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * If haven't read do so.  If the read fails, fts_build sets
33364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * FTS_STOP or the fts_info field of the node.
33464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
33564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (sp->fts_child) {
33664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
33764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_errno = errno;
33864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_flags |= FTS_DONTCHDIR;
33964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				for (p = sp->fts_child; p; p = p->fts_link)
34064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					p->fts_accpath =
34164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					    p->fts_parent->fts_accpath;
34264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
34364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
34464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (ISSET(FTS_STOP))
34564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				return (NULL);
34664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (p);
34764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
34864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p = sp->fts_child;
34964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		sp->fts_child = NULL;
35064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		goto name;
35164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
35264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
35364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Move to the next node on this level. */
35464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossnext:	tmp = p;
35564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((p = p->fts_link)) {
35664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		free(tmp);
35764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
35864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
35964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * If reached the top, return to the original directory (or
36064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * the root of the tree), and load the paths for the next root.
36164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
36264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (p->fts_level == FTS_ROOTLEVEL) {
36364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (FCHDIR(sp, sp->fts_rfd)) {
36464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				SET(FTS_STOP);
36564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				return (NULL);
36664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
36764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			fts_load(sp, p);
36864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (sp->fts_cur = p);
36964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
37064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
37164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
37264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * User may have called fts_set on the node.  If skipped,
37364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * ignore.  If followed, get a file descriptor so we can
37464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * get back if necessary.
37564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
37664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (p->fts_instr == FTS_SKIP)
37764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			goto next;
37864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (p->fts_instr == FTS_FOLLOW) {
3792818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes			p->fts_info = fts_stat(sp, p, 1, -1);
38064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
38164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				if ((p->fts_symfd =
38264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				    open(".", O_RDONLY, 0)) < 0) {
38364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					p->fts_errno = errno;
38464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					p->fts_info = FTS_ERR;
38564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				} else
38664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					p->fts_flags |= FTS_SYMFOLLOW;
38764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
38864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_instr = FTS_NOINSTR;
38964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
39064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
39164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossname:		t = sp->fts_path + NAPPEND(p->fts_parent);
39264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		*t++ = '/';
39364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		memmove(t, p->fts_name, p->fts_namelen + 1);
39464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (sp->fts_cur = p);
39564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
39664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
39764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Move up to the parent node. */
39864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p = tmp->fts_parent;
39964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	free(tmp);
40064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
40164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
40264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
40364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * Done; free everything up and set errno to 0 so the user
40464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * can distinguish between error and EOF.
40564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
40664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		free(p);
40764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = 0;
40864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (sp->fts_cur = NULL);
40964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
41064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
41164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* NUL terminate the pathname. */
41264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_path[p->fts_pathlen] = '\0';
41364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
41464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
41564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Return to the parent directory.  If at a root node or came through
41664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * a symlink, go back through the file descriptor.  Otherwise, cd up
41764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * one directory.
41864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
41964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_level == FTS_ROOTLEVEL) {
42064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (FCHDIR(sp, sp->fts_rfd)) {
42164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			SET(FTS_STOP);
42264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			sp->fts_cur = p;
42364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (NULL);
42464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
42564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	} else if (p->fts_flags & FTS_SYMFOLLOW) {
42664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (FCHDIR(sp, p->fts_symfd)) {
42764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			saved_errno = errno;
42864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			(void)close(p->fts_symfd);
42964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			errno = saved_errno;
43064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			SET(FTS_STOP);
43164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			sp->fts_cur = p;
43264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (NULL);
43364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
43464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		(void)close(p->fts_symfd);
43564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
43664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
43764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		SET(FTS_STOP);
43864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		sp->fts_cur = p;
43964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
44064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
44164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
44264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (sp->fts_cur = p);
44364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
44464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
44564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*
44664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Fts_set takes the stream as an argument although it's not used in this
44764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * implementation; it would be necessary if anyone wanted to add global
44864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * semantics to fts using fts_set.  An error return is allowed for similar
44964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * reasons.
45064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
45164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/* ARGSUSED */
45264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossint
453ec67cded1d2969b5ba21028f0dd1560827947f3dElliott Hughesfts_set(FTS *sp __unused, FTSENT *p, int instr)
45464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
45564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
45664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
45764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = EINVAL;
45864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (1);
45964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
46064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_instr = instr;
46164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (0);
46264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
46364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
46464ceac3f493e3063a289aec4a12c74787be974e4Colin CrossFTSENT *
46564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_children(FTS *sp, int instr)
46664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
46764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p;
46864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int fd;
46964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
47064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (instr && instr != FTS_NAMEONLY) {
47164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = EINVAL;
47264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
47364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
47464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
47564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Set current node pointer. */
47664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p = sp->fts_cur;
47764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
47864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
47964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Errno set to 0 so user can distinguish empty directory from
48064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * an error.
48164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
48264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	errno = 0;
48364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
48464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Fatal errors stop here. */
48564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (ISSET(FTS_STOP))
48664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
48764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
48864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Return logical hierarchy of user's arguments. */
48964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_info == FTS_INIT)
49064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (p->fts_link);
49164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
49264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
49364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If not a directory being visited in pre-order, stop here.  Could
49464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * allow FTS_DNR, assuming the user has fixed the problem, but the
49564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * same effect is available with FTS_AGAIN.
49664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
49764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
49864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
49964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
50064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Free up any previous child list. */
50164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_child)
50264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		fts_lfree(sp->fts_child);
50364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
50464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (instr == FTS_NAMEONLY) {
50564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		SET(FTS_NAMEONLY);
50664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		instr = BNAMES;
50764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	} else
50864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		instr = BCHILD;
50964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
51064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
51164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If using chdir on a relative path and called BEFORE fts_read does
51264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * its chdir to the root of a traversal, we can lose -- we need to
51364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * chdir into the subdirectory, and we don't know where the current
51464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * directory is, so we can't get back so that the upcoming chdir by
51564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * fts_read will work.
51664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
51764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
51864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    ISSET(FTS_NOCHDIR))
51964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (sp->fts_child = fts_build(sp, instr));
52064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
52164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((fd = open(".", O_RDONLY, 0)) < 0)
52264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
52364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_child = fts_build(sp, instr);
52464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (fchdir(fd)) {
52564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		(void)close(fd);
52664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
52764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
52864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	(void)close(fd);
52964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (sp->fts_child);
53064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
53164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
53264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*
53364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * This is the tricky part -- do not casually change *anything* in here.  The
53464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * idea is to build the linked list of entries that are used by fts_children
53564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * and fts_read.  There are lots of special cases.
53664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross *
53764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
53864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * set and it's a physical walk (so that symbolic links can't be directories),
53964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * we can do things quickly.  First, if it's a 4.4BSD file system, the type
54064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * of the file is in the directory entry.  Otherwise, we assume that the number
54164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * of subdirectories in a node is equal to the number of links to the parent.
54264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * The former skips all stat calls.  The latter skips stat calls in any leaf
54364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * directories and for any files after the subdirectories in the directory have
54464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * been found, cutting the stat calls by about 2/3.
54564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
54664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT *
54764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_build(FTS *sp, int type)
54864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
54964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	struct dirent *dp;
55064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p, *head;
55164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *cur, *tail;
55264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	DIR *dirp;
55364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	void *oldaddr;
55464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	size_t len, maxlen;
55550ace4fec5e8cb5afcbc656a4556fa528adfd760David 'Digit' Turner	int nitems, cderrno, descend, level, nlinks, nostat = 0, doadjust;
55664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int saved_errno;
55750ace4fec5e8cb5afcbc656a4556fa528adfd760David 'Digit' Turner	char *cp = NULL;
55864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
55964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Set current node pointer. */
56064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	cur = sp->fts_cur;
56164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
56264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
56364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Open the directory for reading.  If this fails, we're done.
56464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If being called from fts_read, set the fts_info field.
56564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
56664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((dirp = opendir(cur->fts_accpath)) == NULL) {
56764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (type == BREAD) {
56864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			cur->fts_info = FTS_DNR;
56964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			cur->fts_errno = errno;
57064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
57164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
57264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
57364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
57464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
57564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Nlinks is the number of possible entries of type directory in the
57664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * directory if we're cheating on stat calls, 0 if we're not doing
57764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * any stat calls at all, -1 if we're doing stats on everything.
57864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
57964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (type == BNAMES)
58064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		nlinks = 0;
58164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
58264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
58364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		nostat = 1;
58464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	} else {
58564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		nlinks = -1;
58664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		nostat = 0;
58764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
58864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
58964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#ifdef notdef
59064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	(void)printf("nlinks == %d (cur: %u)\n", nlinks, cur->fts_nlink);
59164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
59264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
59364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#endif
59464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
59564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If we're going to need to stat anything or we want to descend
59664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * and stay in the directory, chdir.  If this fails we keep going,
59764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * but set a flag so we don't chdir after the post-order visit.
59864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * We won't be able to stat anything, but we can still return the
59964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * names themselves.  Note, that since fts_read won't be able to
60064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * chdir into the directory, it will have to return different path
60164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * names than before, i.e. "a/b" instead of "b".  Since the node
60264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * has already been visited in pre-order, have to wait until the
60364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * post-order visit to return the error.  There is a special case
60464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * here, if there was nothing to stat then it's not an error to
60564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * not be able to stat.  This is all fairly nasty.  If a program
60664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * needed sorted entries or stat information, they had better be
60764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * checking FTS_NS on the returned nodes.
60864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
60964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	cderrno = 0;
61064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (nlinks || type == BREAD) {
61164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
61264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (nlinks && type == BREAD)
61364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				cur->fts_errno = errno;
61464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			cur->fts_flags |= FTS_DONTCHDIR;
61564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			descend = 0;
61664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			cderrno = errno;
61764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			(void)closedir(dirp);
61864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			dirp = NULL;
61964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		} else
62064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			descend = 1;
62164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	} else
62264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		descend = 0;
62364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
62464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
62564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Figure out the max file name length that can be stored in the
62664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * current path -- the inner loop allocates more path as necessary.
62764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * We really wouldn't have to do the maxlen calculations here, we
62864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * could do them in fts_read before returning the path, but it's a
62964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * lot easier here since the length is part of the dirent structure.
63064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 *
63164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If not changing directories set a pointer so that can just append
63264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * each new name into the path.
63364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
63464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	len = NAPPEND(cur);
63564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (ISSET(FTS_NOCHDIR)) {
63664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		cp = sp->fts_path + len;
63764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		*cp++ = '/';
63864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
63964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	len++;
64064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	maxlen = sp->fts_pathlen - len;
64164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
64264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
643ec67cded1d2969b5ba21028f0dd1560827947f3dElliott Hughes	 * fts_level is signed so we must prevent it from wrapping
64464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL.
64564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
64664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	level = cur->fts_level;
64764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (level < FTS_MAXLEVEL)
64864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    level++;
64964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
65064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Read the directory, attaching each entry to the `link' pointer. */
65164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	doadjust = 0;
65264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
65364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
65464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			continue;
65564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
65664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (!(p = fts_alloc(sp, dp->d_name, strlen(dp->d_name))))
65764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			goto mem1;
65864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (strlen(dp->d_name) >= maxlen) {	/* include space for NUL */
65964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			oldaddr = sp->fts_path;
66064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (fts_palloc(sp, strlen(dp->d_name) +len + 1)) {
66164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				/*
66264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				 * No more memory for path or structures.  Save
66364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				 * errno, free up the current structure and the
66464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				 * structures already allocated.
66564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				 */
66664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossmem1:				saved_errno = errno;
66764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				if (p)
66864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					free(p);
66964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				fts_lfree(head);
67064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				(void)closedir(dirp);
67164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				cur->fts_info = FTS_ERR;
67264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				SET(FTS_STOP);
67364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				errno = saved_errno;
67464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				return (NULL);
67564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
67664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			/* Did realloc() change the pointer? */
67764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (oldaddr != sp->fts_path) {
67864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				doadjust = 1;
67964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				if (ISSET(FTS_NOCHDIR))
68064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross					cp = sp->fts_path + len;
68164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
68264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			maxlen = sp->fts_pathlen - len;
68364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
68464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
68564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_level = level;
68664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_parent = sp->fts_cur;
68764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_pathlen = len + strlen(dp->d_name);
68864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (p->fts_pathlen < len) {
68964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			/*
69064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			 * If we wrap, free up the current structure and
69164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			 * the structures already allocated, then error
69264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			 * out with ENAMETOOLONG.
69364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			 */
69464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			free(p);
69564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			fts_lfree(head);
69664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			(void)closedir(dirp);
69764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			cur->fts_info = FTS_ERR;
69864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			SET(FTS_STOP);
69964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			errno = ENAMETOOLONG;
70064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (NULL);
70164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
70264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
70364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (cderrno) {
70464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (nlinks) {
70564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_info = FTS_NS;
70664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_errno = cderrno;
70764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			} else
70864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_info = FTS_NSOK;
70964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_accpath = cur->fts_accpath;
71064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		} else if (nlinks == 0
71164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#ifdef DT_DIR
71264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		    || (nostat &&
71364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		    dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
71464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#endif
71564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		    ) {
71664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_accpath =
71764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			    ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
71864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_info = FTS_NSOK;
71964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		} else {
72064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			/* Build a file name for fts_stat to stat. */
72164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (ISSET(FTS_NOCHDIR)) {
72264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_accpath = p->fts_path;
723705910094d07ddfc5a3b7a4baab58b0a94bcc691George Burgess IV				assert(cp && "cp should be non-null if FTS_NOCHDIR is set");
724705910094d07ddfc5a3b7a4baab58b0a94bcc691George Burgess IV				memmove(cp, p->fts_name, p->fts_namelen + 1); // NOLINT
7252818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes				p->fts_info = fts_stat(sp, p, 0, dirfd(dirp));
7262818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes			} else {
72764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_accpath = p->fts_name;
7282818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes				p->fts_info = fts_stat(sp, p, 0, -1);
7292818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes			}
73064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
73164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			/* Decrement link count if applicable. */
73264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (nlinks > 0 && (p->fts_info == FTS_D ||
73364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			    p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
73464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				--nlinks;
73564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
73664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
73764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/* We walk in directory order so "ls -f" doesn't get upset. */
73864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_link = NULL;
73964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (head == NULL)
74064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			head = tail = p;
74164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		else {
74264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			tail->fts_link = p;
74364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			tail = p;
74464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
74564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		++nitems;
74664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
74764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (dirp)
74864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		(void)closedir(dirp);
74964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
75064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
75164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If realloc() changed the address of the path, adjust the
75264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * addresses for the rest of the tree and the dir list.
75364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
75464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (doadjust)
75564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		fts_padjust(sp, head);
75664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
75764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
75864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If not changing directories, reset the path back to original
75964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * state.
76064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
76164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (ISSET(FTS_NOCHDIR)) {
76264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (len == sp->fts_pathlen || nitems == 0)
76364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			--cp;
76464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		*cp = '\0';
76564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
76664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
76764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
76864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If descended after called from fts_children or after called from
76964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * fts_read and nothing found, get back.  At the root level we use
77064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * the saved fd; if one of fts_open()'s arguments is a relative path
77164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * to an empty directory, we wind up here with no other way back.  If
77264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * can't get back, we're done.
77364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
77464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (descend && (type == BCHILD || !nitems) &&
77564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    (cur->fts_level == FTS_ROOTLEVEL ? FCHDIR(sp, sp->fts_rfd) :
77664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	    fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
77764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		cur->fts_info = FTS_ERR;
77864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		SET(FTS_STOP);
77964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
78064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
78164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
78264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* If didn't find anything, return NULL. */
78364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (!nitems) {
78464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (type == BREAD)
78564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			cur->fts_info = FTS_DP;
78664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
78764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
78864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
78964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Sort the entries. */
79064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_compar && nitems > 1)
79164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		head = fts_sort(sp, head, nitems);
79264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (head);
79364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
79464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
79564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic u_short
7962818279ace22fb854b00e668c224492c4dd072a4Elliott Hughesfts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
79764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
79864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *t;
79964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	dev_t dev;
80064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	ino_t ino;
80164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	struct stat *sbp, sb;
80264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int saved_errno;
8032818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes	const char *path;
8042818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes
8052818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes	if (dfd == -1) {
8062818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		path = p->fts_accpath;
8072818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		dfd = AT_FDCWD;
8082818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes	} else
8092818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		path = p->fts_name;
81064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
81164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* If user needs stat info, stat buffer already allocated. */
81264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
81364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
81464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
81564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * If doing a logical walk, or application requested FTS_FOLLOW, do
81664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * a stat(2).  If that fails, check for a non-existent symlink.  If
81764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * fail, set the errno from the stat call.
81864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
81964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (ISSET(FTS_LOGICAL) || follow) {
8202818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		if (fstatat(dfd, path, sbp, 0)) {
82164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			saved_errno = errno;
8222818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes			if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
82364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				errno = 0;
82464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				return (FTS_SLNONE);
82564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
82664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			p->fts_errno = saved_errno;
82764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			goto err;
82864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
8292818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes	} else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
83064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_errno = errno;
83164ceac3f493e3063a289aec4a12c74787be974e4Colin Crosserr:		memset(sbp, 0, sizeof(struct stat));
83264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (FTS_NS);
83364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
83464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
83564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (S_ISDIR(sbp->st_mode)) {
83664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
83764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * Set the device/inode.  Used to find cycles and check for
83864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * crossing mount points.  Also remember the link count, used
83964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * in fts_build to limit the number of stat calls.  It is
84064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * understood that these fields are only referenced if fts_info
84164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * is set to FTS_D.
84264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
84364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		dev = p->fts_dev = sbp->st_dev;
84464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		ino = p->fts_ino = sbp->st_ino;
84564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_nlink = sbp->st_nlink;
84664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
84764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (ISDOT(p->fts_name))
84864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (FTS_DOT);
84964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
85064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		/*
85164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * Cycle detection is done by brute force when the directory
85264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * is first encountered.  If the tree gets deep enough or the
85364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * number of symbolic links to directories is high enough,
85464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 * something faster might be worthwhile.
85564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		 */
85664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		for (t = p->fts_parent;
85764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
85864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (ino == t->fts_ino && dev == t->fts_dev) {
85964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				p->fts_cycle = t;
86064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				return (FTS_DC);
86164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			}
86264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (FTS_D);
86364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
86464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (S_ISLNK(sbp->st_mode))
86564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (FTS_SL);
86664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (S_ISREG(sbp->st_mode))
86764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (FTS_F);
86864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (FTS_DEFAULT);
86964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
87064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
87164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT *
87264ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_sort(FTS *sp, FTSENT *head, int nitems)
87364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
87464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT **ap, *p;
87564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
87664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
87764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Construct an array of pointers to the structures and call qsort(3).
87864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Reassemble the array in the order returned by qsort.  If unable to
87964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * sort for memory reasons, return the directory entries in their
88064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * current order.  Allocate enough space for the current needs plus
88164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * 40 so don't realloc one entry at a time.
88264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
88364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (nitems > sp->fts_nitems) {
88464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		struct _ftsent **a;
88564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
88664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		sp->fts_nitems = nitems + 40;
8872818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		if ((a = reallocarray(sp->fts_array,
8882818279ace22fb854b00e668c224492c4dd072a4Elliott Hughes		    sp->fts_nitems, sizeof(FTSENT *))) == NULL) {
88964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			if (sp->fts_array)
89064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross				free(sp->fts_array);
89164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			sp->fts_array = NULL;
89264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			sp->fts_nitems = 0;
89364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			return (head);
89464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		}
89564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		sp->fts_array = a;
89664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
89764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
89864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		*ap++ = p;
89964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
90064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (head = *(ap = sp->fts_array); --nitems; ++ap)
90164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		ap[0]->fts_link = ap[1];
90264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	ap[0]->fts_link = NULL;
90364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (head);
90464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
90564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
90664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic FTSENT *
90764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_alloc(FTS *sp, char *name, size_t namelen)
90864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
90964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p;
91064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	size_t len;
91164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
91264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
91364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * The file name is a variable length array and no stat structure is
91464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * necessary if the user has set the nostat bit.  Allocate the FTSENT
91564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * structure, the file name and the stat structure in one chunk, but
91664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * be careful that the stat structure is reasonably aligned.  Since the
91764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * fts_name field is declared to be of size 1, the fts_name pointer is
91864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * namelen + 2 before the first possible address of the stat structure.
91964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
92064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	len = sizeof(FTSENT) + namelen;
92164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (!ISSET(FTS_NOSTAT))
92264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		len += sizeof(struct stat) + ALIGNBYTES;
923ec67cded1d2969b5ba21028f0dd1560827947f3dElliott Hughes	if ((p = calloc(1, len)) == NULL)
92464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (NULL);
92564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
92664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_path = sp->fts_path;
92764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_namelen = namelen;
92864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p->fts_instr = FTS_NOINSTR;
92964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (!ISSET(FTS_NOSTAT))
93064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
93164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	memcpy(p->fts_name, name, namelen);
93264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
93364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (p);
93464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
93564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
93664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void
93764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_lfree(FTSENT *head)
93864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
93964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p;
94064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
94164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Free a linked list of structures. */
94264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	while ((p = head)) {
94364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		head = head->fts_link;
94464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		free(p);
94564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
94664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
94764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
94864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*
94964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
950ec67cded1d2969b5ba21028f0dd1560827947f3dElliott Hughes * Most systems will allow creation of paths much longer than PATH_MAX, even
95164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * though the kernel won't resolve them.  Add the size (not just what's needed)
95264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * plus 256 bytes so don't realloc the path 2 bytes at a time.
95364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
95464ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int
95564ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_palloc(FTS *sp, size_t more)
95664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
95764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	char *p;
95864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
95964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/*
96064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 * Check for possible wraparound.
96164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	 */
96264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	more += 256;
96364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (sp->fts_pathlen + more < sp->fts_pathlen) {
96464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (sp->fts_path)
96564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			free(sp->fts_path);
96664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		sp->fts_path = NULL;
96764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = ENAMETOOLONG;
96864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (1);
96964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
97064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_pathlen += more;
97164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	p = realloc(sp->fts_path, sp->fts_pathlen);
97264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p == NULL) {
97364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if (sp->fts_path)
97464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			free(sp->fts_path);
97564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		sp->fts_path = NULL;
97664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (1);
97764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
97864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	sp->fts_path = p;
97964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (0);
98064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
98164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
98264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*
98364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * When the path is realloc'd, have to fix all of the pointers in structures
98464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * already returned.
98564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
98664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic void
98764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_padjust(FTS *sp, FTSENT *head)
98864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
98964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	FTSENT *p;
99064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	char *addr = sp->fts_path;
99164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
99264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross#define	ADJUST(p) {							\
99364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if ((p)->fts_accpath != (p)->fts_name) {			\
99464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		(p)->fts_accpath =					\
99564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		    (char *)addr + ((p)->fts_accpath - (p)->fts_path);	\
99664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}								\
99764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	(p)->fts_path = addr;						\
99864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
99964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Adjust the current set of children. */
100064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (p = sp->fts_child; p; p = p->fts_link)
100164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		ADJUST(p);
100264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
100364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	/* Adjust the rest of the tree, including the current level. */
100464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
100564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		ADJUST(p);
100664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		p = p->fts_link ? p->fts_link : p->fts_parent;
100764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
100864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
100964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
101064ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic size_t
101164ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_maxarglen(char * const *argv)
101264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
101364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	size_t len, max;
101464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
101564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	for (max = 0; *argv; ++argv)
101664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		if ((len = strlen(*argv)) > max)
101764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross			max = len;
101864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (max + 1);
101964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
102064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
102164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross/*
102264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Change to dir specified by fd or p->fts_accpath without getting
102364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * tricked by someone changing the world out from underneath us.
102464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross * Assumes p->fts_dev and p->fts_ino are filled in.
102564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross */
102664ceac3f493e3063a289aec4a12c74787be974e4Colin Crossstatic int
102764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossfts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
102864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross{
102964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	int ret, oerrno, newfd;
103064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	struct stat sb;
103164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross
103264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	newfd = fd;
103364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (ISSET(FTS_NOCHDIR))
103464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (0);
103564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
103664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		return (-1);
103764ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (fstat(newfd, &sb)) {
103864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		ret = -1;
103964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		goto bail;
104064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
104164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
104264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		errno = ENOENT;		/* disinformation */
104364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		ret = -1;
104464ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		goto bail;
104564ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	}
104664ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	ret = fchdir(newfd);
104764ceac3f493e3063a289aec4a12c74787be974e4Colin Crossbail:
104864ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	oerrno = errno;
104964ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	if (fd < 0)
105064ceac3f493e3063a289aec4a12c74787be974e4Colin Cross		(void)close(newfd);
105164ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	errno = oerrno;
105264ceac3f493e3063a289aec4a12c74787be974e4Colin Cross	return (ret);
105364ceac3f493e3063a289aec4a12c74787be974e4Colin Cross}
1054