From 64a529254c6a2f1f68d6546928347218c3f696fc Mon Sep 17 00:00:00 2001 From: q66 Date: Tue, 17 Apr 2018 23:13:46 +0200 Subject: [PATCH] add checking file types to directory entry --- examples/listdir.cc | 2 +- ostd/path.hh | 81 +++++++++++++++++++++++++++++++++++++-------- src/posix/path.cc | 39 +++++++++++++++------- 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/examples/listdir.cc b/examples/listdir.cc index fb7b07d..7ddf803 100644 --- a/examples/listdir.cc +++ b/examples/listdir.cc @@ -12,7 +12,7 @@ using namespace ostd; inline void list_dirs(path const &path, int off = 0) { fs::directory_range ds{path}; for (auto &v: ds) { - if (!fs::is_directory(v.path())) { + if (!v.is_directory()) { continue; } for_each(range(off), [](int) { write(' '); }); diff --git a/ostd/path.hh b/ostd/path.hh index 11197a5..7363e47 100644 --- a/ostd/path.hh +++ b/ostd/path.hh @@ -795,7 +795,7 @@ public: OSTD_EXPORT file_mode mode(path const &p); OSTD_EXPORT file_mode symlink_mode(path const &p); -inline bool is_block_file(file_mode st) { +inline bool is_block_file(file_mode st) noexcept { return st.type() == file_type::block; } @@ -803,7 +803,7 @@ inline bool is_block_file(path const &p) { return is_block_file(mode(p)); } -inline bool is_character_file(file_mode st) { +inline bool is_character_file(file_mode st) noexcept { return st.type() == file_type::character; } @@ -811,7 +811,7 @@ inline bool is_character_file(path const &p) { return is_character_file(mode(p)); } -inline bool is_directory(file_mode st) { +inline bool is_directory(file_mode st) noexcept { return st.type() == file_type::directory; } @@ -819,7 +819,7 @@ inline bool is_directory(path const &p) { return is_directory(mode(p)); } -inline bool is_regular_file(file_mode st) { +inline bool is_regular_file(file_mode st) noexcept { return st.type() == file_type::regular; } @@ -827,7 +827,7 @@ inline bool is_regular_file(path const &p) { return is_regular_file(mode(p)); } -inline bool is_fifo(file_mode st) { +inline bool is_fifo(file_mode st) noexcept { return st.type() == file_type::fifo; } @@ -835,7 +835,7 @@ inline bool is_fifo(path const &p) { return is_fifo(mode(p)); } -inline bool is_symlink(file_mode st) { +inline bool is_symlink(file_mode st) noexcept { return st.type() == file_type::symlink; } @@ -843,7 +843,7 @@ inline bool is_symlink(path const &p) { return is_symlink(mode(p)); } -inline bool is_socket(file_mode st) { +inline bool is_socket(file_mode st) noexcept { return st.type() == file_type::socket; } @@ -851,7 +851,7 @@ inline bool is_socket(path const &p) { return is_socket(mode(p)); } -inline bool is_other(file_mode st) { +inline bool is_other(file_mode st) noexcept { return st.type() == file_type::unknown; } @@ -859,7 +859,7 @@ inline bool is_other(path const &p) { return is_other(mode(p)); } -inline bool mode_known(file_mode st) { +inline bool mode_known(file_mode st) noexcept { return st.type() != file_type::none; } @@ -867,9 +867,9 @@ inline bool mode_known(path const &p) { return mode_known(mode(p)); } -struct file_info { - file_info() {} - file_info(ostd::path const &p): p_path(p) {} +struct file_status { + file_status() {} + file_status(ostd::path const &p): p_path(p) {} ostd::path const &path() const noexcept { return p_path; @@ -895,9 +895,16 @@ private: ostd::path p_path{}; }; +namespace detail { + struct dir_range_impl; + struct rdir_range_impl; +} /* namespace detail */ + struct directory_entry { directory_entry() {} - directory_entry(ostd::path const &p): p_path(p) {} + directory_entry(ostd::path const &p): p_path(p) { + refresh(); + } ostd::path const &path() const noexcept { return p_path; @@ -907,8 +914,56 @@ struct directory_entry { return p_path; } + void refresh() { + p_type = symlink_mode(p_path); + } + + bool is_block_file() const noexcept { + return fs::is_block_file(p_type); + } + + bool is_character_file() const noexcept { + return fs::is_character_file(p_type); + } + + bool is_directory() const noexcept { + return fs::is_directory(p_type); + } + + bool is_fifo() const noexcept { + return fs::is_fifo(p_type); + } + + bool is_other() const noexcept { + return fs::is_other(p_type); + } + + bool is_regular_file() const noexcept { + return fs::is_regular_file(p_type); + } + + bool is_socket() const noexcept { + return fs::is_socket(p_type); + } + + bool is_symlink() const noexcept { + return fs::is_symlink(p_type); + } + + bool exists() const noexcept { + return (mode_known(p_type) && (p_type.type() != file_type::not_found)); + } + private: + friend struct detail::dir_range_impl; + friend struct detail::rdir_range_impl; + + directory_entry(ostd::path &&p, file_mode tp): + p_path(p), p_type(tp) + {} + ostd::path p_path{}; + file_mode p_type{}; }; namespace detail { diff --git a/src/posix/path.cc b/src/posix/path.cc index 8f2628b..3decbcf 100644 --- a/src/posix/path.cc +++ b/src/posix/path.cc @@ -93,7 +93,9 @@ namespace ostd { namespace fs { namespace detail { -static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) { +static void dir_read_next( + DIR *dh, path &cur, file_mode &tp, path const &base +) { struct dirent d; struct dirent *o; for (;;) { @@ -102,7 +104,7 @@ static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) { abort(); } if (!o) { - cur = directory_entry{}; + cur = path{}; return; } string_range nm{static_cast(o->d_name)}; @@ -111,6 +113,14 @@ static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) { } path p{base}; p.append(nm); +#ifdef DT_UNKNOWN + /* most systems have d_type */ + file_mode md{mode_to_type(DTTOIF(o->d_type))}; +#else + /* fallback mainly for legacy */ + file_mode md = symlink_mode(p); +#endif + tp = md; cur = std::move(p); break; } @@ -134,7 +144,10 @@ OSTD_EXPORT void dir_range_impl::close() noexcept { } OSTD_EXPORT void dir_range_impl::read_next() { - dir_read_next(static_cast(p_handle), p_current, p_dir); + path cur; + file_mode tp; + dir_read_next(static_cast(p_handle), cur, tp, p_dir); + p_current = directory_entry{std::move(cur), tp}; } /* recursive dir range */ @@ -161,26 +174,29 @@ OSTD_EXPORT void rdir_range_impl::read_next() { if (p_handles.empty()) { return; } + path curd; + file_mode tp; /* can't reuse info from dirent because we need to expand symlinks */ - if (is_directory(p_current.path())) { + if (p_current.is_directory()) { /* directory, recurse into it and if it contains stuff, return */ DIR *nd = opendir(p_current.path().string().data()); if (!nd) { abort(); } - directory_entry based = p_current, curd; - dir_read_next(nd, curd, based); - if (!curd.path().empty()) { + directory_entry based = p_current; + dir_read_next(nd, curd, tp, based); + if (!curd.empty()) { p_dir = based; p_handles.push(nd); - p_current = curd; + p_current = directory_entry{std::move(curd), tp}; return; } else { closedir(nd); } } /* didn't recurse into a directory, go to next file */ - dir_read_next(static_cast(p_handles.top()), p_current, p_dir); + dir_read_next(static_cast(p_handles.top()), curd, tp, p_dir); + p_current = directory_entry{std::move(curd), tp}; /* end of dir, pop while at it */ if (p_current.path().empty()) { closedir(static_cast(p_handles.top())); @@ -188,9 +204,8 @@ OSTD_EXPORT void rdir_range_impl::read_next() { if (!p_handles.empty()) { /* got back to another dir, read next so it's valid */ p_dir.remove_name(); - dir_read_next(static_cast(p_handles.top()), p_current, p_dir); - } else { - p_current = directory_entry{}; + dir_read_next(static_cast(p_handles.top()), curd, tp, p_dir); + p_current = directory_entry{std::move(curd), tp}; } } }