#ifndef lint static char rcsid[] = "@(#$Id: fstreewalk.cpp,v 1.12 2007-07-12 10:53:07 dockes Exp $ (C) 2004 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef TEST_FSTREEWALK #include #include #include #include #include #include #include "debuglog.h" #include "pathut.h" #include "fstreewalk.h" #ifndef NO_NAMESPACES using namespace std; #endif /* NO_NAMESPACES */ class FsTreeWalker::Internal { Options options; stringstream reason; list skippedNames; list skippedPaths; int errors; void logsyserr(const char *call, const string ¶m) { errors++; reason << call << "(" << param << ") : " << errno << " : " << strerror(errno) << endl; } friend class FsTreeWalker; }; FsTreeWalker::FsTreeWalker(Options opts) { data = new Internal; if (data) { data->options = opts; data->errors = 0; } } FsTreeWalker::~FsTreeWalker() { delete data; } string FsTreeWalker::getReason() { return data->reason.str(); } int FsTreeWalker::getErrCnt() { return data->errors; } bool FsTreeWalker::addSkippedName(const string& pattern) { if (find(data->skippedNames.begin(), data->skippedNames.end(), pattern) == data->skippedNames.end()) data->skippedNames.push_back(pattern); return true; } bool FsTreeWalker::setSkippedNames(const list &patterns) { data->skippedNames = patterns; data->skippedNames.sort(); data->skippedNames.unique(); return true; } bool FsTreeWalker::inSkippedNames(const string& name) { list::const_iterator it; for (it = data->skippedNames.begin(); it != data->skippedNames.end(); it++) { if (fnmatch(it->c_str(), name.c_str(), 0) == 0) { return true; } } return false; } bool FsTreeWalker::addSkippedPath(const string& ipath) { string path = path_canon(ipath); if (find(data->skippedPaths.begin(), data->skippedPaths.end(), path) == data->skippedPaths.end()) data->skippedPaths.push_back(path); return true; } bool FsTreeWalker::setSkippedPaths(const list &paths) { data->skippedPaths = paths; for (list::iterator it = data->skippedPaths.begin(); it != data->skippedPaths.end(); it++) *it = path_canon(*it); data->skippedPaths.sort(); data->skippedPaths.unique(); return true; } bool FsTreeWalker::inSkippedPaths(const string& path) { list::const_iterator it; for (it = data->skippedPaths.begin(); it != data->skippedPaths.end(); it++) { if (fnmatch(it->c_str(), path.c_str(), FNM_PATHNAME) == 0) return true; } return false; } FsTreeWalker::Status FsTreeWalker::walk(const string &top, FsTreeWalkerCB& cb) { return iwalk(path_canon(top), cb); } FsTreeWalker::Status FsTreeWalker::iwalk(const string &top, FsTreeWalkerCB& cb) { Status status = FtwOk; struct stat st; int statret; // Handle the top entry statret = (data->options & FtwFollow) ? stat(top.c_str(), &st) : lstat(top.c_str(), &st); if (statret == -1) { data->logsyserr("stat", top); return FtwError; } if (S_ISDIR(st.st_mode)) { if ((status = cb.processone(top, &st, FtwDirEnter)) & (FtwStop|FtwError)) { return status; } } else if (S_ISREG(st.st_mode)) { return cb.processone(top, &st, FtwRegular); } else { return status; } // Handle directory entries DIR *d = opendir(top.c_str()); if (d == 0) { data->logsyserr("opendir", top); switch (errno) { case EPERM: case EACCES: goto out; default: status = FtwError; goto out; } } struct dirent *ent; while ((ent = readdir(d)) != 0) { // Skip . and .. if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; // Skipped file names match ? if (!data->skippedNames.empty()) { if (inSkippedNames(ent->d_name)) goto skip; } { string fn = path_cat(top, ent->d_name); struct stat st; int statret = (data->options & FtwFollow) ? stat(fn.c_str(), &st) : lstat(fn.c_str(), &st); if (statret == -1) { data->logsyserr("stat", fn); continue; } if (!data->skippedPaths.empty()) { if (inSkippedPaths(fn)) goto skip; } if (S_ISDIR(st.st_mode)) { if (data->options & FtwNoRecurse) { status = cb.processone(fn, &st, FtwDirEnter); } else { status = iwalk(fn, cb); } if (status & (FtwStop|FtwError)) goto out; if ((status = cb.processone(top, &st, FtwDirReturn)) & (FtwStop|FtwError)) goto out; } else if (S_ISREG(st.st_mode)) { if ((status = cb.processone(fn, &st, FtwRegular)) & (FtwStop|FtwError)) { goto out; } } } skip: ; // We skip other file types (devices etc...) } out: if (d) closedir(d); return status; } #else // TEST_FSTREEWALK #include #include #include "fstreewalk.h" using namespace std; class myCB : public FsTreeWalkerCB { public: FsTreeWalker::Status processone(const string &path, const struct stat *st, FsTreeWalker::CbFlag flg) { if (flg == FsTreeWalker::FtwDirEnter) { cout << "[Entering " << path << "]" << endl; } else if (flg == FsTreeWalker::FtwDirReturn) { cout << "[Returning to " << path << "]" << endl; } else if (flg == FsTreeWalker::FtwRegular) { cout << path << endl; } return FsTreeWalker::FtwOk; } }; static const char *thisprog; static char usage [] = "trfstreewalk [-p pattern] [-P ignpath] topdir\n\n" ; static void Usage(void) { fprintf(stderr, "%s: usage:\n%s", thisprog, usage); exit(1); } static int op_flags; #define OPT_MOINS 0x1 #define OPT_p 0x2 #define OPT_P 0x4 int main(int argc, const char **argv) { list patterns; list paths; thisprog = argv[0]; argc--; argv++; while (argc > 0 && **argv == '-') { (*argv)++; if (!(**argv)) /* Cas du "adb - core" */ Usage(); while (**argv) switch (*(*argv)++) { case 'p': op_flags |= OPT_p; if (argc < 2) Usage(); patterns.push_back(*(++argv)); argc--; goto b1; case 'P': op_flags |= OPT_P; if (argc < 2) Usage(); paths.push_back(*(++argv)); argc--; goto b1; default: Usage(); break; } b1: argc--; argv++; } if (argc != 1) Usage(); string topdir = *argv++;argc--; FsTreeWalker walker; walker.setSkippedNames(patterns); walker.setSkippedPaths(paths); myCB cb; walker.walk(topdir, cb); if (walker.getErrCnt() > 0) cout << walker.getReason(); } #endif // TEST_FSTREEWALK