forked from OctaForge/libostd
memory-safe dir ranges
parent
1668750308
commit
f395562734
4
build.cc
4
build.cc
|
@ -66,8 +66,8 @@ static fs::path OSTD_SHARED_LIB = "libostd.so";
|
||||||
static fs::path OSTD_STATIC_LIB = "libostd.a";
|
static fs::path OSTD_STATIC_LIB = "libostd.a";
|
||||||
|
|
||||||
static std::string DEFAULT_CXXFLAGS = "-std=c++1z -I. -O2 -Wall -Wextra "
|
static std::string DEFAULT_CXXFLAGS = "-std=c++1z -I. -O2 -Wall -Wextra "
|
||||||
"-Wshadow -Wold-style-cast -fPIC ";
|
"-Wshadow -Wold-style-cast -fPIC "
|
||||||
"-D_FILE_OFFSET_BITS=64"
|
"-D_FILE_OFFSET_BITS=64";
|
||||||
static std::string DEFAULT_LDFLAGS = "-pthread";
|
static std::string DEFAULT_LDFLAGS = "-pthread";
|
||||||
static std::string DEFAULT_ASFLAGS = "-fPIC";
|
static std::string DEFAULT_ASFLAGS = "-fPIC";
|
||||||
|
|
||||||
|
|
125
ostd/path.hh
125
ostd/path.hh
|
@ -26,6 +26,7 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
@ -724,6 +725,51 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
struct OSTD_EXPORT dir_range_impl {
|
||||||
|
void open(path const &p);
|
||||||
|
void close() noexcept;
|
||||||
|
void read_next();
|
||||||
|
|
||||||
|
bool empty() const noexcept {
|
||||||
|
return p_current.path().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_entry const &front() const noexcept {
|
||||||
|
return p_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
~dir_range_impl() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_entry p_current{};
|
||||||
|
path p_dir{};
|
||||||
|
void *p_handle = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OSTD_EXPORT rdir_range_impl {
|
||||||
|
using hstack = std::stack<void *, std::list<void *>>;
|
||||||
|
|
||||||
|
void open(path const &p);
|
||||||
|
void close() noexcept;
|
||||||
|
void read_next();
|
||||||
|
|
||||||
|
bool empty() const noexcept {
|
||||||
|
return p_current.path().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_entry const &front() const noexcept {
|
||||||
|
return p_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
~rdir_range_impl() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_entry p_current{};
|
||||||
|
path p_dir{};
|
||||||
|
hstack p_handles{};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct directory_range: input_range<directory_range> {
|
struct directory_range: input_range<directory_range> {
|
||||||
|
@ -733,47 +779,26 @@ struct directory_range: input_range<directory_range> {
|
||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
|
|
||||||
directory_range() = delete;
|
directory_range() = delete;
|
||||||
directory_range(path const &p) {
|
directory_range(path const &p):
|
||||||
open(p);
|
p_impl{std::make_shared<detail::dir_range_impl>()}
|
||||||
}
|
{
|
||||||
|
p_impl->open(p);
|
||||||
directory_range(directory_range const &r):
|
|
||||||
p_current(r.p_current), p_dir(r.p_dir),
|
|
||||||
p_handle(r.p_handle), p_owned(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~directory_range() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
directory_range &operator=(directory_range const &r) noexcept {
|
|
||||||
close();
|
|
||||||
p_handle = r.p_handle;
|
|
||||||
p_owned = false;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const noexcept {
|
bool empty() const noexcept {
|
||||||
return p_current.path().empty();
|
return p_impl->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_front() {
|
void pop_front() {
|
||||||
read_next();
|
p_impl->read_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const noexcept {
|
reference front() const noexcept {
|
||||||
return p_current;
|
return p_impl->front();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OSTD_EXPORT void open(path const &p);
|
std::shared_ptr<detail::dir_range_impl> p_impl;
|
||||||
OSTD_EXPORT void close() noexcept;
|
|
||||||
OSTD_EXPORT void read_next();
|
|
||||||
|
|
||||||
directory_entry p_current{};
|
|
||||||
path p_dir{};
|
|
||||||
void *p_handle = nullptr;
|
|
||||||
bool p_owned = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct recursive_directory_range: input_range<recursive_directory_range> {
|
struct recursive_directory_range: input_range<recursive_directory_range> {
|
||||||
|
@ -783,52 +808,26 @@ struct recursive_directory_range: input_range<recursive_directory_range> {
|
||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
|
|
||||||
recursive_directory_range() = delete;
|
recursive_directory_range() = delete;
|
||||||
recursive_directory_range(path const &p) {
|
recursive_directory_range(path const &p):
|
||||||
open(p);
|
p_impl{std::make_shared<detail::rdir_range_impl>()}
|
||||||
}
|
{
|
||||||
|
p_impl->open(p);
|
||||||
recursive_directory_range(recursive_directory_range const &r):
|
|
||||||
p_current(r.p_current), p_dir(r.p_dir),
|
|
||||||
p_stack(r.p_stack), p_owned(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~recursive_directory_range() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
recursive_directory_range &operator=(
|
|
||||||
recursive_directory_range const &r
|
|
||||||
) noexcept {
|
|
||||||
close();
|
|
||||||
p_stack = r.p_stack;
|
|
||||||
p_owned = false;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const noexcept {
|
bool empty() const noexcept {
|
||||||
return p_current.path().empty();
|
return p_impl->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_front() {
|
void pop_front() {
|
||||||
read_next();
|
p_impl->read_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const noexcept {
|
reference front() const noexcept {
|
||||||
return p_current;
|
return p_impl->front();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using hstack = std::stack<void *, std::list<void *>>;
|
std::shared_ptr<detail::rdir_range_impl> p_impl;
|
||||||
|
|
||||||
OSTD_EXPORT void open(path const &p);
|
|
||||||
OSTD_EXPORT void close() noexcept;
|
|
||||||
OSTD_EXPORT void read_next();
|
|
||||||
|
|
||||||
directory_entry p_current{};
|
|
||||||
path p_dir{};
|
|
||||||
hstack p_handles{};
|
|
||||||
hstack *p_stack = nullptr;
|
|
||||||
bool p_owned = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OSTD_EXPORT path cwd();
|
OSTD_EXPORT path cwd();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
|
static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
|
||||||
struct dirent d;
|
struct dirent d;
|
||||||
|
@ -37,7 +38,7 @@ static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
|
||||||
|
|
||||||
/* dir range */
|
/* dir range */
|
||||||
|
|
||||||
OSTD_EXPORT void directory_range::open(path const &p) {
|
OSTD_EXPORT void dir_range_impl::open(path const &p) {
|
||||||
DIR *d = opendir(p.string().data());
|
DIR *d = opendir(p.string().data());
|
||||||
if (!d) {
|
if (!d) {
|
||||||
/* FIXME: throw */
|
/* FIXME: throw */
|
||||||
|
@ -45,50 +46,39 @@ OSTD_EXPORT void directory_range::open(path const &p) {
|
||||||
}
|
}
|
||||||
p_dir = p;
|
p_dir = p;
|
||||||
p_handle = d;
|
p_handle = d;
|
||||||
p_owned = true;
|
|
||||||
read_next();
|
read_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
OSTD_EXPORT void directory_range::close() noexcept {
|
OSTD_EXPORT void dir_range_impl::close() noexcept {
|
||||||
if (!p_owned) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
closedir(static_cast<DIR *>(p_handle));
|
closedir(static_cast<DIR *>(p_handle));
|
||||||
p_owned = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OSTD_EXPORT void directory_range::read_next() {
|
OSTD_EXPORT void dir_range_impl::read_next() {
|
||||||
dir_read_next(static_cast<DIR *>(p_handle), p_current, p_dir);
|
dir_read_next(static_cast<DIR *>(p_handle), p_current, p_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* recursive dir range */
|
/* recursive dir range */
|
||||||
|
|
||||||
OSTD_EXPORT void recursive_directory_range::open(path const &p) {
|
OSTD_EXPORT void rdir_range_impl::open(path const &p) {
|
||||||
DIR *d = opendir(p.string().data());
|
DIR *d = opendir(p.string().data());
|
||||||
if (!d) {
|
if (!d) {
|
||||||
/* FIXME: throw */
|
/* FIXME: throw */
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
p_dir = p;
|
p_dir = p;
|
||||||
p_stack = &p_handles;
|
p_handles.push(d);
|
||||||
p_stack->push(d);
|
|
||||||
p_owned = true;
|
|
||||||
read_next();
|
read_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
OSTD_EXPORT void recursive_directory_range::close() noexcept {
|
OSTD_EXPORT void rdir_range_impl::close() noexcept {
|
||||||
if (!p_owned) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (!p_handles.empty()) {
|
while (!p_handles.empty()) {
|
||||||
closedir(static_cast<DIR *>(p_handles.top()));
|
closedir(static_cast<DIR *>(p_handles.top()));
|
||||||
p_handles.pop();
|
p_handles.pop();
|
||||||
}
|
}
|
||||||
p_owned = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OSTD_EXPORT void recursive_directory_range::read_next() {
|
OSTD_EXPORT void rdir_range_impl::read_next() {
|
||||||
if (p_stack->empty()) {
|
if (p_handles.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
@ -106,7 +96,7 @@ OSTD_EXPORT void recursive_directory_range::read_next() {
|
||||||
dir_read_next(nd, curd, based);
|
dir_read_next(nd, curd, based);
|
||||||
if (!curd.path().empty()) {
|
if (!curd.path().empty()) {
|
||||||
p_dir = based;
|
p_dir = based;
|
||||||
p_stack->push(nd);
|
p_handles.push(nd);
|
||||||
p_current = curd;
|
p_current = curd;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -114,20 +104,21 @@ OSTD_EXPORT void recursive_directory_range::read_next() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 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_stack->top()), p_current, p_dir);
|
dir_read_next(static_cast<DIR *>(p_handles.top()), p_current, p_dir);
|
||||||
/* 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_stack->top()));
|
closedir(static_cast<DIR *>(p_handles.top()));
|
||||||
p_stack->pop();
|
p_handles.pop();
|
||||||
if (!p_stack->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_stack->top()), p_current, p_dir);
|
dir_read_next(static_cast<DIR *>(p_handles.top()), p_current, p_dir);
|
||||||
} else {
|
} else {
|
||||||
p_current.clear();
|
p_current.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} /* namespace detail */
|
||||||
} /* namesapce fs */
|
} /* namesapce fs */
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
Loading…
Reference in New Issue