summaryrefslogtreecommitdiff
path: root/libs/pbd3/ftw.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/pbd3/ftw.cc')
-rw-r--r--libs/pbd3/ftw.cc220
1 files changed, 220 insertions, 0 deletions
diff --git a/libs/pbd3/ftw.cc b/libs/pbd3/ftw.cc
new file mode 100644
index 0000000000..ea7162c22e
--- /dev/null
+++ b/libs/pbd3/ftw.cc
@@ -0,0 +1,220 @@
+/*
+ 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.
+*/
+
+#include <string>
+#include <sys/types.h> /* Because fts(3) says so */
+#include <sys/stat.h>
+#include <fts.h>
+#include <alloca.h>
+
+#include <unistd.h> /* We want strcpy */
+
+#include <cerrno> /* Because errno is our friend */
+
+#ifndef __USE_XOPEN_EXTENDED /* We need nftw values, since we implement it */
+#define __USE_XOPEN_EXTENDED
+#endif
+
+#include <pbd/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 */
+
+static int __ftw_core(const char *, void*, int, int, enum __ftw_modes);
+
+/*
+ * 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) {
+ return __ftw_core(dir, (void*)func, descr, 0, MODE_FTW);
+}
+
+int nftw (const char *dir, __nftw_func_t func, int descr, int flags) {
+ return __ftw_core(dir, (void*)func, descr, flags, MODE_NFTW);
+}
+
+/*
+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);
+*/
+
+static int __ftw_core(const char *dir, void* func, int descr, int flags,
+ enum __ftw_modes mode) {
+ FTS *hierarchy = 0;
+ FTSENT *entry = 0;
+ int fts_options;
+ char *paths[2];
+ int ftw_flag = 0, func_ret = 0;
+ struct FTW ftw_st;
+ int skip_entry;
+ __ftw_func_t ftw_func;
+ __nftw_func_t nftw_func;
+
+ /* 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) ? FTS_NOCHDIR : 0;
+ 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. */
+
+ if (!(paths[0] = (char*) alloca(strlen(dir) + 1))) {
+ errno = ENOMEM; /* This is stack... we probably just died anyway. */
+ return -1;
+ }
+
+ strcpy(paths[0], dir);
+ paths[1] = 0; /* null */
+
+ /* Open the file hierarchy. */
+
+ if (!(hierarchy = fts_open(paths, fts_options, 0))) {
+ if (EACCES == errno) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ /* The main loop. Is it not nifty? Worship the loop. */
+
+ bool first = true;
+ while ((entry = fts_read(hierarchy))) {
+ skip_entry = 0;
+ std::string path_name = entry->fts_path;
+
+ switch (entry->fts_info) {
+
+ case FTS_D:
+ if ((MODE_NFTW != mode) || !(flags & FTW_DEPTH)) {
+ if (first) {
+ path_name = path_name.substr(0, path_name.size() - 1);
+ first = false;
+ }
+ ftw_flag = FTW_D;
+ } else {
+ skip_entry = 1;
+ }
+ 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;
+ } else {
+ skip_entry = 1;
+ }
+ 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.
+ */
+
+ skip_entry = 1;
+ }
+
+ if (MODE_FTW == mode) {
+ ftw_func = (__ftw_func_t) func;
+ func_ret = (*ftw_func)
+ (path_name.c_str(), 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)
+ (path_name.c_str(), entry->fts_statp, ftw_flag, &ftw_st);
+ }
+
+ if (0 != func_ret) {
+ return func_ret;
+ }
+ }
+
+ if (0 != errno) { /* fts_read returned NULL, and set errno - bail */
+ return -1;
+ }
+
+ /* The janitors will be upset if we don't clean up after ourselves. */
+
+ if (0 != fts_close(hierarchy)) {
+ return -1;
+ }
+
+ return 0;
+}