diff --git a/include/vfs/directory_entry.hpp b/include/vfs/directory_entry.hpp index b2a3337..01cb12a 100644 --- a/include/vfs/directory_entry.hpp +++ b/include/vfs/directory_entry.hpp @@ -17,16 +17,16 @@ class directory_entry { directory_entry(directory_entry&&) noexcept = default; directory_entry(Fs const& fs) noexcept - : fs_(fs.current_path(fs.current_path())) { } + : fs_(fs.shared_from_this()) { } explicit directory_entry(Fs const& fs, std::filesystem::path p) - : fs_(fs.current_path(fs.current_path())) + : fs_(fs.shared_from_this()) , path_(std::move(p)) { this->refresh(); } directory_entry(Fs const& fs, std::filesystem::path p, std::error_code& ec) - : fs_(fs.current_path(fs.current_path())) + : fs_(fs.shared_from_this()) , path_(std::move(p)) { this->refresh(ec); } @@ -415,7 +415,7 @@ class directory_entry { return this->status().type(); } - std::shared_ptr fs_; + std::shared_ptr fs_; std::filesystem::path path_; std::filesystem::file_type type_ = std::filesystem::file_type::none; }; diff --git a/include/vfs/fs.hpp b/include/vfs/fs.hpp index 019715f..dcd74b4 100644 --- a/include/vfs/fs.hpp +++ b/include/vfs/fs.hpp @@ -14,7 +14,7 @@ class directory_entry; class directory_iterator; class recursive_directory_iterator; -class Fs { +class Fs: public std::enable_shared_from_this { public: virtual ~Fs() = default; @@ -481,7 +481,7 @@ class Fs { * @param[in] p Path to change the current working directory to. * @return Same file system where the working directory is \p p. */ - [[nodiscard]] virtual std::shared_ptr current_path(std::filesystem::path const& p) const = 0; + [[nodiscard]] virtual std::shared_ptr current_path(std::filesystem::path const& p) const = 0; /** * @brief Creates a new Fs that share the same file system but have different working directory. @@ -490,7 +490,24 @@ class Fs { * @param[out] ec Error code to store error status to. * @return Same file system where the working directory is \p p. */ - [[nodiscard]] virtual std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept = 0; + [[nodiscard]] virtual std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept = 0; + + /** + * @brief Creates a new Fs that share the same file system but have different working directory. + * + * @param[in] p Path to change the current working directory to. + * @return Same file system where the working directory is \p p. + */ + [[nodiscard]] virtual std::shared_ptr current_path(std::filesystem::path const& p) = 0; + + /** + * @brief Creates a new Fs that share the same file system but have different working directory. + * + * @param[in] p Path to change the current working directory to. + * @param[out] ec Error code to store error status to. + * @return Same file system where the working directory is \p p. + */ + [[nodiscard]] virtual std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) noexcept = 0; /** * @brief Checks whether the path refers to an existing file system object @@ -1154,4 +1171,6 @@ std::shared_ptr make_mem_fs(std::filesystem::path const& temp_dir = "/tmp"); std::shared_ptr make_union_fs(Fs& upper, Fs const& lower); +std::shared_ptr make_read_only_fs(Fs const& fs); + } // namespace vfs diff --git a/internal/vfs/impl/fs.hpp b/internal/vfs/impl/fs.hpp index f01ae86..f6b201a 100644 --- a/internal/vfs/impl/fs.hpp +++ b/internal/vfs/impl/fs.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include #include +#include #include "vfs/impl/file.hpp" @@ -34,32 +36,20 @@ std::logic_error err_unknown_fs_() { } // namespace -inline FsBase& fs_base(Fs& fs) { - auto* b = dynamic_cast(&fs); +template +requires std::same_as, Fs> +inline auto& fs_base(T& fs) { + auto* b = dynamic_cast, FsBase const, FsBase>*>(&fs); if(b == nullptr) { throw err_unknown_fs_(); } return *b; } -inline FsBase const& fs_base(Fs const& fs) { - auto const* b = dynamic_cast(&fs); - if(b == nullptr) { - throw err_unknown_fs_(); - } - return *b; -} - -inline std::shared_ptr fs_base(std::shared_ptr&& fs) { - auto b = std::dynamic_pointer_cast(std::move(fs)); - if(!b) { - throw err_unknown_fs_(); - } - return b; -} - -inline std::shared_ptr fs_base(std::shared_ptr const& fs) { - auto b = std::dynamic_pointer_cast(fs); +template +requires std::same_as, Fs> +inline auto fs_base(std::shared_ptr fs) { + auto b = std::dynamic_pointer_cast, FsBase const, FsBase>>(std::move(fs)); if(!b) { throw err_unknown_fs_(); } diff --git a/internal/vfs/impl/fs_proxy.hpp b/internal/vfs/impl/fs_proxy.hpp index fd07a86..1fc0425 100644 --- a/internal/vfs/impl/fs_proxy.hpp +++ b/internal/vfs/impl/fs_proxy.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "vfs/impl/fs.hpp" @@ -14,20 +15,19 @@ namespace vfs { namespace impl { -class FsProxy: public FsBase { +template +requires std::same_as, FsBase> +class BasicFsProxy: public FsBase { public: - FsProxy(std::shared_ptr fs) - : fs_(fs_base(fs)) { } - - FsProxy(std::shared_ptr fs) - : fs_(std::move(fs)) { } + BasicFsProxy(std::conditional_t, Fs const, Fs>& fs) + : fs_(fs_base(fs.shared_from_this())) { } [[nodiscard]] std::shared_ptr open_read(std::filesystem::path const& filename, std::ios_base::openmode mode) const override { return this->fs_->open_read(filename, mode); } std::shared_ptr open_write(std::filesystem::path const& filename, std::ios_base::openmode mode) override { - return this->fs_->open_write(filename, mode); + return this->mutable_fs_()->open_write(filename, mode); } [[nodiscard]] std::shared_ptr change_root(std::filesystem::path const& p, std::filesystem::path const& temp_dir) const override { @@ -36,16 +36,16 @@ class FsProxy: public FsBase { } [[nodiscard]] std::shared_ptr change_root(std::filesystem::path const& p, std::filesystem::path const& temp_dir) override { - auto fs = this->fs_->change_root(p, temp_dir); + auto fs = this->mutable_fs_()->change_root(p, temp_dir); return this->make_proxy_(std::move(fs)); } void mount(std::filesystem::path const& target, Fs& other, std::filesystem::path const& source) override { - this->fs_->mount(target, other, source); + this->mutable_fs_()->mount(target, other, source); } void unmount(std::filesystem::path const& target) override { - this->fs_->unmount(target); + this->mutable_fs_()->unmount(target); } [[nodiscard]] std::filesystem::path canonical(std::filesystem::path const& p) const override { @@ -65,59 +65,59 @@ class FsProxy: public FsBase { } void copy(std::filesystem::path const& src, std::filesystem::path const& dst, std::filesystem::copy_options opts) override { - this->fs_->copy(src, dst, opts); + this->mutable_fs_()->copy(src, dst, opts); } void copy(std::filesystem::path const& src, std::filesystem::path const& dst, std::filesystem::copy_options opts, std::error_code& ec) override { - this->fs_->copy(src, dst, opts, ec); + this->mutable_fs_()->copy(src, dst, opts, ec); } bool copy_file(std::filesystem::path const& src, std::filesystem::path const& dst, std::filesystem::copy_options opts) override { - return this->fs_->copy_file(src, dst, opts); + return this->mutable_fs_()->copy_file(src, dst, opts); } bool copy_file(std::filesystem::path const& src, std::filesystem::path const& dst, std::filesystem::copy_options opts, std::error_code& ec) override { - return this->fs_->copy_file(src, dst, opts, ec); + return this->mutable_fs_()->copy_file(src, dst, opts, ec); } bool create_directory(std::filesystem::path const& p) override { - return this->fs_->create_directory(p); + return this->mutable_fs_()->create_directory(p); } bool create_directory(std::filesystem::path const& p, std::error_code& ec) noexcept override { - return this->fs_->create_directory(p, ec); + return this->mutable_fs_()->create_directory(p, ec); } bool create_directory(std::filesystem::path const& p, std::filesystem::path const& attr) override { - return this->fs_->create_directory(p, attr); + return this->mutable_fs_()->create_directory(p, attr); } bool create_directory(std::filesystem::path const& p, std::filesystem::path const& attr, std::error_code& ec) noexcept override { - return this->fs_->create_directory(p, attr, ec); + return this->mutable_fs_()->create_directory(p, attr, ec); } bool create_directories(std::filesystem::path const& p) override { - return this->fs_->create_directories(p); + return this->mutable_fs_()->create_directories(p); } bool create_directories(std::filesystem::path const& p, std::error_code& ec) override { - return this->fs_->create_directories(p, ec); + return this->mutable_fs_()->create_directories(p, ec); } void create_hard_link(std::filesystem::path const& target, std::filesystem::path const& link) override { - return this->fs_->create_hard_link(target, link); + return this->mutable_fs_()->create_hard_link(target, link); } void create_hard_link(std::filesystem::path const& target, std::filesystem::path const& link, std::error_code& ec) noexcept override { - return this->fs_->create_hard_link(target, link, ec); + return this->mutable_fs_()->create_hard_link(target, link, ec); } void create_symlink(std::filesystem::path const& target, std::filesystem::path const& link) override { - return this->fs_->create_symlink(target, link); + return this->mutable_fs_()->create_symlink(target, link); } void create_symlink(std::filesystem::path const& target, std::filesystem::path const& link, std::error_code& ec) noexcept override { - return this->fs_->create_symlink(target, link, ec); + return this->mutable_fs_()->create_symlink(target, link, ec); } [[nodiscard]] std::filesystem::path current_path() const override { @@ -128,11 +128,11 @@ class FsProxy: public FsBase { return this->fs_->current_path(ec); } - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override { + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override { return this->make_proxy_(this->fs_->current_path(p)); } - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept override { + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept override { auto fs = this->fs_->current_path(p, ec); if(ec) { return nullptr; @@ -141,6 +141,19 @@ class FsProxy: public FsBase { return this->make_proxy_(std::move(fs)); } + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) override { + return this->make_proxy_(this->mutable_fs_()->current_path(p)); + } + + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) noexcept override { + auto fs = this->mutable_fs_()->current_path(p, ec); + if(ec) { + return nullptr; + } + + return this->make_proxy_(std::move(fs)); + } + [[nodiscard]] bool equivalent(std::filesystem::path const& p1, std::filesystem::path const& p2) const override { return this->fs_->equivalent(p1, p2); } @@ -174,19 +187,19 @@ class FsProxy: public FsBase { } void last_write_time(std::filesystem::path const& p, std::filesystem::file_time_type t) override { - this->fs_->last_write_time(p, t); + this->mutable_fs_()->last_write_time(p, t); } void last_write_time(std::filesystem::path const& p, std::filesystem::file_time_type t, std::error_code& ec) noexcept override { - this->fs_->last_write_time(p, t, ec); + this->mutable_fs_()->last_write_time(p, t, ec); } void permissions(std::filesystem::path const& p, std::filesystem::perms prms, std::filesystem::perm_options opts) override { - this->fs_->permissions(p, prms, opts); + this->mutable_fs_()->permissions(p, prms, opts); } void permissions(std::filesystem::path const& p, std::filesystem::perms prms, std::filesystem::perm_options opts, std::error_code& ec) override { - this->fs_->permissions(p, prms, opts, ec); + this->mutable_fs_()->permissions(p, prms, opts, ec); } [[nodiscard]] std::filesystem::path read_symlink(std::filesystem::path const& p) const override { @@ -198,35 +211,35 @@ class FsProxy: public FsBase { } bool remove(std::filesystem::path const& p) override { - return this->fs_->remove(p); + return this->mutable_fs_()->remove(p); } bool remove(std::filesystem::path const& p, std::error_code& ec) noexcept override { - return this->fs_->remove(p, ec); + return this->mutable_fs_()->remove(p, ec); } std::uintmax_t remove_all(std::filesystem::path const& p) override { - return this->fs_->remove_all(p); + return this->mutable_fs_()->remove_all(p); } std::uintmax_t remove_all(std::filesystem::path const& p, std::error_code& ec) override { - return this->fs_->remove_all(p, ec); + return this->mutable_fs_()->remove_all(p, ec); } void rename(std::filesystem::path const& src, std::filesystem::path const& dst) override { - this->fs_->rename(src, dst); + this->mutable_fs_()->rename(src, dst); } void rename(std::filesystem::path const& src, std::filesystem::path const& dst, std::error_code& ec) noexcept override { - this->fs_->rename(src, dst, ec); + this->mutable_fs_()->rename(src, dst, ec); } void resize_file(std::filesystem::path const& p, std::uintmax_t n) override { - this->fs_->resize_file(p, n); + this->mutable_fs_()->resize_file(p, n); } void resize_file(std::filesystem::path const& p, std::uintmax_t n, std::error_code& ec) noexcept override { - this->fs_->resize_file(p, n, ec); + this->mutable_fs_()->resize_file(p, n, ec); } [[nodiscard]] std::filesystem::space_info space(std::filesystem::path const& p) const override { @@ -274,7 +287,7 @@ class FsProxy: public FsBase { } [[nodiscard]] std::shared_ptr file_at(std::filesystem::path const& p) override { - return this->fs_->file_at(p); + return this->mutable_fs_()->file_at(p); } [[nodiscard]] std::shared_ptr file_at_followed(std::filesystem::path const& p) const override { @@ -282,7 +295,7 @@ class FsProxy: public FsBase { } [[nodiscard]] std::shared_ptr file_at_followed(std::filesystem::path const& p) override { - return this->fs_->file_at_followed(p); + return this->mutable_fs_()->file_at_followed(p); } [[nodiscard]] std::shared_ptr cwd() const override { @@ -290,24 +303,36 @@ class FsProxy: public FsBase { } [[nodiscard]] std::shared_ptr cwd() override { - return this->fs_->cwd(); + return this->mutable_fs_()->cwd(); } [[nodiscard]] std::shared_ptr source_fs() const { return this->fs_; } - [[nodiscard]] std::shared_ptr const& source_fs() { + [[nodiscard]] auto const& source_fs() { return this->fs_; } protected: + [[nodiscard]] std::shared_ptr> const& mutable_fs_() const { + if constexpr(std::is_const_v) { + throw std::filesystem::filesystem_error("", std::make_error_code(std::errc::read_only_file_system)); + } else { + return this->fs_; + } + } + void copy_(std::filesystem::path const& src, Fs& other, std::filesystem::path const& dst, std::filesystem::copy_options opts) const override { this->fs_->copy(src, other, dst, opts); } - [[nodiscard]] virtual std::shared_ptr make_proxy_(std::shared_ptr fs) const { - return std::make_shared(std::move(fs)); + [[nodiscard]] virtual std::shared_ptr const> make_proxy_(std::shared_ptr fs) const { + return std::make_shared>(*fs); + } + + [[nodiscard]] virtual std::shared_ptr> make_proxy_(std::shared_ptr fs) { + return std::make_shared>(*fs); } [[nodiscard]] std::shared_ptr cursor_(std::filesystem::path const& p, std::filesystem::directory_options opts) const override { @@ -318,9 +343,12 @@ class FsProxy: public FsBase { return Fs::recursive_cursor_of_(*this->fs_, p, opts); } - std::shared_ptr fs_; + std::shared_ptr, FsBase const, FsBase>> fs_; }; +using FsProxy = BasicFsProxy; +using ReadOnlyFsProxy = BasicFsProxy; + template T> T* fs_cast(std::conditional_t, Fs const, Fs>* fs) { if(auto proxy = dynamic_cast, FsProxy const, FsProxy>*>(fs); proxy) { diff --git a/internal/vfs/impl/os_fs.hpp b/internal/vfs/impl/os_fs.hpp index b384be9..caefc8a 100644 --- a/internal/vfs/impl/os_fs.hpp +++ b/internal/vfs/impl/os_fs.hpp @@ -1,10 +1,12 @@ #pragma once +#include #include #include #include #include #include +#include #include #include "vfs/impl/file.hpp" @@ -20,16 +22,21 @@ namespace vfs { namespace impl { -class OsFsProxy: public FsProxy { +template +requires std::same_as, FsBase> +class OsFsProxy: public BasicFsProxy { public: - OsFsProxy(std::shared_ptr fs) - : FsProxy(std::move(fs)) { } + using BasicFsProxy::BasicFsProxy; void mount(std::filesystem::path const& target, Fs& other, std::filesystem::path const& source) override; protected: - [[nodiscard]] std::shared_ptr make_proxy_(std::shared_ptr fs) const override { - return std::make_shared(fs_base(std::move(fs))); + [[nodiscard]] std::shared_ptr const> make_proxy_(std::shared_ptr fs) const override { + return std::make_shared>(*fs); + } + + [[nodiscard]] std::shared_ptr> make_proxy_(std::shared_ptr fs) override { + return std::make_shared>(*fs); } }; @@ -177,7 +184,7 @@ class StdFs: public OsFs { return this->cwd_; } - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override { + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override { auto c = this->canonical(p); if(!this->is_directory(c)) { throw std::filesystem::filesystem_error("", c, std::make_error_code(std::errc::not_a_directory)); @@ -186,7 +193,15 @@ class StdFs: public OsFs { return std::make_shared(this->canonical(p)); } - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept override { + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept override { + return handle_error([&] { return this->current_path(p); }, ec); + } + + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) override { + return std::const_pointer_cast(static_cast(this)->current_path(p)); + } + + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) noexcept override { return handle_error([&] { return this->current_path(p); }, ec); } @@ -377,7 +392,7 @@ class ChRootedStdFs: public StdFs { return this->confine_(StdFs::weakly_canonical(p)); } - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override { + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override { auto c = this->canonical(p); if(!this->is_directory(c)) { throw std::filesystem::filesystem_error("", c, std::make_error_code(std::errc::not_a_directory)); diff --git a/internal/vfs/impl/vfs.hpp b/internal/vfs/impl/vfs.hpp index 36dbbb3..cfe8a02 100644 --- a/internal/vfs/impl/vfs.hpp +++ b/internal/vfs/impl/vfs.hpp @@ -79,8 +79,11 @@ class Vfs: public FsBase { [[nodiscard]] std::filesystem::path current_path() const override; [[nodiscard]] std::filesystem::path current_path(std::error_code& ec) const override; - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override; - [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept override; + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) const override; + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) const noexcept override; + + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p) override; + [[nodiscard]] std::shared_ptr current_path(std::filesystem::path const& p, std::error_code& ec) noexcept override; [[nodiscard]] bool equivalent(std::filesystem::path const& p1, std::filesystem::path const& p2) const override; [[nodiscard]] bool equivalent(std::filesystem::path const& p1, std::filesystem::path const& p2, std::error_code& ec) const noexcept override; diff --git a/src/mount.cpp b/src/mount.cpp index 73913b0..7341015 100644 --- a/src/mount.cpp +++ b/src/mount.cpp @@ -142,7 +142,13 @@ std::shared_ptr StdFs::make_mount(fs::path const& target, Fs& other, fs::pa return vfs; } -void OsFsProxy::mount(fs::path const& target, Fs& other, fs::path const& source) { +template<> +void OsFsProxy::mount(std::filesystem::path const& target, Fs& other, std::filesystem::path const& source) { + throw fs::filesystem_error("", std::make_error_code(std::errc::read_only_file_system)); +} + +template<> +void OsFsProxy::mount(fs::path const& target, Fs& other, fs::path const& source) { if(auto os_fs = std::dynamic_pointer_cast(this->fs_); os_fs) { this->fs_ = os_fs->make_mount(target, other, source); } else { diff --git a/src/os_fs.cpp b/src/os_fs.cpp index 43bd96d..a6ebb23 100644 --- a/src/os_fs.cpp +++ b/src/os_fs.cpp @@ -171,7 +171,11 @@ fs::path ChRootedStdFs::os_path_of(fs::path const& p) const { std::shared_ptr make_os_fs() { auto std_fs = std::make_shared(fs::current_path()); - return std::make_shared(std::move(std_fs)); + return std::make_shared>(*std_fs); +} + +std::shared_ptr make_read_only_fs(Fs const& fs) { + return std::make_shared(fs); } } // namespace vfs diff --git a/src/vfs.cpp b/src/vfs.cpp index e017d3d..e2ae0fb 100644 --- a/src/vfs.cpp +++ b/src/vfs.cpp @@ -301,15 +301,23 @@ fs::path Vfs::current_path(std::error_code& ec) const { return this->cwd_->path(); } -std::shared_ptr Vfs::current_path(fs::path const& p) const { +std::shared_ptr Vfs::current_path(fs::path const& p) const { auto d = this->navigate(p / "")->must_be(); return std::make_shared(*this, const_cast(*d)); } -std::shared_ptr Vfs::current_path(fs::path const& p, std::error_code& ec) const noexcept { +std::shared_ptr Vfs::current_path(fs::path const& p, std::error_code& ec) const noexcept { return handle_error([&] { return this->current_path(p); }, ec); } +std::shared_ptr Vfs::current_path(fs::path const& p) { + return std::const_pointer_cast(static_cast(this)->current_path(p)); +} + +std::shared_ptr Vfs::current_path(fs::path const& p, std::error_code& ec) noexcept { + return std::const_pointer_cast(static_cast(this)->current_path(p, ec)); +} + bool Vfs::equivalent(fs::path const& p1, fs::path const& p2) const { std::shared_ptr f1; std::shared_ptr f2;