diff --git a/support/include/utils/error.hpp b/support/include/utils/error.hpp index 11671fdf..bf3e9778 100644 --- a/support/include/utils/error.hpp +++ b/support/include/utils/error.hpp @@ -42,11 +42,33 @@ protected: i_exception_handler() = default; }; +struct iostream_exception_handler final : i_exception_handler { + void handle_exception(std::string_view function_name) const override { + std::cerr << function_name << "|exception|unknown" << std::endl; + } + + void handle_exception(std::string_view function_name, + const std::exception &ex) const override { + std::cerr << function_name << "|exception|" + << (ex.what() == nullptr ? "unknown" : ex.what()) << std::endl; + } +}; +inline const iostream_exception_handler default_exception_handler{}; + +extern std::atomic exception_handler; + +#if defined(PROJECT_ENABLE_TESTING) +[[nodiscard]] inline auto +get_exception_handler() -> const i_exception_handler * { + return exception_handler; +} +#endif // defined(PROJECT_ENABLE_TESTING) + void handle_exception(std::string_view function_name); void handle_exception(std::string_view function_name, const std::exception &ex); -void set_exception_handler(i_exception_handler *handler); +void set_exception_handler(const i_exception_handler *handler); } // namespace repertory::utils::error #endif // REPERTORY_INCLUDE_UTILS_ERROR_HPP_ diff --git a/support/include/utils/file.hpp b/support/include/utils/file.hpp index 0ea91979..e0f682ac 100644 --- a/support/include/utils/file.hpp +++ b/support/include/utils/file.hpp @@ -295,6 +295,89 @@ public: [[nodiscard]] operator bool() const override { return file_ != nullptr; } }; +#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) +class enc_file final : public i_file { +public: + [[nodiscard]] static auto attach_file(fs_file_t file) -> fs_file_t; + +public: + enc_file() noexcept = default; + +protected: + enc_file(fs_file_t file); + +public: + enc_file(const enc_file &) = delete; + + enc_file(enc_file &&move_file) noexcept : file_(std::move(move_file.file_)) {} + + ~enc_file() override { close(); } + +private: + fs_file_t file_; + +public: + void close() override; + + [[nodiscard]] auto exists() const -> bool override { return file_->exists(); } + + void flush() const override; + + [[nodiscard]] auto get_handle() const -> native_handle override { + return file_->get_handle(); + } + + [[nodiscard]] auto get_path() const -> std::string override { + return file_->get_path(); + } + + [[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override { + return file_->get_read_buffer_size(); + } + + [[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override; + + [[nodiscard]] auto is_read_only() const -> bool override { + return file_->is_read_only(); + }; + + [[nodiscard]] auto move_to(std::string_view new_path) -> bool override; + + [[nodiscard]] auto read(unsigned char *data, std::size_t to_read, + std::uint64_t offset, + std::size_t *total_read = nullptr) -> bool override; + + [[nodiscard]] auto remove() -> bool override; + + auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override { + return file_->set_read_buffer_size(size); + } + + [[nodiscard]] auto size() const -> std::uint64_t override; + + [[nodiscard]] auto truncate(std::size_t size) -> bool override; + + [[nodiscard]] auto + write(const unsigned char *data, std::size_t to_write, std::size_t offset, + std::size_t *total_written = nullptr) -> bool override; + +public: + [[nodiscard]] operator bool() const override { + return static_cast(*file_); + } + + auto operator=(const file &) noexcept -> enc_file & = delete; + + auto operator=(enc_file &&move_file) noexcept -> enc_file & { + if (&move_file != this) { + file_ = std::move(move_file.file_); + } + + return *this; + } +}; +#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) + class thread_file final : public i_file { public: // [[nodiscard]] static auto diff --git a/support/include/utils/path.hpp b/support/include/utils/path.hpp index f1998b8e..56622da7 100644 --- a/support/include/utils/path.hpp +++ b/support/include/utils/path.hpp @@ -192,6 +192,10 @@ combine(std::string_view path, combine(std::wstring_view path, const std::vector &paths) -> std::wstring; +[[nodiscard]] auto contains_trash_directory(std::string_view path) -> bool; + +[[nodiscard]] auto contains_trash_directory(std::wstring_view path) -> bool; + [[nodiscard]] auto inline create_api_path(std::string_view path) -> std::string; [[nodiscard]] auto inline create_api_path(std::wstring_view path) @@ -224,10 +228,6 @@ get_parent_api_path(std::wstring_view path) -> std::wstring; [[nodiscard]] auto get_parent_directory(std::wstring_view path) -> std::wstring; -[[nodiscard]] auto is_trash_directory(std::string_view path) -> bool; - -[[nodiscard]] auto is_trash_directory(std::wstring_view path) -> bool; - [[nodiscard]] auto make_file_uri(std::string_view path) -> std::string; [[nodiscard]] auto make_file_uri(std::wstring_view path) -> std::wstring; diff --git a/support/src/utils/error.cpp b/support/src/utils/error.cpp index 6b42fa79..095e8945 100644 --- a/support/src/utils/error.cpp +++ b/support/src/utils/error.cpp @@ -21,51 +21,32 @@ */ #include "utils/error.hpp" -namespace { -struct default_exception_handler final - : repertory::utils::error::i_exception_handler { - void handle_exception(std::string_view function_name) const override { - std::cerr << function_name << "|exception|unknown" << std::endl; - } - - void handle_exception(std::string_view function_name, - const std::exception &ex) const override { - std::cerr << function_name << "|exception|" - << (ex.what() == nullptr ? "unknown" : ex.what()) << std::endl; - } -}; - -static default_exception_handler default_handler{}; - -static std::atomic - exception_handler{ - &default_handler, - }; -} // namespace - namespace repertory::utils::error { +std::atomic exception_handler{ + &default_exception_handler}; + void handle_exception(std::string_view function_name) { - i_exception_handler *handler{exception_handler}; + const i_exception_handler *handler{exception_handler}; if (handler != nullptr) { handler->handle_exception(function_name); return; } - default_handler.handle_exception(function_name); + default_exception_handler.handle_exception(function_name); } void handle_exception(std::string_view function_name, const std::exception &ex) { - i_exception_handler *handler{exception_handler}; + const i_exception_handler *handler{exception_handler}; if (handler != nullptr) { handler->handle_exception(function_name, ex); return; } - default_handler.handle_exception(function_name, ex); + default_exception_handler.handle_exception(function_name, ex); } -void set_exception_handler(i_exception_handler *handler) { +void set_exception_handler(const i_exception_handler *handler) { exception_handler = handler; } } // namespace repertory::utils::error diff --git a/support/src/utils/file_enc_file.cpp b/support/src/utils/file_enc_file.cpp new file mode 100644 index 00000000..9beb135f --- /dev/null +++ b/support/src/utils/file_enc_file.cpp @@ -0,0 +1,52 @@ +/* + Copyright <2018-2024> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "utils/file.hpp" + +#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) + +namespace repertory::utils::file { +auto enc_file::attach_file(fs_file_t file) -> fs_file_t {} + +enc_file::enc_file(fs_file_t file) : file_(std::move(file)) {} + +void enc_file::close() {} + +void enc_file::flush() const {} + +auto enc_file::get_time(time_types type) const -> std::uint64_t {} + +auto enc_file::move_to(std::string_view path) -> bool {} + +auto enc_file::read(unsigned char *data, std::size_t to_read, + std::uint64_t offset, std::size_t *total_read) -> bool {} + +auto enc_file::remove() -> bool {} + +auto enc_file::truncate(std::size_t size) -> bool {} + +auto enc_file::write(const unsigned char *data, std::size_t to_write, + std::size_t offset, std::size_t *total_written) -> bool {} + +auto enc_file::size() const -> std::uint64_t {} +} // namespace repertory::utils::file + +#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) diff --git a/support/src/utils/path.cpp b/support/src/utils/path.cpp index bde5ca79..172991e6 100644 --- a/support/src/utils/path.cpp +++ b/support/src/utils/path.cpp @@ -182,17 +182,18 @@ auto get_parent_directory(std::wstring_view path) -> std::wstring { get_parent_directory(utils::string::to_utf8(path))); } -auto is_trash_directory(std::string_view path) -> bool { - std::string dir_sep_t{get_directory_seperator()}; +auto contains_trash_directory(std::string_view path) -> bool { + auto parts = utils::string::split(utils::string::to_lower(absolute(path)), + get_directory_seperator(), false); - auto trash_path = utils::string::to_lower(absolute(path)); - return utils::string::begins_with(trash_path, dir_sep_t + ".trash-") || - utils::string::begins_with(trash_path, dir_sep_t + ".trashes") || - utils::string::begins_with(trash_path, dir_sep_t + "$recycle.bin"); + return std::find_if(parts.begin(), parts.end(), [](auto &&part) -> bool { + return utils::string::begins_with(part, ".trash-") || + part == ".trashes" || part == "$recycle.bin"; + }) != parts.end(); } -auto is_trash_directory(std::wstring_view path) -> bool { - return is_trash_directory(utils::string::to_utf8(path)); +auto contains_trash_directory(std::wstring_view path) -> bool { + return contains_trash_directory(utils::string::to_utf8(path)); } auto make_file_uri(std::string_view path) -> std::string { diff --git a/support/src/utils/time.cpp b/support/src/utils/time.cpp index 0c30977e..00b115c8 100644 --- a/support/src/utils/time.cpp +++ b/support/src/utils/time.cpp @@ -97,7 +97,7 @@ auto time64_to_unix_time(const __time64_t &time) -> std::uint64_t { // https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ auto unix_time_to_filetime(std::uint64_t unix_time) -> FILETIME { - const auto win_time = (unix_time / 100ULL) + 116444736000000000ULL; + auto win_time = (unix_time / 100ULL) + 116444736000000000ULL; FILETIME file_time{}; file_time.dwHighDateTime = static_cast(win_time >> 32U); file_time.dwLowDateTime = win_time & 0xFFFFFFFF; diff --git a/support/test/src/utils/error_test.cpp b/support/test/src/utils/error_test.cpp new file mode 100644 index 00000000..31f09b78 --- /dev/null +++ b/support/test/src/utils/error_test.cpp @@ -0,0 +1,65 @@ +/* + Copyright <2018-2024> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "test.hpp" + +namespace repertory { +template +constexpr bool is_decay_equ = std::is_same_v, U>; + +TEST(utils_error, check_default_exception_handler) { + EXPECT_EQ(&utils::error::default_exception_handler, + utils::error::get_exception_handler()); + + auto default_handler_is_iostream = + is_decay_equ; + EXPECT_TRUE(default_handler_is_iostream); +} + +TEST(utils_error, can_override_exception_handler) { + struct my_exc_handler : public utils::error::i_exception_handler { + MOCK_METHOD(void, handle_exception, (std::string_view function_name), + (const, override)); + + MOCK_METHOD(void, handle_exception, + (std::string_view function_name, const std::exception &ex), + (const, override)); + }; + + my_exc_handler handler{}; + utils::error::set_exception_handler(&handler); + + EXPECT_CALL(handler, handle_exception("test_func")).WillOnce(Return()); + utils::error::handle_exception("test_func"); + + auto ex = std::runtime_error("moose"); + EXPECT_CALL(handler, handle_exception(_, _)) + .WillOnce( + [&ex](std::string_view function_name, const std::exception &ex2) { + EXPECT_EQ("test_func_ex", function_name); + EXPECT_STREQ(ex.what(), ex2.what()); + }); + utils::error::handle_exception("test_func_ex", ex); + + utils::error::set_exception_handler(&utils::error::default_exception_handler); +} +} // namespace repertory diff --git a/support/test/src/utils/path_test.cpp b/support/test/src/utils/path_test.cpp index 25d81ea6..28b1cd63 100644 --- a/support/test/src/utils/path_test.cpp +++ b/support/test/src/utils/path_test.cpp @@ -393,4 +393,128 @@ TEST(utils_path, absolute_can_resolve_path_variables) { EXPECT_STREQ(home.c_str(), expanded_str.c_str()); #endif // defined(_WIN32) } + +TEST(utils_path, get_parent_directory) { +#if defined(_WIN32) + { + auto dir = R"(c:\test)"; + auto parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ("c:", parent.c_str()); + + dir = R"(c:\test\file.txt)"; + parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ(R"(c:\test)", parent.c_str()); + + dir = "c:"; + parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ("c:", parent.c_str()); + } + + { + auto dir = LR"(c:\test)"; + auto parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ(L"c:", parent.c_str()); + + dir = LR"(c:\test\file.txt)"; + parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ(LR"(c:\test)", parent.c_str()); + + dir = L"c:"; + parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ(L"c:", parent.c_str()); + } +#else // !defined(_WIN32) + { + auto dir = "/test"; + auto parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ("/", parent.c_str()); + + dir = "/test/test"; + parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ("/test", parent.c_str()); + } + + { + auto dir = L"/test"; + auto parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ(L"/", parent.c_str()); + + dir = L"/test/test"; + parent = utils::path::get_parent_directory(dir); + EXPECT_STREQ(L"/test", parent.c_str()); + } +#endif // defined(_WIN32) +} + +TEST(utils_path, contains_trash_directory) { +#if defined(_WIN32) + { + auto dir = R"(c:\$recycle.bin)"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + + dir = R"(c:\$recycle.bin\moose.txt)"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + } + + { + auto dir = LR"(c:\$recycle.bin)"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + + dir = LR"(c:\$recycle.bin\moose.txt)"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + } +#else // !defined(_WIN32) + { + auto dir = "/$recycle.bin"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + + dir = "/$recycle.bin/moose.txt"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + } + + { + auto dir = L"/$recycle.bin"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + + dir = L"/$recycle.bin/moose.txt"; + EXPECT_TRUE(utils::path::contains_trash_directory(dir)); + } +#endif // defined(_WIN32) +} + +TEST(utils_path, does_not_contain_trash_directory) { +#if defined(_WIN32) + { + auto dir = R"(c:\recycle.bin)"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + + dir = R"(c:\recycle.bin\moose.txt)"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + } + + { + auto dir = LR"(c:\recycle.bin)"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + + dir = LR"(c:\recycle.bin\moose.txt)"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + } +#else // !defined(_WIN32) + { + auto dir = "/recycle.bin"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + + dir = "/recycle.bin/moose.txt)"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + } + + { + auto dir = L"/recycle.bin"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + + dir = L"/recycle.bin/moose.txt)"; + EXPECT_FALSE(utils::path::contains_trash_directory(dir)); + } +#endif // defined(_WIN32) +} } // namespace repertory