From 02af7e788f3fef0dbba0ba49442054fb451f5bdc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 9 Jul 2015 12:25:47 +0200 Subject: Implement directory iteration support --- butl/filesystem.cxx | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 4 deletions(-) (limited to 'butl/filesystem.cxx') diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx index 7c8893e..4cf60b2 100644 --- a/butl/filesystem.cxx +++ b/butl/filesystem.cxx @@ -8,6 +8,7 @@ #include // stat #include // stat, lstat(), S_IS*, mkdir() +#include // unique_ptr #include using namespace std; @@ -17,25 +18,25 @@ namespace butl // Figuring out whether we have the nanoseconds in some form. // template - constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec) + inline constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec) { return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris). } template - constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec) + inline constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec) { return s->st_mtimespec.tv_nsec; // MacOS X. } template - constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n) + inline constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n) { return s->st_mtime_n; // AIX 5.2 and later. } template - constexpr int nsec (...) {return 0;} + inline constexpr int nsec (...) {return 0;} timestamp file_mtime (const path& p) @@ -140,4 +141,128 @@ namespace butl return r; } + +#ifndef _WIN32 + + // dir_entry + // + entry_type dir_entry:: + type (bool link) const + { + path_type p (b_ / p_); + struct stat s; + if ((link + ? ::stat (p.string ().c_str (), &s) + : ::lstat (p.string ().c_str (), &s)) != 0) + { + throw system_error (errno, system_category ()); + } + + entry_type r; + + if (S_ISREG (s.st_mode)) + r = entry_type::regular; + else if (S_ISDIR (s.st_mode)) + r = entry_type::directory; + else if (S_ISLNK (s.st_mode)) + r = entry_type::symlink; + else + r = entry_type::other; + + return r; + } + + // dir_iterator + // + struct dir_deleter + { + void operator() (DIR* p) const {if (p != nullptr) ::closedir (p);} + }; + + dir_iterator:: + dir_iterator (const dir_path& d) + { + unique_ptr h (::opendir (d.string ().c_str ())); + h_ = h.get (); + + if (h_ == nullptr) + throw system_error (errno, system_category ()); + + next (); + + if (h_ != nullptr) + e_.b_ = d; + + h.release (); + } + + template + inline /*constexpr*/ entry_type d_type (const D* d, decltype(d->d_type)*) + { + switch (d->d_type) + { +#ifdef DT_DIR + case DT_DIR: return entry_type::directory; +#endif +#ifdef DT_REG + case DT_REG: return entry_type::regular; +#endif +#ifdef DT_LNK + case DT_LNK: return entry_type::symlink; +#endif +#ifdef DT_BLK + case DT_BLK: +#endif +#ifdef DT_CHR + case DT_CHR: +#endif +#ifdef DT_FIFO + case DT_FIFO: +#endif +#ifdef DT_SOCK + case DT_SOCK: +#endif + return entry_type::other; + + default: return entry_type::unknown; + } + } + + template + inline constexpr entry_type d_type (...) {return entry_type::unknown;} + + void dir_iterator:: + next () + { + for (;;) + { + errno = 0; + if (struct dirent* de = ::readdir (h_)) + { + const char* n (de->d_name); + + // Skip '.' and '..'. + // + if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) + continue; + + e_.p_ = path (n); + e_.t_ = d_type (de, nullptr); + e_.lt_ = entry_type::unknown; + } + else if (errno == 0) + { + // End of stream. + // + ::closedir (h_); + h_ = nullptr; + } + else + throw system_error (errno, system_category ()); + + break; + } + } +#else +#endif } -- cgit v1.1