2018-04-15 21:23:19 +00:00
|
|
|
/* Path implementation bits.
|
|
|
|
*
|
|
|
|
* This file is part of libostd. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <dirent.h>
|
2018-04-15 22:19:48 +00:00
|
|
|
#include <sys/stat.h>
|
2018-04-15 21:23:19 +00:00
|
|
|
|
|
|
|
#include "ostd/path.hh"
|
|
|
|
|
|
|
|
namespace ostd {
|
|
|
|
namespace fs {
|
2018-04-15 23:58:59 +00:00
|
|
|
namespace detail {
|
2018-04-15 21:23:19 +00:00
|
|
|
|
2018-04-15 22:19:48 +00:00
|
|
|
static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
|
|
|
|
struct dirent d;
|
|
|
|
struct dirent *o;
|
|
|
|
for (;;) {
|
|
|
|
if (readdir_r(dh, &d, &o)) {
|
|
|
|
/* FIXME: throw */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if (!o) {
|
|
|
|
cur.clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
string_range nm{static_cast<char const *>(o->d_name)};
|
|
|
|
if ((nm == ".") || (nm == "..")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
path p{base};
|
|
|
|
p.append(nm);
|
|
|
|
cur.assign(std::move(p));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* dir range */
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
OSTD_EXPORT void dir_range_impl::open(path const &p) {
|
2018-04-15 21:23:19 +00:00
|
|
|
DIR *d = opendir(p.string().data());
|
|
|
|
if (!d) {
|
|
|
|
/* FIXME: throw */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
p_dir = p;
|
|
|
|
p_handle = d;
|
|
|
|
read_next();
|
|
|
|
}
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
OSTD_EXPORT void dir_range_impl::close() noexcept {
|
2018-04-15 21:23:19 +00:00
|
|
|
closedir(static_cast<DIR *>(p_handle));
|
|
|
|
}
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
OSTD_EXPORT void dir_range_impl::read_next() {
|
2018-04-15 22:19:48 +00:00
|
|
|
dir_read_next(static_cast<DIR *>(p_handle), p_current, p_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* recursive dir range */
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
OSTD_EXPORT void rdir_range_impl::open(path const &p) {
|
2018-04-15 22:19:48 +00:00
|
|
|
DIR *d = opendir(p.string().data());
|
|
|
|
if (!d) {
|
|
|
|
/* FIXME: throw */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
p_dir = p;
|
2018-04-15 23:58:59 +00:00
|
|
|
p_handles.push(d);
|
2018-04-15 22:19:48 +00:00
|
|
|
read_next();
|
|
|
|
}
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
OSTD_EXPORT void rdir_range_impl::close() noexcept {
|
2018-04-15 22:19:48 +00:00
|
|
|
while (!p_handles.empty()) {
|
|
|
|
closedir(static_cast<DIR *>(p_handles.top()));
|
|
|
|
p_handles.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
OSTD_EXPORT void rdir_range_impl::read_next() {
|
|
|
|
if (p_handles.empty()) {
|
2018-04-15 22:19:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
struct stat sb;
|
2018-04-15 23:10:03 +00:00
|
|
|
if (stat(p_current.path().string().data(), &sb) < 0) {
|
|
|
|
/* FIXME: throw */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if (S_ISDIR(sb.st_mode)) {
|
|
|
|
/* directory, recurse into it and if it contains stuff, return */
|
|
|
|
DIR *nd = opendir(p_current.path().string().data());
|
|
|
|
if (!nd) {
|
2018-04-15 21:23:19 +00:00
|
|
|
abort();
|
|
|
|
}
|
2018-04-15 23:10:03 +00:00
|
|
|
directory_entry based = p_current, curd;
|
|
|
|
dir_read_next(nd, curd, based);
|
|
|
|
if (!curd.path().empty()) {
|
|
|
|
p_dir = based;
|
2018-04-15 23:58:59 +00:00
|
|
|
p_handles.push(nd);
|
2018-04-15 22:19:48 +00:00
|
|
|
p_current = curd;
|
2018-04-15 21:23:19 +00:00
|
|
|
return;
|
2018-04-15 23:10:03 +00:00
|
|
|
} else {
|
|
|
|
closedir(nd);
|
2018-04-15 21:23:19 +00:00
|
|
|
}
|
2018-04-15 22:19:48 +00:00
|
|
|
}
|
2018-04-15 23:10:03 +00:00
|
|
|
/* didn't recurse into a directory, go to next file */
|
2018-04-15 23:58:59 +00:00
|
|
|
dir_read_next(static_cast<DIR *>(p_handles.top()), p_current, p_dir);
|
2018-04-15 23:10:03 +00:00
|
|
|
/* end of dir, pop while at it */
|
|
|
|
if (p_current.path().empty()) {
|
2018-04-15 23:58:59 +00:00
|
|
|
closedir(static_cast<DIR *>(p_handles.top()));
|
|
|
|
p_handles.pop();
|
|
|
|
if (!p_handles.empty()) {
|
2018-04-15 23:10:03 +00:00
|
|
|
/* got back to another dir, read next so it's valid */
|
|
|
|
p_dir.remove_name();
|
2018-04-15 23:58:59 +00:00
|
|
|
dir_read_next(static_cast<DIR *>(p_handles.top()), p_current, p_dir);
|
2018-04-15 23:10:03 +00:00
|
|
|
} else {
|
|
|
|
p_current.clear();
|
|
|
|
}
|
2018-04-15 21:23:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-15 23:58:59 +00:00
|
|
|
} /* namespace detail */
|
2018-04-15 21:23:19 +00:00
|
|
|
} /* namesapce fs */
|
|
|
|
} /* namespace ostd */
|