From 597c930cd1ef55781893ae2864c1a006e842325f Mon Sep 17 00:00:00 2001 From: dockes Date: Fri, 10 Dec 2004 18:13:14 +0000 Subject: [PATCH] *** empty log message *** --- src/utils/fstreewalk.cpp | 168 +++++++++++++++++++++++++++++++++++++++ src/utils/fstreewalk.h | 28 +++++++ src/utils/pathut.cpp | 68 ++++++++++++++++ src/utils/pathut.h | 19 +++++ 4 files changed, 283 insertions(+) create mode 100644 src/utils/fstreewalk.cpp create mode 100644 src/utils/fstreewalk.h create mode 100644 src/utils/pathut.cpp create mode 100644 src/utils/pathut.h diff --git a/src/utils/fstreewalk.cpp b/src/utils/fstreewalk.cpp new file mode 100644 index 00000000..0f2679f6 --- /dev/null +++ b/src/utils/fstreewalk.cpp @@ -0,0 +1,168 @@ +#ifndef lint +static char rcsid[] = "@(#$Id: fstreewalk.cpp,v 1.1 2004-12-10 18:13:13 dockes Exp $ (C) 2004 J.F.Dockes"; +#endif + +#ifndef TEST_FSTREEWALK + +#include +#include +#include + +#include + +#include "debuglog.h" +#include "pathut.h" +#include "fstreewalk.h" + +using namespace std; + +class FsTreeWalker::Internal { + Options options; + stringstream reason; + 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; +} + +FsTreeWalker::Status FsTreeWalker::walk(const string &top, CbType fun, + void *cdata) +{ + 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 = fun(cdata, top, &st, FtwDirEnter)) & + (FtwStop|FtwError)) { + return status; + } + } else if (S_ISREG(st.st_mode)) { + return fun(cdata, 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) { + // We do process hidden files for now + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + + string fn = top; + path_cat(fn, 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 (S_ISDIR(st.st_mode)) { + if (data->options & FtwNoRecurse) { + status = fun(cdata, fn, &st, FtwDirEnter); + } else { + status=walk(fn, fun, cdata); + } + if (status & (FtwStop|FtwError)) { + goto out; + } + } else if (S_ISREG(st.st_mode)) { + if ((status = fun(cdata, fn, &st, FtwRegular)) & + (FtwStop|FtwError)) { + goto out; + } + } + // 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; + +FsTreeWalker::Status walkfunc(void *, const string &path, + const struct stat *st, + FsTreeWalker::CbFlag flg) +{ + if (flg == FsTreeWalker::FtwDirEnter) { + cout << "[Entering " << path << "]" << endl; + } else if (flg == FsTreeWalker::FtwRegular) { + cout << path << endl; + } + return FsTreeWalker::FtwOk; +} + +int main(int argc, const char **argv) +{ + if (argc != 2) { + cerr << "Usage: fstreewalk " << endl; + exit(1); + } + FsTreeWalker walker; + walker.walk(argv[1], walkfunc, 0); + if (walker.getErrCnt() > 0) + cout << walker.getReason(); +} + +#endif // TEST_FSTREEWALK diff --git a/src/utils/fstreewalk.h b/src/utils/fstreewalk.h new file mode 100644 index 00000000..2ec05077 --- /dev/null +++ b/src/utils/fstreewalk.h @@ -0,0 +1,28 @@ +#ifndef _FSTREEWALK_H_INCLUDED_ +#define _FSTREEWALK_H_INCLUDED_ +/* @(#$Id: fstreewalk.h,v 1.1 2004-12-10 18:13:13 dockes Exp $ (C) 2004 J.F.Dockes */ + +#include + + +class FsTreeWalker { + public: + enum CbFlag {FtwRegular, FtwDirEnter, FtwDirReturn}; + enum Status {FtwOk=0, FtwError=1, FtwStop=2, + FtwStatAll = FtwError|FtwStop}; + enum Options {FtwOptNone = 0, FtwNoRecurse = 1, FtwFollow = 2}; + + typedef Status (*CbType)(void *cdata, + const std::string &, const struct stat *, CbFlag); + + FsTreeWalker(Options opts = FtwOptNone); + ~FsTreeWalker(); + Status walk(const std::string &dir, CbType fun, void *cdata); + std::string getReason(); + int getErrCnt(); + private: + class Internal; + Internal *data; +}; + +#endif /* _FSTREEWALK_H_INCLUDED_ */ diff --git a/src/utils/pathut.cpp b/src/utils/pathut.cpp new file mode 100644 index 00000000..4881c732 --- /dev/null +++ b/src/utils/pathut.cpp @@ -0,0 +1,68 @@ +#ifndef lint +static char rcsid[] = "@(#$Id: pathut.cpp,v 1.1 2004-12-10 18:13:14 dockes Exp $ (C) 2004 J.F.Dockes"; +#endif + +#ifndef TEST_PATHUT + +#include + +#include "pathut.h" + +std::string path_getfather(const std::string &s) { + std::string father = s; + + // ?? + if (father.empty()) + return "./"; + + if (father[father.length() - 1] == '/') { + // Input ends with /. Strip it, handle special case for root + if (father.length() == 1) + return father; + father.erase(father.length()-1); + } + + std::string::size_type slp = father.rfind('/'); + if (slp == std::string::npos) + return "./"; + + father.erase(slp); + path_catslash(father); + return father; +} + +std::string path_home() +{ + uid_t uid = getuid(); + + struct passwd *entry = getpwuid(uid); + if (entry == 0) + return "/"; + + std::string homedir = entry->pw_dir; + path_catslash(homedir); + return homedir; +} + +#else // TEST_PATHUT + +#include +using namespace std; + +#include "pathut.h" + +const char *tstvec[] = {"", "/", "/dir", "/dir/", "/dir1/dir2", + "/dir1/dir2", + "./dir", "./dir1/", "dir", "../dir"}; + +int main(int argc, const char **argv) +{ + + for (int i = 0;i < sizeof(tstvec) / sizeof(char *); i++) { + cout << tstvec[i] << " -> " << path_getfather(tstvec[i]) << endl; + } + return 0; +} + +#endif // TEST_PATHUT + diff --git a/src/utils/pathut.h b/src/utils/pathut.h new file mode 100644 index 00000000..a4e253b4 --- /dev/null +++ b/src/utils/pathut.h @@ -0,0 +1,19 @@ +#ifndef _PATHUT_H_INCLUDED_ +#define _PATHUT_H_INCLUDED_ +/* @(#$Id: pathut.h,v 1.1 2004-12-10 18:13:14 dockes Exp $ (C) 2004 J.F.Dockes */ + +#include + +inline void path_catslash(std::string &s) { + if (s.empty() || s[s.length() - 1] != '/') + s += '/'; +} +inline void path_cat(std::string &s1, const std::string &s2) { + path_catslash(s1); + s1 += s2; +} + +extern std::string path_getfather(const std::string &s); +extern std::string path_home(); + +#endif /* _PATHUT_H_INCLUDED_ */