1/*	$OpenBSD: nftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $	*/
2
3/*
4 * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * Sponsored in part by the Defense Advanced Research Projects
19 * Agency (DARPA) and Air Force Research Laboratory, Air Force
20 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
21 */
22
23#if 0
24#if defined(LIBC_SCCS) && !defined(lint)
25static const char rcsid[] = "$OpenBSD: nftw.c,v 1.4 2004/07/07 16:05:23 millert Exp $";
26#endif /* LIBC_SCCS and not lint */
27#endif
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <errno.h>
35#include <fts.h>
36#include <ftw.h>
37
38int
39nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
40     struct FTW *), int nfds, int ftwflags)
41{
42	char * const paths[2] = { (char *)path, NULL };
43	struct FTW ftw;
44	FTSENT *cur;
45	FTS *ftsp;
46	int error = 0, ftsflags, fnflag, postorder, sverrno;
47
48	/* XXX - nfds is currently unused */
49	if (nfds < 1) {
50		errno = EINVAL;
51		return (-1);
52	}
53
54	ftsflags = FTS_COMFOLLOW;
55	if (!(ftwflags & FTW_CHDIR))
56		ftsflags |= FTS_NOCHDIR;
57	if (ftwflags & FTW_MOUNT)
58		ftsflags |= FTS_XDEV;
59	if (ftwflags & FTW_PHYS)
60		ftsflags |= FTS_PHYSICAL;
61	else
62		ftsflags |= FTS_LOGICAL;
63	postorder = (ftwflags & FTW_DEPTH) != 0;
64	ftsp = fts_open(paths, ftsflags, NULL);
65	if (ftsp == NULL)
66		return (-1);
67	while ((cur = fts_read(ftsp)) != NULL) {
68		switch (cur->fts_info) {
69		case FTS_D:
70			if (postorder)
71				continue;
72			fnflag = FTW_D;
73			break;
74		case FTS_DNR:
75			fnflag = FTW_DNR;
76			break;
77		case FTS_DP:
78			if (!postorder)
79				continue;
80			fnflag = FTW_DP;
81			break;
82		case FTS_F:
83		case FTS_DEFAULT:
84			fnflag = FTW_F;
85			break;
86		case FTS_NS:
87		case FTS_NSOK:
88			fnflag = FTW_NS;
89			break;
90		case FTS_SL:
91			fnflag = FTW_SL;
92			break;
93		case FTS_SLNONE:
94			fnflag = FTW_SLN;
95			break;
96		case FTS_DC:
97			errno = ELOOP;
98			/* FALLTHROUGH */
99		default:
100			error = -1;
101			goto done;
102		}
103		ftw.base = cur->fts_pathlen - cur->fts_namelen;
104		ftw.level = cur->fts_level;
105		error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
106		if (error != 0)
107			break;
108	}
109done:
110	sverrno = errno;
111	if (fts_close(ftsp) != 0 && error == 0)
112		error = -1;
113	else
114		errno = sverrno;
115	return (error);
116}
117