aboutsummaryrefslogtreecommitdiff
path: root/butl/filesystem.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-07-09 12:25:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-07-09 12:25:47 +0200
commit02af7e788f3fef0dbba0ba49442054fb451f5bdc (patch)
tree5e0295bc0d06579cfffd0df3ad176945c9c51c79 /butl/filesystem.cxx
parent38c8f0efd8f033be8fb8278aa5d0eb704dedee55 (diff)
Implement directory iteration support
Diffstat (limited to 'butl/filesystem.cxx')
-rw-r--r--butl/filesystem.cxx133
1 files changed, 129 insertions, 4 deletions
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 <sys/types.h> // stat
#include <sys/stat.h> // stat, lstat(), S_IS*, mkdir()
+#include <memory> // unique_ptr
#include <system_error>
using namespace std;
@@ -17,25 +18,25 @@ namespace butl
// Figuring out whether we have the nanoseconds in some form.
//
template <typename S>
- 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 <typename S>
- 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 <typename S>
- 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 <typename S>
- 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<DIR, dir_deleter> 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 <typename D>
+ 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 <typename D>
+ 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<struct dirent> (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
}