[broken build] refactor encryption provider db
This commit is contained in:
parent
2017897ad6
commit
db0b209ca6
34
repertory/librepertory/include/db/file_db.hpp
Normal file
34
repertory/librepertory/include/db/file_db.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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<i_file_db>;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // REPERTORY_INCLUDE_DB_FILE_DB_HPP_
|
83
repertory/librepertory/include/db/i_file_db.hpp
Normal file
83
repertory/librepertory/include/db/i_file_db.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
|
||||
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_
|
65
repertory/librepertory/include/db/impl/rdb_file_db.hpp
Normal file
65
repertory/librepertory/include/db/impl/rdb_file_db.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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<rocksdb::TransactionDB> db_{nullptr};
|
||||
|
||||
private:
|
||||
void create_or_open(bool clear);
|
||||
|
||||
[[nodiscard]] auto create_iterator() const
|
||||
-> std::shared_ptr<rocksdb::Iterator>;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
perform_action(std::string_view function_name,
|
||||
std::function<rocksdb::Status()> action) -> bool;
|
||||
|
||||
[[nodiscard]] auto perform_action(
|
||||
std::string_view function_name,
|
||||
std::function<rocksdb::Status(rocksdb::Transaction *txn)> action) -> bool;
|
||||
|
||||
public:
|
||||
void clear() override;
|
||||
};
|
||||
} // namespace repertory
|
||||
|
||||
#endif // REPERTORY_INCLUDE_DB_IMPL_RDB_FILE_DB_HPP_
|
86
repertory/librepertory/include/db/impl/sqlite_file_db.hpp
Normal file
86
repertory/librepertory/include/db/impl/sqlite_file_db.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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_
|
@ -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<i_file_db> db_;
|
||||
|
||||
private:
|
||||
i_file_manager *fm_{nullptr};
|
||||
|
38
repertory/librepertory/src/db/file_db.cpp
Normal file
38
repertory/librepertory/src/db/file_db.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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<i_file_db> {
|
||||
switch (cfg.get_database_type()) {
|
||||
case database_type::sqlite:
|
||||
return std::make_unique<sqlite_file_db>(cfg);
|
||||
|
||||
default:
|
||||
return std::make_unique<rdb_file_db>(cfg);
|
||||
}
|
||||
}
|
||||
} // namespace repertory
|
141
repertory/librepertory/src/db/impl/rdb_file_db.cpp
Normal file
141
repertory/librepertory/src/db/impl/rdb_file_db.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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<rocksdb::ColumnFamilyDescriptor> &families,
|
||||
std::vector<rocksdb::ColumnFamilyHandle *> &handles, bool clear)
|
||||
-> std::unique_ptr<rocksdb::TransactionDB> {
|
||||
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<rocksdb::TransactionDB>(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<rocksdb::ColumnFamilyDescriptor>();
|
||||
families.emplace_back(rocksdb::kDefaultColumnFamilyName,
|
||||
rocksdb::ColumnFamilyOptions());
|
||||
|
||||
auto handles = std::vector<rocksdb::ColumnFamilyHandle *>();
|
||||
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<rocksdb::Iterator> {
|
||||
return std::shared_ptr<rocksdb::Iterator>(
|
||||
db_->NewIterator(rocksdb::ReadOptions()));
|
||||
}
|
||||
|
||||
auto rdb_file_db::perform_action(std::string_view function_name,
|
||||
std::function<rocksdb::Status()> 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<rocksdb::Status(rocksdb::Transaction *txn)> action) -> bool {
|
||||
std::unique_ptr<rocksdb::Transaction> 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
|
297
repertory/librepertory/src/db/impl/sqlite_file_db.cpp
Normal file
297
repertory/librepertory/src/db/impl/sqlite_file_db.cpp
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
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<std::string, std::string> 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<std::int64_t>(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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
return static_cast<std::uint64_t>(
|
||||
row->get_column("count").get_value<std::int64_t>());
|
||||
}
|
||||
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path = row->get_column("api_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path = row->get_column("api_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
source_path = row->get_column("source_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path = row->get_column("api_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
data.api_path = api_path;
|
||||
data.file_size = static_cast<std::uint64_t>(
|
||||
row->get_column("size").get_value<std::int64_t>());
|
||||
data.source_path = row->get_column("source_path").get_value<std::string>();
|
||||
|
||||
auto str_data = row->get_column("iv").get_value<std::string>();
|
||||
if (not str_data.empty()) {
|
||||
data.iv_list =
|
||||
json::parse(str_data)
|
||||
.get<std::vector<
|
||||
std::array<unsigned char,
|
||||
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>>();
|
||||
}
|
||||
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
source_path = row->get_column("source_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
source_path = row->get_column("source_path").get_value<std::string>();
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
} // namespace repertory
|
@ -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<std::string, std::string> 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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path = row->get_column("api_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
current_api_path =
|
||||
row->get_column("api_path").get_value<std::string>();
|
||||
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<std::string>();
|
||||
}
|
||||
} 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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path_data =
|
||||
row->get_column("data").get_value<std::string>();
|
||||
current_api_path =
|
||||
row->get_column("api_path").get_value<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> 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<std::string>());
|
||||
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<utils::db::sqlite::db_result::row> 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<std::string>();
|
||||
|
||||
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<utils::db::sqlite::db_result::row> 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>();
|
||||
|
||||
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<std::string>();
|
||||
|
||||
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<std::string>();
|
||||
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<utils::db::sqlite::db_result::row> 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<std::string>();
|
||||
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
return static_cast<std::uint64_t>(
|
||||
row->get_column("count").get_value<std::int64_t>());
|
||||
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<utils::db::sqlite::db_result::row> 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<std::string>(),
|
||||
}
|
||||
.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<utils::db::sqlite::db_result::row> 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<std::string>(),
|
||||
}
|
||||
.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<const unsigned char *>(
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
current_api_path = row->get_column("api_path").get_value<std::string>();
|
||||
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<const unsigned char *>(
|
||||
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<filesystem_item_added>(
|
||||
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<const utils::file::i_file *>(&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<filesystem_item_added>(
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path_data = row->get_column("data").get_value<std::string>();
|
||||
api_path = row->get_column("api_path").get_value<std::string>();
|
||||
}
|
||||
|
||||
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<std::string>();
|
||||
}
|
||||
|
||||
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<const utils::file::i_file *>(&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<filesystem_item_added>(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<utils::db::sqlite::db_result::row> 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<std::string>();
|
||||
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<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>
|
||||
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<std::uint64_t>() != 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<reader_info>();
|
||||
info->reader = std::make_unique<utils::encryption::encrypting_reader>(
|
||||
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<std::vector<
|
||||
std::array<unsigned char,
|
||||
crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>>>();
|
||||
if (reader_lookup_.find(source_path) == reader_lookup_.end()) {
|
||||
auto info = std::make_shared<reader_info>();
|
||||
info->reader = std::make_unique<utils::encryption::encrypting_reader>(
|
||||
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<reader_info>();
|
||||
info->reader = std::make_unique<utils::encryption::encrypting_reader>(
|
||||
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<file_removed_externally>(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<directory_removed_externally>(
|
||||
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<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user