2004-07-05 23:13:16 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2003 by Joel Baker.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the Author nor the names of any contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* $FreeBSD$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h> /* Because fts(3) says so */
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fts.h>
|
|
|
|
|
|
|
|
#include <unistd.h> /* We want strcpy */
|
|
|
|
|
|
|
|
#include <errno.h> /* Because errno is our friend */
|
|
|
|
|
|
|
|
#include "ftw.h"
|
|
|
|
|
|
|
|
/* I like symbolic values - this is only used in this file. */
|
|
|
|
|
|
|
|
enum __ftw_modes {
|
|
|
|
MODE_FTW,
|
|
|
|
MODE_NFTW
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Prototype this so that we can have it later */
|
|
|
|
|
2004-08-02 08:18:43 +00:00
|
|
|
static int __ftw_core(const char *, void (*)(), int, int, enum __ftw_modes);
|
2004-07-05 23:13:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The external function calls are really just wrappers around __ftw_core,
|
|
|
|
* since the work they do is 90% the same.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int ftw (const char *dir, __ftw_func_t func, int descr) {
|
2004-08-02 08:18:43 +00:00
|
|
|
return __ftw_core(dir, (void (*)())func, descr, 0, MODE_FTW);
|
2004-07-05 23:13:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int nftw (const char *dir, __nftw_func_t func, int descr, int flags) {
|
2004-08-02 08:18:43 +00:00
|
|
|
return __ftw_core(dir, (void (*)())func, descr, flags, MODE_NFTW);
|
2004-07-05 23:13:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
typedef int (*__ftw_func_t) \
|
|
|
|
(const char *file, const struct stat status, int flag);
|
|
|
|
typedef int (*__nftw_func_t) \
|
|
|
|
(const char *file, const struct stat status, int flag, struct FTW detail);
|
|
|
|
*/
|
|
|
|
|
2004-08-02 08:18:43 +00:00
|
|
|
static int __ftw_core(const char *dir, void (*func)(), int descr, int flags,
|
2004-07-05 23:13:16 +00:00
|
|
|
enum __ftw_modes mode) {
|
|
|
|
FTS *hierarchy;
|
|
|
|
FTSENT *entry;
|
|
|
|
int fts_options;
|
|
|
|
const char *paths[2];
|
|
|
|
int ftw_flag, func_ret;
|
|
|
|
struct FTW ftw_st;
|
|
|
|
__ftw_func_t ftw_func;
|
|
|
|
__nftw_func_t nftw_func;
|
|
|
|
int saved_errno;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
/* We need at least one descriptor to call fts */
|
|
|
|
|
|
|
|
if (descr < 1) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Decide which mode we're running in, and set the FTS options suitably. */
|
|
|
|
|
|
|
|
if (MODE_NFTW == mode) { /* NFTW mode, with all the bells and whistles. */
|
|
|
|
fts_options = (flags & FTW_PHYS) ? FTS_PHYSICAL : FTS_LOGICAL;
|
|
|
|
fts_options |= (flags & FTW_CHDIR) ? 0 : FTS_NOCHDIR;
|
|
|
|
fts_options |= (flags & FTW_MOUNT) ? FTS_XDEV : 0;
|
|
|
|
} else { /* We must be in FTW mode. Nothing else makes sense. */
|
|
|
|
fts_options = FTS_LOGICAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FTW gets a const char *, but FTS expects a null-term array of them. */
|
|
|
|
|
|
|
|
paths[0] = dir;
|
|
|
|
paths[1] = NULL;
|
|
|
|
|
|
|
|
/* Open the file hierarchy. */
|
|
|
|
|
|
|
|
if (!(hierarchy = fts_open((char * const *)paths, fts_options, NULL))) {
|
|
|
|
if (EACCES == errno) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The main loop. Is it not nifty? Worship the loop. */
|
|
|
|
|
|
|
|
while ((entry = fts_read(hierarchy))) {
|
|
|
|
switch (entry->fts_info) {
|
|
|
|
|
|
|
|
case FTS_D:
|
|
|
|
if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) {
|
|
|
|
ftw_flag = FTW_D;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FTS_DNR:
|
|
|
|
ftw_flag = FTW_DNR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FTS_F:
|
|
|
|
ftw_flag = FTW_F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FTS_SL:
|
|
|
|
ftw_flag = FTW_SL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FTS_NS:
|
|
|
|
ftw_flag = FTW_NS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Values that should only occur in nftw mode */
|
|
|
|
|
|
|
|
case FTS_SLNONE:
|
|
|
|
if (MODE_NFTW == mode) {
|
|
|
|
ftw_flag = FTW_SLN;
|
|
|
|
} else {
|
|
|
|
ftw_flag = FTW_SL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FTS_DP:
|
|
|
|
if ((MODE_NFTW == mode) && (flags & FTW_DEPTH)) {
|
|
|
|
ftw_flag = FTW_D;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* I'm not sure this is right, but we don't have a valid FTW
|
|
|
|
* type to call with, so cowardice seems the better part of
|
|
|
|
* guessing.
|
|
|
|
*/
|
2004-07-23 06:01:00 +00:00
|
|
|
break;
|
2004-07-05 23:13:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (MODE_FTW == mode) {
|
|
|
|
ftw_func = (__ftw_func_t) func;
|
|
|
|
func_ret = (*ftw_func)
|
|
|
|
(entry->fts_path, entry->fts_statp, ftw_flag);
|
|
|
|
} else if (MODE_NFTW == mode) {
|
|
|
|
ftw_st.base = (entry->fts_pathlen - entry->fts_namelen);
|
|
|
|
ftw_st.level = entry->fts_level;
|
|
|
|
|
|
|
|
nftw_func = (__nftw_func_t) func;
|
|
|
|
func_ret = (*nftw_func)
|
|
|
|
(entry->fts_path, entry->fts_statp, ftw_flag, &ftw_st);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 != func_ret) {
|
|
|
|
saved_errno = errno;
|
|
|
|
fts_close(hierarchy);
|
|
|
|
errno = saved_errno;
|
|
|
|
return func_ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The janitors will be upset if we don't clean up after ourselves. */
|
|
|
|
|
|
|
|
saved_errno = errno;
|
|
|
|
fts_close(hierarchy);
|
|
|
|
if (0 != saved_errno) { /* fts_read returned NULL, and set errno - bail */
|
|
|
|
errno = saved_errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
return errno ? -1 : 0;
|
|
|
|
}
|