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) {
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(' '); });

View File

@ -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 {

View File

@ -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<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};
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<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 */
@ -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<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 */
if (p_current.path().empty()) {
closedir(static_cast<DIR *>(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<DIR *>(p_handles.top()), p_current, p_dir);
} else {
p_current = directory_entry{};
dir_read_next(static_cast<DIR *>(p_handles.top()), curd, tp, p_dir);
p_current = directory_entry{std::move(curd), tp};
}
}
}