diff --git a/support/include/utils/file.hpp b/support/include/utils/file.hpp index 370b0bd0..3fb4200c 100644 --- a/support/include/utils/file.hpp +++ b/support/include/utils/file.hpp @@ -472,10 +472,12 @@ public: directory() noexcept = default; - directory(std::string_view path) : path_(utils::path::absolute(path)) {} + directory(std::string_view path, stop_type *stop_requested = nullptr) + : path_(utils::path::absolute(path)), stop_requested_(stop_requested) {} - directory(std::wstring_view path) - : path_(utils::path::absolute(utils::string::to_utf8(path))) {} + directory(std::wstring_view path, stop_type *stop_requested = nullptr) + : path_(utils::path::absolute(utils::string::to_utf8(path))), + stop_requested_(stop_requested) {} directory(const directory &) noexcept = delete; @@ -485,6 +487,7 @@ public: private: std::string path_; + stop_type *stop_requested_{nullptr}; public: [[nodiscard]] auto copy_to(std::string_view new_path, @@ -516,6 +519,8 @@ public: [[nodiscard]] auto get_path() const -> std::string override { return path_; } + [[nodiscard]] auto is_stop_requested() const -> bool override; + [[nodiscard]] auto is_symlink() const -> bool override; [[nodiscard]] auto move_to(std::string_view new_path) -> bool override; @@ -622,6 +627,7 @@ public: } [[nodiscard]] auto is_symlink() const -> bool override; + [[nodiscard]] auto move_to(std::string_view new_path) -> bool override; [[nodiscard]] auto open(bool read_only) -> bool; @@ -671,12 +677,13 @@ public: [[nodiscard]] static auto open(std::string_view host, std::string_view user, std::string_view password, - std::string_view share_name) -> smb_directory_t; + std::string_view path, + stop_type *stop_requested = nullptr) -> smb_directory_t; [[nodiscard]] static auto open(std::wstring_view host, std::wstring_view user, - std::wstring_view password, - std::wstring_view share_name) -> smb_directory_t; + std::wstring_view password, std::wstring_view path, + stop_type *stop_requested = nullptr) -> smb_directory_t; public: smb_directory() noexcept = default; @@ -689,17 +696,20 @@ public: private: smb_directory(std::string path, smb_session_t session, - std::string_view share_name, smb_tid tid) + std::string_view share_name, smb_tid tid, + stop_type *stop_requested) : path_(std::move(path)), session_(std::move(session)), share_name_(share_name), - tid_(tid) {} + tid_(tid), + stop_requested_(stop_requested) {} private: std::string path_{}; smb_session_t session_{}; std::string share_name_{}; smb_tid tid_{}; + stop_type *stop_requested_{nullptr}; public: [[nodiscard]] auto @@ -750,6 +760,8 @@ public: return smb_get_uri_path(path_, user, password); } + [[nodiscard]] auto is_stop_requested() const -> bool override; + [[nodiscard]] auto is_symlink() const -> bool override; [[nodiscard]] auto move_to(std::string_view new_path) -> bool override; diff --git a/support/include/utils/types/file/i_directory.hpp b/support/include/utils/types/file/i_directory.hpp index 464e9667..9746467e 100644 --- a/support/include/utils/types/file/i_directory.hpp +++ b/support/include/utils/types/file/i_directory.hpp @@ -43,8 +43,6 @@ struct i_directory : public i_fs_item { [[nodiscard]] virtual auto create_file(std::string_view file_name, bool read_only) const -> fs_file_t = 0; - [[nodiscard]] auto is_directory_item() const -> bool override { return true; } - [[nodiscard]] virtual auto get_directory(std::string_view path) const -> fs_directory_t = 0; @@ -58,6 +56,10 @@ struct i_directory : public i_fs_item { [[nodiscard]] virtual auto get_items() const -> std::vector = 0; + [[nodiscard]] auto is_directory_item() const -> bool override { return true; } + + [[nodiscard]] virtual auto is_stop_requested() const -> bool = 0; + [[nodiscard]] virtual auto remove_recursively() -> bool = 0; [[nodiscard]] virtual auto diff --git a/support/src/utils/file.cpp b/support/src/utils/file.cpp index 579c2182..63c9bb64 100644 --- a/support/src/utils/file.cpp +++ b/support/src/utils/file.cpp @@ -467,7 +467,7 @@ static constexpr const auto validate_smb_path = [](std::string_view path) -> bool { return (not utils::string::begins_with(path, "///") && utils::string::begins_with(path, "//") && - not utils::string::contains(path, " ") && + // not utils::string::contains(path, " ") && std::count(path.begin(), path.end(), '/') >= 3U); }; @@ -483,7 +483,6 @@ auto smb_create_smb_path(std::string_view smb_path, auto old_parts = repertory::utils::string::split(smb_path.substr(2U), '/', false); - old_parts.erase(std::next(old_parts.begin(), 2U), old_parts.end()); auto new_parts = repertory::utils::string::split(path, '/', false); old_parts.insert(old_parts.end(), new_parts.begin(), new_parts.end()); diff --git a/support/src/utils/file_directory.cpp b/support/src/utils/file_directory.cpp index a62a989b..c8714829 100644 --- a/support/src/utils/file_directory.cpp +++ b/support/src/utils/file_directory.cpp @@ -30,9 +30,14 @@ namespace { auto traverse_directory( std::string_view path, std::function directory_action, - std::function file_action) -> bool { + std::function file_action, + repertory::stop_type *stop_requested) -> bool { auto res{true}; + const auto is_stop_requested = [&stop_requested]() -> bool { + return (stop_requested != nullptr && !*stop_requested); + }; + #if defined(_WIN32) WIN32_FIND_DATAA fd{}; auto search = repertory::utils::path::combine(path, {"*.*"}); @@ -48,13 +53,15 @@ auto traverse_directory( if ((std::string_view(fd.cFileName) != ".") && (std::string_view(fd.cFileName) != "..")) { res = directory_action(repertory::utils::file::directory{ - repertory::utils::path::combine(path, {fd.cFileName})}); + repertory::utils::path::combine(path, {fd.cFileName}), + stop_requested_, + }); } } else { res = file_action(repertory::utils::file::file( repertory::utils::path::combine(path, {fd.cFileName}))); } - } while (res && (::FindNextFileA(find, &fd) != 0)); + } while (res && (::FindNextFileA(find, &fd) != 0) && !is_stop_requested()); ::FindClose(find); #else // !defined(_WIN32) @@ -66,7 +73,7 @@ auto traverse_directory( } struct dirent *de{nullptr}; - while (res && (de = readdir(root))) { + while (res && (de = readdir(root)) && !is_stop_requested()) { if (de->d_type == DT_DIR) { if ((std::string_view(de->d_name) != ".") && (std::string_view(de->d_name) != "..")) { @@ -127,7 +134,8 @@ auto directory::count(bool recursive) const -> std::uint64_t { [&ret](auto /* file_item */) -> bool { ++ret; return true; - }); + }, + stop_requested_); return ret; } catch (const std::exception &e) { @@ -147,7 +155,7 @@ auto directory::create_directory(std::string_view path) const try { auto abs_path = utils::path::combine(path_, {path}); - if (directory{abs_path}.exists()) { + if (directory{abs_path, stop_requested_}.exists()) { return std::make_unique(abs_path); } @@ -165,7 +173,8 @@ auto directory::create_directory(std::string_view path) const utils::string::split(abs_path, utils::path::directory_seperator, false); std::string current_path; - for (std::size_t idx = 0U; ret && (idx < paths.size()); ++idx) { + for (std::size_t idx = 0U; + !is_stop_requested() && ret && (idx < paths.size()); ++idx) { if (paths.at(idx).empty()) { current_path = utils::path::directory_seperator; continue; @@ -206,7 +215,9 @@ auto directory::get_directory(std::string_view path) const -> fs_directory_t { try { auto dir_path = utils::path::combine(path_, {path}); return fs_directory_t{ - directory{dir_path}.exists() ? new directory{dir_path} : nullptr, + directory{dir_path, stop_requested_}.exists() + ? new directory(dir_path, stop_requested_) + : nullptr, }; } catch (const std::exception &e) { utils::error::handle_exception(function_name, e); @@ -227,14 +238,14 @@ auto directory::get_directories() const -> std::vector { traverse_directory( path_, - [&ret](auto dir_item) -> bool { + [this, &ret](auto dir_item) -> bool { ret.emplace_back(fs_directory_t{ - new directory(dir_item.get_path()), + new directory(dir_item.get_path(), stop_requested_), }); return true; }, - [](auto /* file_item */) -> bool { return true; }); + [](auto /* file_item */) -> bool { return true; }, stop_requested_); return ret; } catch (const std::exception &e) { @@ -298,7 +309,8 @@ auto directory::get_files() const -> std::vector { new file(file_item.get_path()), }); return true; - }); + }, + stop_requested_); return ret; } catch (const std::exception &e) { @@ -320,9 +332,9 @@ auto directory::get_items() const -> std::vector { traverse_directory( path_, - [&ret](auto dir_item) -> bool { + [this, &ret](auto dir_item) -> bool { ret.emplace_back(fs_item_t{ - new directory(dir_item.get_path()), + new directory(dir_item.get_path(), stop_requested_), }); return true; }, @@ -331,7 +343,8 @@ auto directory::get_items() const -> std::vector { new file(file_item.get_path()), }); return true; - }); + }, + stop_requested_); return ret; } catch (const std::exception &e) { @@ -343,6 +356,10 @@ auto directory::get_items() const -> std::vector { return {}; } +auto directory::is_stop_requested() const -> bool { + return (stop_requested_ != nullptr) && *stop_requested_; +} + auto directory::is_symlink() const -> bool { static constexpr const std::string_view function_name{ static_cast(__FUNCTION__), @@ -415,7 +432,8 @@ auto directory::remove_recursively() -> bool { if (not traverse_directory( path_, [](auto dir_item) -> bool { return dir_item.remove_recursively(); }, - [](auto file_item) -> bool { return file_item.remove(); })) { + [](auto file_item) -> bool { return file_item.remove(); }, + stop_requested_)) { return false; } @@ -452,7 +470,8 @@ auto directory::size(bool recursive) const -> std::uint64_t { ret += cur_size.value(); } return true; - }); + }, + stop_requested_); return ret; } catch (const std::exception &e) { diff --git a/support/src/utils/file_smb_directory.cpp b/support/src/utils/file_smb_directory.cpp index 0f909d81..beb01d75 100644 --- a/support/src/utils/file_smb_directory.cpp +++ b/support/src/utils/file_smb_directory.cpp @@ -27,8 +27,8 @@ #if defined(PROJECT_ENABLE_LIBDSM) namespace repertory::utils::file { auto smb_directory::open(std::string_view host, std::string_view user, - std::string_view password, - std::string_view share_name) -> smb_directory_t { + std::string_view password, std::string_view path, + stop_type *stop_requested) -> smb_directory_t { static constexpr const std::string_view function_name{ static_cast(__FUNCTION__), }; @@ -74,9 +74,10 @@ auto smb_directory::open(std::string_view host, std::string_view user, std::to_string(res)); } + auto share_name = utils::string::split(path, '/', false).at(0U); + smb_tid tid{}; - res = - smb_tree_connect(session.get(), std::string{share_name}.c_str(), &tid); + res = smb_tree_connect(session.get(), share_name.c_str(), &tid); if (res != DSM_SUCCESS) { throw std::runtime_error("failed to connect to share|" + std::string{share_name} + '|' + @@ -85,10 +86,11 @@ auto smb_directory::open(std::string_view host, std::string_view user, return smb_directory_t{ new smb_directory{ - "//" + std::string{host} + "/" + std::string{share_name}, + "//" + std::string{host} + "/" + std::string{path}, session, share_name, tid, + stop_requested, }, }; } catch (const std::exception &e) { @@ -101,11 +103,11 @@ auto smb_directory::open(std::string_view host, std::string_view user, } auto smb_directory::open(std::wstring_view host, std::wstring_view user, - std::wstring_view password, - std::wstring_view share_name) -> smb_directory_t { + std::wstring_view password, std::wstring_view path, + stop_type *stop_requested) -> smb_directory_t { return open(utils::string::to_utf8(host), utils::string::to_utf8(user), - utils::string::to_utf8(password), - utils::string::to_utf8(share_name)); + utils::string::to_utf8(password), utils::string::to_utf8(path), + stop_requested); } auto smb_directory::copy_to(std::string_view new_path, @@ -305,6 +307,7 @@ auto smb_directory::get_directory(std::string_view path) const session_, share_name_, tid_, + stop_requested_, }, }; } catch (const std::exception &e) { @@ -325,9 +328,9 @@ auto smb_directory::get_directories() const -> std::vector { if (not session_) { throw std::runtime_error("session not found|" + path_); } - smb_stat_list_t list{ smb_find(session_.get(), tid_, smb_create_search_path(path_).c_str()), + smb_stat_list_deleter(), }; if (not list) { @@ -337,27 +340,34 @@ auto smb_directory::get_directories() const -> std::vector { std::vector ret{}; auto count = smb_stat_list_count(list.get()); - for (std::size_t idx = 0U; idx < count; ++idx) { - auto st = smb_stat_list_at(list.get(), idx); + for (std::size_t idx = 0U; !is_stop_requested() && idx < count; ++idx) { + auto *item_st = smb_stat_list_at(list.get(), idx); - bool is_dir{smb_stat_get(st, SMB_STAT_ISDIR) != 0U}; + bool is_dir{smb_stat_get(item_st, SMB_STAT_ISDIR) != 0U}; if (not is_dir) { continue; } - std::string name{smb_stat_name(st)}; + std::string name{smb_stat_name(item_st)}; if (name == "." || name == "..") { continue; } - ret.emplace_back(smb_directory_t{ - new smb_directory{ - smb_create_smb_path(path_, name), - session_, - share_name_, - tid_, - }, - }); + try { + ret.emplace_back(smb_directory_t{ + new smb_directory{ + smb_create_smb_path(path_, name), + session_, + share_name_, + tid_, + stop_requested_, + }, + }); + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } } return ret; @@ -427,17 +437,24 @@ auto smb_directory::get_files() const -> std::vector { std::vector ret{}; auto count = smb_stat_list_count(list.get()); - for (std::size_t idx = 0U; idx < count; ++idx) { - auto st = smb_stat_list_at(list.get(), idx); - bool is_dir{smb_stat_get(st, SMB_STAT_ISDIR) != 0U}; + for (std::size_t idx = 0U; !is_stop_requested() && idx < count; ++idx) { + auto *item_st = smb_stat_list_at(list.get(), idx); + + bool is_dir{smb_stat_get(item_st, SMB_STAT_ISDIR) != 0U}; if (is_dir) { continue; } - std::string name{smb_stat_name(st)}; - ret.emplace_back(std::make_unique( - std::nullopt, smb_create_smb_path(path_, name), session_, share_name_, - tid_)); + try { + std::string name{smb_stat_name(item_st)}; + ret.emplace_back(std::make_unique( + std::nullopt, smb_create_smb_path(path_, name), session_, + share_name_, tid_)); + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } } return ret; @@ -470,31 +487,44 @@ auto smb_directory::get_items() const -> std::vector { std::vector ret{}; auto count = smb_stat_list_count(list.get()); - for (std::size_t idx = 0U; idx < count; ++idx) { - auto st = smb_stat_list_at(list.get(), idx); + for (std::size_t idx = 0U; !is_stop_requested() && idx < count; ++idx) { + auto *item_st = smb_stat_list_at(list.get(), idx); - bool is_dir{smb_stat_get(st, SMB_STAT_ISDIR) != 0U}; - std::string name{smb_stat_name(st)}; + bool is_dir{smb_stat_get(item_st, SMB_STAT_ISDIR) != 0U}; + std::string name{smb_stat_name(item_st)}; if (is_dir) { if (name == "." || name == "..") { continue; } - ret.emplace_back(smb_directory_t{ - new smb_directory{ - path_ + '/' + name, - session_, - share_name_, - tid_, - }, - }); + try { + ret.emplace_back(smb_directory_t{ + new smb_directory{ + path_ + '/' + name, + session_, + share_name_, + tid_, + stop_requested_, + }, + }); + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } continue; } - ret.emplace_back(std::make_unique( - std::nullopt, smb_create_smb_path(path_, name), session_, share_name_, - tid_)); + try { + ret.emplace_back(std::make_unique( + std::nullopt, smb_create_smb_path(path_, name), session_, + share_name_, tid_)); + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } } return ret; @@ -507,6 +537,10 @@ auto smb_directory::get_items() const -> std::vector { return {}; } +auto smb_directory::is_stop_requested() const -> bool { + return (stop_requested_ != nullptr) && *stop_requested_; +} + auto smb_directory::is_symlink() const -> bool { static constexpr const std::string_view function_name{ static_cast(__FUNCTION__), diff --git a/support/test/src/utils/file_test.cpp b/support/test/src/utils/file_test.cpp index d726c336..1db2f1fd 100644 --- a/support/test/src/utils/file_test.cpp +++ b/support/test/src/utils/file_test.cpp @@ -256,6 +256,10 @@ TEST(utils_file, smb_parent_is_same) { path1 = "//server/share/one"; path2 = "//server/share/two"; EXPECT_TRUE(utils::file::smb_parent_is_same(path1, path2)); + + path1 = "// server/cow"; + path2 = "// server/cow"; + EXPECT_TRUE(utils::file::smb_parent_is_same(path1, path2)); } TEST(utils_file, smb_parent_is_not_same) { @@ -294,10 +298,6 @@ TEST(utils_file, smb_parent_is_not_same) { path1 = "//server"; path2 = "//server"; EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2)); - - path1 = "// server/cow"; - path2 = "// server/cow"; - EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2)); } #endif // defined(PROJECT_ENABLE_LIBDSM)