diff --git a/repertory/librepertory/include/db/file_db.hpp b/repertory/librepertory/include/db/file_db.hpp new file mode 100644 index 00000000..0567f5f8 --- /dev/null +++ b/repertory/librepertory/include/db/file_db.hpp @@ -0,0 +1,34 @@ +/* + 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. +*/ +#ifndef REPERTORY_INCLUDE_DB_FILE_DB_HPP_ +#define REPERTORY_INCLUDE_DB_FILE_DB_HPP_ + +#include "db/i_file_db.hpp" + +namespace repertory { +class app_config; + +[[nodiscard]] auto create_file_db(const app_config &cfg) + -> std::unique_ptr; +} // namespace repertory + +#endif // REPERTORY_INCLUDE_DB_FILE_DB_HPP_ diff --git a/repertory/librepertory/include/db/i_file_db.hpp b/repertory/librepertory/include/db/i_file_db.hpp new file mode 100644 index 00000000..48825fd6 --- /dev/null +++ b/repertory/librepertory/include/db/i_file_db.hpp @@ -0,0 +1,83 @@ +/* + 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. +*/ +#ifndef REPERTORY_INCLUDE_DB_I_FILE_DB_HPP_ +#define REPERTORY_INCLUDE_DB_I_FILE_DB_HPP_ + +#include "types/repertory.hpp" + +namespace repertory { +class i_file_db { + INTERFACE_SETUP(i_file_db); + +public: + struct file_data final { + std::string api_path; + std::uint64_t file_size{}; + std::vector< + std::array> + iv_list{}; + std::string source_path; + }; + +public: + [[nodiscard]] virtual auto add_directory(const std::string &api_path, + const std::string &source_path) + -> api_error = 0; + + [[nodiscard]] virtual auto add_or_update_file(const file_data &data) + -> api_error = 0; + + virtual void clear() = 0; + + [[nodiscard]] virtual auto count() const -> std::uint64_t = 0; + + [[nodiscard]] virtual auto get_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error = 0; + + [[nodiscard]] virtual auto + get_directory_api_path(const std::string &source_path, + std::string &api_path) const -> api_error = 0; + + [[nodiscard]] virtual auto + get_directory_source_path(const std::string &api_path, + std::string &source_path) const -> api_error = 0; + + [[nodiscard]] virtual auto get_file_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error = 0; + + [[nodiscard]] virtual auto get_file_data(const std::string &api_path, + file_data &data) const + -> api_error = 0; + + [[nodiscard]] virtual auto + get_file_source_path(const std::string &api_path, + std::string &source_path) const -> api_error = 0; + + [[nodiscard]] virtual auto get_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error = 0; +}; +} // namespace repertory + +#endif // REPERTORY_INCLUDE_DB_I_FILE_DB_HPP_ diff --git a/repertory/librepertory/include/db/impl/rdb_file_db.hpp b/repertory/librepertory/include/db/impl/rdb_file_db.hpp new file mode 100644 index 00000000..cd8c6928 --- /dev/null +++ b/repertory/librepertory/include/db/impl/rdb_file_db.hpp @@ -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. +*/ +#ifndef REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_ +#define REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_ + +#include "db/i_file_db.hpp" + +namespace repertory { +class app_config; + +class rdb_file_db final : public i_file_db { +public: + rdb_file_db(const app_config &cfg); + ~rdb_file_db() override; + + rdb_file_db(const rdb_file_db &) = delete; + rdb_file_db(rdb_file_db &&) = delete; + auto operator=(const rdb_file_db &) -> rdb_file_db & = delete; + auto operator=(rdb_file_db &&) -> rdb_file_db & = delete; + +private: + const app_config &cfg_; + +private: + std::unique_ptr db_{nullptr}; + +private: + void create_or_open(bool clear); + + [[nodiscard]] auto create_iterator() const + -> std::shared_ptr; + + [[nodiscard]] static auto + perform_action(std::string_view function_name, + std::function action) -> bool; + + [[nodiscard]] auto perform_action( + std::string_view function_name, + std::function action) -> bool; + +public: + void clear() override; +}; +} // namespace repertory + +#endif // REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_ diff --git a/repertory/librepertory/include/db/impl/sqlite_file_db.hpp b/repertory/librepertory/include/db/impl/sqlite_file_db.hpp new file mode 100644 index 00000000..147cfee7 --- /dev/null +++ b/repertory/librepertory/include/db/impl/sqlite_file_db.hpp @@ -0,0 +1,86 @@ +/* + 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. +*/ +#ifndef REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_DB_HPP_ +#define REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_DB_HPP_ + +#include "db/i_file_db.hpp" +#include "utils/db/sqlite/db_common.hpp" + +namespace repertory { +class app_config; + +class sqlite_file_db final : public i_file_db { +public: + sqlite_file_db(const app_config &cfg); + ~sqlite_file_db() override; + + sqlite_file_db(const sqlite_file_db &) = delete; + sqlite_file_db(sqlite_file_db &&) = delete; + auto operator=(const sqlite_file_db &) -> sqlite_file_db & = delete; + auto operator=(sqlite_file_db &&) -> sqlite_file_db & = delete; + +private: + utils::db::sqlite::db3_t db_; + +public: + [[nodiscard]] auto add_directory(const std::string &api_path, + const std::string &source_path) + -> api_error override; + + [[nodiscard]] auto add_or_update_file(const i_file_db::file_data &data) + -> api_error override; + + void clear() override; + + [[nodiscard]] auto count() const -> std::uint64_t override; + + [[nodiscard]] auto get_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error override; + + [[nodiscard]] auto get_directory_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error override; + + [[nodiscard]] auto get_directory_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error override; + + [[nodiscard]] auto get_file_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error override; + + [[nodiscard]] auto get_file_data(const std::string &api_path, + i_file_db::file_data &data) const + -> api_error override; + + [[nodiscard]] auto get_file_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error override; + + [[nodiscard]] auto get_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error override; +}; +} // namespace repertory + +#endif // REPERTORY_INCLUDE_DB_IMPL_SQLITE_FILE_DB_HPP_ diff --git a/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp b/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp index b96bf1e9..ea4847a9 100644 --- a/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp +++ b/repertory/librepertory/include/providers/encrypt/encrypt_provider.hpp @@ -23,8 +23,8 @@ #define REPERTORY_INCLUDE_PROVIDERS_ENCRYPT_ENCRYPT_PROVIDER_HPP_ #include "app_config.hpp" +#include "db/i_file_db.hpp" #include "providers/i_provider.hpp" -#include "utils/db/sqlite/db_common.hpp" #include "utils/encrypting_reader.hpp" namespace repertory { @@ -54,7 +54,7 @@ private: private: app_config &config_; - utils::db::sqlite::db3_t db_; + std::unique_ptr db_; private: i_file_manager *fm_{nullptr}; diff --git a/repertory/librepertory/src/db/file_db.cpp b/repertory/librepertory/src/db/file_db.cpp new file mode 100644 index 00000000..53de46bc --- /dev/null +++ b/repertory/librepertory/src/db/file_db.cpp @@ -0,0 +1,38 @@ +/* + 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 "db/file_db.hpp" + +#include "app_config.hpp" +#include "db/impl/rdb_file_db.hpp" +#include "db/impl/sqlite_file_db.hpp" + +namespace repertory { +auto create_file_db(const app_config &cfg) -> std::unique_ptr { + switch (cfg.get_database_type()) { + case database_type::sqlite: + return std::make_unique(cfg); + + default: + return std::make_unique(cfg); + } +} +} // namespace repertory diff --git a/repertory/librepertory/src/db/impl/rdb_file_db.cpp b/repertory/librepertory/src/db/impl/rdb_file_db.cpp new file mode 100644 index 00000000..ba143185 --- /dev/null +++ b/repertory/librepertory/src/db/impl/rdb_file_db.cpp @@ -0,0 +1,141 @@ +/* + 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 "db/impl/rdb_file_db.hpp" + +#include "app_config.hpp" +#include "types/startup_exception.hpp" +#include "utils/config.hpp" +#include "utils/error_utils.hpp" +#include "utils/file.hpp" +#include "utils/path.hpp" +#include "utils/string.hpp" + +namespace { +[[nodiscard]] auto +create_rocksdb(const repertory::app_config &cfg, const std::string &name, + const std::vector &families, + std::vector &handles, bool clear) + -> std::unique_ptr { + REPERTORY_USES_FUNCTION_NAME(); + + auto path = repertory::utils::path::combine(cfg.get_data_directory(), {name}); + if (clear && + not repertory::utils::file::directory{path}.remove_recursively()) { + repertory::utils::error::raise_error( + function_name, "failed to remove " + name + " db|" + path); + } + + rocksdb::Options options{}; + options.create_if_missing = true; + options.create_missing_column_families = true; + options.db_log_dir = cfg.get_log_directory(); + options.keep_log_file_num = 10; + + rocksdb::TransactionDB *ptr{}; + auto status = rocksdb::TransactionDB::Open( + options, rocksdb::TransactionDBOptions{}, path, families, &handles, &ptr); + if (not status.ok()) { + repertory::utils::error::raise_error(function_name, status.ToString()); + throw repertory::startup_exception(status.ToString()); + } + + return std::unique_ptr(ptr); +} +} // namespace + +namespace repertory { +rdb_file_db::rdb_file_db(const app_config &cfg) : cfg_(cfg) { + create_or_open(false); +} + +rdb_file_db::~rdb_file_db() { db_.reset(); } + +void rdb_file_db::create_or_open(bool clear) { + db_.reset(); + + auto families = std::vector(); + families.emplace_back(rocksdb::kDefaultColumnFamilyName, + rocksdb::ColumnFamilyOptions()); + + auto handles = std::vector(); + db_ = create_rocksdb(cfg_, "file", families, handles, clear); +} + +void rdb_file_db::clear() { create_or_open(true); } + +auto rdb_file_db::create_iterator() const + -> std::shared_ptr { + return std::shared_ptr( + db_->NewIterator(rocksdb::ReadOptions())); +} + +auto rdb_file_db::perform_action(std::string_view function_name, + std::function action) + -> bool { + try { + auto res = action(); + if (not res.ok()) { + utils::error::raise_error(function_name, res.ToString()); + } + + return res.ok(); + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex); + } + + return false; +} + +auto rdb_file_db::perform_action( + std::string_view function_name, + std::function action) -> bool { + std::unique_ptr txn{ + db_->BeginTransaction(rocksdb::WriteOptions{}, + rocksdb::TransactionOptions{}), + }; + + try { + auto res = action(txn.get()); + if (res.ok()) { + auto commit_res = txn->Commit(); + if (commit_res.ok()) { + return true; + } + + utils::error::raise_error(function_name, + "rocksdb commit failed|" + res.ToString()); + return false; + } + + utils::error::raise_error(function_name, + "rocksdb action failed|" + res.ToString()); + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, + "failed to handle rocksdb action"); + } + + auto rollback_res = txn->Rollback(); + utils::error::raise_error(function_name, "rocksdb rollback failed|" + + rollback_res.ToString()); + return false; +} +} // namespace repertory diff --git a/repertory/librepertory/src/db/impl/sqlite_file_db.cpp b/repertory/librepertory/src/db/impl/sqlite_file_db.cpp new file mode 100644 index 00000000..8187eb37 --- /dev/null +++ b/repertory/librepertory/src/db/impl/sqlite_file_db.cpp @@ -0,0 +1,297 @@ +/* + 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 "db/impl/sqlite_file_db.hpp" + +#include "app_config.hpp" +#include "utils/config.hpp" +#include "utils/db/sqlite/db_common.hpp" +#include "utils/db/sqlite/db_delete.hpp" +#include "utils/db/sqlite/db_insert.hpp" +#include "utils/db/sqlite/db_select.hpp" +#include "utils/db/sqlite/db_update.hpp" +#include "utils/error_utils.hpp" +#include "utils/path.hpp" +#include "utils/string.hpp" + +namespace { +const std::string file_table = "file"; +const std::map sql_create_tables = { + { + {file_table}, + {"CREATE TABLE IF NOT EXISTS " + file_table + + "(" + "source_path TEXT PRIMARY KEY ASC, " + "api_path TEXT UNIQUE NOT NULL, " + "iv TEXT, " + "directory INTEGER NOT NULL, " + "size INTEGER" + ");"}, + }, +}; +} // namespace + +namespace repertory { +sqlite_file_db::sqlite_file_db(const app_config &cfg) { + db_ = utils::db::sqlite::create_db( + utils::path::combine(cfg.get_data_directory(), {"file.db"}), + sql_create_tables); +} + +sqlite_file_db::~sqlite_file_db() { db_.reset(); } + +auto sqlite_file_db::add_directory(const std::string &api_path, + const std::string &source_path) + -> api_error { + REPERTORY_USES_FUNCTION_NAME(); + + auto result = utils::db::sqlite::db_insert{*db_, file_table} + .column_value("api_path", api_path) + .column_value("directory", 1) + .column_value("source_path", source_path) + .go(); + if (result.ok()) { + return api_error::success; + } + + utils::error::raise_api_path_error( + function_name, api_path, + fmt::format("failed to add directory|{}", result.get_error_str())); + return api_error::error; +} + +auto sqlite_file_db::add_or_update_file(const i_file_db::file_data &data) + -> api_error { + REPERTORY_USES_FUNCTION_NAME(); + + auto result = + utils::db::sqlite::db_insert{*db_, file_table} + .or_replace() + .column_value("api_path", data.api_path) + .column_value("directory", 0) + .column_value("iv", json(data.iv_list).dump()) + .column_value("size", static_cast(data.file_size)) + .column_value("source_path", data.source_path) + .go(); + if (result.ok()) { + return api_error::success; + } + + utils::error::raise_api_path_error( + function_name, data.api_path, + fmt::format("failed to add file|{}", result.get_error_str())); + return api_error::error; +} + +void sqlite_file_db::clear() { + REPERTORY_USES_FUNCTION_NAME(); + + auto result = utils::db::sqlite::db_delete{*db_, file_table}.go(); + if (not result.ok()) { + utils::error::raise_error(function_name, + fmt::format("failed to clear file table|{}", + std::to_string(result.get_error()))); + } +} + +auto sqlite_file_db::count() const -> std::uint64_t { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .count("api_path", "count") + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + return static_cast( + row->get_column("count").get_value()); + } + + return 0U; +} + +auto sqlite_file_db::get_api_path(const std::string &source_path, + std::string &api_path) const -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("api_path") + .where("source_path") + .equals(source_path) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + api_path = row->get_column("api_path").get_value(); + return api_error::success; + } + + return api_error::item_not_found; +} + +auto sqlite_file_db::get_directory_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("api_path") + .where("source_path") + .equals(source_path) + .and_() + .where("directory") + .equals(1) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + api_path = row->get_column("api_path").get_value(); + return api_error::success; + } + + return api_error::directory_not_found; +} + +auto sqlite_file_db::get_directory_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("source_path") + .where("api_path") + .equals(api_path) + .and_() + .where("directory") + .equals(1) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + source_path = row->get_column("source_path").get_value(); + return api_error::success; + } + + return api_error::directory_not_found; +} + +auto sqlite_file_db::get_file_api_path(const std::string &source_path, + std::string &api_path) const + -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("api_path") + .where("source_path") + .equals(source_path) + .and_() + .where("directory") + .equals(0) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + api_path = row->get_column("api_path").get_value(); + return api_error::success; + } + + return api_error::item_not_found; +} + +auto sqlite_file_db::get_file_data(const std::string &api_path, + i_file_db::file_data &data) const + -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("iv") + .column("size") + .column("source_path") + .where("api_path") + .equals(api_path) + .and_() + .where("directory") + .equals(0) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + data.api_path = api_path; + data.file_size = static_cast( + row->get_column("size").get_value()); + data.source_path = row->get_column("source_path").get_value(); + + auto str_data = row->get_column("iv").get_value(); + if (not str_data.empty()) { + data.iv_list = + json::parse(str_data) + .get>>(); + } + + return api_error::success; + } + + return api_error::item_not_found; +} + +auto sqlite_file_db::get_file_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("source_path") + .where("api_path") + .equals(api_path) + .and_() + .where("directory") + .equals(0) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + source_path = row->get_column("source_path").get_value(); + return api_error::success; + } + + return api_error::item_not_found; +} + +auto sqlite_file_db::get_source_path(const std::string &api_path, + std::string &source_path) const + -> api_error { + auto result = utils::db::sqlite::db_select{*db_, file_table} + .column("source_path") + .where("api_path") + .equals(api_path) + .op() + .limit(1) + .go(); + + std::optional row; + if (result.get_row(row) && row.has_value()) { + source_path = row->get_column("source_path").get_value(); + return api_error::success; + } + + return api_error::item_not_found; +} +} // namespace repertory diff --git a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp index 261f3355..f5c80715 100644 --- a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp +++ b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp @@ -21,6 +21,7 @@ */ #include "providers/encrypt/encrypt_provider.hpp" +#include "db/file_db.hpp" #include "events/event_system.hpp" #include "events/events.hpp" #include "types/repertory.hpp" @@ -38,18 +39,6 @@ namespace { const std::string file_table = "file"; -const std::map sql_create_tables = { - { - {file_table}, - {"CREATE TABLE IF NOT EXISTS " + file_table + - "(" - "source_path TEXT PRIMARY KEY ASC, " - "api_path TEXT NOT NULL, " - "data TEXT, " - "directory INTEGER NOT NULL" - ");"}, - }, -}; } // namespace namespace repertory { @@ -172,18 +161,7 @@ auto encrypt_provider::get_api_path_from_source(const std::string &source_path, REPERTORY_USES_FUNCTION_NAME(); try { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .where("source_path") - .equals(source_path) - .go(); - std::optional row; - if (result.get_row(row) && row.has_value()) { - api_path = row->get_column("api_path").get_value(); - return api_error::success; - } - - return api_error::item_not_found; + return db_->get_api_path(source_path, api_path); } catch (const std::exception &ex) { utils::error::raise_error(function_name, ex, source_path, "failed to get api path from source path"); @@ -231,61 +209,37 @@ auto encrypt_provider::get_directory_items(const std::string &api_path, for (const auto &dir_entry : utils::file::directory{source_path}.get_items()) { try { - std::string current_api_path{}; + std::string current_api_path; if (dir_entry->is_directory_item()) { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .where("source_path") - .equals(dir_entry->get_path()) - .and_() - .where("directory") - .equals(1) - .go(); - std::optional row; - if (result.get_row(row) && row.has_value()) { - current_api_path = - row->get_column("api_path").get_value(); + auto result = db_->get_directory_api_path(dir_entry->get_path(), + current_api_path); + if (result != api_error::success && + result != api_error::directory_not_found) { + // TODO raise error + continue; } - if (current_api_path.empty()) { + + if (result == api_error::directory_not_found) { process_directory_entry(*dir_entry.get(), cfg, current_api_path); - result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .where("source_path") - .equals(dir_entry->get_path()) - .and_() - .where("directory") - .equals(1) - .go(); - row.reset(); - if (not(result.get_row(row) && row.has_value())) { + result = get_directory_api_path(dir_entry->get_path(), + current_api_path); + if (result != api_error::success && + result != api_error::directory_not_found) { + // TODO raise error continue; } - - current_api_path = - row->get_column("api_path").get_value(); } } else { - std::string api_path_data{}; - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .column("data") - .where("source_path") - .equals(dir_entry->get_path()) - .and_() - .where("directory") - .equals(0) - .go(); - std::optional row; - if (result.get_row(row) && row.has_value()) { - api_path_data = - row->get_column("data").get_value(); - current_api_path = - row->get_column("api_path").get_value(); + auto result = db_->get_file_api_path(dir_entry->get_path(), + current_api_path); + if (result != api_error::success && + result != api_error::item_not_found) { + // TODO raise error + continue; } - - if (api_path_data.empty() && + if (result == api_error::item_not_found && not process_directory_entry(*dir_entry.get(), cfg, current_api_path)) { continue; @@ -356,22 +310,13 @@ auto encrypt_provider::get_file(const std::string &api_path, return api_error::directory_exists; } - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("source_path") - .where("api_path") - .equals(api_path) - .and_() - .where("directory") - .equals(0) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - return api_error::item_not_found; + std::string source_path; + auto result = db_->get_file_source_path(api_path, source_path); + if (result != api_error::success) { + return result; } - file = create_api_file( - api_path, false, - row->get_column("source_path").get_value()); + file = create_api_file(api_path, false, source_path); return api_error::success; } catch (const std::exception &ex) { utils::error::raise_error(function_name, ex, api_path, @@ -412,19 +357,11 @@ auto encrypt_provider::get_file_size(const std::string &api_path, REPERTORY_USES_FUNCTION_NAME(); try { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("source_path") - .where("api_path") - .equals(api_path) - .and_() - .where("directory") - .equals(0) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - return api_error::item_not_found; + std::string source_path; + auto result = db_->get_file_source_path(api_path, source_path); + if (result != api_error::success) { + return result; } - auto source_path = row->get_column("source_path").get_value(); file_size = utils::encryption::encrypting_reader::calculate_encrypted_size( source_path); @@ -441,60 +378,27 @@ auto encrypt_provider::get_filesystem_item(const std::string &api_path, bool directory, filesystem_item &fsi) const -> api_error { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("source_path") - .where("api_path") - .equals(api_path) - .and_() - .where("directory") - .equals(directory ? 1 : 0) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - return directory ? api_error::directory_not_found - : api_error::item_not_found; - } - - auto source_path = row->get_column("source_path").get_value(); - + std::string source_path; if (directory) { - result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .where("source_path") - .equals(source_path) - .and_() - .where("directory") - .equals(1) - .go(); - row.reset(); - if (not(result.get_row(row) && row.has_value())) { - return api_error::item_not_found; + auto result = db_->get_directory_source_path(api_path, source_path); + if (result != api_error::success) { + return result; } - auto db_api_path = row->get_column("api_path").get_value(); - fsi.api_parent = utils::path::get_parent_api_path(db_api_path); - fsi.api_path = db_api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.api_path = api_path; fsi.directory = true; fsi.size = 0U; fsi.source_path = source_path; return api_error::success; } - result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .column("data") - .where("source_path") - .equals(source_path) - .and_() - .where("directory") - .equals(0) - .go(); - row.reset(); - if (not(result.get_row(row) && row.has_value())) { - return api_error::item_not_found; + auto result = db_->get_file_source_path(api_path, source_path); + if (result != api_error::success) { + return result; } - fsi.api_path = row->get_column("api_path").get_value(); + fsi.api_path = api_path; fsi.api_parent = utils::path::get_parent_api_path(fsi.api_path); fsi.directory = false; fsi.size = utils::encryption::encrypting_reader::calculate_encrypted_size( @@ -564,26 +468,20 @@ auto encrypt_provider::get_item_meta(const std::string &api_path, REPERTORY_USES_FUNCTION_NAME(); try { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("source_path") - .where("api_path") - .equals(api_path) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - return api_error::item_not_found; + std::string source_path; + auto result = db_->get_source_path(api_path, source_path); + if (result != api_error::success) { + return result; } - auto source_path = row->get_column("source_path").get_value(); - - bool exists{}; - auto res = is_directory(api_path, exists); - if (res != api_error::success) { - return res; + bool is_dir{}; + result = is_directory(api_path, is_dir); + if (result != api_error::success) { + return result; } - auto file = create_api_file(api_path, exists, source_path); - create_item_meta(meta, exists, file); + auto file = create_api_file(api_path, is_dir, source_path); + create_item_meta(meta, is_dir, file); return api_error::success; } catch (const std::exception &ex) { utils::error::raise_error(function_name, ex, api_path, @@ -613,14 +511,13 @@ auto encrypt_provider::get_total_drive_space() const -> std::uint64_t { } auto encrypt_provider::get_total_item_count() const -> std::uint64_t { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .count("api_path", "count") - .go(); + REPERTORY_USES_FUNCTION_NAME(); - std::optional row; - if (result.get_row(row) && row.has_value()) { - return static_cast( - row->get_column("count").get_value()); + try { + return db_->count(); + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, + "failed to get total item count"); } return 0U; @@ -635,50 +532,44 @@ auto encrypt_provider::get_used_drive_space() const -> std::uint64_t { auto encrypt_provider::is_directory(const std::string &api_path, bool &exists) const -> api_error { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("source_path") - .where("api_path") - .equals(api_path) - .and_() - .where("directory") - .equals(1) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - exists = false; + REPERTORY_USES_FUNCTION_NAME(); + + try { + std::string source_path; + auto result = db_->get_directory_source_path(api_path, source_path); + if (result != api_error::success) { + return result; + } + + exists = utils::file::directory{source_path}.exists(); return api_error::success; + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, api_path, + "failed determin if api path is directory"); } - exists = - utils::file::directory{ - row->get_column("source_path").get_value(), - } - .exists(); - return api_error::success; + return api_error::error; } auto encrypt_provider::is_file(const std::string &api_path, bool &exists) const -> api_error { - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("source_path") - .where("api_path") - .equals(api_path) - .and_() - .where("directory") - .equals(0) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - exists = false; + REPERTORY_USES_FUNCTION_NAME(); + + try { + std::string source_path; + auto result = db_->get_file_source_path(api_path, source_path); + if (result != api_error::success) { + return result; + } + + exists = utils::file::file{source_path}.exists(); return api_error::success; + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, api_path, + "failed determin if api path is directory"); } - exists = - utils::file::file{ - row->get_column("source_path").get_value(), - } - .exists(); - return api_error::success; + return api_error::error; } auto encrypt_provider::is_file_writeable(const std::string & /*api_path*/) const @@ -696,148 +587,133 @@ auto encrypt_provider::is_online() const -> bool { auto encrypt_provider::process_directory_entry( const utils::file::i_fs_item &dir_entry, const encrypt_config &cfg, std::string &api_path) const -> bool { - const auto add_directory = [this, - &cfg](std::string_view dir_path) -> std::string { - auto encrypted_parts = utils::string::split( - utils::path::create_api_path(dir_path), '/', false); + REPERTORY_USES_FUNCTION_NAME(); - for (std::size_t part_idx = 1U; part_idx < encrypted_parts.size(); - ++part_idx) { - data_buffer encrypted_data; - utils::encryption::encrypt_data( - cfg.encryption_token, - reinterpret_cast( - encrypted_parts.at(part_idx).c_str()), - strnlen(encrypted_parts.at(part_idx).c_str(), - encrypted_parts.at(part_idx).size()), - encrypted_data); - encrypted_parts[part_idx] = - utils::collection::to_hex_string(encrypted_data); - } + try { + const auto do_add_directory = + [this, &cfg](std::string_view dir_path) -> std::string { + auto encrypted_parts = utils::string::split( + utils::path::create_api_path(dir_path), '/', false); - std::size_t current_idx{1U}; - std::string current_encrypted_path{}; - auto current_source_path{cfg.path}; - for (const auto &part : utils::path::get_parts(dir_path)) { - current_source_path = utils::path::combine(current_source_path, {part}); - - std::string current_api_path{}; - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .where("source_path") - .equals(current_source_path) - .and_() - .where("directory") - .equals(1) - .go(); - std::optional row; - if (result.get_row(row) && row.has_value()) { - current_api_path = row->get_column("api_path").get_value(); + for (std::size_t part_idx = 1U; part_idx < encrypted_parts.size(); + ++part_idx) { + data_buffer encrypted_data; + utils::encryption::encrypt_data( + cfg.encryption_token, + reinterpret_cast( + encrypted_parts.at(part_idx).c_str()), + strnlen(encrypted_parts.at(part_idx).c_str(), + encrypted_parts.at(part_idx).size()), + encrypted_data); + encrypted_parts[part_idx] = + utils::collection::to_hex_string(encrypted_data); } - if (current_api_path.empty()) { - current_api_path = utils::path::create_api_path( - current_encrypted_path + '/' + encrypted_parts.at(current_idx)); + std::size_t current_idx{1U}; + std::string current_encrypted_path{}; + auto current_source_path{cfg.path}; + for (const auto &part : utils::path::get_parts(dir_path)) { + current_source_path = utils::path::combine(current_source_path, {part}); + + std::string current_api_path{}; + auto result = + db_->get_directory_api_path(current_source_path, current_api_path); + if (result == api_error::directory_not_found) { + current_api_path = utils::path::create_api_path( + current_encrypted_path + '/' + encrypted_parts.at(current_idx)); + + result = db_->add_directory(current_api_path, current_source_path); + if (result != api_error::success) { + std::runtime_error( + fmt::format("failed to get directory api path|{}", + api_error_to_string(result))); + } + + event_system::instance().raise( + current_api_path, + utils::path::get_parent_api_path(current_api_path), true); + } else { + if (result != api_error::success) { + std::runtime_error( + fmt::format("failed to get directory api path|{}", + api_error_to_string(result))); + } + + encrypted_parts[current_idx] = + utils::string::split(current_api_path, '/', false)[current_idx]; + } + + current_encrypted_path = utils::path::create_api_path( + current_encrypted_path + '/' + encrypted_parts.at(current_idx++)); + } + + return current_encrypted_path; + }; + + if (dir_entry.is_directory_item()) { + api_path = do_add_directory( + utils::path::get_relative_path(dir_entry.get_path(), cfg.path)); + return false; + } + + if (dir_entry.is_file_item() && not dir_entry.is_symlink()) { + auto relative_path = + utils::path::get_relative_path(dir_entry.get_path(), cfg.path); + + i_file_db::file_data data; + auto file_res = db_->get_file_data(dir_entry.get_path(), data); + if (file_res != api_error::success && + file_res != api_error::item_not_found) { + // TODO raise error + return false; + } + + std::string api_parent{}; + auto parent_res = db_->get_directory_api_path( + utils::path::get_parent_path(dir_entry.get_path()), api_parent); + if (parent_res != api_error::success && + parent_res != api_error::directory_not_found) { + // TODO raise error + return false; + } + + if (parent_res == api_error::directory_not_found) { + api_parent = + do_add_directory(utils::path::get_parent_path(relative_path)); + } + + if (file_res == api_error::item_not_found) { + stop_type stop_requested{false}; + utils::encryption::encrypting_reader reader( + utils::path::strip_to_file_name(relative_path), + dir_entry.get_path(), stop_requested, cfg.encryption_token, + utils::path::get_parent_path(relative_path)); + api_path = utils::path::create_api_path( + api_parent + "/" + reader.get_encrypted_file_name()); + + file_res = db_->add_or_update_file( + i_file_db::file_data{ + api_path, + dynamic_cast(&dir_entry) + ->size() + .value_or(0U), + reader.get_iv_list(), + }, + dir_entry.get_path()); + if (file_res != api_error::success) { + // TODO raise error + return false; + } - // TODO handle error - auto ins_res = utils::db::sqlite::db_insert{*db_, file_table} - .column_value("api_path", current_api_path) - .column_value("data", "") - .column_value("directory", 1) - .column_value("source_path", current_source_path) - .go(); event_system::instance().raise( - current_api_path, - utils::path::get_parent_api_path(current_api_path), true); - } else { - encrypted_parts[current_idx] = - utils::string::split(current_api_path, '/', false)[current_idx]; + api_path, api_parent, false); } - current_encrypted_path = utils::path::create_api_path( - current_encrypted_path + '/' + encrypted_parts.at(current_idx++)); + return true; } - - return current_encrypted_path; - }; - - if (dir_entry.is_directory_item()) { - api_path = add_directory( - utils::path::get_relative_path(dir_entry.get_path(), cfg.path)); - return false; - } - - if (dir_entry.is_file_item() && not dir_entry.is_symlink()) { - auto relative_path = - utils::path::get_relative_path(dir_entry.get_path(), cfg.path); - - std::string api_path_data{}; - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .column("data") - .where("source_path") - .equals(dir_entry.get_path()) - .and_() - .where("directory") - .equals(0) - .go(); - std::optional row; - if (result.get_row(row) && row.has_value()) { - api_path_data = row->get_column("data").get_value(); - api_path = row->get_column("api_path").get_value(); - } - - std::string api_parent{}; - result = utils::db::sqlite::db_select{*db_, file_table} - .column("api_path") - .where("source_path") - .equals(utils::path::get_parent_path(dir_entry.get_path())) - .and_() - .where("directory") - .equals(1) - .go(); - row.reset(); - if (result.get_row(row) && row.has_value()) { - api_parent = row->get_column("api_path").get_value(); - } - - if (api_parent.empty()) { - api_parent = add_directory(utils::path::get_parent_path(relative_path)); - } - - if (api_path.empty()) { - stop_type stop_requested = false; - utils::encryption::encrypting_reader reader( - utils::path::strip_to_file_name(relative_path), dir_entry.get_path(), - stop_requested, cfg.encryption_token, - utils::path::get_parent_path(relative_path)); - api_path = utils::path::create_api_path(api_parent + "/" + - reader.get_encrypted_file_name()); - - auto iv_list = reader.get_iv_list(); - json data = { - {"iv_list", iv_list}, - { - "original_file_size", - (dynamic_cast(&dir_entry) - ->size() - .value_or(0U)), - }, - }; - - // TODO handle error - auto ins_res = utils::db::sqlite::db_insert{*db_, file_table} - .column_value("api_path", api_path) - .column_value("data", data.dump()) - .column_value("directory", 0) - .column_value("source_path", dir_entry.get_path()) - .go(); - - event_system::instance().raise(api_path, - api_parent, false); - } - - return true; + } catch (const std::exception &ex) { + utils::error::raise_error(function_name, ex, dir_entry.get_path(), + "failed to process directory entry"); } return false; @@ -849,84 +725,57 @@ auto encrypt_provider::read_file_bytes(const std::string &api_path, stop_type &stop_requested) -> api_error { REPERTORY_USES_FUNCTION_NAME(); - auto result = utils::db::sqlite::db_select{*db_, file_table} - .column("data") - .column("source_path") - .where("api_path") - .equals(api_path) - .and_() - .where("directory") - .equals(0) - .go(); - std::optional row; - if (not(result.get_row(row) && row.has_value())) { - return api_error::item_not_found; + i_file_db::file_data file_data{}; + auto result = db_->get_file_data(api_path, file_data); + if (result != api_error::success) { + return result; } - auto source_path = row->get_column("source_path").get_value(); - if (source_path.empty()) { - return api_error::item_not_found; - } - - auto file_data = row->get_column("data").get_value_as_json(); - - auto opt_size = utils::file::file{source_path}.size(); + auto opt_size = utils::file::file{data.source_path}.size(); if (not opt_size.has_value()) { return api_error::os_error; } auto file_size{opt_size.value()}; - std::vector< - std::array> - iv_list{}; - auto cfg = config_.get_encrypt_config(); unique_recur_mutex_lock reader_lookup_lock(reader_lookup_mtx_); - if (file_data.at("original_file_size").get() != file_size) { - auto relative_path = utils::path::get_relative_path(source_path, cfg.path); + if (file_data.file_size != file_size) { + auto relative_path = + utils::path::get_relative_path(file_data.source_path, cfg.path); auto info = std::make_shared(); info->reader = std::make_unique( - relative_path, source_path, stop_requested, cfg.encryption_token, - utils::path::get_parent_path(relative_path)); - reader_lookup_[source_path] = info; - iv_list = info->reader->get_iv_list(); + relative_path, file_data.source_path, stop_requested, + cfg.encryption_token, utils::path::get_parent_path(relative_path)); + reader_lookup_[file_data.source_path] = info; + file_data.file_size = file_size; + file_data.iv_list = info->reader->get_iv_list(); - file_data["original_file_size"] = file_size; - file_data["iv_list"] = iv_list; - auto ins_res = utils::db::sqlite::db_insert{*db_, file_table} - .or_replace() - .column_value("data", file_data.dump()) - .column_value("source_path", source_path) - .go(); - if (not ins_res.ok()) { - utils::error::raise_error(function_name, ins_res.get_error(), source_path, - "failed to update meta db"); - return api_error::error; - } - } else { - iv_list = - file_data["iv_list"] - .get>>(); - if (reader_lookup_.find(source_path) == reader_lookup_.end()) { - auto info = std::make_shared(); - info->reader = std::make_unique( - api_path, source_path, stop_requested, cfg.encryption_token, - std::move(iv_list)); - reader_lookup_[source_path] = info; + result = db_->add_or_update_file(file_data); + file_data.iv_list.clear(); + + if (result != api_error::success) { + utils::error::raise_error(function_name, result, file_data.source_path, + "failed to update file"); + return result; } + } else if (reader_lookup_.find(file_data.source_path) == + reader_lookup_.end()) { + auto info = std::make_shared(); + info->reader = std::make_unique( + api_path, file_data.source_path, stop_requested, cfg.encryption_token, + std::move(file_data.iv_list)); + reader_lookup_[file_data.source_path] = info; } if (file_size == 0U || size == 0U) { return api_error::success; } - auto info = reader_lookup_.at(source_path); + auto info = reader_lookup_.at(file_data.source_path); info->last_access_time = std::chrono::system_clock::now(); reader_lookup_lock.unlock(); @@ -978,6 +827,8 @@ void encrypt_provider::remove_deleted_files(const stop_type &stop_requested) { .column("source_path") .where("source_path") .equals(source_path) + .op() + .limit(1) .go(); removed_list.emplace_back(removed_item{ api_path, @@ -1003,6 +854,8 @@ void encrypt_provider::remove_deleted_files(const stop_type &stop_requested) { .and_() .where("directory") .equals(0) + .op() + .limit(1) .go(); event_system::instance().raise(item.api_path, item.source_path); @@ -1024,6 +877,8 @@ void encrypt_provider::remove_deleted_files(const stop_type &stop_requested) { .and_() .where("directory") .equals(1) + .op() + .limit(1) .go(); event_system::instance().raise( item.api_path, item.source_path); @@ -1038,9 +893,7 @@ auto encrypt_provider::start(api_item_added_callback /*api_item_added*/, return false; } - db_ = utils::db::sqlite::create_db( - utils::path::combine(config_.get_data_directory(), {"provider_meta.db"}), - sql_create_tables); + db_ = create_file_db(config_); auto cfg = config_.get_encrypt_config(); auto cfg_path = utils::path::absolute(cfg.path); @@ -1052,6 +905,8 @@ auto encrypt_provider::start(api_item_added_callback /*api_item_added*/, .and_() .where("directory") .equals(1) + .op() + .limit(1) .go(); std::optional row; if (result.get_row(row) && row.has_value()) {