add checking file types to directory entry

master
Daniel Kolesa 2018-04-17 23:13:46 +02:00
parent 4c0c4e8f41
commit 64a529254c
3 changed files with 96 additions and 26 deletions

View File

@ -12,7 +12,7 @@ using namespace ostd;
inline void list_dirs(path const &path, int off = 0) { inline void list_dirs(path const &path, int off = 0) {
fs::directory_range ds{path}; fs::directory_range ds{path};
for (auto &v: ds) { for (auto &v: ds) {
if (!fs::is_directory(v.path())) { if (!v.is_directory()) {
continue; continue;
} }
for_each(range(off), [](int) { write(' '); }); for_each(range(off), [](int) { write(' '); });

View File

@ -795,7 +795,7 @@ public:
OSTD_EXPORT file_mode mode(path const &p); OSTD_EXPORT file_mode mode(path const &p);
OSTD_EXPORT file_mode symlink_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; return st.type() == file_type::block;
} }
@ -803,7 +803,7 @@ inline bool is_block_file(path const &p) {
return is_block_file(mode(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; return st.type() == file_type::character;
} }
@ -811,7 +811,7 @@ inline bool is_character_file(path const &p) {
return is_character_file(mode(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; return st.type() == file_type::directory;
} }
@ -819,7 +819,7 @@ inline bool is_directory(path const &p) {
return is_directory(mode(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; return st.type() == file_type::regular;
} }
@ -827,7 +827,7 @@ inline bool is_regular_file(path const &p) {
return is_regular_file(mode(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; return st.type() == file_type::fifo;
} }
@ -835,7 +835,7 @@ inline bool is_fifo(path const &p) {
return is_fifo(mode(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; return st.type() == file_type::symlink;
} }
@ -843,7 +843,7 @@ inline bool is_symlink(path const &p) {
return is_symlink(mode(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; return st.type() == file_type::socket;
} }
@ -851,7 +851,7 @@ inline bool is_socket(path const &p) {
return is_socket(mode(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; return st.type() == file_type::unknown;
} }
@ -859,7 +859,7 @@ inline bool is_other(path const &p) {
return is_other(mode(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; return st.type() != file_type::none;
} }
@ -867,9 +867,9 @@ inline bool mode_known(path const &p) {
return mode_known(mode(p)); return mode_known(mode(p));
} }
struct file_info { struct file_status {
file_info() {} file_status() {}
file_info(ostd::path const &p): p_path(p) {} file_status(ostd::path const &p): p_path(p) {}
ostd::path const &path() const noexcept { ostd::path const &path() const noexcept {
return p_path; return p_path;
@ -895,9 +895,16 @@ private:
ostd::path p_path{}; ostd::path p_path{};
}; };
namespace detail {
struct dir_range_impl;
struct rdir_range_impl;
} /* namespace detail */
struct directory_entry { struct directory_entry {
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 { ostd::path const &path() const noexcept {
return p_path; return p_path;
@ -907,8 +914,56 @@ struct directory_entry {
return p_path; 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: 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{}; ostd::path p_path{};
file_mode p_type{};
}; };
namespace detail { namespace detail {

View File

@ -93,7 +93,9 @@ namespace ostd {
namespace fs { namespace fs {
namespace detail { 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 d;
struct dirent *o; struct dirent *o;
for (;;) { for (;;) {
@ -102,7 +104,7 @@ static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
abort(); abort();
} }
if (!o) { if (!o) {
cur = directory_entry{}; cur = path{};
return; return;
} }
string_range nm{static_cast<char const *>(o->d_name)}; string_range nm{static_cast<char const *>(o->d_name)};
@ -111,6 +113,14 @@ static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
} }
path p{base}; path p{base};
p.append(nm); 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); cur = std::move(p);
break; break;
} }
@ -134,7 +144,10 @@ OSTD_EXPORT void dir_range_impl::close() noexcept {
} }
OSTD_EXPORT void dir_range_impl::read_next() { OSTD_EXPORT void dir_range_impl::read_next() {
dir_read_next(static_cast<DIR *>(p_handle), p_current, p_dir); path cur;
file_mode tp;
dir_read_next(static_cast<DIR *>(p_handle), cur, tp, p_dir);
p_current = directory_entry{std::move(cur), tp};
} }
/* recursive dir range */ /* recursive dir range */
@ -161,26 +174,29 @@ OSTD_EXPORT void rdir_range_impl::read_next() {
if (p_handles.empty()) { if (p_handles.empty()) {
return; return;
} }
path curd;
file_mode tp;
/* can't reuse info from dirent because we need to expand symlinks */ /* 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 */ /* directory, recurse into it and if it contains stuff, return */
DIR *nd = opendir(p_current.path().string().data()); DIR *nd = opendir(p_current.path().string().data());
if (!nd) { if (!nd) {
abort(); abort();
} }
directory_entry based = p_current, curd; directory_entry based = p_current;
dir_read_next(nd, curd, based); dir_read_next(nd, curd, tp, based);
if (!curd.path().empty()) { if (!curd.empty()) {
p_dir = based; p_dir = based;
p_handles.push(nd); p_handles.push(nd);
p_current = curd; p_current = directory_entry{std::move(curd), tp};
return; return;
} else { } else {
closedir(nd); closedir(nd);
} }
} }
/* didn't recurse into a directory, go to next file */ /* didn't recurse into a directory, go to next file */
dir_read_next(static_cast<DIR *>(p_handles.top()), p_current, p_dir); dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
p_current = directory_entry{std::move(curd), tp};
/* end of dir, pop while at it */ /* end of dir, pop while at it */
if (p_current.path().empty()) { if (p_current.path().empty()) {
closedir(static_cast<DIR *>(p_handles.top())); closedir(static_cast<DIR *>(p_handles.top()));
@ -188,9 +204,8 @@ OSTD_EXPORT void rdir_range_impl::read_next() {
if (!p_handles.empty()) { if (!p_handles.empty()) {
/* got back to another dir, read next so it's valid */ /* got back to another dir, read next so it's valid */
p_dir.remove_name(); p_dir.remove_name();
dir_read_next(static_cast<DIR *>(p_handles.top()), p_current, p_dir); dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
} else { p_current = directory_entry{std::move(curd), tp};
p_current = directory_entry{};
} }
} }
} }