ftw.c revision 131661
1131661Sdas/*
2131661Sdas * Copyright (c) 2003 by Joel Baker.
3131661Sdas * All rights reserved.
4131661Sdas *
5131661Sdas * Redistribution and use in source and binary forms, with or without
6131661Sdas * modification, are permitted provided that the following conditions
7131661Sdas * are met:
8131661Sdas * 1. Redistributions of source code must retain the above copyright
9131661Sdas *    notice, this list of conditions and the following disclaimer.
10131661Sdas * 2. Redistributions in binary form must reproduce the above copyright
11131661Sdas *    notice, this list of conditions and the following disclaimer in the
12131661Sdas *    documentation and/or other materials provided with the distribution.
13131661Sdas * 3. Neither the name of the Author nor the names of any contributors
14131661Sdas *    may be used to endorse or promote products derived from this software
15131661Sdas *    without specific prior written permission.
16131661Sdas *
17131661Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18131661Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19131661Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20131661Sdas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21131661Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22131661Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23131661Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24131661Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25131661Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26131661Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27131661Sdas * SUCH DAMAGE.
28131661Sdas *
29131661Sdas * $FreeBSD: head/lib/libc/gen/ftw.c 131661 2004-07-05 23:13:16Z das $
30131661Sdas */
31131661Sdas
32131661Sdas#include <sys/types.h> /* Because fts(3) says so */
33131661Sdas#include <sys/stat.h>
34131661Sdas#include <fts.h>
35131661Sdas
36131661Sdas#include <unistd.h> /* We want strcpy */
37131661Sdas
38131661Sdas#include <errno.h> /* Because errno is our friend */
39131661Sdas
40131661Sdas#include "ftw.h"
41131661Sdas
42131661Sdas/* I like symbolic values - this is only used in this file. */
43131661Sdas
44131661Sdasenum __ftw_modes {
45131661Sdas    MODE_FTW,
46131661Sdas    MODE_NFTW
47131661Sdas};
48131661Sdas
49131661Sdas/* Prototype this so that we can have it later */
50131661Sdas
51131661Sdasstatic int __ftw_core(const char *, void *, int, int, enum __ftw_modes);
52131661Sdas
53131661Sdas/*
54131661Sdas * The external function calls are really just wrappers around __ftw_core,
55131661Sdas * since the work they do is 90% the same.
56131661Sdas */
57131661Sdas
58131661Sdasint ftw (const char *dir, __ftw_func_t func, int descr) {
59131661Sdas    return __ftw_core(dir, func, descr, 0, MODE_FTW);
60131661Sdas}
61131661Sdas
62131661Sdasint nftw (const char *dir, __nftw_func_t func, int descr, int flags) {
63131661Sdas    return __ftw_core(dir, func, descr, flags, MODE_NFTW);
64131661Sdas}
65131661Sdas
66131661Sdas/*
67131661Sdastypedef int (*__ftw_func_t) \
68131661Sdas    (const char *file, const struct stat status, int flag);
69131661Sdastypedef int (*__nftw_func_t) \
70131661Sdas    (const char *file, const struct stat status, int flag, struct FTW detail);
71131661Sdas*/
72131661Sdas
73131661Sdasstatic int __ftw_core(const char *dir, void *func, int descr, int flags,
74131661Sdas                      enum __ftw_modes mode) {
75131661Sdas    FTS *hierarchy;
76131661Sdas    FTSENT *entry;
77131661Sdas    int fts_options;
78131661Sdas    const char *paths[2];
79131661Sdas    int ftw_flag, func_ret;
80131661Sdas    struct FTW ftw_st;
81131661Sdas    int skip_entry;
82131661Sdas    __ftw_func_t ftw_func;
83131661Sdas    __nftw_func_t nftw_func;
84131661Sdas    int saved_errno;
85131661Sdas
86131661Sdas    errno = 0;
87131661Sdas
88131661Sdas    /* We need at least one descriptor to call fts */
89131661Sdas
90131661Sdas    if (descr < 1) {
91131661Sdas        errno = EINVAL;
92131661Sdas        return -1;
93131661Sdas    }
94131661Sdas
95131661Sdas    /* Decide which mode we're running in, and set the FTS options suitably. */
96131661Sdas
97131661Sdas    if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */
98131661Sdas        fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL;
99131661Sdas        fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR;
100131661Sdas        fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0;
101131661Sdas    } else { /* We must be in FTW mode. Nothing else makes sense. */
102131661Sdas        fts_options = FTS_LOGICAL;
103131661Sdas    }
104131661Sdas
105131661Sdas    /* FTW gets a const char *, but FTS expects a null-term array of them. */
106131661Sdas
107131661Sdas    paths[0] = dir;
108131661Sdas    paths[1] = NULL;
109131661Sdas
110131661Sdas    /* Open the file hierarchy. */
111131661Sdas
112131661Sdas    if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) {
113131661Sdas        if (EACCES == errno) {
114131661Sdas            return 0;
115131661Sdas        } else {
116131661Sdas            return -1;
117131661Sdas        }
118131661Sdas    }
119131661Sdas
120131661Sdas    /* The main loop. Is it not nifty? Worship the loop. */
121131661Sdas
122131661Sdas    while ((entry = fts_read(hierarchy))) {
123131661Sdas        skip_entry = 0;
124131661Sdas
125131661Sdas        switch (entry->fts_info) {
126131661Sdas
127131661Sdas            case FTS_D:
128131661Sdas                if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) {
129131661Sdas                    ftw_flag = FTW_D;
130131661Sdas                } else {
131131661Sdas                    skip_entry = 1;
132131661Sdas                }
133131661Sdas                break;
134131661Sdas
135131661Sdas            case FTS_DNR:
136131661Sdas                ftw_flag = FTW_DNR;
137131661Sdas                break;
138131661Sdas
139131661Sdas            case FTS_F:
140131661Sdas                ftw_flag = FTW_F;
141131661Sdas                break;
142131661Sdas
143131661Sdas            case FTS_SL:
144131661Sdas                ftw_flag = FTW_SL;
145131661Sdas                break;
146131661Sdas
147131661Sdas            case FTS_NS:
148131661Sdas                ftw_flag = FTW_NS;
149131661Sdas                break;
150131661Sdas
151131661Sdas            /* Values that should only occur in nftw mode */
152131661Sdas
153131661Sdas            case FTS_SLNONE:
154131661Sdas                if (MODE_NFTW == mode) {
155131661Sdas                    ftw_flag = FTW_SLN;
156131661Sdas                } else {
157131661Sdas                    ftw_flag = FTW_SL;
158131661Sdas                }
159131661Sdas                break;
160131661Sdas
161131661Sdas            case FTS_DP:
162131661Sdas                if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) {
163131661Sdas                    ftw_flag = FTW_D;
164131661Sdas                } else {
165131661Sdas                    skip_entry = 1;
166131661Sdas                }
167131661Sdas                break;
168131661Sdas
169131661Sdas            default:
170131661Sdas                /* I'm not sure this is right, but we don't have a valid FTW
171131661Sdas                 * type to call with, so cowardice seems the better part of
172131661Sdas                 * guessing.
173131661Sdas                 */
174131661Sdas
175131661Sdas                skip_entry = 1;
176131661Sdas        }
177131661Sdas
178131661Sdas        if (MODE_FTW == mode) {
179131661Sdas            ftw_func = (__ftw_func_t) func;
180131661Sdas            func_ret = (*ftw_func)
181131661Sdas                (entry->fts_path, entry->fts_statp, ftw_flag);
182131661Sdas        } else if (MODE_NFTW == mode) {
183131661Sdas            ftw_st.base = (entry->fts_pathlen - entry->fts_namelen);
184131661Sdas            ftw_st.level = entry->fts_level;
185131661Sdas
186131661Sdas            nftw_func = (__nftw_func_t) func;
187131661Sdas            func_ret = (*nftw_func)
188131661Sdas                (entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st);
189131661Sdas        }
190131661Sdas
191131661Sdas        if (0 != func_ret) {
192131661Sdas	    saved_errno = errno;
193131661Sdas	    fts_close(hierarchy);
194131661Sdas	    errno = saved_errno;
195131661Sdas            return func_ret;
196131661Sdas        }
197131661Sdas    }
198131661Sdas
199131661Sdas    /* The janitors will be upset if we don't clean up after ourselves. */
200131661Sdas
201131661Sdas    saved_errno = errno;
202131661Sdas    fts_close(hierarchy);
203131661Sdas    if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */
204131661Sdas	errno = saved_errno;
205131661Sdas    }
206131661Sdas
207131661Sdas    return errno ? -1 : 0;
208131661Sdas}
209