xref: /onnv-gate/usr/src/lib/libast/common/misc/fts.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Phong Vo
254887Schin  * Glenn Fowler
264887Schin  * AT&T Research
274887Schin  *
284887Schin  * fts implementation unwound from the kpv ftwalk() of 1988-10-30
294887Schin  */
304887Schin 
314887Schin #include <ast.h>
324887Schin #include <ast_dir.h>
334887Schin #include <error.h>
344887Schin #include <fs3d.h>
358462SApril.Chin@Sun.COM #include <ls.h>
364887Schin 
374887Schin struct Ftsent;
384887Schin 
394887Schin typedef int (*Compar_f)(struct Ftsent* const*, struct Ftsent* const*);
404887Schin typedef int (*Stat_f)(const char*, struct stat*);
414887Schin 
4210898Sroland.mainz@nrubsig.org #define _fts_status	status
4310898Sroland.mainz@nrubsig.org #define _fts_statb	statb
4410898Sroland.mainz@nrubsig.org 
454887Schin #define _FTS_PRIVATE_ \
464887Schin 	FTSENT*		parent;			/* top parent		*/ \
474887Schin 	FTSENT*		todo;			/* todo list		*/ \
484887Schin 	FTSENT*		top;			/* top element		*/ \
494887Schin 	FTSENT*		root;						   \
504887Schin 	FTSENT*		bot;			/* bottom element	*/ \
514887Schin 	FTSENT*		free;			/* free element		*/ \
524887Schin 	FTSENT*		diroot;						   \
534887Schin 	FTSENT*		curdir;						   \
544887Schin 	FTSENT*		current;		/* current element	*/ \
554887Schin 	FTSENT*		previous;		/* previous current	*/ \
564887Schin 	FTSENT*		dotdot;						   \
574887Schin 	FTSENT*		link;			/* real current fts_link*/ \
584887Schin 	FTSENT*		pwd;			/* pwd parent		*/ \
594887Schin 	DIR*		dir;			/* current dir stream	*/ \
604887Schin 	Compar_f	comparf;		/* node comparison func	*/ \
6110898Sroland.mainz@nrubsig.org 	size_t		baselen;		/* current strlen(base)	*/ \
6210898Sroland.mainz@nrubsig.org 	size_t		homesize;		/* sizeof(home)		*/ \
634887Schin 	int		cd;			/* chdir status		*/ \
644887Schin 	int		cpname;						   \
654887Schin 	int		flags;			/* fts_open() flags	*/ \
664887Schin 	int		nd;						   \
674887Schin 	unsigned char	children;					   \
684887Schin 	unsigned char	fs3d;						   \
694887Schin 	unsigned char	nostat;					   	   \
704887Schin 	unsigned char	state;			/* fts_read() state	*/ \
714887Schin 	char*		base;			/* basename in path	*/ \
724887Schin 	char*		name;						   \
734887Schin 	char*		path;			/* path workspace	*/ \
744887Schin 	char*		home;			/* home/path buffer	*/ \
754887Schin 	char*		endbase;		/* space to build paths */ \
764887Schin 	char*		endbuf;			/* space to build paths */ \
778462SApril.Chin@Sun.COM 	char*		pad[2];			/* $0.02 to splain this	*/
784887Schin 
794887Schin /*
804887Schin  * NOTE: <ftwalk.h> relies on status and statb being the first two elements
814887Schin  */
824887Schin 
834887Schin #define _FTSENT_PRIVATE_ \
844887Schin 	int		nd;			/* popdir() count	*/ \
854887Schin 	FTSENT*		left;			/* left child		*/ \
864887Schin 	FTSENT*		right;			/* right child		*/ \
874887Schin 	FTSENT*		pwd;			/* pwd parent		*/ \
884887Schin 	FTSENT*		stack;			/* getlist() stack	*/ \
894887Schin 	long		nlink;			/* FTS_D link count	*/ \
904887Schin 	unsigned char	must;			/* must stat		*/ \
914887Schin 	unsigned char	type;			/* DT_* type		*/ \
924887Schin 	unsigned char	symlink;		/* originally a symlink	*/ \
934887Schin 	char		name[sizeof(int)];	/* fts_name data	*/
944887Schin 
954887Schin #include <fts.h>
964887Schin 
974887Schin #ifndef ENOSYS
984887Schin #define ENOSYS		EINVAL
994887Schin #endif
1004887Schin 
1014887Schin 
1024887Schin #if MAXNAMLEN > 16
1034887Schin #define MINNAME		32
1044887Schin #else
1054887Schin #define MINNAME		16
1064887Schin #endif
1074887Schin 
1084887Schin #define drop(p,f)	(((f)->fts_namelen < MINNAME) ? ((f)->fts_link = (p)->free, (p)->free = (f)) : (free(f), (p)->free))
1094887Schin 
1104887Schin #define ACCESS(p,f)	((p)->cd==0?(f)->fts_name:(f)->fts_path)
1114887Schin #define PATH(f,p,l)	((!((f)->flags&FTS_SEEDOTDIR)&&(l)>0&&(p)[0]=='.'&&(p)[1]=='/')?((p)+2):(p))
1124887Schin #define SAME(one,two)	((one)->st_ino==(two)->st_ino&&(one)->st_dev==(two)->st_dev)
1134887Schin #define SKIPLINK(p,f)	((f)->fts_parent->nlink == 0)
1144887Schin 
1154887Schin #ifdef D_TYPE
1164887Schin #define ISTYPE(f,t)	((f)->type == (t))
1174887Schin #define TYPE(f,t)	((f)->type = (t))
1184887Schin #define SKIP(p,f)	((f)->fts_parent->must == 0 && (((f)->type == DT_UNKNOWN) ? SKIPLINK(p,f) : ((f)->type != DT_DIR && ((f)->type != DT_LNK || ((p)->flags & FTS_PHYSICAL)))))
1194887Schin #else
1204887Schin #undef	DT_UNKNOWN
1214887Schin #define DT_UNKNOWN	0
1224887Schin #undef	DT_LNK
1234887Schin #define DT_LNK		1
1244887Schin #define ISTYPE(f,t)	((t)==DT_UNKNOWN)
1254887Schin #define TYPE(f,d)
1264887Schin #define SKIP(p,f)	((f)->fts_parent->must == 0 && SKIPLINK(p,f))
1274887Schin #endif
1284887Schin 
1294887Schin #ifndef D_FILENO
1304887Schin #define D_FILENO(d)	(1)
1314887Schin #endif
1324887Schin 
1334887Schin /*
1344887Schin  * NOTE: a malicious dir rename() could change .. underfoot so we
1354887Schin  *	 must always verify; undef verify to enable the unsafe code
1364887Schin  */
1374887Schin 
1384887Schin #define verify		1
1394887Schin 
1404887Schin /*
1414887Schin  * FTS_NOSTAT requires a dir with
1424887Schin  *	D_TYPE(&dirent_t)!=DT_UNKNOWN
1434887Schin  *	    OR
1444887Schin  *	st_nlink>=2
1454887Schin  */
1464887Schin 
1474887Schin #define FTS_children_resume	1
1484887Schin #define FTS_children_return	2
1494887Schin #define FTS_error		3
1504887Schin #define FTS_popstack		4
1514887Schin #define FTS_popstack_resume	5
1524887Schin #define FTS_popstack_return	6
1534887Schin #define FTS_preorder		7
1544887Schin #define FTS_preorder_resume	8
1554887Schin #define FTS_preorder_return	9
1564887Schin #define FTS_readdir		10
1574887Schin #define FTS_terminal		11
1584887Schin #define FTS_todo		12
1594887Schin #define FTS_top_return		13
1604887Schin 
1614887Schin typedef int (*Notify_f)(FTS*, FTSENT*, void*);
1624887Schin 
1634887Schin typedef struct Notify_s
1644887Schin {
1654887Schin 	struct Notify_s*	next;
1664887Schin 	Notify_f		notifyf;
1674887Schin 	void*			context;
1684887Schin } Notify_t;
1694887Schin 
1704887Schin static Notify_t*		notify;
1714887Schin 
1724887Schin /*
1734887Schin  * allocate an FTSENT node
1744887Schin  */
1754887Schin 
1764887Schin static FTSENT*
node(FTS * fts,FTSENT * parent,register char * name,register size_t namelen)17710898Sroland.mainz@nrubsig.org node(FTS* fts, FTSENT* parent, register char* name, register size_t namelen)
1784887Schin {
1794887Schin 	register FTSENT*	f;
18010898Sroland.mainz@nrubsig.org 	register size_t		n;
1814887Schin 
1824887Schin 	if (fts->free && namelen < MINNAME)
1834887Schin 	{
1844887Schin 		f = fts->free;
1854887Schin 		fts->free = f->fts_link;
1864887Schin 	}
1874887Schin 	else
1884887Schin 	{
1894887Schin 		n = (namelen < MINNAME ? MINNAME : namelen + 1) - sizeof(int);
1904887Schin 		if (!(f = newof(0, FTSENT, 1, n)))
1914887Schin 		{
1924887Schin 			fts->fts_errno = errno;
1934887Schin 			fts->state = FTS_error;
1944887Schin 			return 0;
1954887Schin 		}
1964887Schin 		f->fts = fts;
1974887Schin 	}
1984887Schin 	TYPE(f, DT_UNKNOWN);
1994887Schin 	f->status = 0;
2004887Schin 	f->symlink = 0;
2014887Schin 	f->fts_level = (f->fts_parent = parent)->fts_level + 1;
20210898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
20310898Sroland.mainz@nrubsig.org 	f->_fts_level = (short)f->fts_level;
20410898Sroland.mainz@nrubsig.org #endif
2054887Schin 	f->fts_link = 0;
2064887Schin 	f->fts_pointer = 0;
2074887Schin 	f->fts_number = 0;
2084887Schin 	f->fts_errno = 0;
2094887Schin 	f->fts_namelen = namelen;
21010898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
21110898Sroland.mainz@nrubsig.org 	f->_fts_namelen = (unsigned short)f->fts_namelen;
21210898Sroland.mainz@nrubsig.org #endif
2134887Schin 	f->fts_name = f->name;
2144887Schin 	f->fts_statp = &f->statb;
2154887Schin 	memcpy(f->fts_name, name, namelen + 1);
2164887Schin 	return f;
2174887Schin }
2184887Schin 
2194887Schin /*
2204887Schin  * compare directories by device/inode
2214887Schin  */
2224887Schin 
2234887Schin static int
statcmp(FTSENT * const * pf1,FTSENT * const * pf2)2244887Schin statcmp(FTSENT* const* pf1, FTSENT* const* pf2)
2254887Schin {
2264887Schin 	register const FTSENT*	f1 = *pf1;
2274887Schin 	register const FTSENT*	f2 = *pf2;
2284887Schin 
2294887Schin 	if (f1->statb.st_ino < f2->statb.st_ino)
2304887Schin 		return -1;
2314887Schin 	if (f1->statb.st_ino > f2->statb.st_ino)
2324887Schin 		return 1;
2334887Schin 	if (f1->statb.st_dev < f2->statb.st_dev)
2344887Schin 		return -1;
2354887Schin 	if (f1->statb.st_dev > f2->statb.st_dev)
2364887Schin 		return 1;
2374887Schin 
2384887Schin 	/*
2394887Schin 	 * hack for NFS where <dev,ino> may not uniquely identify objects
2404887Schin 	 */
2414887Schin 
2424887Schin 	if (f1->statb.st_mtime < f2->statb.st_mtime)
2434887Schin 		return -1;
2444887Schin 	if (f1->statb.st_mtime > f2->statb.st_mtime)
2454887Schin 		return 1;
2464887Schin 	return 0;
2474887Schin }
2484887Schin 
2494887Schin /*
2504887Schin  * search trees with top-down splaying (a la Tarjan and Sleator)
2514887Schin  * when used for insertion sort, this implements a stable sort
2524887Schin  */
2534887Schin 
2544887Schin #define RROTATE(r)	(t = r->left, r->left = t->right, t->right = r, r = t)
2554887Schin #define LROTATE(r)	(t = r->right, r->right = t->left, t->left = r, r = t)
2564887Schin 
2574887Schin static FTSENT*
search(FTSENT * e,FTSENT * root,int (* comparf)(FTSENT * const *,FTSENT * const *),int insert)2584887Schin search(FTSENT* e, FTSENT* root, int(*comparf)(FTSENT* const*, FTSENT* const*), int insert)
2594887Schin {
2604887Schin 	register int		cmp;
2614887Schin 	register FTSENT*	t;
2624887Schin 	register FTSENT*	left;
2634887Schin 	register FTSENT*	right;
2644887Schin 	register FTSENT*	lroot;
2654887Schin 	register FTSENT*	rroot;
2664887Schin 
2674887Schin 	left = right = lroot = rroot = 0;
2684887Schin 	while (root)
2694887Schin 	{
2704887Schin 		if (!(cmp = (*comparf)(&e, &root)) && !insert)
2714887Schin 			break;
2724887Schin 		if (cmp < 0)
2734887Schin 		{
2744887Schin 			/*
2754887Schin 			 * this is the left zig-zig case
2764887Schin 			 */
2774887Schin 
2784887Schin 			if (root->left && (cmp = (*comparf)(&e, &root->left)) <= 0)
2794887Schin 			{
2804887Schin 				RROTATE(root);
2814887Schin 				if (!cmp && !insert)
2824887Schin 					break;
2834887Schin 			}
2844887Schin 
2854887Schin 			/*
2864887Schin 			 * stick all things > e to the right tree
2874887Schin 			 */
2884887Schin 
2894887Schin 			if (right)
2904887Schin 				right->left = root;
2914887Schin 			else
2924887Schin 				rroot = root;
2934887Schin 			right = root;
2944887Schin 			root = root->left;
2954887Schin 			right->left = 0;
2964887Schin 		}
2974887Schin 		else
2984887Schin 		{
2994887Schin 			/*
3004887Schin 			 * this is the right zig-zig case
3014887Schin 			 */
3024887Schin 
3034887Schin 			if (root->right && (cmp = (*comparf)(&e, &root->right)) >= 0)
3044887Schin 			{
3054887Schin 				LROTATE(root);
3064887Schin 				if (!cmp && !insert)
3074887Schin 					break;
3084887Schin 			}
3094887Schin 
3104887Schin 			/*
3114887Schin 			 * stick all things <= e to the left tree
3124887Schin 			 */
3134887Schin 
3144887Schin 			if (left)
3154887Schin 				left->right = root;
3164887Schin 			else
3174887Schin 				lroot = root;
3184887Schin 			left = root;
3194887Schin 			root = root->right;
3204887Schin 			left->right = 0;
3214887Schin 		}
3224887Schin 	}
3234887Schin 	if (!root)
3244887Schin 		root = e;
3254887Schin 	else
3264887Schin 	{
3274887Schin 		if (right)
3284887Schin 			right->left = root->right;
3294887Schin 		else
3304887Schin 			rroot = root->right;
3314887Schin 		if (left)
3324887Schin 			left->right = root->left;
3334887Schin 		else
3344887Schin 			lroot = root->left;
3354887Schin 	}
3364887Schin 	root->left = lroot;
3374887Schin 	root->right = rroot;
3384887Schin 	return root;
3394887Schin }
3404887Schin 
3414887Schin /*
3424887Schin  * delete the root element from the tree
3434887Schin  */
3444887Schin 
3454887Schin static FTSENT*
deleteroot(register FTSENT * root)3464887Schin deleteroot(register FTSENT* root)
3474887Schin {
3484887Schin 	register FTSENT*	t;
3494887Schin 	register FTSENT*	left;
3504887Schin 	register FTSENT*	right;
3514887Schin 
3524887Schin 	right = root->right;
3534887Schin 	if (!(left = root->left))
3544887Schin 		root = right;
3554887Schin 	else
3564887Schin 	{
3574887Schin 		while (left->right)
3584887Schin 			LROTATE(left);
3594887Schin 		left->right = right;
3604887Schin 		root = left;
3614887Schin 	}
3624887Schin 	return root;
3634887Schin }
3644887Schin 
3654887Schin /*
3664887Schin  * generate ordered fts_link list from binary tree at root
3674887Schin  * FTSENT.stack instead of recursion to avoid blowing the real
3684887Schin  * stack on big directories
3694887Schin  */
3704887Schin 
3714887Schin static void
getlist(register FTSENT ** top,register FTSENT ** bot,register FTSENT * root)3724887Schin getlist(register FTSENT** top, register FTSENT** bot, register FTSENT* root)
3734887Schin {
3744887Schin 	register FTSENT*	stack = 0;
3754887Schin 
3764887Schin 	for (;;)
3774887Schin 	{
3784887Schin 		if (root->left)
3794887Schin 		{
3804887Schin 			root->stack = stack;
3814887Schin 			stack = root;
3824887Schin 			root = root->left;
3834887Schin 		}
3844887Schin 		else
3854887Schin 		{
3864887Schin 			for (;;)
3874887Schin 			{
3884887Schin 				if (*top)
3894887Schin 					*bot = (*bot)->fts_link = root;
3904887Schin 				else
3914887Schin 					*bot = *top = root;
3924887Schin 				if (root->right)
3934887Schin 				{
3944887Schin 					root = root->right;
3954887Schin 					break;
3964887Schin 				}
3974887Schin 				if (!(root = stack))
39810898Sroland.mainz@nrubsig.org 				{
39910898Sroland.mainz@nrubsig.org 					(*bot)->fts_link = 0;
4004887Schin 					return;
40110898Sroland.mainz@nrubsig.org 				}
4024887Schin 				stack = stack->stack;
4034887Schin 			}
4044887Schin 		}
4054887Schin 	}
4064887Schin }
4074887Schin 
4084887Schin /*
4094887Schin  * set directory when curdir is lost in space
4104887Schin  */
4114887Schin 
4124887Schin static int
setdir(register char * home,register char * path)4134887Schin setdir(register char* home, register char* path)
4144887Schin {
4154887Schin 	register int	cdrv;
4164887Schin 
4174887Schin 	if (path[0] == '/')
4184887Schin 		cdrv = pathcd(path, NiL);
4194887Schin 	else
4204887Schin 	{
4214887Schin 		/*
4224887Schin 		 * note that path and home are in the same buffer
4234887Schin 		 */
4244887Schin 
4254887Schin 		path[-1] = '/';
4264887Schin 		cdrv = pathcd(home, NiL);
4274887Schin 		path[-1] = 0;
4284887Schin 	}
4294887Schin 	if (cdrv < 0)
4304887Schin 		pathcd(home, NiL);
4314887Schin 	return cdrv;
4324887Schin }
4334887Schin 
4344887Schin /*
4354887Schin  * set to parent dir
4364887Schin  */
4374887Schin 
4384887Schin static int
setpdir(register char * home,register char * path,register char * base)4394887Schin setpdir(register char* home, register char* path, register char* base)
4404887Schin {
4414887Schin 	register int	c;
4424887Schin 	register int	cdrv;
4434887Schin 
4444887Schin 	if (base > path)
4454887Schin 	{
4464887Schin 		c = base[0];
4474887Schin 		base[0] = 0;
4484887Schin 		cdrv = setdir(home, path);
4494887Schin 		base[0] = c;
4504887Schin 	}
4514887Schin 	else
4524887Schin 		cdrv = pathcd(home, NiL);
4534887Schin 	return cdrv;
4544887Schin }
4554887Schin 
4564887Schin /*
4574887Schin  * pop a set of directories
4584887Schin  */
4594887Schin static int
popdirs(FTS * fts)4604887Schin popdirs(FTS* fts)
4614887Schin {
4624887Schin 	register FTSENT*f;
4634887Schin 	register char*	s;
4644887Schin 	register char*	e;
4654887Schin #ifndef verify
4664887Schin 	register int	verify;
4674887Schin #endif
4684887Schin 	struct stat	sb;
4694887Schin 	char		buf[PATH_MAX];
4704887Schin 
4714887Schin 	if (!(f = fts->curdir) || f->fts_level < 0)
4724887Schin 		return -1;
4734887Schin 	e = buf + sizeof(buf) - 4;
4744887Schin #ifndef verify
4754887Schin 	verify = 0;
4764887Schin #endif
4774887Schin 	while (fts->nd > 0)
4784887Schin 	{
4794887Schin 		for (s = buf; s < e && fts->nd > 0; fts->nd--)
4804887Schin 		{
4814887Schin 			if (fts->pwd)
4824887Schin 			{
4834887Schin #ifndef verify
4844887Schin 				verify |= fts->pwd->symlink;
4854887Schin #endif
4864887Schin 				fts->pwd = fts->pwd->pwd;
4874887Schin 			}
4884887Schin 			*s++ = '.';
4894887Schin 			*s++ = '.';
4904887Schin 			*s++ = '/';
4914887Schin 		}
4924887Schin 		*s = 0;
4934887Schin 		if (chdir(buf))
4944887Schin 			return -1;
4954887Schin 	}
4964887Schin 	return (verify && (stat(".", &sb) < 0 || !SAME(&sb, f->fts_statp))) ? -1 : 0;
4974887Schin }
4984887Schin 
4994887Schin /*
5004887Schin  * initialize st from path and fts_info from st
5014887Schin  */
5024887Schin 
5034887Schin static int
info(FTS * fts,register FTSENT * f,const char * path,struct stat * sp,int flags)5044887Schin info(FTS* fts, register FTSENT* f, const char* path, struct stat* sp, int flags)
5054887Schin {
5064887Schin 	if (path)
5074887Schin 	{
5084887Schin #ifdef S_ISLNK
5094887Schin 		if (!f->symlink && (ISTYPE(f, DT_UNKNOWN) || ISTYPE(f, DT_LNK)))
5104887Schin 		{
5114887Schin 			if (lstat(path, sp) < 0)
5124887Schin 				goto bad;
5134887Schin 		}
5144887Schin 		else
5154887Schin #endif
5164887Schin 			if (stat(path, sp) < 0)
5174887Schin 				goto bad;
5184887Schin 	}
5194887Schin #ifdef S_ISLNK
5204887Schin  again:
5214887Schin #endif
5224887Schin 	if (S_ISDIR(sp->st_mode))
5234887Schin 	{
5244887Schin 		if ((flags & FTS_NOSTAT) && !fts->fs3d)
5254887Schin 		{
5264887Schin 			f->fts_parent->nlink--;
5274887Schin #ifdef D_TYPE
5284887Schin 			if ((f->nlink = sp->st_nlink) < 2)
5298462SApril.Chin@Sun.COM 			{
5308462SApril.Chin@Sun.COM 				f->must = 2;
5314887Schin 				f->nlink = 2;
5328462SApril.Chin@Sun.COM 			}
5338462SApril.Chin@Sun.COM 			else
5348462SApril.Chin@Sun.COM 				f->must = 0;
5354887Schin #else
5364887Schin 			if ((f->nlink = sp->st_nlink) >= 2)
5374887Schin 				f->must = 1;
5384887Schin 			else
5394887Schin 				f->must = 2;
5404887Schin #endif
5414887Schin 		}
5424887Schin 		else
5434887Schin 			f->must = 2;
5444887Schin 		TYPE(f, DT_DIR);
5454887Schin 		f->fts_info = FTS_D;
5464887Schin 	}
5474887Schin #ifdef S_ISLNK
5484887Schin 	else if (S_ISLNK((sp)->st_mode))
5494887Schin 	{
5504887Schin 		struct stat	sb;
5514887Schin 
5524887Schin 		f->symlink = 1;
5534887Schin 		if (!(flags & FTS_PHYSICAL) && stat(path, &sb) >= 0)
5544887Schin 		{
5554887Schin 			*sp = sb;
5564887Schin 			flags = FTS_PHYSICAL;
5574887Schin 			goto again;
5584887Schin 		}
5594887Schin 		TYPE(f, DT_LNK);
5604887Schin 		f->fts_info = FTS_SL;
5614887Schin 	}
5624887Schin #endif
5634887Schin 	else
5644887Schin 	{
5654887Schin 		TYPE(f, DT_REG);
5664887Schin 		f->fts_info = FTS_F;
5674887Schin 	}
5684887Schin 	return 0;
5694887Schin  bad:
5704887Schin 	TYPE(f, DT_UNKNOWN);
5714887Schin 	f->fts_info = FTS_NS;
5724887Schin 	return -1;
5734887Schin }
5744887Schin 
5754887Schin /*
5764887Schin  * get top list of elements to process
57710898Sroland.mainz@nrubsig.org  * ordering delayed until first fts_read()
57810898Sroland.mainz@nrubsig.org  * to give caller a chance to set fts->handle
5794887Schin  */
5804887Schin 
5814887Schin static FTSENT*
toplist(FTS * fts,register char * const * pathnames)5824887Schin toplist(FTS* fts, register char* const* pathnames)
5834887Schin {
5844887Schin 	register char*		path;
5854887Schin 	register FTSENT*	f;
58610898Sroland.mainz@nrubsig.org 	register FTSENT*	top;
58710898Sroland.mainz@nrubsig.org 	register FTSENT*	bot;
5884887Schin 	int			physical;
5894887Schin 	int			metaphysical;
5904887Schin 	char*			s;
5914887Schin 	struct stat		st;
5924887Schin 
5934887Schin 	if (fts->flags & FTS_NOSEEDOTDIR)
5944887Schin 		fts->flags &= ~FTS_SEEDOTDIR;
5954887Schin 	physical = (fts->flags & FTS_PHYSICAL);
5964887Schin 	metaphysical = (fts->flags & (FTS_META|FTS_PHYSICAL)) == (FTS_META|FTS_PHYSICAL);
59710898Sroland.mainz@nrubsig.org 	top = bot = 0;
5984887Schin 	while (path = *pathnames++)
5994887Schin 	{
6004887Schin 		/*
6014887Schin 		 * make elements
6024887Schin 		 */
6034887Schin 
6044887Schin 		if (!(f = node(fts, fts->parent, path, strlen(path))))
6054887Schin 			break;
6064887Schin 		path = f->fts_name;
6074887Schin 		if (!physical)
6084887Schin 			f->fts_namelen = (fts->flags & FTS_SEEDOTDIR) ? strlen(path) : (pathcanon(path, 0) - path);
6094887Schin 		else if (*path != '.')
6104887Schin 		{
6114887Schin 			f->fts_namelen = strlen(path);
6124887Schin 			fts->flags |= FTS_SEEDOTDIR;
6134887Schin 		}
6144887Schin 		else
6154887Schin 		{
6164887Schin 			if (fts->flags & FTS_NOSEEDOTDIR)
6174887Schin 			{
6184887Schin 				fts->flags &= ~FTS_SEEDOTDIR;
6194887Schin 				s = path;
6204887Schin 				while (*s++ == '.' && *s++ == '/')
6214887Schin 				{
6224887Schin 					while (*s == '/')
6234887Schin 						s++;
6244887Schin 					if (!*s)
6254887Schin 						break;
6264887Schin 					path = f->fts_name;
6274887Schin 					while (*path++ = *s++);
6284887Schin 					path = f->fts_name;
6294887Schin 				}
6304887Schin 			}
6314887Schin 			else
6324887Schin 				fts->flags |= FTS_SEEDOTDIR;
6334887Schin 			for (s = path + strlen(path); s > path && *(s - 1) == '/'; s--);
6344887Schin 			*s = 0;
6354887Schin 			f->fts_namelen = s - path;
6364887Schin 		}
63710898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
63810898Sroland.mainz@nrubsig.org 		f->_fts_namelen = (unsigned short)f->fts_namelen;
63910898Sroland.mainz@nrubsig.org #endif
6404887Schin 		if (!*path)
6414887Schin 		{
6424887Schin 			errno = ENOENT;
6434887Schin 			f->fts_info = FTS_NS;
6444887Schin 		}
6454887Schin 		else
64610898Sroland.mainz@nrubsig.org 			info(fts, f, path, f->fts_statp, fts->flags);
6474887Schin #ifdef S_ISLNK
6484887Schin 
6494887Schin 		/*
6504887Schin 		 * don't let any standards committee get
6514887Schin 		 * away with calling your idea a hack
6524887Schin 		 */
6534887Schin 
6544887Schin 		if (metaphysical && f->fts_info == FTS_SL && stat(path, &st) >= 0)
6554887Schin 		{
65610898Sroland.mainz@nrubsig.org 			*f->fts_statp = st;
65710898Sroland.mainz@nrubsig.org 			info(fts, f, NiL, f->fts_statp, 0);
6584887Schin 		}
6594887Schin #endif
66010898Sroland.mainz@nrubsig.org 		if (bot)
6614887Schin 		{
6624887Schin 			bot->fts_link = f;
6634887Schin 			bot = f;
6644887Schin 		}
6654887Schin 		else
6664887Schin 			top = bot = f;
6674887Schin 	}
6684887Schin 	return top;
6694887Schin }
6704887Schin 
6714887Schin /*
67210898Sroland.mainz@nrubsig.org  * order fts->todo if fts->comparf != 0
67310898Sroland.mainz@nrubsig.org  */
67410898Sroland.mainz@nrubsig.org 
67510898Sroland.mainz@nrubsig.org static void
order(FTS * fts)67610898Sroland.mainz@nrubsig.org order(FTS* fts)
67710898Sroland.mainz@nrubsig.org {
67810898Sroland.mainz@nrubsig.org 	register FTSENT*	f;
67910898Sroland.mainz@nrubsig.org 	register FTSENT*	root;
68010898Sroland.mainz@nrubsig.org 	FTSENT*			top;
68110898Sroland.mainz@nrubsig.org 	FTSENT*			bot;
68210898Sroland.mainz@nrubsig.org 
68310898Sroland.mainz@nrubsig.org 	top = bot = root = 0;
68410898Sroland.mainz@nrubsig.org 	for (f = fts->todo; f; f = f->fts_link)
68510898Sroland.mainz@nrubsig.org 		root = search(f, root, fts->comparf, 1);
68610898Sroland.mainz@nrubsig.org 	getlist(&top, &bot, root);
68710898Sroland.mainz@nrubsig.org 	fts->todo = top;
68810898Sroland.mainz@nrubsig.org }
68910898Sroland.mainz@nrubsig.org 
69010898Sroland.mainz@nrubsig.org /*
6914887Schin  * resize the path buffer
6924887Schin  * note that free() is not used because we may need to chdir(fts->home)
6934887Schin  * if there isn't enough space to continue
6944887Schin  */
6954887Schin 
6964887Schin static int
resize(register FTS * fts,size_t inc)69710898Sroland.mainz@nrubsig.org resize(register FTS* fts, size_t inc)
6984887Schin {
6994887Schin 	register char*	old;
7004887Schin 	register char*	newp;
70110898Sroland.mainz@nrubsig.org 	register size_t	n_old;
7024887Schin 
7034887Schin 	/*
7044887Schin 	 * add space for "/." used in testing FTS_DNX
7054887Schin 	 */
7064887Schin 
7074887Schin 	n_old = fts->homesize;
7084887Schin 	fts->homesize = ((fts->homesize + inc + 4) / PATH_MAX + 1) * PATH_MAX;
7094887Schin 	if (!(newp = newof(0, char, fts->homesize, 0)))
7104887Schin 	{
7114887Schin 		fts->fts_errno = errno;
7124887Schin 		fts->state = FTS_error;
7134887Schin 		return -1;
7144887Schin 	}
7154887Schin 	old = fts->home;
7164887Schin 	fts->home = newp;
7174887Schin 	memcpy(newp, old, n_old);
7184887Schin 	if (fts->endbuf)
7194887Schin 		fts->endbuf = newp + fts->homesize - 4;
7204887Schin 	if (fts->path)
7214887Schin 		fts->path = newp + (fts->path - old);
7224887Schin 	if (fts->base)
7234887Schin 		fts->base = newp + (fts->base - old);
7244887Schin 	free(old);
7254887Schin 	return 0;
7264887Schin }
7274887Schin 
7284887Schin /*
7294887Schin  * open a new fts stream on pathnames
7304887Schin  */
7314887Schin 
7324887Schin FTS*
fts_open(char * const * pathnames,int flags,int (* comparf)(FTSENT * const *,FTSENT * const *))7334887Schin fts_open(char* const* pathnames, int flags, int (*comparf)(FTSENT* const*, FTSENT* const*))
7344887Schin {
7354887Schin 	register FTS*	fts;
7364887Schin 
7374887Schin 	if (!(fts = newof(0, FTS, 1, sizeof(FTSENT))))
7384887Schin 		return 0;
7394887Schin 	fts->flags = flags;
7404887Schin 	fts->cd = (flags & FTS_NOCHDIR) ? 1 : -1;
7414887Schin 	fts->comparf = comparf;
7424887Schin 	fts->fs3d = fs3d(FS3D_TEST);
7434887Schin 
7444887Schin 	/*
7454887Schin 	 * set up the path work buffer
7464887Schin 	 */
7474887Schin 
7484887Schin 	fts->homesize = 2 * PATH_MAX;
7494887Schin 	for (;;)
7504887Schin 	{
7514887Schin 		if (!(fts->home = newof(fts->home, char, fts->homesize, 0)))
7524887Schin 		{
7534887Schin 			free(fts);
7544887Schin 			return 0;
7554887Schin 		}
7564887Schin 		if (fts->cd > 0 || getcwd(fts->home, fts->homesize))
7574887Schin 			break;
7584887Schin 		if (errno == ERANGE)
7594887Schin 			fts->homesize += PATH_MAX;
7604887Schin 		else
7614887Schin 			fts->cd = 1;
7624887Schin 	}
7634887Schin 	fts->endbuf = fts->home + fts->homesize - 4;
7644887Schin 
7654887Schin 	/*
7664887Schin 	 * initialize the tippity-top
7674887Schin 	 */
7684887Schin 
7694887Schin 	fts->parent = (FTSENT*)(fts + 1);
7704887Schin 	fts->parent->fts_info = FTS_D;
7714887Schin 	memcpy(fts->parent->fts_accpath = fts->parent->fts_path = fts->parent->fts_name = fts->parent->name, ".", 2);
7724887Schin 	fts->parent->fts_level = -1;
77310898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
77410898Sroland.mainz@nrubsig.org 	fts->parent->_fts_level = (short)fts->parent->fts_level;
77510898Sroland.mainz@nrubsig.org #endif
7764887Schin 	fts->parent->fts_statp = &fts->parent->statb;
7774887Schin 	fts->parent->must = 2;
7784887Schin 	fts->parent->type = DT_UNKNOWN;
7794887Schin 	fts->path = fts->home + strlen(fts->home) + 1;
7804887Schin 
7814887Schin 	/*
7824887Schin 	 * make the list of top elements
7834887Schin 	 */
7844887Schin 
7854887Schin 	if (!pathnames || (flags & FTS_ONEPATH) || !*pathnames)
7864887Schin 	{
7874887Schin 		char*	v[2];
7884887Schin 
7894887Schin 		v[0] = pathnames && (flags & FTS_ONEPATH) ? (char*)pathnames : ".";
7904887Schin 		v[1] = 0;
7914887Schin 		fts->todo = toplist(fts, v);
7924887Schin 	}
7934887Schin 	else
7944887Schin 		fts->todo = toplist(fts, pathnames);
7954887Schin 	if (!fts->todo || fts->todo->fts_info == FTS_NS && !fts->todo->fts_link)
7964887Schin 	{
7974887Schin 		fts_close(fts);
7984887Schin 		return 0;
7994887Schin 	}
8004887Schin 	return fts;
8014887Schin }
8024887Schin 
8034887Schin /*
8044887Schin  * return the next FTS entry
8054887Schin  */
8064887Schin 
8074887Schin FTSENT*
fts_read(register FTS * fts)8084887Schin fts_read(register FTS* fts)
8094887Schin {
8104887Schin 	register char*		s;
8114887Schin 	register int		n;
8124887Schin 	register FTSENT*	f;
8134887Schin 	struct dirent*		d;
81410898Sroland.mainz@nrubsig.org 	size_t			i;
8154887Schin 	FTSENT*			t;
8164887Schin 	Notify_t*		p;
8174887Schin #ifdef verify
8184887Schin 	struct stat		sb;
8194887Schin #endif
8204887Schin 
82110898Sroland.mainz@nrubsig.org 	for (;;)
82210898Sroland.mainz@nrubsig.org 		switch (fts->state)
82310898Sroland.mainz@nrubsig.org 		{
8244887Schin 
82510898Sroland.mainz@nrubsig.org 		case FTS_top_return:
8264887Schin 
82710898Sroland.mainz@nrubsig.org 			f = fts->todo;
82810898Sroland.mainz@nrubsig.org 			t = 0;
82910898Sroland.mainz@nrubsig.org 			while (f)
83010898Sroland.mainz@nrubsig.org 				if (f->status == FTS_SKIP)
8314887Schin 				{
83210898Sroland.mainz@nrubsig.org 					if (t)
83310898Sroland.mainz@nrubsig.org 					{
83410898Sroland.mainz@nrubsig.org 						t->fts_link = f->fts_link;
83510898Sroland.mainz@nrubsig.org 						drop(fts, f);
83610898Sroland.mainz@nrubsig.org 						f = t->fts_link;
83710898Sroland.mainz@nrubsig.org 					}
83810898Sroland.mainz@nrubsig.org 					else
83910898Sroland.mainz@nrubsig.org 					{
84010898Sroland.mainz@nrubsig.org 						fts->todo = f->fts_link;
84110898Sroland.mainz@nrubsig.org 						drop(fts, f);
84210898Sroland.mainz@nrubsig.org 						f = fts->todo;
84310898Sroland.mainz@nrubsig.org 					}
8444887Schin 				}
8454887Schin 				else
8464887Schin 				{
84710898Sroland.mainz@nrubsig.org 					t = f;
84810898Sroland.mainz@nrubsig.org 					f = f->fts_link;
84910898Sroland.mainz@nrubsig.org 				}
85010898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
85110898Sroland.mainz@nrubsig.org 
85210898Sroland.mainz@nrubsig.org 		case 0:
85310898Sroland.mainz@nrubsig.org 
85410898Sroland.mainz@nrubsig.org 			if (!fts->state && fts->comparf)
85510898Sroland.mainz@nrubsig.org 				order(fts);
85610898Sroland.mainz@nrubsig.org 			if (!(f = fts->todo))
85710898Sroland.mainz@nrubsig.org 				return 0;
85810898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
85910898Sroland.mainz@nrubsig.org 
86010898Sroland.mainz@nrubsig.org 		case FTS_todo:
86110898Sroland.mainz@nrubsig.org 
86210898Sroland.mainz@nrubsig.org 			/*
86310898Sroland.mainz@nrubsig.org 			 * process the top object on the stack
86410898Sroland.mainz@nrubsig.org 			 */
86510898Sroland.mainz@nrubsig.org 
86610898Sroland.mainz@nrubsig.org 			fts->root = fts->top = fts->bot = 0;
86710898Sroland.mainz@nrubsig.org 
86810898Sroland.mainz@nrubsig.org 			/*
86910898Sroland.mainz@nrubsig.org 			 * initialize the top level
87010898Sroland.mainz@nrubsig.org 			 */
87110898Sroland.mainz@nrubsig.org 
87210898Sroland.mainz@nrubsig.org 			if (f->fts_level == 0)
87310898Sroland.mainz@nrubsig.org 			{
87410898Sroland.mainz@nrubsig.org 				fts->parent->fts_number = f->fts_number;
87510898Sroland.mainz@nrubsig.org 				fts->parent->fts_pointer = f->fts_pointer;
87610898Sroland.mainz@nrubsig.org 				fts->parent->fts_statp = f->fts_statp;
87710898Sroland.mainz@nrubsig.org 				fts->parent->statb = *f->fts_statp;
87810898Sroland.mainz@nrubsig.org 				f->fts_parent = fts->parent;
87910898Sroland.mainz@nrubsig.org 				fts->diroot = 0;
88010898Sroland.mainz@nrubsig.org 				if (fts->cd == 0)
88110898Sroland.mainz@nrubsig.org 					pathcd(fts->home, NiL);
88210898Sroland.mainz@nrubsig.org 				else if (fts->cd < 0)
88310898Sroland.mainz@nrubsig.org 					fts->cd = 0;
88410898Sroland.mainz@nrubsig.org 				fts->pwd = f->fts_parent;
88510898Sroland.mainz@nrubsig.org 				fts->curdir = fts->cd ? 0 : f->fts_parent;
88610898Sroland.mainz@nrubsig.org 				*(fts->base = fts->path) = 0;
88710898Sroland.mainz@nrubsig.org 			}
88810898Sroland.mainz@nrubsig.org 
88910898Sroland.mainz@nrubsig.org 			/*
89010898Sroland.mainz@nrubsig.org 			 * chdir to parent if asked for
89110898Sroland.mainz@nrubsig.org 			 */
89210898Sroland.mainz@nrubsig.org 
89310898Sroland.mainz@nrubsig.org 			if (fts->cd < 0)
89410898Sroland.mainz@nrubsig.org 			{
89510898Sroland.mainz@nrubsig.org 				fts->cd = setdir(fts->home, fts->path);
89610898Sroland.mainz@nrubsig.org 				fts->pwd = f->fts_parent;
89710898Sroland.mainz@nrubsig.org 				fts->curdir = fts->cd ? 0 : f->fts_parent;
89810898Sroland.mainz@nrubsig.org 			}
89910898Sroland.mainz@nrubsig.org 
90010898Sroland.mainz@nrubsig.org 			/*
90110898Sroland.mainz@nrubsig.org 			 * add object's name to the path
90210898Sroland.mainz@nrubsig.org 			 */
90310898Sroland.mainz@nrubsig.org 
90410898Sroland.mainz@nrubsig.org 			if ((fts->baselen = f->fts_namelen) >= (fts->endbuf - fts->base) && resize(fts, fts->baselen))
90510898Sroland.mainz@nrubsig.org 				return 0;
90610898Sroland.mainz@nrubsig.org 			memcpy(fts->base, f->name, fts->baselen + 1);
90710898Sroland.mainz@nrubsig.org 			fts->name = fts->cd ? fts->path : fts->base;
90810898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
90910898Sroland.mainz@nrubsig.org 
91010898Sroland.mainz@nrubsig.org 		case FTS_preorder:
91110898Sroland.mainz@nrubsig.org 
91210898Sroland.mainz@nrubsig.org 			/*
91310898Sroland.mainz@nrubsig.org 			 * check for cycle and open dir
91410898Sroland.mainz@nrubsig.org 			 */
91510898Sroland.mainz@nrubsig.org 
91610898Sroland.mainz@nrubsig.org 			if (f->fts_info == FTS_D)
91710898Sroland.mainz@nrubsig.org 			{
91810898Sroland.mainz@nrubsig.org 				if ((fts->diroot = search(f, fts->diroot, statcmp, 0)) != f || f->fts_level > 0 && (t = f) && statcmp(&t, &f->fts_parent) == 0)
91910898Sroland.mainz@nrubsig.org 				{
92010898Sroland.mainz@nrubsig.org 					f->fts_info = FTS_DC;
92110898Sroland.mainz@nrubsig.org 					f->fts_cycle = fts->diroot;
92210898Sroland.mainz@nrubsig.org 				}
92310898Sroland.mainz@nrubsig.org 				else if (!(fts->flags & FTS_TOP) && (!(fts->flags & FTS_XDEV) || f->statb.st_dev == f->fts_parent->statb.st_dev))
92410898Sroland.mainz@nrubsig.org 				{
92510898Sroland.mainz@nrubsig.org 					/*
92610898Sroland.mainz@nrubsig.org 					 * buffer is known to be large enough here!
92710898Sroland.mainz@nrubsig.org 					 */
92810898Sroland.mainz@nrubsig.org 
92910898Sroland.mainz@nrubsig.org 					if (fts->base[fts->baselen - 1] != '/')
93010898Sroland.mainz@nrubsig.org 						memcpy(fts->base + fts->baselen, "/.", 3);
93110898Sroland.mainz@nrubsig.org 					if (!(fts->dir = opendir(fts->name)))
93210898Sroland.mainz@nrubsig.org 						f->fts_info = FTS_DNX;
93310898Sroland.mainz@nrubsig.org 					fts->base[fts->baselen] = 0;
93410898Sroland.mainz@nrubsig.org 					if (!fts->dir && !(fts->dir = opendir(fts->name)))
93510898Sroland.mainz@nrubsig.org 						f->fts_info = FTS_DNR;
9364887Schin 				}
9374887Schin 			}
93810898Sroland.mainz@nrubsig.org 			f->nd = f->fts_info & ~FTS_DNX;
93910898Sroland.mainz@nrubsig.org 			if (f->nd || !(fts->flags & FTS_NOPREORDER))
9404887Schin 			{
94110898Sroland.mainz@nrubsig.org 				fts->current = f;
94210898Sroland.mainz@nrubsig.org 				fts->link = f->fts_link;
94310898Sroland.mainz@nrubsig.org 				f->fts_link = 0;
94410898Sroland.mainz@nrubsig.org 				f->fts_path = PATH(fts, fts->path, f->fts_level);
94510898Sroland.mainz@nrubsig.org 				f->fts_pathlen = (fts->base - f->fts_path) + fts->baselen;
94610898Sroland.mainz@nrubsig.org 				f->fts_accpath = ACCESS(fts, f);
94710898Sroland.mainz@nrubsig.org 				fts->state = FTS_preorder_return;
94810898Sroland.mainz@nrubsig.org 				goto note;
9494887Schin 			}
95010898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
9514887Schin 
95210898Sroland.mainz@nrubsig.org 		case FTS_preorder_resume:
9534887Schin 
95410898Sroland.mainz@nrubsig.org 			/*
95510898Sroland.mainz@nrubsig.org 			 * prune
95610898Sroland.mainz@nrubsig.org 			 */
9574887Schin 
95810898Sroland.mainz@nrubsig.org 			if (!fts->dir || f->nd || f->status == FTS_SKIP)
95910898Sroland.mainz@nrubsig.org 			{
96010898Sroland.mainz@nrubsig.org 				if (fts->dir)
96110898Sroland.mainz@nrubsig.org 				{
96210898Sroland.mainz@nrubsig.org 					closedir(fts->dir);
96310898Sroland.mainz@nrubsig.org 					fts->dir = 0;
96410898Sroland.mainz@nrubsig.org 				}
96510898Sroland.mainz@nrubsig.org 				fts->state = FTS_popstack;
96610898Sroland.mainz@nrubsig.org 				continue;
96710898Sroland.mainz@nrubsig.org 			}
9684887Schin 
96910898Sroland.mainz@nrubsig.org 			/*
97010898Sroland.mainz@nrubsig.org 			 * FTS_D or FTS_DNX, about to read children
97110898Sroland.mainz@nrubsig.org 			 */
9724887Schin 
97310898Sroland.mainz@nrubsig.org 			if (fts->cd == 0)
97410898Sroland.mainz@nrubsig.org 			{
97510898Sroland.mainz@nrubsig.org 				if ((fts->cd = chdir(fts->name)) < 0)
97610898Sroland.mainz@nrubsig.org 					pathcd(fts->home, NiL);
97710898Sroland.mainz@nrubsig.org 				else if (fts->pwd != f)
97810898Sroland.mainz@nrubsig.org 				{
97910898Sroland.mainz@nrubsig.org 					f->pwd = fts->pwd;
98010898Sroland.mainz@nrubsig.org 					fts->pwd = f;
98110898Sroland.mainz@nrubsig.org 				}
98210898Sroland.mainz@nrubsig.org 				fts->curdir = fts->cd < 0 ? 0 : f;
9834887Schin 			}
98410898Sroland.mainz@nrubsig.org 			fts->nostat = fts->children > 1 || f->fts_info == FTS_DNX;
98510898Sroland.mainz@nrubsig.org 			fts->cpname = fts->cd && !fts->nostat || !fts->children && !fts->comparf;
98610898Sroland.mainz@nrubsig.org 			fts->dotdot = 0;
98710898Sroland.mainz@nrubsig.org 			fts->endbase = fts->base + fts->baselen;
98810898Sroland.mainz@nrubsig.org 			if (fts->endbase[-1] != '/')
98910898Sroland.mainz@nrubsig.org 				*fts->endbase++ = '/';
9904887Schin 			fts->current = f;
99110898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
9924887Schin 
99310898Sroland.mainz@nrubsig.org 		case FTS_readdir:
9944887Schin 
99510898Sroland.mainz@nrubsig.org 			while (d = readdir(fts->dir))
9964887Schin 			{
99710898Sroland.mainz@nrubsig.org 				s = d->d_name;
99810898Sroland.mainz@nrubsig.org 				if (s[0] == '.')
9994887Schin 				{
100010898Sroland.mainz@nrubsig.org 					if (s[1] == 0)
100110898Sroland.mainz@nrubsig.org 					{
100210898Sroland.mainz@nrubsig.org 						fts->current->nlink--;
100310898Sroland.mainz@nrubsig.org 						if (!(fts->flags & FTS_SEEDOT))
100410898Sroland.mainz@nrubsig.org 							continue;
100510898Sroland.mainz@nrubsig.org 						n = 1;
100610898Sroland.mainz@nrubsig.org 					}
100710898Sroland.mainz@nrubsig.org 					else if (s[1] == '.' && s[2] == 0)
100810898Sroland.mainz@nrubsig.org 					{
100910898Sroland.mainz@nrubsig.org 						fts->current->nlink--;
101010898Sroland.mainz@nrubsig.org 						if (fts->current->must == 1)
101110898Sroland.mainz@nrubsig.org 							fts->current->must = 0;
101210898Sroland.mainz@nrubsig.org 						if (!(fts->flags & FTS_SEEDOT))
101310898Sroland.mainz@nrubsig.org 							continue;
101410898Sroland.mainz@nrubsig.org 						n = 2;
101510898Sroland.mainz@nrubsig.org 					}
101610898Sroland.mainz@nrubsig.org 					else
101710898Sroland.mainz@nrubsig.org 						n = 0;
10184887Schin 				}
10194887Schin 				else
10204887Schin 					n = 0;
10214887Schin 
10224887Schin 				/*
102310898Sroland.mainz@nrubsig.org 				 * make a new entry
10244887Schin 				 */
10254887Schin 
102610898Sroland.mainz@nrubsig.org 				i = D_NAMLEN(d);
102710898Sroland.mainz@nrubsig.org 				if (!(f = node(fts, fts->current, s, i)))
102810898Sroland.mainz@nrubsig.org 					return 0;
102910898Sroland.mainz@nrubsig.org 				TYPE(f, D_TYPE(d));
103010898Sroland.mainz@nrubsig.org 
10314887Schin 				/*
103210898Sroland.mainz@nrubsig.org 				 * check for space
10334887Schin 				 */
10344887Schin 
103510898Sroland.mainz@nrubsig.org 				if (i >= fts->endbuf - fts->endbase)
10364887Schin 				{
103710898Sroland.mainz@nrubsig.org 		   	   		if (resize(fts, i))
103810898Sroland.mainz@nrubsig.org 						return 0;
103910898Sroland.mainz@nrubsig.org 					fts->endbase = fts->base + fts->baselen;
104010898Sroland.mainz@nrubsig.org 					if (fts->endbase[-1] != '/')
104110898Sroland.mainz@nrubsig.org 						fts->endbase++;
10424887Schin 				}
104310898Sroland.mainz@nrubsig.org 				if (fts->cpname)
104410898Sroland.mainz@nrubsig.org 				{
104510898Sroland.mainz@nrubsig.org 					memcpy(fts->endbase, s, i + 1);
104610898Sroland.mainz@nrubsig.org 					if (fts->cd)
104710898Sroland.mainz@nrubsig.org 						s = fts->path;
104810898Sroland.mainz@nrubsig.org 				}
104910898Sroland.mainz@nrubsig.org 				if (n)
10504887Schin 				{
10514887Schin 					/*
105210898Sroland.mainz@nrubsig.org 					 * don't recurse on . and ..
10534887Schin 					 */
10544887Schin 
105510898Sroland.mainz@nrubsig.org 					if (n == 1)
105610898Sroland.mainz@nrubsig.org 						f->fts_statp = fts->current->fts_statp;
105710898Sroland.mainz@nrubsig.org 					else
105810898Sroland.mainz@nrubsig.org 					{
105910898Sroland.mainz@nrubsig.org 						if (f->fts_info != FTS_NS)
106010898Sroland.mainz@nrubsig.org 							fts->dotdot = f;
106110898Sroland.mainz@nrubsig.org 						if (fts->current->fts_parent->fts_level < 0)
106210898Sroland.mainz@nrubsig.org 						{
106310898Sroland.mainz@nrubsig.org 							f->fts_statp = &fts->current->fts_parent->statb;
106410898Sroland.mainz@nrubsig.org 							info(fts, f, s, f->fts_statp, 0);
106510898Sroland.mainz@nrubsig.org 						}
106610898Sroland.mainz@nrubsig.org 						else
106710898Sroland.mainz@nrubsig.org 							f->fts_statp = fts->current->fts_parent->fts_statp;
106810898Sroland.mainz@nrubsig.org 					}
106910898Sroland.mainz@nrubsig.org 					f->fts_info = FTS_DOT;
107010898Sroland.mainz@nrubsig.org 				}
107110898Sroland.mainz@nrubsig.org 				else if ((fts->nostat || SKIP(fts, f)) && (f->fts_info = FTS_NSOK) || info(fts, f, s, &f->statb, fts->flags))
107210898Sroland.mainz@nrubsig.org 					f->statb.st_ino = D_FILENO(d);
107310898Sroland.mainz@nrubsig.org 				if (fts->comparf)
107410898Sroland.mainz@nrubsig.org 					fts->root = search(f, fts->root, fts->comparf, 1);
107510898Sroland.mainz@nrubsig.org 				else if (fts->children || f->fts_info == FTS_D || f->fts_info == FTS_SL)
107610898Sroland.mainz@nrubsig.org 				{
107710898Sroland.mainz@nrubsig.org 					if (fts->top)
107810898Sroland.mainz@nrubsig.org 						fts->bot = fts->bot->fts_link = f;
107910898Sroland.mainz@nrubsig.org 					else
108010898Sroland.mainz@nrubsig.org 						fts->top = fts->bot = f;
108110898Sroland.mainz@nrubsig.org 				}
108210898Sroland.mainz@nrubsig.org 				else
108310898Sroland.mainz@nrubsig.org 				{
10844887Schin 					/*
108510898Sroland.mainz@nrubsig.org 					 * terminal node
10864887Schin 					 */
10874887Schin 
108810898Sroland.mainz@nrubsig.org 					f->fts_path = PATH(fts, fts->path, 1);
108910898Sroland.mainz@nrubsig.org 					f->fts_pathlen = fts->endbase - f->fts_path + f->fts_namelen;
109010898Sroland.mainz@nrubsig.org 					f->fts_accpath = ACCESS(fts, f);
109110898Sroland.mainz@nrubsig.org 					fts->previous = fts->current;
109210898Sroland.mainz@nrubsig.org 					fts->current = f;
109310898Sroland.mainz@nrubsig.org 					fts->state = FTS_terminal;
10944887Schin 					goto note;
10954887Schin 				}
10964887Schin 			}
10974887Schin 
10984887Schin 			/*
109910898Sroland.mainz@nrubsig.org 			 * done with the directory
110010898Sroland.mainz@nrubsig.org 			 */
110110898Sroland.mainz@nrubsig.org 
110210898Sroland.mainz@nrubsig.org 			closedir(fts->dir);
110310898Sroland.mainz@nrubsig.org 			fts->dir = 0;
110410898Sroland.mainz@nrubsig.org 			if (fts->root)
110510898Sroland.mainz@nrubsig.org 				getlist(&fts->top, &fts->bot, fts->root);
110610898Sroland.mainz@nrubsig.org 			if (fts->children)
110710898Sroland.mainz@nrubsig.org 			{
110810898Sroland.mainz@nrubsig.org 				/*
110910898Sroland.mainz@nrubsig.org 				 * try moving back to parent dir
111010898Sroland.mainz@nrubsig.org 				 */
111110898Sroland.mainz@nrubsig.org 
111210898Sroland.mainz@nrubsig.org 				fts->base[fts->baselen] = 0;
111310898Sroland.mainz@nrubsig.org 				if (fts->cd <= 0)
111410898Sroland.mainz@nrubsig.org 				{
111510898Sroland.mainz@nrubsig.org 					f = fts->current->fts_parent;
111610898Sroland.mainz@nrubsig.org 					if (fts->cd < 0
111710898Sroland.mainz@nrubsig.org 					    || f != fts->curdir
111810898Sroland.mainz@nrubsig.org 					    || !fts->dotdot
111910898Sroland.mainz@nrubsig.org 					    || !SAME(f->fts_statp, fts->dotdot->fts_statp)
112010898Sroland.mainz@nrubsig.org 					    || fts->pwd && fts->pwd->symlink
112110898Sroland.mainz@nrubsig.org 					    || (fts->cd = chdir("..")) < 0
112210898Sroland.mainz@nrubsig.org #ifdef verify
112310898Sroland.mainz@nrubsig.org 					    || stat(".", &sb) < 0
112410898Sroland.mainz@nrubsig.org 					    || !SAME(&sb, fts->dotdot->fts_statp)
112510898Sroland.mainz@nrubsig.org #endif
112610898Sroland.mainz@nrubsig.org 					    )
112710898Sroland.mainz@nrubsig.org 						fts->cd = setpdir(fts->home, fts->path, fts->base);
112810898Sroland.mainz@nrubsig.org 					if (fts->pwd)
112910898Sroland.mainz@nrubsig.org 						fts->pwd = fts->pwd->pwd;
113010898Sroland.mainz@nrubsig.org 					fts->curdir = fts->cd ? 0 : f;
113110898Sroland.mainz@nrubsig.org 				}
113210898Sroland.mainz@nrubsig.org 				f = fts->current;
113310898Sroland.mainz@nrubsig.org 				fts->link = f->fts_link;
113410898Sroland.mainz@nrubsig.org 				f->fts_link = fts->top;
113510898Sroland.mainz@nrubsig.org 				f->fts_path = PATH(fts, fts->path, f->fts_level);
113610898Sroland.mainz@nrubsig.org 				f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen;
113710898Sroland.mainz@nrubsig.org 				f->fts_accpath = ACCESS(fts, f);
113810898Sroland.mainz@nrubsig.org 				fts->state = FTS_children_return;
113910898Sroland.mainz@nrubsig.org 				goto note;
114010898Sroland.mainz@nrubsig.org 			}
114110898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
114210898Sroland.mainz@nrubsig.org 
114310898Sroland.mainz@nrubsig.org 		case FTS_children_resume:
114410898Sroland.mainz@nrubsig.org 
114510898Sroland.mainz@nrubsig.org 			fts->base[fts->baselen] = 0;
114610898Sroland.mainz@nrubsig.org 			if (fts->top)
114710898Sroland.mainz@nrubsig.org 			{
114810898Sroland.mainz@nrubsig.org 				fts->bot->fts_link = fts->todo;
114910898Sroland.mainz@nrubsig.org 				fts->todo = fts->top;
115010898Sroland.mainz@nrubsig.org 				fts->top = 0;
115110898Sroland.mainz@nrubsig.org 			}
115210898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
115310898Sroland.mainz@nrubsig.org 
115410898Sroland.mainz@nrubsig.org 		case FTS_popstack:
115510898Sroland.mainz@nrubsig.org 
115610898Sroland.mainz@nrubsig.org 			/*
115710898Sroland.mainz@nrubsig.org 			 * pop objects completely processed
11584887Schin 			 */
11594887Schin 
116010898Sroland.mainz@nrubsig.org 			fts->nd = 0;
116110898Sroland.mainz@nrubsig.org 			f = fts->current;
116210898Sroland.mainz@nrubsig.org 			/*FALLTHROUGH*/
116310898Sroland.mainz@nrubsig.org 
116410898Sroland.mainz@nrubsig.org 		case FTS_popstack_resume:
116510898Sroland.mainz@nrubsig.org 
116610898Sroland.mainz@nrubsig.org 			while (fts->todo && f == fts->todo)
116710898Sroland.mainz@nrubsig.org 			{
116810898Sroland.mainz@nrubsig.org 				t = f->fts_parent;
116910898Sroland.mainz@nrubsig.org 				if ((f->fts_info & FTS_DP) == FTS_D)
117010898Sroland.mainz@nrubsig.org 				{
117110898Sroland.mainz@nrubsig.org 					/*
117210898Sroland.mainz@nrubsig.org 					 * delete from <dev,ino> tree
117310898Sroland.mainz@nrubsig.org 					 */
117410898Sroland.mainz@nrubsig.org 
117510898Sroland.mainz@nrubsig.org 					if (f != fts->diroot)
117610898Sroland.mainz@nrubsig.org 						fts->diroot = search(f, fts->diroot, statcmp, 0);
117710898Sroland.mainz@nrubsig.org 					fts->diroot = deleteroot(fts->diroot);
117810898Sroland.mainz@nrubsig.org 					if (f == fts->curdir)
117910898Sroland.mainz@nrubsig.org 					{
118010898Sroland.mainz@nrubsig.org 						fts->nd++;
118110898Sroland.mainz@nrubsig.org 						fts->curdir = t;
118210898Sroland.mainz@nrubsig.org 					}
118310898Sroland.mainz@nrubsig.org 
118410898Sroland.mainz@nrubsig.org 					/*
118510898Sroland.mainz@nrubsig.org 					 * perform post-order processing
118610898Sroland.mainz@nrubsig.org 					 */
118710898Sroland.mainz@nrubsig.org 
118810898Sroland.mainz@nrubsig.org 					if (!(fts->flags & FTS_NOPOSTORDER) &&
118910898Sroland.mainz@nrubsig.org 					    f->status != FTS_SKIP &&
119010898Sroland.mainz@nrubsig.org 					    f->status != FTS_NOPOSTORDER)
119110898Sroland.mainz@nrubsig.org 					{
119210898Sroland.mainz@nrubsig.org 						/*
119310898Sroland.mainz@nrubsig.org 						 * move to parent dir
119410898Sroland.mainz@nrubsig.org 						 */
119510898Sroland.mainz@nrubsig.org 
119610898Sroland.mainz@nrubsig.org 						if (fts->nd > 0)
119710898Sroland.mainz@nrubsig.org 							fts->cd = popdirs(fts);
119810898Sroland.mainz@nrubsig.org 						if (fts->cd < 0)
119910898Sroland.mainz@nrubsig.org 							fts->cd = setpdir(fts->home, fts->path, fts->base);
120010898Sroland.mainz@nrubsig.org 						fts->curdir = fts->cd ? 0 : t;
120110898Sroland.mainz@nrubsig.org 						f->fts_info = FTS_DP;
120210898Sroland.mainz@nrubsig.org 						f->fts_path = PATH(fts, fts->path, f->fts_level);
120310898Sroland.mainz@nrubsig.org 						f->fts_pathlen = (fts->base - f->fts_path) + f->fts_namelen;
120410898Sroland.mainz@nrubsig.org 						f->fts_accpath = ACCESS(fts, f);
120510898Sroland.mainz@nrubsig.org 
120610898Sroland.mainz@nrubsig.org 						/*
120710898Sroland.mainz@nrubsig.org 						 * re-stat to update nlink/times
120810898Sroland.mainz@nrubsig.org 						 */
120910898Sroland.mainz@nrubsig.org 
121010898Sroland.mainz@nrubsig.org 						stat(f->fts_accpath, f->fts_statp);
121110898Sroland.mainz@nrubsig.org 						fts->link = f->fts_link;
121210898Sroland.mainz@nrubsig.org 						f->fts_link = 0;
121310898Sroland.mainz@nrubsig.org 						fts->state = FTS_popstack_return;
121410898Sroland.mainz@nrubsig.org 						goto note;
121510898Sroland.mainz@nrubsig.org 					}
121610898Sroland.mainz@nrubsig.org 				}
121710898Sroland.mainz@nrubsig.org 
121810898Sroland.mainz@nrubsig.org 				/*
121910898Sroland.mainz@nrubsig.org 				 * reset base
122010898Sroland.mainz@nrubsig.org 				 */
122110898Sroland.mainz@nrubsig.org 
122210898Sroland.mainz@nrubsig.org 				if (fts->base > fts->path + t->fts_namelen)
122310898Sroland.mainz@nrubsig.org 					fts->base--;
122410898Sroland.mainz@nrubsig.org 				*fts->base = 0;
122510898Sroland.mainz@nrubsig.org 				fts->base -= t->fts_namelen;
122610898Sroland.mainz@nrubsig.org 
122710898Sroland.mainz@nrubsig.org 				/*
122810898Sroland.mainz@nrubsig.org 				 * try again or delete from top of stack
122910898Sroland.mainz@nrubsig.org 				 */
123010898Sroland.mainz@nrubsig.org 
123110898Sroland.mainz@nrubsig.org 				if (f->status == FTS_AGAIN)
123210898Sroland.mainz@nrubsig.org 				{
123310898Sroland.mainz@nrubsig.org 					f->fts_info = FTS_D;
123410898Sroland.mainz@nrubsig.org 					f->status = 0;
123510898Sroland.mainz@nrubsig.org 				}
123610898Sroland.mainz@nrubsig.org 				else
123710898Sroland.mainz@nrubsig.org 				{
123810898Sroland.mainz@nrubsig.org 					fts->todo = fts->todo->fts_link;
123910898Sroland.mainz@nrubsig.org 					drop(fts, f);
124010898Sroland.mainz@nrubsig.org 				}
124110898Sroland.mainz@nrubsig.org 				f = t;
124210898Sroland.mainz@nrubsig.org 			}
12434887Schin 
12444887Schin 			/*
124510898Sroland.mainz@nrubsig.org 			 * reset current directory
12464887Schin 			 */
12474887Schin 
124810898Sroland.mainz@nrubsig.org 			if (fts->nd > 0 && popdirs(fts) < 0)
12494887Schin 			{
125010898Sroland.mainz@nrubsig.org 				pathcd(fts->home, NiL);
125110898Sroland.mainz@nrubsig.org 				fts->curdir = 0;
125210898Sroland.mainz@nrubsig.org 				fts->cd = -1;
12534887Schin 			}
125410898Sroland.mainz@nrubsig.org 			if (fts->todo)
12554887Schin 			{
125610898Sroland.mainz@nrubsig.org 				if (*fts->base)
125710898Sroland.mainz@nrubsig.org 					fts->base += f->fts_namelen;
125810898Sroland.mainz@nrubsig.org 				if (*(fts->base - 1) != '/')
125910898Sroland.mainz@nrubsig.org 					*fts->base++ = '/';
126010898Sroland.mainz@nrubsig.org 				*fts->base = 0;
126110898Sroland.mainz@nrubsig.org 				f = fts->todo;
126210898Sroland.mainz@nrubsig.org 				fts->state = FTS_todo;
126310898Sroland.mainz@nrubsig.org 				continue;
12644887Schin 			}
126510898Sroland.mainz@nrubsig.org 			return 0;
12664887Schin 
126710898Sroland.mainz@nrubsig.org 		case FTS_children_return:
12684887Schin 
126910898Sroland.mainz@nrubsig.org 			f = fts->current;
127010898Sroland.mainz@nrubsig.org 			f->fts_link = fts->link;
127110898Sroland.mainz@nrubsig.org 
127210898Sroland.mainz@nrubsig.org 			/*
127310898Sroland.mainz@nrubsig.org 			 * chdir down again
127410898Sroland.mainz@nrubsig.org 			 */
12754887Schin 
127610898Sroland.mainz@nrubsig.org 			i = f->fts_info != FTS_DNX;
127710898Sroland.mainz@nrubsig.org 			n = f->status == FTS_SKIP;
127810898Sroland.mainz@nrubsig.org 			if (!n && fts->cd == 0)
127910898Sroland.mainz@nrubsig.org 			{
128010898Sroland.mainz@nrubsig.org 				if ((fts->cd = chdir(fts->base)) < 0)
128110898Sroland.mainz@nrubsig.org 					pathcd(fts->home, NiL);
128210898Sroland.mainz@nrubsig.org 				else if (fts->pwd != f)
128310898Sroland.mainz@nrubsig.org 				{
128410898Sroland.mainz@nrubsig.org 					f->pwd = fts->pwd;
128510898Sroland.mainz@nrubsig.org 					fts->pwd = f;
128610898Sroland.mainz@nrubsig.org 				}
128710898Sroland.mainz@nrubsig.org 				fts->curdir = fts->cd ? 0 : f;
128810898Sroland.mainz@nrubsig.org 			}
12894887Schin 
129010898Sroland.mainz@nrubsig.org 			/*
129110898Sroland.mainz@nrubsig.org 			 * prune
129210898Sroland.mainz@nrubsig.org 			 */
12934887Schin 
129410898Sroland.mainz@nrubsig.org 			if (fts->base[fts->baselen - 1] != '/')
129510898Sroland.mainz@nrubsig.org 				fts->base[fts->baselen] = '/';
129610898Sroland.mainz@nrubsig.org 			for (fts->bot = 0, f = fts->top; f; )
129710898Sroland.mainz@nrubsig.org 				if (n || f->status == FTS_SKIP)
129810898Sroland.mainz@nrubsig.org 				{
129910898Sroland.mainz@nrubsig.org 					if (fts->bot)
130010898Sroland.mainz@nrubsig.org 						fts->bot->fts_link = f->fts_link;
130110898Sroland.mainz@nrubsig.org 					else
130210898Sroland.mainz@nrubsig.org 						fts->top = f->fts_link;
130310898Sroland.mainz@nrubsig.org 					drop(fts, f);
130410898Sroland.mainz@nrubsig.org 					f = fts->bot ? fts->bot->fts_link : fts->top;
130510898Sroland.mainz@nrubsig.org 				}
130610898Sroland.mainz@nrubsig.org 				else
130710898Sroland.mainz@nrubsig.org 				{
130810898Sroland.mainz@nrubsig.org 					if (fts->children > 1 && i)
130910898Sroland.mainz@nrubsig.org 					{
131010898Sroland.mainz@nrubsig.org 						if (f->status == FTS_STAT)
131110898Sroland.mainz@nrubsig.org 							info(fts, f, NiL, f->fts_statp, 0);
131210898Sroland.mainz@nrubsig.org 						else if (f->fts_info == FTS_NSOK && !SKIP(fts, f))
131310898Sroland.mainz@nrubsig.org 						{
131410898Sroland.mainz@nrubsig.org 							s = f->fts_name;
131510898Sroland.mainz@nrubsig.org 							if (fts->cd)
131610898Sroland.mainz@nrubsig.org 							{
131710898Sroland.mainz@nrubsig.org 								memcpy(fts->endbase, s, f->fts_namelen + 1);
131810898Sroland.mainz@nrubsig.org 								s = fts->path;
131910898Sroland.mainz@nrubsig.org 							}
132010898Sroland.mainz@nrubsig.org 							info(fts, f, s, f->fts_statp, fts->flags);
132110898Sroland.mainz@nrubsig.org 						}
132210898Sroland.mainz@nrubsig.org 					}
132310898Sroland.mainz@nrubsig.org 					fts->bot = f;
132410898Sroland.mainz@nrubsig.org 					f = f->fts_link;
132510898Sroland.mainz@nrubsig.org 				}
132610898Sroland.mainz@nrubsig.org 			fts->children = 0;
132710898Sroland.mainz@nrubsig.org 			fts->state = FTS_children_resume;
132810898Sroland.mainz@nrubsig.org 			continue;
13294887Schin 
133010898Sroland.mainz@nrubsig.org 		case FTS_popstack_return:
133110898Sroland.mainz@nrubsig.org 
133210898Sroland.mainz@nrubsig.org 			f = fts->todo;
133310898Sroland.mainz@nrubsig.org 			f->fts_link = fts->link;
133410898Sroland.mainz@nrubsig.org 			f->fts_info = f->status == FTS_AGAIN ? FTS_DP : 0;
133510898Sroland.mainz@nrubsig.org 			fts->state = FTS_popstack_resume;
133610898Sroland.mainz@nrubsig.org 			continue;
13374887Schin 
133810898Sroland.mainz@nrubsig.org 		case FTS_preorder_return:
133910898Sroland.mainz@nrubsig.org 
134010898Sroland.mainz@nrubsig.org 			f = fts->current;
134110898Sroland.mainz@nrubsig.org 			f->fts_link = fts->link;
134210898Sroland.mainz@nrubsig.org 
134310898Sroland.mainz@nrubsig.org 			/*
134410898Sroland.mainz@nrubsig.org 			 * follow symlink if asked to
134510898Sroland.mainz@nrubsig.org 			 */
134610898Sroland.mainz@nrubsig.org 
134710898Sroland.mainz@nrubsig.org 			if (f->status == FTS_FOLLOW)
13484887Schin 			{
134910898Sroland.mainz@nrubsig.org 				f->status = 0;
135010898Sroland.mainz@nrubsig.org 				if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK)
13514887Schin 				{
135210898Sroland.mainz@nrubsig.org 					info(fts, f, f->fts_accpath, f->fts_statp, 0);
135310898Sroland.mainz@nrubsig.org 					if (f->fts_info != FTS_SL)
13544887Schin 					{
135510898Sroland.mainz@nrubsig.org 						fts->state = FTS_preorder;
135610898Sroland.mainz@nrubsig.org 						continue;
13574887Schin 					}
13584887Schin 				}
13594887Schin 			}
136010898Sroland.mainz@nrubsig.org 
136110898Sroland.mainz@nrubsig.org 			/*
136210898Sroland.mainz@nrubsig.org 			 * about to prune this f and already at home
136310898Sroland.mainz@nrubsig.org 			 */
13644887Schin 
136510898Sroland.mainz@nrubsig.org 			if (fts->cd == 0 && f->fts_level == 0 && f->nd)
136610898Sroland.mainz@nrubsig.org 				fts->cd = -1;
136710898Sroland.mainz@nrubsig.org 			fts->state = FTS_preorder_resume;
136810898Sroland.mainz@nrubsig.org 			continue;
13694887Schin 
137010898Sroland.mainz@nrubsig.org 		case FTS_terminal:
13714887Schin 
137210898Sroland.mainz@nrubsig.org 			f = fts->current;
137310898Sroland.mainz@nrubsig.org 			if (f->status == FTS_FOLLOW)
13744887Schin 			{
137510898Sroland.mainz@nrubsig.org 				f->status = 0;
137610898Sroland.mainz@nrubsig.org 				if (f->fts_info == FTS_SL || ISTYPE(f, DT_LNK) || f->fts_info == FTS_NSOK)
13774887Schin 				{
137810898Sroland.mainz@nrubsig.org 					info(fts, f, f->fts_accpath, f->fts_statp, 0);
137910898Sroland.mainz@nrubsig.org 					if (f->symlink && f->fts_info != FTS_SL)
138010898Sroland.mainz@nrubsig.org 					{
138110898Sroland.mainz@nrubsig.org 						if (!(f->fts_link = fts->top))
138210898Sroland.mainz@nrubsig.org 							fts->bot = f;
138310898Sroland.mainz@nrubsig.org 						fts->top = f;
138410898Sroland.mainz@nrubsig.org 						fts->current = fts->previous;
138510898Sroland.mainz@nrubsig.org 						fts->state = FTS_readdir;
138610898Sroland.mainz@nrubsig.org 						continue;
138710898Sroland.mainz@nrubsig.org 					}
13884887Schin 				}
13894887Schin 			}
139010898Sroland.mainz@nrubsig.org 			f = f->fts_parent;
139110898Sroland.mainz@nrubsig.org 			drop(fts, fts->current);
139210898Sroland.mainz@nrubsig.org 			fts->current = f;
139310898Sroland.mainz@nrubsig.org 			fts->state = FTS_readdir;
139410898Sroland.mainz@nrubsig.org 			continue;
13954887Schin 
139610898Sroland.mainz@nrubsig.org 		case FTS_error:
13974887Schin 
139810898Sroland.mainz@nrubsig.org 			return 0;
13994887Schin 
140010898Sroland.mainz@nrubsig.org 		default:
140110898Sroland.mainz@nrubsig.org 
140210898Sroland.mainz@nrubsig.org 			fts->fts_errno = EINVAL;
140310898Sroland.mainz@nrubsig.org 			fts->state = FTS_error;
140410898Sroland.mainz@nrubsig.org 			return 0;
140510898Sroland.mainz@nrubsig.org 
14064887Schin 		}
14074887Schin  note:
140810898Sroland.mainz@nrubsig.org #if __OBSOLETE__ < 20140101
140910898Sroland.mainz@nrubsig.org 	f->_fts_pathlen = (unsigned short)f->fts_pathlen;
141010898Sroland.mainz@nrubsig.org #endif
14114887Schin 	for (p = notify; p; p = p->next)
14124887Schin 		if ((n = (*p->notifyf)(fts, f, p->context)) > 0)
14134887Schin 			break;
14144887Schin 		else if (n < 0)
14154887Schin 		{
14164887Schin 			fts->fts_errno = EINVAL;
14174887Schin 			fts->state = FTS_error;
14184887Schin 			return 0;
14194887Schin 		}
14204887Schin 	return f;
14214887Schin }
14224887Schin 
14234887Schin /*
14244887Schin  * set stream or entry flags
14254887Schin  */
14264887Schin 
14274887Schin int
fts_set(register FTS * fts,register FTSENT * f,int status)14284887Schin fts_set(register FTS* fts, register FTSENT* f, int status)
14294887Schin {
14304887Schin 	if (fts || !f || f->fts->current != f)
14314887Schin 		return -1;
14324887Schin 	switch (status)
14334887Schin 	{
14344887Schin 	case FTS_AGAIN:
14354887Schin 		break;
14364887Schin 	case FTS_FOLLOW:
14374887Schin 		if (!(f->fts_info & FTS_SL))
14384887Schin 			return -1;
14394887Schin 		break;
14404887Schin 	case FTS_NOPOSTORDER:
14414887Schin 		break;
14424887Schin 	case FTS_SKIP:
14434887Schin 		if ((f->fts_info & (FTS_D|FTS_P)) != FTS_D)
14444887Schin 			return -1;
14454887Schin 		break;
14464887Schin 	default:
14474887Schin 		return -1;
14484887Schin 	}
14494887Schin 	f->status = status;
14504887Schin 	return 0;
14514887Schin }
14524887Schin 
14534887Schin /*
14544887Schin  * return the list of child entries
14554887Schin  */
14564887Schin 
14574887Schin FTSENT*
fts_children(register FTS * fts,int flags)14584887Schin fts_children(register FTS* fts, int flags)
14594887Schin {
14604887Schin 	register FTSENT*	f;
14614887Schin 
14624887Schin 	switch (fts->state)
14634887Schin 	{
14644887Schin 
14654887Schin 	case 0:
14664887Schin 
146710898Sroland.mainz@nrubsig.org 		if (fts->comparf)
146810898Sroland.mainz@nrubsig.org 			order(fts);
14694887Schin 		fts->state = FTS_top_return;
14704887Schin 		return fts->todo;
14714887Schin 
14724887Schin 	case FTS_preorder_return:
14734887Schin 
14744887Schin 		fts->children = ((flags | fts->flags) & FTS_NOSTAT) ? 2 : 1;
14754887Schin 		if (f = fts_read(fts))
14764887Schin 			f = f->fts_link;
14774887Schin 		return f;
14784887Schin 
14794887Schin 	}
14804887Schin 	return 0;
14814887Schin }
14824887Schin 
14834887Schin /*
14844887Schin  * return default (FTS_LOGICAL|FTS_META|FTS_PHYSICAL|FTS_SEEDOTDIR) flags
14854887Schin  * conditioned by astconf()
14864887Schin  */
14874887Schin 
14884887Schin int
fts_flags(void)14894887Schin fts_flags(void)
14904887Schin {
14914887Schin 	register char*	s;
14924887Schin 
14934887Schin 	s = astconf("PATH_RESOLVE", NiL, NiL);
14944887Schin 	if (streq(s, "logical"))
14954887Schin 		return FTS_LOGICAL;
14964887Schin 	if (streq(s, "physical"))
14974887Schin 		return FTS_PHYSICAL|FTS_SEEDOTDIR;
14984887Schin 	return FTS_META|FTS_PHYSICAL|FTS_SEEDOTDIR;
14994887Schin }
15004887Schin 
15014887Schin /*
15028462SApril.Chin@Sun.COM  * return 1 if ent is mounted on a local filesystem
15038462SApril.Chin@Sun.COM  */
15048462SApril.Chin@Sun.COM 
15058462SApril.Chin@Sun.COM int
fts_local(FTSENT * ent)15068462SApril.Chin@Sun.COM fts_local(FTSENT* ent)
15078462SApril.Chin@Sun.COM {
15088462SApril.Chin@Sun.COM #ifdef ST_LOCAL
15098462SApril.Chin@Sun.COM 	struct statvfs	fs;
15108462SApril.Chin@Sun.COM 
15118462SApril.Chin@Sun.COM 	return statvfs(ent->fts_path, &fs) || (fs.f_flag & ST_LOCAL);
15128462SApril.Chin@Sun.COM #else
15138462SApril.Chin@Sun.COM 	return !strgrpmatch(fmtfs(ent->fts_statp), "([an]fs|samb)", NiL, 0, STR_LEFT|STR_ICASE);
15148462SApril.Chin@Sun.COM #endif
15158462SApril.Chin@Sun.COM }
15168462SApril.Chin@Sun.COM 
15178462SApril.Chin@Sun.COM /*
15184887Schin  * close an open fts stream
15194887Schin  */
15204887Schin 
15214887Schin int
fts_close(register FTS * fts)15224887Schin fts_close(register FTS* fts)
15234887Schin {
15244887Schin 	register FTSENT*	f;
15254887Schin 	register FTSENT*	x;
15264887Schin 
15274887Schin 	if (fts->dir)
15284887Schin 		closedir(fts->dir);
15294887Schin 	if (fts->cd == 0)
15304887Schin 		pathcd(fts->home, NiL);
15314887Schin 	free(fts->home);
15324887Schin 	if (fts->state == FTS_children_return)
15334887Schin 		fts->current->fts_link = fts->link;
15344887Schin 	if (fts->top)
15354887Schin 	{
15364887Schin 		fts->bot->fts_link = fts->todo;
15374887Schin 		fts->todo = fts->top;
15384887Schin 	}
15394887Schin 	for (f = fts->todo; f; f = x)
15404887Schin 	{
15414887Schin 		x = f->fts_link;
15424887Schin 		free(f);
15434887Schin 	}
15444887Schin 	for (f = fts->free; f; f = x)
15454887Schin 	{
15464887Schin 		x = f->fts_link;
15474887Schin 		free(f);
15484887Schin 	}
15498462SApril.Chin@Sun.COM 	free(fts);
15504887Schin 	return 0;
15514887Schin }
15524887Schin 
15534887Schin /*
15544887Schin  * register function to be called for each fts_read() entry
15558462SApril.Chin@Sun.COM  * context==0 => unregister notifyf
15564887Schin  */
15574887Schin 
15584887Schin int
fts_notify(Notify_f notifyf,void * context)15594887Schin fts_notify(Notify_f notifyf, void* context)
15604887Schin {
15614887Schin 	register Notify_t*	np;
15628462SApril.Chin@Sun.COM 	register Notify_t*	pp;
15634887Schin 
15648462SApril.Chin@Sun.COM 	if (context)
15658462SApril.Chin@Sun.COM 	{
15668462SApril.Chin@Sun.COM 		if (!(np = newof(0, Notify_t, 1, 0)))
15678462SApril.Chin@Sun.COM 			return -1;
15688462SApril.Chin@Sun.COM 		np->notifyf = notifyf;
15698462SApril.Chin@Sun.COM 		np->context = context;
15708462SApril.Chin@Sun.COM 		np->next = notify;
15718462SApril.Chin@Sun.COM 		notify = np;
15728462SApril.Chin@Sun.COM 	}
15738462SApril.Chin@Sun.COM 	else
15748462SApril.Chin@Sun.COM 	{
15758462SApril.Chin@Sun.COM 		for (np = notify, pp = 0; np; pp = np, np = np->next)
15768462SApril.Chin@Sun.COM 			if (np->notifyf == notifyf)
15778462SApril.Chin@Sun.COM 			{
15788462SApril.Chin@Sun.COM 				if (pp)
15798462SApril.Chin@Sun.COM 					pp->next = np->next;
15808462SApril.Chin@Sun.COM 				else
15818462SApril.Chin@Sun.COM 					notify = np->next;
15828462SApril.Chin@Sun.COM 				free(np);
15838462SApril.Chin@Sun.COM 				return 0;
15848462SApril.Chin@Sun.COM 			}
15854887Schin 		return -1;
15868462SApril.Chin@Sun.COM 	}
15874887Schin 	return 0;
15884887Schin }
1589