Compare commits
23 Commits
3c001c11ae
...
c960df8f70
Author | SHA1 | Date | |
---|---|---|---|
c960df8f70 | |||
9d0baf30b8 | |||
312e4bc0f1 | |||
1d7f5b7ef1 | |||
08e381a307 | |||
49e518ac19 | |||
8e2ebf05b8 | |||
924b79add2 | |||
857dcc5535 | |||
7c0d583435 | |||
2b6a88f8cb | |||
fbf31c77ed | |||
9c2aa62f1f | |||
b6456abf0d | |||
5138b0d1ab | |||
0f60a5a467 | |||
982e5357a5 | |||
0ad0ff508b | |||
b4d61649cb | |||
cdfbaa47b6 | |||
211805e460 | |||
841d57cf13 | |||
bd25904371 |
@ -170,6 +170,9 @@ renterd
|
||||
richtext
|
||||
rocksdb_library
|
||||
rpcrt4
|
||||
s_igid
|
||||
s_isvtx
|
||||
s_iuid
|
||||
sddl_revision_1
|
||||
secp256k1
|
||||
secur32
|
||||
@ -218,4 +221,4 @@ wsign-conversion
|
||||
wunused
|
||||
wuseless
|
||||
wxwidgets_version
|
||||
xattr
|
||||
xattr
|
@ -6,7 +6,7 @@ pipeline {
|
||||
environment {
|
||||
DEVELOPER_PRIVATE_KEY = "/.ci/repertory/cert/developer.priv"
|
||||
DEVELOPER_PUBLIC_KEY = "/.ci/repertory/cert/developer.pub"
|
||||
PROJECT_TEST_DIR = "/.ci/repertory/test"
|
||||
PROJECT_TEST_CONFIG_DIR = "/.ci/repertory/test_config"
|
||||
}
|
||||
|
||||
options {
|
||||
|
@ -11,13 +11,14 @@
|
||||
* A single 64-bit Linux Jenkins server is used to build all Linux and Windows versions
|
||||
* All dependency sources are now included
|
||||
* MSVC is no longer supported
|
||||
* MSYS2 is required for building Windows binaries Windows
|
||||
* MSYS2 is required for building Windows binaries on Windows
|
||||
* OS X support is temporarily disabled
|
||||
* \#19 \[bug\] Rename file is broken for files that are existing
|
||||
|
||||
### Changes from v2.0.1-rc
|
||||
|
||||
* Corrected file times on S3 and Sia providers
|
||||
* Corrected handling of `chown()` and `chmod()`
|
||||
|
||||
## v2.0.1-rc
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
CURRENT_DIR=$(dirname "$0")
|
||||
CURRENT_DIR=$(realpath ${CURRENT_DIR})
|
||||
|
||||
rsync -av --progress ${CURRENT_DIR}/${PROJECT_NAME}/${PROJECT_NAME}_test/test_config/ \
|
||||
${PROJECT_BUILD_DIR}/build/test_config/
|
||||
rsync -av --progress ${CURRENT_DIR}/${PROJECT_NAME}/${PROJECT_NAME}_test/test_input/ \
|
||||
${PROJECT_BUILD_DIR}/build/test_input/
|
||||
|
||||
rsync -av --progress ${CURRENT_DIR}/${PROJECT_NAME}/${PROJECT_NAME}_test/test_config/ \
|
||||
${PROJECT_DIST_DIR}/test_config/
|
||||
rsync -av --progress ${CURRENT_DIR}/${PROJECT_NAME}/${PROJECT_NAME}_test/test_input/ \
|
||||
${PROJECT_DIST_DIR}/test_input/
|
||||
|
@ -67,6 +67,11 @@ auto fuse_drive::chmod_impl(std::string api_path, mode_t mode,
|
||||
auto fuse_drive::chmod_impl(std::string api_path, mode_t mode) -> api_error {
|
||||
#endif // FUSE_USE_VERSION >= 30
|
||||
return check_and_perform(api_path, X_OK, [&](api_meta_map &) -> api_error {
|
||||
if ((mode & (S_IGID | S_IUID | S_ISVTX) != 0) &&
|
||||
(get_effective_uid() != 0)) {
|
||||
return api_error::permission_denied;
|
||||
}
|
||||
|
||||
return provider_.set_item_meta(api_path, META_MODE, std::to_string(mode));
|
||||
});
|
||||
}
|
||||
@ -79,23 +84,32 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
||||
auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||
-> api_error {
|
||||
#endif
|
||||
return check_and_perform(api_path, X_OK,
|
||||
[&](api_meta_map &meta) -> api_error {
|
||||
meta.clear();
|
||||
if (uid != static_cast<uid_t>(-1)) {
|
||||
meta[META_UID] = std::to_string(uid);
|
||||
}
|
||||
return check_and_perform(
|
||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||
meta.clear();
|
||||
if (uid != static_cast<uid_t>(-1)) {
|
||||
if (get_effective_uid() != 0) {
|
||||
return api_error::permission_denied;
|
||||
}
|
||||
|
||||
if (gid != static_cast<gid_t>(-1)) {
|
||||
meta[META_GID] = std::to_string(gid);
|
||||
}
|
||||
meta[META_UID] = std::to_string(uid);
|
||||
}
|
||||
|
||||
if (not meta.empty()) {
|
||||
return provider_.set_item_meta(api_path, meta);
|
||||
}
|
||||
if (gid != static_cast<gid_t>(-1)) {
|
||||
if (get_effective_uid() != 0 &&
|
||||
not utils::is_uid_member_of_group(get_effective_uid(), gid)) {
|
||||
return api_error::permission_denied;
|
||||
}
|
||||
|
||||
return api_error::success;
|
||||
});
|
||||
meta[META_GID] = std::to_string(gid);
|
||||
}
|
||||
|
||||
if (meta.empty()) {
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
return provider_.set_item_meta(api_path, meta);
|
||||
});
|
||||
}
|
||||
|
||||
auto fuse_drive::create_impl(std::string api_path, mode_t mode,
|
||||
|
@ -43,8 +43,8 @@
|
||||
#include "utils/time.hpp"
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] auto
|
||||
create_resume_entry(const repertory::i_open_file &file) -> json {
|
||||
[[nodiscard]] auto create_resume_entry(const repertory::i_open_file &file)
|
||||
-> json {
|
||||
return {
|
||||
{"chunk_size", file.get_chunk_size()},
|
||||
{"path", file.get_api_path()},
|
||||
@ -338,7 +338,7 @@ auto file_manager::get_stored_downloads() const -> std::vector<json> {
|
||||
auto result = utils::db::sqlite::db_select{*db_, resume_table}.go();
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not result.get_row(row)) {
|
||||
continue;
|
||||
}
|
||||
@ -375,7 +375,7 @@ auto file_manager::handle_file_rename(const std::string &from_api_path,
|
||||
.where("api_path")
|
||||
.equals(from_api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
should_upload = result.get_row(row) && row.has_value();
|
||||
if (should_upload && source_path.empty()) {
|
||||
source_path = row->get_column("source_path").get_value<std::string>();
|
||||
@ -438,10 +438,11 @@ auto file_manager::open(const std::string &api_path, bool directory,
|
||||
return open(api_path, directory, ofd, handle, file, nullptr);
|
||||
}
|
||||
|
||||
auto file_manager::open(
|
||||
const std::string &api_path, bool directory, const open_file_data &ofd,
|
||||
std::uint64_t &handle, std::shared_ptr<i_open_file> &file,
|
||||
std::shared_ptr<i_closeable_open_file> closeable_file) -> api_error {
|
||||
auto file_manager::open(const std::string &api_path, bool directory,
|
||||
const open_file_data &ofd, std::uint64_t &handle,
|
||||
std::shared_ptr<i_open_file> &file,
|
||||
std::shared_ptr<i_closeable_open_file> closeable_file)
|
||||
-> api_error {
|
||||
const auto create_and_add_handle =
|
||||
[&](std::shared_ptr<i_closeable_open_file> cur_file) {
|
||||
handle = get_next_handle();
|
||||
@ -700,8 +701,8 @@ auto file_manager::rename_directory(const std::string &from_api_path,
|
||||
}
|
||||
|
||||
auto file_manager::rename_file(const std::string &from_api_path,
|
||||
const std::string &to_api_path,
|
||||
bool overwrite) -> api_error {
|
||||
const std::string &to_api_path, bool overwrite)
|
||||
-> api_error {
|
||||
if (not provider_.is_rename_supported()) {
|
||||
return api_error::not_implemented;
|
||||
}
|
||||
@ -800,7 +801,7 @@ void file_manager::start() {
|
||||
auto result = utils::db::sqlite::db_select{*db_, upload_active_table}.go();
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
active_items.emplace_back(active_item{
|
||||
row->get_column("api_path").get_value<std::string>(),
|
||||
@ -824,7 +825,7 @@ void file_manager::start() {
|
||||
|
||||
while (result.has_row()) {
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return;
|
||||
}
|
||||
@ -1039,7 +1040,7 @@ void file_manager::upload_handler() {
|
||||
.limit(1)
|
||||
.go();
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
auto api_path = row->get_column("api_path").get_value<std::string>();
|
||||
auto source_path =
|
||||
|
@ -69,9 +69,10 @@ const std::map<std::string, std::string> sql_create_tables = {
|
||||
namespace repertory {
|
||||
encrypt_provider::encrypt_provider(app_config &config) : config_(config) {}
|
||||
|
||||
auto encrypt_provider::create_api_file(
|
||||
const std::string &api_path, bool directory,
|
||||
const std::string &source_path) -> api_file {
|
||||
auto encrypt_provider::create_api_file(const std::string &api_path,
|
||||
bool directory,
|
||||
const std::string &source_path)
|
||||
-> api_file {
|
||||
auto times = utils::file::get_times(source_path);
|
||||
if (not times.has_value()) {
|
||||
throw std::runtime_error("failed to get file times");
|
||||
@ -97,10 +98,10 @@ auto encrypt_provider::create_api_file(
|
||||
void encrypt_provider::create_item_meta(api_meta_map &meta, bool directory,
|
||||
const api_file &file) {
|
||||
#if defined(_WIN32)
|
||||
struct _stat64 buf {};
|
||||
struct _stat64 buf{};
|
||||
_stat64(file.source_path.c_str(), &buf);
|
||||
#else // !defined(_WIN32)
|
||||
struct stat buf {};
|
||||
struct stat buf{};
|
||||
stat(file.source_path.c_str(), &buf);
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
@ -187,8 +188,9 @@ auto encrypt_provider::do_fs_operation(
|
||||
return callback(cfg, source_path);
|
||||
}
|
||||
|
||||
auto encrypt_provider::get_api_path_from_source(
|
||||
const std::string &source_path, std::string &api_path) const -> api_error {
|
||||
auto encrypt_provider::get_api_path_from_source(const std::string &source_path,
|
||||
std::string &api_path) const
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
try {
|
||||
@ -197,7 +199,7 @@ auto encrypt_provider::get_api_path_from_source(
|
||||
.where("source_path")
|
||||
.equals(source_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
api_path = row->get_column("data")
|
||||
.get_value_as_json()
|
||||
@ -253,8 +255,9 @@ auto encrypt_provider::get_directory_item_count(
|
||||
return count;
|
||||
}
|
||||
|
||||
auto encrypt_provider::get_directory_items(
|
||||
const std::string &api_path, directory_item_list &list) const -> api_error {
|
||||
auto encrypt_provider::get_directory_items(const std::string &api_path,
|
||||
directory_item_list &list) const
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
return do_fs_operation(
|
||||
@ -273,7 +276,7 @@ auto encrypt_provider::get_directory_items(
|
||||
.where("source_path")
|
||||
.equals(dir_entry->get_path())
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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>();
|
||||
@ -302,7 +305,7 @@ auto encrypt_provider::get_directory_items(
|
||||
.where("source_path")
|
||||
.equals(dir_entry->get_path())
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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>();
|
||||
@ -385,7 +388,7 @@ auto encrypt_provider::get_file(const std::string &api_path,
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
@ -427,8 +430,9 @@ auto encrypt_provider::get_file_list(api_file_list &list) const -> api_error {
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto encrypt_provider::get_file_size(
|
||||
const std::string &api_path, std::uint64_t &file_size) const -> api_error {
|
||||
auto encrypt_provider::get_file_size(const std::string &api_path,
|
||||
std::uint64_t &file_size) const
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
try {
|
||||
@ -437,7 +441,7 @@ auto encrypt_provider::get_file_size(
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
@ -454,15 +458,16 @@ auto encrypt_provider::get_file_size(
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto encrypt_provider::get_filesystem_item(
|
||||
const std::string &api_path, bool directory,
|
||||
filesystem_item &fsi) const -> api_error {
|
||||
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_, source_table}
|
||||
.column("source_path")
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
@ -532,9 +537,10 @@ auto encrypt_provider::get_filesystem_item_from_source_path(
|
||||
return get_filesystem_item(api_path, false, fsi);
|
||||
}
|
||||
|
||||
auto encrypt_provider::get_filesystem_item_and_file(
|
||||
const std::string &api_path, api_file &file,
|
||||
filesystem_item &fsi) const -> api_error {
|
||||
auto encrypt_provider::get_filesystem_item_and_file(const std::string &api_path,
|
||||
api_file &file,
|
||||
filesystem_item &fsi) const
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
try {
|
||||
@ -576,7 +582,7 @@ auto encrypt_provider::get_item_meta(const std::string &api_path,
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
@ -624,7 +630,7 @@ auto encrypt_provider::get_total_item_count() const -> std::uint64_t {
|
||||
.count("api_path", "count")
|
||||
.go();
|
||||
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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>());
|
||||
@ -647,7 +653,7 @@ auto encrypt_provider::is_directory(const std::string &api_path,
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
exists = false;
|
||||
return api_error::success;
|
||||
@ -661,14 +667,14 @@ auto encrypt_provider::is_directory(const std::string &api_path,
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto encrypt_provider::is_file(const std::string &api_path,
|
||||
bool &exists) const -> api_error {
|
||||
auto encrypt_provider::is_file(const std::string &api_path, bool &exists) const
|
||||
-> api_error {
|
||||
auto result = utils::db::sqlite::db_select{*db_, source_table}
|
||||
.column("source_path")
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
exists = false;
|
||||
return api_error::success;
|
||||
@ -730,7 +736,7 @@ auto encrypt_provider::process_directory_entry(
|
||||
.where("source_path")
|
||||
.equals(current_source_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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>();
|
||||
}
|
||||
@ -780,7 +786,7 @@ auto encrypt_provider::process_directory_entry(
|
||||
.where("source_path")
|
||||
.equals(dir_entry.get_path())
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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>();
|
||||
}
|
||||
@ -854,7 +860,7 @@ auto encrypt_provider::read_file_bytes(const std::string &api_path,
|
||||
.where("api_path")
|
||||
.equals(api_path)
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (not(result.get_row(row) && row.has_value())) {
|
||||
return api_error::item_not_found;
|
||||
}
|
||||
@ -958,11 +964,11 @@ void encrypt_provider::remove_deleted_files() {
|
||||
};
|
||||
|
||||
std::vector<removed_item> removed_list{};
|
||||
std::vector<utils::db::sqlite::db_select::row> row_list{};
|
||||
std::vector<utils::db::sqlite::db_result::row> row_list{};
|
||||
|
||||
auto result = utils::db::sqlite::db_select{*db_, source_table}.go();
|
||||
while (result.has_row()) {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
row_list.push_back(row.value());
|
||||
}
|
||||
@ -1037,7 +1043,7 @@ auto encrypt_provider::start(api_item_added_callback /*api_item_added*/,
|
||||
.where("api_path")
|
||||
.equals("/")
|
||||
.go();
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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>();
|
||||
} else {
|
||||
|
@ -66,7 +66,7 @@ auto meta_db::get_api_path(const std::string &source_path,
|
||||
.limit(1)
|
||||
.go();
|
||||
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
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;
|
||||
@ -81,7 +81,7 @@ auto meta_db::get_api_path_list() -> std::vector<std::string> {
|
||||
auto result =
|
||||
utils::db::sqlite::db_select{*db_, table_name}.column("api_path").go();
|
||||
while (result.has_row()) {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
ret.push_back(row->get_column("api_path").get_value<std::string>());
|
||||
}
|
||||
@ -90,8 +90,8 @@ auto meta_db::get_api_path_list() -> std::vector<std::string> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto meta_db::get_item_meta(const std::string &api_path,
|
||||
api_meta_map &meta) -> api_error {
|
||||
auto meta_db::get_item_meta(const std::string &api_path, api_meta_map &meta)
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
auto result = utils::db::sqlite::db_select{*db_, table_name}
|
||||
@ -106,7 +106,7 @@ auto meta_db::get_item_meta(const std::string &api_path,
|
||||
}
|
||||
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
meta = json::parse(row->get_column("data").get_value<std::string>())
|
||||
.get<api_meta_map>();
|
||||
@ -145,7 +145,7 @@ auto meta_db::get_item_meta(const std::string &api_path, const std::string &key,
|
||||
}
|
||||
|
||||
try {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
value =
|
||||
key == META_SOURCE
|
||||
@ -183,7 +183,7 @@ auto meta_db::get_pinned_files() const -> std::vector<std::string> {
|
||||
.equals(1)
|
||||
.go();
|
||||
while (result.has_row()) {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
ret.emplace_back(row->get_column("api_path").get_value<std::string>());
|
||||
}
|
||||
@ -205,7 +205,7 @@ auto meta_db::get_total_item_count() const -> std::uint64_t {
|
||||
.count("api_path", "count")
|
||||
.go();
|
||||
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
if (result.get_row(row) && row.has_value()) {
|
||||
ret = static_cast<std::uint64_t>(
|
||||
row->get_column("count").get_value<std::int64_t>());
|
||||
@ -274,8 +274,8 @@ auto meta_db::set_item_meta(const std::string &api_path,
|
||||
return update_item_meta(api_path, existing_meta);
|
||||
}
|
||||
|
||||
auto meta_db::update_item_meta(const std::string &api_path,
|
||||
api_meta_map meta) -> api_error {
|
||||
auto meta_db::update_item_meta(const std::string &api_path, api_meta_map meta)
|
||||
-> api_error {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
auto directory = utils::string::to_bool(meta[META_DIRECTORY]);
|
||||
|
@ -32,16 +32,22 @@
|
||||
#include "providers/encrypt/encrypt_provider.hpp"
|
||||
#include "providers/s3/s3_provider.hpp"
|
||||
#include "providers/sia/sia_provider.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/event_capture.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
#if !defined(ACCESSPERMS)
|
||||
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
|
||||
#endif
|
||||
|
||||
namespace repertory {
|
||||
inline constexpr const auto SLEEP_SECONDS{1.5s};
|
||||
namespace {
|
||||
std::atomic<std::size_t> idx{0U};
|
||||
constexpr const auto SLEEP_SECONDS{1.5s};
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
template <typename provider_t> class fuse_test : public ::testing::Test {
|
||||
public:
|
||||
static std::string cfg_directory;
|
||||
@ -49,7 +55,6 @@ public:
|
||||
static std::unique_ptr<app_config> config;
|
||||
static std::filesystem::path current_directory;
|
||||
static std::unique_ptr<fuse_drive> drive;
|
||||
static lock_data lock_data_;
|
||||
static std::string mount_location;
|
||||
static std::unique_ptr<i_provider> provider;
|
||||
static std::string test_directory;
|
||||
@ -81,7 +86,7 @@ protected:
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::s3,
|
||||
utils::path::combine(test::get_test_input_dir(), {"storj"}),
|
||||
utils::path::combine(test::get_test_config_dir(), {"storj"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
@ -100,7 +105,7 @@ protected:
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::sia,
|
||||
utils::path::combine(test::get_test_input_dir(), {"sia"}),
|
||||
utils::path::combine(test::get_test_config_dir(), {"sia"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::debug);
|
||||
@ -146,8 +151,9 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
static auto create_file_and_test(std::string name) -> std::string {
|
||||
auto file_path = utils::path::combine(mount_location, {name});
|
||||
static auto create_file_and_test(std::string &file_name) -> std::string {
|
||||
file_name += std::to_string(++idx);
|
||||
auto file_path = utils::path::combine(mount_location, {file_name});
|
||||
|
||||
auto fd =
|
||||
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||
@ -166,40 +172,62 @@ public:
|
||||
return file_path;
|
||||
}
|
||||
|
||||
static auto create_root_file(std::string &file_name) -> std::string {
|
||||
auto file_path = create_file_and_test(file_name);
|
||||
auto api_path = utils::path::create_api_path(file_name);
|
||||
|
||||
provider->set_item_meta(api_path, {
|
||||
{META_UID, "0"},
|
||||
{META_GID, "0"},
|
||||
});
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
static void execute_mount(auto &&drive_args) {
|
||||
auto mount_cmd = "./repertory -dd \"" + config->get_data_directory() +
|
||||
"\"" + " " + utils::string::join(drive_args, ' ');
|
||||
std::cout << "mount command: " << mount_cmd << std::endl;
|
||||
ASSERT_EQ(0, system(mount_cmd.c_str()));
|
||||
std::this_thread::sleep_for(5s);
|
||||
EXPECT_EQ(0, system(("mount|grep \"" + mount_location + "\"").c_str()));
|
||||
ASSERT_TRUE(utils::file::directory{mount_location}.exists());
|
||||
}
|
||||
|
||||
static void execute_unmount() {
|
||||
auto unmounted{false};
|
||||
|
||||
auto unmount_cmd =
|
||||
"./repertory -dd \"" + config->get_data_directory() + "\" -unmount";
|
||||
for (int i = 0; not unmounted && (i < 50); i++) {
|
||||
unmounted = (fuse_base::unmount(mount_location) == 0);
|
||||
std::cout << "unmount command: " << unmount_cmd << std::endl;
|
||||
ASSERT_EQ(0, system(unmount_cmd.c_str()));
|
||||
unmounted = not utils::file::directory{mount_location}.exists();
|
||||
if (not unmounted) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
std::this_thread::sleep_for(5s);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unmounted);
|
||||
}
|
||||
|
||||
static void unlink_file_and_test(const std::string &file_path) {
|
||||
int ret = 0;
|
||||
for (auto i = 0; ((ret = unlink(file_path.c_str())) != 0) && (i < 20);
|
||||
i++) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, ret);
|
||||
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
static void unlink_file_and_test(std::string_view file_path) {
|
||||
EXPECT_TRUE(utils::file::file(file_path).remove());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
}
|
||||
|
||||
static void unlink_root_file(const std::string &file_path) {
|
||||
auto api_path =
|
||||
utils::path::create_api_path(utils::path::strip_to_filename(file_path));
|
||||
|
||||
provider->set_item_meta(api_path, {
|
||||
{META_UID, std::to_string(getuid())},
|
||||
{META_GID, std::to_string(getgid())},
|
||||
});
|
||||
|
||||
unlink_file_and_test(file_path);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename provider_t>
|
||||
@ -217,8 +245,6 @@ std::filesystem::path fuse_test<provider_t>::current_directory{};
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<fuse_drive> fuse_test<provider_t>::drive{};
|
||||
|
||||
template <typename provider_t> lock_data fuse_test<provider_t>::lock_data_{};
|
||||
|
||||
template <typename provider_t>
|
||||
std::string fuse_test<provider_t>::mount_location{};
|
||||
|
||||
@ -228,7 +254,7 @@ std::unique_ptr<i_provider> fuse_test<provider_t>::provider{};
|
||||
template <typename provider_t>
|
||||
std::string fuse_test<provider_t>::test_directory;
|
||||
|
||||
typedef ::testing::Types<s3_provider, sia_provider> fuse_provider_types;
|
||||
using fuse_provider_types = ::testing::Types<s3_provider, sia_provider>;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // !defined(_WIN32)
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
#ifndef REPERTORY_TEST_INCLUDE_FIXTURES_WINFSP_FIXTURE_HPP
|
||||
#define REPERTORY_TEST_INCLUDE_FIXTURES_WINFSP_FIXTURE_HPP
|
||||
#if 0
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "test_common.hpp"
|
||||
@ -29,135 +30,222 @@
|
||||
#include "comm/curl/curl_comm.hpp"
|
||||
#include "drives/winfsp/winfsp_drive.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
#include "providers/i_provider.hpp"
|
||||
#include "providers/s3/s3_provider.hpp"
|
||||
#include "providers/sia/sia_provider.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
|
||||
extern std::size_t PROVIDER_INDEX;
|
||||
namespace {
|
||||
std::atomic<std::size_t> idx{0U};
|
||||
constexpr const auto SLEEP_SECONDS{1.5s};
|
||||
} // namespace
|
||||
|
||||
namespace repertory {
|
||||
class winfsp_test : public ::testing::Test {
|
||||
template <typename provider_t> class winfsp_test : public ::testing::Test {
|
||||
public:
|
||||
lock_data lock_data_;
|
||||
std::unique_ptr<app_config> config;
|
||||
std::unique_ptr<curl_comm> comm;
|
||||
std::unique_ptr<i_provider> provider;
|
||||
std::unique_ptr<winfsp_drive> drive;
|
||||
static std::string cfg_directory;
|
||||
static std::unique_ptr<curl_comm> comm;
|
||||
static std::unique_ptr<app_config> config;
|
||||
static std::filesystem::path current_directory;
|
||||
static std::unique_ptr<winfsp_drive> drive;
|
||||
static std::string mount_location;
|
||||
static std::unique_ptr<i_provider> provider;
|
||||
static std::string test_directory;
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
if (PROVIDER_INDEX != 0) {
|
||||
if (PROVIDER_INDEX == 1) {
|
||||
EXPECT_TRUE(utils::file::directory(
|
||||
utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}))
|
||||
.remove_recursively());
|
||||
static void SetUpTestCase() {
|
||||
current_directory = std::filesystem::current_path();
|
||||
|
||||
app_config src_cfg(
|
||||
test_directory = utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{
|
||||
"winfsp_test",
|
||||
std::to_string(static_cast<std::uint8_t>(provider_t::type)),
|
||||
});
|
||||
mount_location = "U:";
|
||||
|
||||
cfg_directory = utils::path::combine(test_directory, {"cfg"});
|
||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||
|
||||
config = std::make_unique<app_config>(provider_t::type, cfg_directory);
|
||||
|
||||
std::vector<std::string> drive_args{};
|
||||
|
||||
switch (provider_t::type) {
|
||||
case provider_type::s3: {
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::s3,
|
||||
utils::path::combine(test::get_test_input_dir(), {"storj"}));
|
||||
config = std::make_unique<app_config>(
|
||||
provider_type::s3,
|
||||
utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}));
|
||||
EXPECT_FALSE(config
|
||||
->set_value_by_name("S3Config.AccessKey",
|
||||
src_cfg.get_s3_config().access_key)
|
||||
.empty());
|
||||
EXPECT_FALSE(config
|
||||
->set_value_by_name("S3Config.SecretKey",
|
||||
src_cfg.get_s3_config().secret_key)
|
||||
.empty());
|
||||
EXPECT_FALSE(config
|
||||
->set_value_by_name("S3Config.Region",
|
||||
src_cfg.get_s3_config().region)
|
||||
.empty());
|
||||
EXPECT_FALSE(
|
||||
config
|
||||
->set_value_by_name("S3Config.EncryptionToken",
|
||||
src_cfg.get_s3_config().encryption_token)
|
||||
.empty());
|
||||
EXPECT_FALSE(
|
||||
config
|
||||
->set_value_by_name("S3Config.URL", src_cfg.get_s3_config().url)
|
||||
.empty());
|
||||
EXPECT_FALSE(
|
||||
config->set_value_by_name("S3Config.Bucket", "repertory").empty());
|
||||
utils::path::combine(test::get_test_config_dir(), {"storj"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::trace);
|
||||
config->set_enable_drive_events(true);
|
||||
event_system::instance().start();
|
||||
|
||||
comm = std::make_unique<curl_comm>(config->get_s3_config());
|
||||
provider = std::make_unique<s3_provider>(*config, *comm);
|
||||
drive = std::make_unique<winfsp_drive>(*config, lock_data_, *provider);
|
||||
return;
|
||||
config->set_s3_config(src_cfg.get_s3_config());
|
||||
}
|
||||
|
||||
if (PROVIDER_INDEX == 2) {
|
||||
EXPECT_TRUE(utils::file::directory(
|
||||
utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}))
|
||||
.remove_recursively());
|
||||
comm = std::make_unique<curl_comm>(config->get_s3_config());
|
||||
drive_args = std::vector<std::string>({
|
||||
"-s3",
|
||||
"-na",
|
||||
"storj",
|
||||
});
|
||||
} break;
|
||||
|
||||
app_config src_cfg(
|
||||
case provider_type::sia: {
|
||||
{
|
||||
app_config src_cfg{
|
||||
provider_type::sia,
|
||||
utils::path::combine(test::get_test_input_dir(), {"sia"}));
|
||||
config = std::make_unique<app_config>(
|
||||
provider_type::sia,
|
||||
utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}));
|
||||
[[maybe_unused]] auto val = config->set_value_by_name(
|
||||
"HostConfig.AgentString", src_cfg.get_host_config().agent_string);
|
||||
EXPECT_FALSE(
|
||||
config
|
||||
->set_value_by_name("HostConfig.ApiPassword",
|
||||
src_cfg.get_host_config().api_password)
|
||||
.empty());
|
||||
EXPECT_FALSE(config
|
||||
->set_value_by_name(
|
||||
"HostConfig.ApiPort",
|
||||
std::to_string(src_cfg.get_host_config().api_port))
|
||||
.empty());
|
||||
EXPECT_FALSE(
|
||||
config
|
||||
->set_value_by_name("HostConfig.HostNameOrIp",
|
||||
src_cfg.get_host_config().host_name_or_ip)
|
||||
.empty());
|
||||
utils::path::combine(test::get_test_config_dir(), {"sia"}),
|
||||
};
|
||||
config->set_enable_drive_events(true);
|
||||
config->set_event_level(event_level::debug);
|
||||
config->set_enable_drive_events(true);
|
||||
event_system::instance().start();
|
||||
|
||||
comm = std::make_unique<curl_comm>(config->get_host_config());
|
||||
provider = std::make_unique<sia_provider>(*config, *comm);
|
||||
drive = std::make_unique<winfsp_drive>(*config, lock_data_, *provider);
|
||||
|
||||
return;
|
||||
config->set_host_config(src_cfg.get_host_config());
|
||||
}
|
||||
|
||||
comm = std::make_unique<curl_comm>(config->get_host_config());
|
||||
} break;
|
||||
// case 0U: {
|
||||
// config =
|
||||
// std::make_unique<app_config>(provider_type::encrypt,
|
||||
// cfg_directory);
|
||||
// {
|
||||
// app_config src_cfg(
|
||||
// provider_type::s3,
|
||||
// utils::path::combine(test::get_test_input_dir(), {"encrypt"}));
|
||||
// config->set_enable_drive_events(true);
|
||||
// config->set_event_level(event_level::trace);
|
||||
// config->set_s3_config(src_cfg.get_s3_config());
|
||||
// }
|
||||
//
|
||||
// comm = std::make_unique<curl_comm>(config->get_s3_config());
|
||||
// provider = std::make_unique<s3_provider>(*config, *comm);
|
||||
// drive_args = std::vector<std::string>({"-en"});
|
||||
// } break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("provider type is not implemented");
|
||||
return;
|
||||
}
|
||||
|
||||
provider = std::make_unique<provider_t>(*config, *comm);
|
||||
drive_args.push_back(mount_location);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (PROVIDER_INDEX != 0) {
|
||||
drive.reset();
|
||||
provider.reset();
|
||||
comm.reset();
|
||||
config.reset();
|
||||
static void TearDownTestCase() {
|
||||
execute_unmount();
|
||||
std::filesystem::current_path(current_directory);
|
||||
[[maybe_unused]] auto ret =
|
||||
utils::file::directory(test_directory).remove_recursively();
|
||||
}
|
||||
|
||||
event_system::instance().stop();
|
||||
EXPECT_TRUE(utils::file::directory(
|
||||
utils::path::combine(
|
||||
test::get_test_output_dir(),
|
||||
{"winfsp_test" + std::to_string(PROVIDER_INDEX)}))
|
||||
.remove_recursively());
|
||||
public:
|
||||
[[nodiscard]] static auto create_directory_and_test(std::string &dir_name)
|
||||
-> std::string {
|
||||
dir_name += std::to_string(++idx);
|
||||
auto api_path = utils::path::create_api_path(dir_name);
|
||||
auto dir_path = utils::path::combine(mount_location, {dir_name});
|
||||
|
||||
EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
EXPECT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||
EXPECT_TRUE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
return dir_path;
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto create_file_and_test(std::string &file_name)
|
||||
-> std::string {
|
||||
file_name += std::to_string(++idx);
|
||||
auto api_path = utils::path::create_api_path(file_name);
|
||||
auto file_path = utils::path::combine(mount_location, {file_name});
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
EXPECT_TRUE(utils::file::file(file_path).exists());
|
||||
|
||||
auto opt_size = utils::file::file(file_path).size();
|
||||
EXPECT_TRUE(opt_size.has_value());
|
||||
EXPECT_EQ(0, opt_size.value());
|
||||
|
||||
std::string attr;
|
||||
EXPECT_EQ(api_error::success,
|
||||
provider->get_item_meta(api_path, META_ATTRIBUTES, attr));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_NORMAL, utils::string::to_uint32(attr));
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
static void delete_directory_and_test(const std::string &dir_path) {
|
||||
EXPECT_TRUE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||
EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
}
|
||||
|
||||
static void delete_file_and_test(std::string_view file_path) {
|
||||
EXPECT_TRUE(utils::file::file(file_path).remove());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
}
|
||||
|
||||
static void execute_mount(auto &&drive_args) {
|
||||
auto mount_cmd = ".\\repertory.exe -dd \"" + config->get_data_directory() +
|
||||
"\"" + " " + utils::string::join(drive_args, ' ');
|
||||
std::cout << "mount command: " << mount_cmd << std::endl;
|
||||
ASSERT_EQ(0, system(mount_cmd.c_str()));
|
||||
std::this_thread::sleep_for(5s);
|
||||
ASSERT_TRUE(utils::file::directory{mount_location}.exists());
|
||||
}
|
||||
|
||||
static void execute_unmount() {
|
||||
auto unmounted{false};
|
||||
|
||||
auto unmount_cmd = ".\\repertory.exe -dd \"" +
|
||||
config->get_data_directory() + "\" -unmount";
|
||||
for (int i = 0; not unmounted && (i < 50); i++) {
|
||||
std::cout << "unmount command: " << unmount_cmd << std::endl;
|
||||
ASSERT_EQ(0, system(unmount_cmd.c_str()));
|
||||
unmounted = not utils::file::directory{mount_location}.exists();
|
||||
if (not unmounted) {
|
||||
std::this_thread::sleep_for(5s);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(unmounted);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename provider_t>
|
||||
std::string winfsp_test<provider_t>::cfg_directory;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<app_config> winfsp_test<provider_t>::config;
|
||||
|
||||
template <typename provider_t>
|
||||
std::filesystem::path winfsp_test<provider_t>::current_directory;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<curl_comm> winfsp_test<provider_t>::comm;
|
||||
|
||||
template <typename provider_t>
|
||||
std::string winfsp_test<provider_t>::mount_location;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<i_provider> winfsp_test<provider_t>::provider;
|
||||
|
||||
template <typename provider_t>
|
||||
std::string winfsp_test<provider_t>::test_directory;
|
||||
|
||||
template <typename provider_t>
|
||||
std::unique_ptr<winfsp_drive> winfsp_test<provider_t>::drive;
|
||||
|
||||
using winfsp_provider_types = ::testing::Types<s3_provider, sia_provider>;
|
||||
} // namespace repertory
|
||||
|
||||
#endif
|
||||
#endif // defined(_WIN32)
|
||||
#endif // 0
|
||||
#endif // REPERTORY_TEST_INCLUDE_FIXTURES_WINFSP_FIXTURE_HPP
|
||||
|
@ -39,11 +39,12 @@ public:
|
||||
: mount_location_(std::move(mount_location)) {}
|
||||
|
||||
private:
|
||||
const std::string mount_location_;
|
||||
std::string mount_location_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto get_directory_item_count(
|
||||
const std::string & /*api_path*/) const -> std::uint64_t override {
|
||||
[[nodiscard]] auto
|
||||
get_directory_item_count(const std::string & /*api_path*/) const
|
||||
-> std::uint64_t override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -54,13 +55,12 @@ public:
|
||||
directory_item di{};
|
||||
di.api_path = ".";
|
||||
di.directory = true;
|
||||
di.size = 0u;
|
||||
di.meta = {
|
||||
{META_ATTRIBUTES, "16"},
|
||||
{META_MODIFIED, std::to_string(utils::time::get_time_now())},
|
||||
{META_WRITTEN, std::to_string(utils::time::get_time_now())},
|
||||
{META_ACCESSED, std::to_string(utils::time::get_time_now())},
|
||||
{META_CREATION, std::to_string(utils::time::get_time_now())}};
|
||||
di.size = 0U;
|
||||
di.meta = {{META_ATTRIBUTES, "16"},
|
||||
{META_MODIFIED, std::to_string(utils::time::get_time_now())},
|
||||
{META_WRITTEN, std::to_string(utils::time::get_time_now())},
|
||||
{META_ACCESSED, std::to_string(utils::time::get_time_now())},
|
||||
{META_CREATION, std::to_string(utils::time::get_time_now())}};
|
||||
list.emplace_back(di);
|
||||
|
||||
di.api_path = "..";
|
||||
@ -75,7 +75,7 @@ public:
|
||||
}
|
||||
|
||||
auto get_item_meta(const std::string & /*api_path*/,
|
||||
api_meta_map &meta) const -> api_error override {
|
||||
api_meta_map & /* meta */) const -> api_error override {
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
@ -85,19 +85,19 @@ public:
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
auto
|
||||
get_security_by_name(PWSTR /*file_name*/, PUINT32 attributes,
|
||||
PSECURITY_DESCRIPTOR descriptor,
|
||||
std::uint64_t *descriptor_size) -> NTSTATUS override {
|
||||
auto get_security_by_name(PWSTR /*file_name*/, PUINT32 attributes,
|
||||
PSECURITY_DESCRIPTOR descriptor,
|
||||
std::uint64_t *descriptor_size)
|
||||
-> NTSTATUS override {
|
||||
auto ret = STATUS_SUCCESS;
|
||||
|
||||
if (attributes) {
|
||||
if (attributes != nullptr) {
|
||||
*attributes = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
|
||||
if (descriptor_size) {
|
||||
ULONG sz = 0;
|
||||
PSECURITY_DESCRIPTOR sd = nullptr;
|
||||
ULONG sz{0U};
|
||||
PSECURITY_DESCRIPTOR sd{nullptr};
|
||||
if (::ConvertStringSecurityDescriptorToSecurityDescriptor(
|
||||
"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)",
|
||||
SDDL_REVISION_1, &sd, &sz)) {
|
||||
@ -117,36 +117,38 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_total_drive_space() const -> std::uint64_t override {
|
||||
return 100 * 1024 * 1024;
|
||||
return 100ULL * 1024ULL * 1024ULL;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_total_item_count() const -> std::uint64_t override {
|
||||
return 0;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_used_drive_space() const -> std::uint64_t override {
|
||||
return 0;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
||||
std::string &volume_label) const override {
|
||||
free_size = 100;
|
||||
total_size = 200;
|
||||
free_size = 100U;
|
||||
total_size = 200U;
|
||||
volume_label = "TestVolumeLabel";
|
||||
}
|
||||
|
||||
auto populate_file_info(const std::string &api_path,
|
||||
remote::file_info &file_info) -> api_error override {
|
||||
const auto file_path = utils::path::combine(mount_location_, {api_path});
|
||||
const auto directory = utils::file::directory(file_path).exists();
|
||||
const auto attributes =
|
||||
auto file_path = utils::path::combine(mount_location_, {api_path});
|
||||
auto directory = utils::file::directory(file_path).exists();
|
||||
auto attributes =
|
||||
FILE_FLAG_BACKUP_SEMANTICS |
|
||||
(directory ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL);
|
||||
const auto share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
auto handle = ::CreateFileA(&file_path[0], GENERIC_READ, share_mode,
|
||||
nullptr, OPEN_EXISTING, attributes, nullptr);
|
||||
FILE_BASIC_INFO fi{};
|
||||
::GetFileInformationByHandleEx(handle, FileBasicInfo, &fi, sizeof(fi));
|
||||
auto share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
auto handle = ::CreateFileA(
|
||||
file_path.c_str(), GENERIC_READ, static_cast<DWORD>(share_mode),
|
||||
nullptr, OPEN_EXISTING, static_cast<DWORD>(attributes), nullptr);
|
||||
FILE_BASIC_INFO basic_info{};
|
||||
::GetFileInformationByHandleEx(handle, FileBasicInfo, &basic_info,
|
||||
sizeof(basic_info));
|
||||
if (not directory) {
|
||||
auto opt_size = utils::file::file{file_path}.size();
|
||||
if (not opt_size.has_value()) {
|
||||
@ -161,11 +163,14 @@ public:
|
||||
: utils::divide_with_ceiling(file_info.FileSize,
|
||||
WINFSP_ALLOCATION_UNIT) *
|
||||
WINFSP_ALLOCATION_UNIT;
|
||||
file_info.FileAttributes = fi.FileAttributes;
|
||||
file_info.ChangeTime = fi.ChangeTime.QuadPart;
|
||||
file_info.CreationTime = fi.CreationTime.QuadPart;
|
||||
file_info.LastAccessTime = fi.LastAccessTime.QuadPart;
|
||||
file_info.LastWriteTime = fi.LastWriteTime.QuadPart;
|
||||
file_info.FileAttributes = basic_info.FileAttributes;
|
||||
file_info.ChangeTime = static_cast<UINT64>(basic_info.ChangeTime.QuadPart);
|
||||
file_info.CreationTime =
|
||||
static_cast<UINT64>(basic_info.CreationTime.QuadPart);
|
||||
file_info.LastAccessTime =
|
||||
static_cast<UINT64>(basic_info.LastAccessTime.QuadPart);
|
||||
file_info.LastWriteTime =
|
||||
static_cast<UINT64>(basic_info.LastWriteTime.QuadPart);
|
||||
::CloseHandle(handle);
|
||||
return api_error::success;
|
||||
}
|
||||
|
@ -25,16 +25,9 @@
|
||||
|
||||
#include "initialize.hpp"
|
||||
#include "test_common.hpp"
|
||||
#if defined(_WIN32)
|
||||
#include "utils/cli_utils.hpp"
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
using namespace repertory;
|
||||
|
||||
#if defined(_WIN32)
|
||||
std::size_t PROVIDER_INDEX{0U};
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
auto main(int argc, char **argv) -> int {
|
||||
#if defined(PROJECT_ENABLE_BACKWARD_CPP)
|
||||
static backward::SignalHandling sh;
|
||||
@ -45,21 +38,6 @@ auto main(int argc, char **argv) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
std::vector<const char *> args;
|
||||
{
|
||||
auto args_span = std::span(argv, static_cast<std::size_t>(argc));
|
||||
std::copy(args_span.begin(), args_span.end(), std::back_inserter(args));
|
||||
}
|
||||
|
||||
if (utils::cli::has_option(args, "--provider_index")) {
|
||||
PROVIDER_INDEX = static_cast<std::size_t>(
|
||||
utils::string::to_uint64(
|
||||
utils::cli::parse_option(args, "--provider_index", 1U)[0U]) +
|
||||
1U);
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
auto ret = RUN_ALL_TESTS();
|
||||
|
||||
|
@ -19,22 +19,10 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#if 0
|
||||
#if !defined(_WIN32)
|
||||
|
||||
#include "fixtures/fuse_fixture.hpp"
|
||||
|
||||
// #include "app_config.hpp"
|
||||
// #include "comm/curl/curl_comm.hpp"
|
||||
// #include "drives/fuse/fuse_drive.hpp"
|
||||
// #include "platform/platform.hpp"
|
||||
// #include "providers/s3/s3_provider.hpp"
|
||||
// #include "providers/sia/sia_provider.hpp"
|
||||
// #include "types/repertory.hpp"
|
||||
// #include "utils/event_capture.hpp"
|
||||
// #include "utils/file_utils.hpp"
|
||||
// #include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
// static void rmdir_and_test(const std::string &directory_path) {
|
||||
// std::cout << __FUNCTION__ << std::endl;
|
||||
@ -529,36 +517,133 @@ namespace repertory {
|
||||
|
||||
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
||||
|
||||
TYPED_TEST(fuse_test, chmod) {
|
||||
auto file_path = this->create_file_and_test("chmod_test");
|
||||
TYPED_TEST(fuse_test, can_chmod_if_owner) {
|
||||
std::string file_name{"chmod_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
struct stat64 unix_st {};
|
||||
struct stat64 unix_st{};
|
||||
stat64(file_path.c_str(), &unix_st);
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
|
||||
ACCESSPERMS & unix_st.st_mode);
|
||||
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, chown) {
|
||||
auto file_path = this->create_file_and_test("chown_test");
|
||||
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
||||
TYPED_TEST(fuse_test, can_not_chmod_if_not_owner) {
|
||||
std::string file_name{"chmod_test"};
|
||||
auto file_path = this->create_root_file(file_name);
|
||||
|
||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
this->unlink_root_file(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, can_not_chmod_setgid_if_not_root) {
|
||||
std::string file_name{"chmod_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_IGID));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, can_not_chmod_setuid_if_not_root) {
|
||||
std::string file_name{"chmod_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_IUID));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, can_not_chmod_set_sticky_if_not_root) {
|
||||
std::string file_name{"chown_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISVTX));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, can_chown_group_if_owner_and_a_member_of_the_group) {
|
||||
std::string file_name{"chown_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
struct stat64 unix_st{};
|
||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||
|
||||
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
|
||||
struct stat64 unix_st {};
|
||||
stat64(file_path.c_str(), &unix_st);
|
||||
EXPECT_EQ(0U, unix_st.st_gid);
|
||||
struct stat64 unix_st2{};
|
||||
stat64(file_path.c_str(), &unix_st2);
|
||||
EXPECT_EQ(getgid(), unix_st2.st_gid);
|
||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||
|
||||
EXPECT_EQ(0, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
|
||||
stat64(file_path.c_str(), &unix_st);
|
||||
EXPECT_EQ(0U, unix_st.st_gid);
|
||||
TYPED_TEST(fuse_test,
|
||||
can_not_chown_group_if_owner_but_not_a_member_of_the_group) {
|
||||
std::string file_name{"chown_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
struct stat64 unix_st{};
|
||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||
|
||||
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
struct stat64 unix_st2{};
|
||||
stat64(file_path.c_str(), &unix_st2);
|
||||
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, can_not_chown_group_if_not_the_owner) {
|
||||
std::string file_name{"chown_test"};
|
||||
auto file_path = this->create_root_file(file_name);
|
||||
|
||||
struct stat64 unix_st{};
|
||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||
|
||||
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
struct stat64 unix_st2{};
|
||||
stat64(file_path.c_str(), &unix_st2);
|
||||
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||
|
||||
this->unlink_root_file(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(fuse_test, can_not_chown_user_if_not_root) {
|
||||
std::string file_name{"chown_test"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
struct stat64 unix_st{};
|
||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||
|
||||
EXPECT_EQ(-1, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
||||
EXPECT_EQ(EPERM, errno);
|
||||
|
||||
struct stat64 unix_st2{};
|
||||
stat64(file_path.c_str(), &unix_st2);
|
||||
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||
|
||||
this->unlink_file_and_test(file_path);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif // !defined(_WIN32)
|
||||
#endif // 0
|
||||
|
@ -683,7 +683,7 @@ TEST(providers, s3_provider) {
|
||||
{
|
||||
app_config src_cfg(
|
||||
provider_type::s3,
|
||||
utils::path::combine(test::get_test_input_dir(), {"storj"}));
|
||||
utils::path::combine(test::get_test_config_dir(), {"storj"}));
|
||||
cfg.set_s3_config(src_cfg.get_s3_config());
|
||||
}
|
||||
|
||||
@ -722,7 +722,7 @@ TEST(providers, sia_provider) {
|
||||
{
|
||||
app_config src_cfg(
|
||||
provider_type::sia,
|
||||
utils::path::combine(test::get_test_input_dir(), {"sia"}));
|
||||
utils::path::combine(test::get_test_config_dir(), {"sia"}));
|
||||
cfg.set_host_config(src_cfg.get_host_config());
|
||||
}
|
||||
|
||||
|
@ -436,15 +436,17 @@ static void set_basic_info_test(remote_client &client) {
|
||||
const auto change_time = last_write_time;
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS,
|
||||
client.winfsp_set_basic_info(file_desc, attributes, creation_time,
|
||||
last_access_time, last_write_time,
|
||||
change_time, &fi));
|
||||
EXPECT_EQ(static_cast<std::uint32_t>(attributes), fi.FileAttributes);
|
||||
EXPECT_EQ(creation_time, fi.CreationTime);
|
||||
EXPECT_EQ(last_access_time, fi.LastAccessTime);
|
||||
EXPECT_EQ(last_write_time, fi.LastWriteTime);
|
||||
EXPECT_EQ(change_time, fi.ChangeTime);
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_set_basic_info(
|
||||
file_desc, static_cast<UINT32>(attributes),
|
||||
static_cast<UINT64>(creation_time),
|
||||
static_cast<UINT64>(last_access_time),
|
||||
static_cast<UINT64>(last_write_time),
|
||||
static_cast<UINT64>(change_time), &fi));
|
||||
EXPECT_EQ(static_cast<UINT32>(attributes), fi.FileAttributes);
|
||||
EXPECT_EQ(static_cast<UINT64>(creation_time), fi.CreationTime);
|
||||
EXPECT_EQ(static_cast<UINT64>(last_access_time), fi.LastAccessTime);
|
||||
EXPECT_EQ(static_cast<UINT64>(last_write_time), fi.LastWriteTime);
|
||||
EXPECT_EQ(static_cast<UINT64>(change_time), fi.ChangeTime);
|
||||
|
||||
EXPECT_EQ(STATUS_SUCCESS, client.winfsp_close(file_desc));
|
||||
|
||||
|
225
repertory/repertory_test/src/winfsp_drive_test.cpp
Normal file
225
repertory/repertory_test/src/winfsp_drive_test.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
#if 0
|
||||
|
||||
#include "fixtures/winfsp_fixture.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TYPED_TEST_CASE(winfsp_test, winfsp_provider_types);
|
||||
|
||||
TYPED_TEST(winfsp_test, root_is_created) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA ad{};
|
||||
ASSERT_TRUE(::GetFileAttributesEx(this->mount_location.c_str(),
|
||||
GetFileExInfoStandard, &ad));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_DIRECTORY, ad.dwFileAttributes);
|
||||
EXPECT_EQ(0, ad.nFileSizeHigh);
|
||||
EXPECT_EQ(0, ad.nFileSizeLow);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_create_and_delete_directory) {
|
||||
std::string dir_name{"test_create_and_delete_dir"};
|
||||
auto dir_path = this->create_directory_and_test(dir_name);
|
||||
this->delete_directory_and_test(dir_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_create_and_delete_file) {
|
||||
std::string file_name{"test_create_and_delete_file"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
this->delete_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_write_to_and_read_from_file) {
|
||||
std::string file_name{"test_write_file"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string write_buffer{"0123456789"};
|
||||
{
|
||||
DWORD bytes_written{0};
|
||||
EXPECT_TRUE(::WriteFile(handle, write_buffer.c_str(),
|
||||
static_cast<DWORD>(write_buffer.size()),
|
||||
&bytes_written, nullptr));
|
||||
EXPECT_EQ(static_cast<DWORD>(write_buffer.size()), bytes_written);
|
||||
|
||||
auto opt_size = utils::file::file(file_path).size();
|
||||
EXPECT_TRUE(opt_size.has_value());
|
||||
EXPECT_EQ(write_buffer.size(), opt_size.value());
|
||||
}
|
||||
|
||||
{
|
||||
data_buffer read_buffer;
|
||||
read_buffer.resize(write_buffer.size());
|
||||
|
||||
DWORD bytes_read{0};
|
||||
EXPECT_EQ(0, ::SetFilePointer(handle, 0, nullptr, FILE_BEGIN));
|
||||
EXPECT_TRUE(::ReadFile(handle, read_buffer.data(),
|
||||
static_cast<DWORD>(read_buffer.size()), &bytes_read,
|
||||
nullptr));
|
||||
EXPECT_EQ(static_cast<DWORD>(write_buffer.size()), bytes_read);
|
||||
EXPECT_EQ(0,
|
||||
std::memcmp(write_buffer.data(), read_buffer.data(),
|
||||
std::min(read_buffer.size(), write_buffer.size())));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
this->delete_file_and_test(file_path);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_rename_file) {
|
||||
std::string file_name{"rename_file"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
auto api_path = utils::path::create_api_path(file_name);
|
||||
|
||||
api_meta_map meta1{};
|
||||
EXPECT_EQ(api_error::success, this->provider->get_item_meta(api_path, meta1));
|
||||
|
||||
auto file_path2 =
|
||||
utils::path::combine(this->mount_location, {file_name + "_2"});
|
||||
auto api_path2 = api_path + "_2";
|
||||
EXPECT_TRUE(::MoveFile(file_path.c_str(), file_path2.c_str()));
|
||||
|
||||
EXPECT_TRUE(utils::file::file(file_path2).exists());
|
||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||
|
||||
api_meta_map meta2{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
this->provider->get_item_meta(api_path2, meta2));
|
||||
EXPECT_STREQ(meta1[META_SOURCE].c_str(), meta2[META_SOURCE].c_str());
|
||||
|
||||
filesystem_item fsi{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
this->provider->get_filesystem_item(api_path2, false, fsi));
|
||||
EXPECT_STREQ(meta1[META_SOURCE].c_str(), fsi.source_path.c_str());
|
||||
|
||||
filesystem_item fsi2{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
this->provider->get_filesystem_item_from_source_path(
|
||||
fsi.source_path, fsi2));
|
||||
EXPECT_STREQ(api_path2.c_str(), fsi2.api_path.c_str());
|
||||
|
||||
EXPECT_EQ(api_error::item_not_found,
|
||||
this->provider->get_item_meta(api_path, meta2));
|
||||
|
||||
this->delete_file_and_test(file_path2);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_rename_directory) {
|
||||
std::string dir_name{"rename_dir"};
|
||||
auto dir_path = this->create_directory_and_test(dir_name);
|
||||
|
||||
auto dir_path2{dir_path + "_2"};
|
||||
|
||||
EXPECT_TRUE(::MoveFileA(dir_path.c_str(), dir_path2.c_str()));
|
||||
EXPECT_FALSE(::PathIsDirectoryA(dir_path.c_str()));
|
||||
EXPECT_TRUE(::PathIsDirectoryA(dir_path2.c_str()));
|
||||
|
||||
this->delete_directory_and_test(dir_path2);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_overwrite_file) {
|
||||
std::string file_name{"overwrite_file"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
auto file_path2{file_path + "_2"};
|
||||
EXPECT_TRUE(::CopyFile(file_path.c_str(), file_path2.c_str(), TRUE));
|
||||
EXPECT_TRUE(::CopyFile(file_path.c_str(), file_path2.c_str(), FALSE));
|
||||
EXPECT_FALSE(::CopyFile(file_path.c_str(), file_path2.c_str(), TRUE));
|
||||
|
||||
this->delete_file_and_test(file_path);
|
||||
this->delete_file_and_test(file_path2);
|
||||
}
|
||||
|
||||
TYPED_TEST(winfsp_test, can_get_and_set_basic_info_test) {
|
||||
std::string file_name{"overwrite_file"};
|
||||
auto file_path = this->create_file_and_test(file_name);
|
||||
|
||||
auto handle =
|
||||
::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
SYSTEMTIME st{};
|
||||
::GetSystemTime(&st);
|
||||
st.wMinute = 0;
|
||||
|
||||
FILETIME test_ch_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_ch_time);
|
||||
|
||||
FILETIME test_cr_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_cr_time);
|
||||
|
||||
FILETIME test_la_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_la_time);
|
||||
|
||||
FILETIME test_lw_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_lw_time);
|
||||
|
||||
FILE_BASIC_INFO fbi{};
|
||||
fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
|
||||
fbi.ChangeTime.HighPart = static_cast<LONG>(test_ch_time.dwHighDateTime);
|
||||
fbi.ChangeTime.LowPart = test_ch_time.dwLowDateTime;
|
||||
fbi.CreationTime = *reinterpret_cast<LARGE_INTEGER *>(&test_cr_time);
|
||||
fbi.LastAccessTime = *reinterpret_cast<LARGE_INTEGER *>(&test_la_time);
|
||||
fbi.LastWriteTime = *reinterpret_cast<LARGE_INTEGER *>(&test_lw_time);
|
||||
|
||||
EXPECT_TRUE(::SetFileInformationByHandle(handle, FileBasicInfo, &fbi,
|
||||
sizeof(FILE_BASIC_INFO)));
|
||||
|
||||
FILE_BASIC_INFO fbi2{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandleEx(handle, FileBasicInfo, &fbi2,
|
||||
sizeof(FILE_BASIC_INFO)));
|
||||
|
||||
EXPECT_EQ(0, memcmp(&fbi, &fbi2, sizeof(FILE_BASIC_INFO)));
|
||||
|
||||
std::cout << fbi.FileAttributes << " " << fbi.ChangeTime.QuadPart << " "
|
||||
<< fbi.CreationTime.QuadPart << " " << fbi.LastAccessTime.QuadPart
|
||||
<< " " << fbi.LastWriteTime.QuadPart << std::endl;
|
||||
std::cout << fbi2.FileAttributes << " " << fbi2.ChangeTime.QuadPart << " "
|
||||
<< fbi2.CreationTime.QuadPart << " " << fbi2.LastAccessTime.QuadPart
|
||||
<< " " << fbi2.LastWriteTime.QuadPart << std::endl;
|
||||
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
this->delete_file_and_test(file_path);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif // 0
|
||||
#endif // defined(_WIN32)
|
@ -1,385 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#if 0
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "fixtures/winfsp_fixture.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/event_capture.hpp"
|
||||
|
||||
namespace repertory {
|
||||
void launch_app(std::string cmd) {
|
||||
PROCESS_INFORMATION pi{};
|
||||
STARTUPINFO si{};
|
||||
si.cb = sizeof(si);
|
||||
|
||||
if (!::CreateProcessA(nullptr, (LPSTR)cmd.c_str(), nullptr, nullptr, FALSE,
|
||||
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, nullptr,
|
||||
nullptr, &si, &pi)) {
|
||||
throw std::runtime_error("CreateProcess failed (" +
|
||||
std::to_string(::GetLastError()) + ")");
|
||||
}
|
||||
|
||||
::WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
DWORD code{};
|
||||
::GetExitCodeProcess(pi.hProcess, &code);
|
||||
|
||||
::CloseHandle(pi.hProcess);
|
||||
::CloseHandle(pi.hThread);
|
||||
EXPECT_EQ(0, code);
|
||||
}
|
||||
|
||||
E_SIMPLE1(test_begin, info, false, std::string, test_name, TN, E_FROM_STRING);
|
||||
#define TEST_HEADER(func) \
|
||||
event_system::instance().raise<test_begin>( \
|
||||
std::string(func) + \
|
||||
"\r\n***********************\r\n***********************")
|
||||
|
||||
static auto mount_setup(std::string &mount_point) {
|
||||
mount_point = "U:";
|
||||
return std::vector<std::string>({"unittests", "-f", mount_point});
|
||||
}
|
||||
|
||||
static void execute_mount(winfsp_test *test,
|
||||
const std::vector<std::string> &drive_args,
|
||||
std::thread &th) {
|
||||
ASSERT_EQ(0, test->drive->mount(drive_args));
|
||||
th.join();
|
||||
}
|
||||
|
||||
static void unmount(winfsp_test *test, const std::string &mount_point) {
|
||||
test->drive->shutdown();
|
||||
auto mounted = utils::file::directory(mount_point).exists();
|
||||
for (auto i = 0; mounted && (i < 50); i++) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
mounted = utils::file::directory(mount_point).exists();
|
||||
}
|
||||
EXPECT_FALSE(utils::file::directory(mount_point).exists());
|
||||
}
|
||||
|
||||
static void root_creation_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
WIN32_FILE_ATTRIBUTE_DATA ad{};
|
||||
EXPECT_TRUE(
|
||||
::GetFileAttributesEx(mount_point.c_str(), GetFileExInfoStandard, &ad));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_DIRECTORY, ad.dwFileAttributes);
|
||||
EXPECT_EQ(0, ad.nFileSizeHigh);
|
||||
EXPECT_EQ(0, ad.nFileSizeLow);
|
||||
}
|
||||
|
||||
static auto create_test(winfsp_test *test, const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
auto file = utils::path::combine(mount_point, {{"test_create.txt"}});
|
||||
auto handle = ::CreateFileA(&file[0], GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
EXPECT_TRUE(utils::file::file(file).exists());
|
||||
|
||||
auto opt_size = utils::file::file(file).size();
|
||||
EXPECT_TRUE(opt_size.has_value());
|
||||
EXPECT_EQ(0, opt_size.value());
|
||||
|
||||
std::string attr;
|
||||
EXPECT_EQ(api_error::success, test->provider->get_item_meta(
|
||||
"/test_create.txt", META_ATTRIBUTES, attr));
|
||||
EXPECT_EQ(FILE_ATTRIBUTE_NORMAL, utils::string::to_uint32(attr));
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static void delete_file_test(const std::string &file) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
event_capture ec({"file_removed"});
|
||||
EXPECT_TRUE(utils::file::file(file).remove());
|
||||
EXPECT_FALSE(utils::file::file(file).exists());
|
||||
}
|
||||
|
||||
static void create_directory_test(const std::string &directory) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
EXPECT_FALSE(::PathIsDirectory(&directory[0]));
|
||||
EXPECT_TRUE(::CreateDirectoryA(&directory[0], nullptr));
|
||||
EXPECT_TRUE(::PathIsDirectory(&directory[0]));
|
||||
}
|
||||
|
||||
static void remove_directory_test(const std::string &directory) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
event_capture ec({"directory_removed"});
|
||||
EXPECT_TRUE(::PathIsDirectory(&directory[0]));
|
||||
EXPECT_TRUE(::RemoveDirectoryA(&directory[0]));
|
||||
EXPECT_FALSE(::PathIsDirectory(&directory[0]));
|
||||
}
|
||||
|
||||
static void write_file_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
const auto file = utils::path::combine(mount_point, {"test_write.txt"});
|
||||
auto handle =
|
||||
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
const std::string data = "0123456789";
|
||||
DWORD bytes_written = 0;
|
||||
EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
|
||||
&bytes_written, nullptr));
|
||||
EXPECT_EQ(10, bytes_written);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
EXPECT_TRUE(utils::file::file(file).exists());
|
||||
|
||||
auto opt_size = utils::file::file(file).size();
|
||||
EXPECT_TRUE(opt_size.has_value());
|
||||
EXPECT_EQ(10U, opt_size.value());
|
||||
}
|
||||
|
||||
static void read_file_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
const auto file = utils::path::combine(mount_point, {"test_read.txt"});
|
||||
auto handle =
|
||||
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
const std::string data = "0123456789";
|
||||
DWORD bytes_written = 0;
|
||||
EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
|
||||
&bytes_written, nullptr));
|
||||
EXPECT_EQ(10, bytes_written);
|
||||
|
||||
data_buffer data2;
|
||||
data2.resize(10);
|
||||
DWORD bytes_read = 0;
|
||||
EXPECT_EQ(0, ::SetFilePointer(handle, 0, nullptr, FILE_BEGIN));
|
||||
EXPECT_TRUE(::ReadFile(handle, &data2[0], static_cast<DWORD>(data2.size()),
|
||||
&bytes_read, nullptr));
|
||||
EXPECT_EQ(10, bytes_read);
|
||||
for (auto i = 0; i < data.size(); i++) {
|
||||
EXPECT_EQ(data[i], data2[i]);
|
||||
}
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
}
|
||||
|
||||
static void rename_file_test(winfsp_test *test,
|
||||
const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
const auto file = utils::path::combine(mount_point, {"rename_file.txt"});
|
||||
auto handle = ::CreateFileA(&file[0], GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
api_meta_map meta1{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
test->provider->get_item_meta("/rename_file.txt", meta1));
|
||||
|
||||
const auto file2 = utils::path::combine(mount_point, {"rename_file2.txt"});
|
||||
EXPECT_TRUE(::MoveFile(&file[0], &file2[0]));
|
||||
|
||||
EXPECT_TRUE(utils::file::file(file2).exists());
|
||||
EXPECT_FALSE(utils::file::file(file).exists());
|
||||
|
||||
api_meta_map meta2{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
test->provider->get_item_meta("/rename_file2.txt", meta2));
|
||||
EXPECT_STREQ(meta1[META_SOURCE].c_str(), meta2[META_SOURCE].c_str());
|
||||
|
||||
filesystem_item fsi{};
|
||||
EXPECT_EQ(api_error::success, test->provider->get_filesystem_item(
|
||||
"/rename_file2.txt", false, fsi));
|
||||
EXPECT_STREQ(meta1[META_SOURCE].c_str(), fsi.source_path.c_str());
|
||||
|
||||
filesystem_item fsi2{};
|
||||
EXPECT_EQ(api_error::success,
|
||||
test->provider->get_filesystem_item_from_source_path(
|
||||
fsi.source_path, fsi2));
|
||||
EXPECT_STREQ("/rename_file2.txt", fsi2.api_path.c_str());
|
||||
|
||||
EXPECT_EQ(api_error::item_not_found,
|
||||
test->provider->get_item_meta("/rename_file.txt", meta2));
|
||||
}
|
||||
|
||||
static void rename_directory_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
std::string directory = "rename_dir";
|
||||
const auto full_directory = utils::path::combine(mount_point, {directory});
|
||||
std::string directory2 = "rename_dir2";
|
||||
const auto full_directory2 = utils::path::combine(mount_point, {directory2});
|
||||
|
||||
EXPECT_FALSE(::PathIsDirectory(&full_directory[0]));
|
||||
EXPECT_TRUE(::CreateDirectoryA(&full_directory[0], nullptr));
|
||||
EXPECT_TRUE(::PathIsDirectory(&full_directory[0]));
|
||||
EXPECT_TRUE(::MoveFile(&full_directory[0], &full_directory2[0]));
|
||||
EXPECT_FALSE(::PathIsDirectory(&full_directory[0]));
|
||||
EXPECT_TRUE(::PathIsDirectory(&full_directory2[0]));
|
||||
}
|
||||
|
||||
static void get_set_basic_info_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
const auto file =
|
||||
utils::path::combine(mount_point, {"setbasicinfo_file.txt"});
|
||||
auto handle =
|
||||
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
|
||||
SYSTEMTIME st{};
|
||||
::GetSystemTime(&st);
|
||||
st.wMinute = 0;
|
||||
|
||||
FILETIME test_ch_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_ch_time);
|
||||
|
||||
FILETIME test_cr_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_cr_time);
|
||||
|
||||
FILETIME test_la_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_la_time);
|
||||
|
||||
FILETIME test_lw_time{};
|
||||
st.wMinute++;
|
||||
::SystemTimeToFileTime(&st, &test_lw_time);
|
||||
|
||||
FILE_BASIC_INFO fbi{};
|
||||
fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
|
||||
fbi.ChangeTime.HighPart = test_ch_time.dwHighDateTime;
|
||||
fbi.ChangeTime.LowPart = test_ch_time.dwLowDateTime;
|
||||
fbi.CreationTime = *(LARGE_INTEGER *)&test_cr_time;
|
||||
fbi.LastAccessTime = *(LARGE_INTEGER *)&test_la_time;
|
||||
fbi.LastWriteTime = *(LARGE_INTEGER *)&test_lw_time;
|
||||
|
||||
EXPECT_TRUE(::SetFileInformationByHandle(handle, FileBasicInfo, &fbi,
|
||||
sizeof(FILE_BASIC_INFO)));
|
||||
|
||||
FILE_BASIC_INFO fbi2{};
|
||||
EXPECT_TRUE(::GetFileInformationByHandleEx(handle, FileBasicInfo, &fbi2,
|
||||
sizeof(FILE_BASIC_INFO)));
|
||||
|
||||
EXPECT_EQ(0, memcmp(&fbi, &fbi2, sizeof(FILE_BASIC_INFO)));
|
||||
|
||||
std::cout << fbi.FileAttributes << " " << fbi.ChangeTime.QuadPart << " "
|
||||
<< fbi.CreationTime.QuadPart << " " << fbi.LastAccessTime.QuadPart
|
||||
<< " " << fbi.LastWriteTime.QuadPart << std::endl;
|
||||
std::cout << fbi2.FileAttributes << " " << fbi2.ChangeTime.QuadPart << " "
|
||||
<< fbi2.CreationTime.QuadPart << " " << fbi2.LastAccessTime.QuadPart
|
||||
<< " " << fbi2.LastWriteTime.QuadPart << std::endl;
|
||||
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
}
|
||||
|
||||
static void overwrite_file_test(const std::string &mount_point) {
|
||||
TEST_HEADER(__FUNCTION__);
|
||||
|
||||
const auto file = utils::path::combine("./", {"test_overwrite.txt"});
|
||||
auto handle =
|
||||
::CreateFileA(&file[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
EXPECT_NE(INVALID_HANDLE_VALUE, handle);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
const std::string data = "0123456789";
|
||||
DWORD bytes_written = 0;
|
||||
EXPECT_TRUE(::WriteFile(handle, &data[0], static_cast<DWORD>(data.size()),
|
||||
&bytes_written, nullptr));
|
||||
EXPECT_EQ(10, bytes_written);
|
||||
EXPECT_TRUE(::CloseHandle(handle));
|
||||
|
||||
if (bytes_written == 10) {
|
||||
const auto file2 =
|
||||
utils::path::combine(mount_point, {"test_overwrite2.txt"});
|
||||
EXPECT_TRUE(::CopyFile(&file[0], &file2[0], TRUE));
|
||||
|
||||
EXPECT_FALSE(::CopyFile(&file[0], &file2[0], TRUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(winfsp_test, all_tests) {
|
||||
if (PROVIDER_INDEX == 0) {
|
||||
for (std::size_t idx = 0U; idx < 2U; idx++) {
|
||||
launch_app(
|
||||
("cmd.exe /c unittests.exe --gtest_filter=winfsp_test.all_tests "
|
||||
"--provider_index " +
|
||||
std::to_string(idx) + " > unittests" + std::to_string(idx) +
|
||||
".log 2>&1"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (PROVIDER_INDEX == 1U) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string mount_point;
|
||||
const auto drive_args = mount_setup(mount_point);
|
||||
|
||||
event_capture ec({
|
||||
"drive_mounted",
|
||||
"drive_unmounted",
|
||||
"drive_unmount_pending",
|
||||
"drive_mount_result",
|
||||
});
|
||||
|
||||
std::thread th([&] {
|
||||
const auto mounted = ec.wait_for_event("drive_mounted");
|
||||
EXPECT_TRUE(mounted);
|
||||
if (mounted) {
|
||||
root_creation_test(mount_point);
|
||||
{
|
||||
const auto file = create_test(this, mount_point);
|
||||
delete_file_test(file);
|
||||
}
|
||||
{
|
||||
const auto dir = utils::path::combine(mount_point, {"TestDir"});
|
||||
create_directory_test(dir);
|
||||
remove_directory_test(dir);
|
||||
}
|
||||
write_file_test(mount_point);
|
||||
read_file_test(mount_point);
|
||||
// TODO enable after rename support is available
|
||||
// rename_file_test(this, mount_point);
|
||||
// rename_directory_test(mount_point);
|
||||
overwrite_file_test(mount_point);
|
||||
get_set_basic_info_test(mount_point);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
unmount(this, mount_point);
|
||||
ec.wait_for_empty();
|
||||
}
|
||||
});
|
||||
|
||||
execute_mount(this, drive_args, th);
|
||||
}
|
||||
} // namespace repertory
|
||||
|
||||
#endif // defined(_WIN32)
|
||||
#endif // 0
|
@ -1 +1 @@
|
||||
test
|
||||
test
|
@ -1 +1 @@
|
||||
moose
|
||||
moose
|
@ -66,8 +66,6 @@ struct db_context_t {
|
||||
|
||||
sqlite3 *db3{};
|
||||
std::string table_name;
|
||||
|
||||
db3_stmt_t stmt;
|
||||
};
|
||||
|
||||
class db_column final {
|
||||
@ -178,13 +176,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ctx_t> struct db_result final {
|
||||
db_result(std::shared_ptr<ctx_t> ctx, std::int32_t res)
|
||||
: ctx_(std::move(ctx)), res_(res) {
|
||||
if (res == SQLITE_OK) {
|
||||
set_res(sqlite3_step(ctx_->stmt.get()));
|
||||
}
|
||||
}
|
||||
struct db_result final {
|
||||
struct context final {
|
||||
db3_stmt_t stmt;
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
|
||||
db_result(sqlite3_stmt *stmt, std::int32_t res);
|
||||
|
||||
db_result() = default;
|
||||
db_result(const db_result &) = default;
|
||||
@ -193,52 +192,25 @@ template <typename ctx_t> struct db_result final {
|
||||
auto operator=(const db_result &) -> db_result & = default;
|
||||
auto operator=(db_result &&) -> db_result & = default;
|
||||
|
||||
~db_result() {
|
||||
if (ctx_) {
|
||||
ctx_->clear();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ctx_t> ctx_;
|
||||
std::shared_ptr<context> ctx_;
|
||||
mutable std::int32_t res_{};
|
||||
|
||||
private:
|
||||
void set_res(std::int32_t res) const { res_ = res; }
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto ok() const -> bool {
|
||||
return res_ == SQLITE_DONE || res_ == SQLITE_ROW;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_error() const -> std::int32_t { return res_; }
|
||||
|
||||
[[nodiscard]] auto get_error_str() const -> std::string {
|
||||
auto &&err_msg = sqlite3_errstr(res_);
|
||||
return err_msg == nullptr ? std::to_string(res_) : err_msg;
|
||||
}
|
||||
[[nodiscard]] auto get_error_str() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto get_row(std::optional<db_row<ctx_t>> &row) const -> bool {
|
||||
row.reset();
|
||||
[[nodiscard]] auto get_row(std::optional<row> &opt_row) const -> bool;
|
||||
|
||||
if (not has_row()) {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] auto has_row() const -> bool;
|
||||
|
||||
row = db_row{ctx_};
|
||||
set_res(sqlite3_step(ctx_->stmt.get()));
|
||||
return true;
|
||||
}
|
||||
void next_row() const;
|
||||
|
||||
[[nodiscard]] auto has_row() const -> bool { return res_ == SQLITE_ROW; }
|
||||
|
||||
void next_row() const {
|
||||
if (not has_row()) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_res(sqlite3_step(ctx_->stmt.get()));
|
||||
}
|
||||
[[nodiscard]] auto ok() const -> bool;
|
||||
};
|
||||
} // namespace repertory::utils::db::sqlite
|
||||
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
};
|
||||
|
||||
context(sqlite3 *db3_, std::string table_name_)
|
||||
@ -46,8 +46,6 @@ public:
|
||||
using wd_t = where_data_t<w_t>;
|
||||
|
||||
std::unique_ptr<wd_t> where_data;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
@ -64,10 +62,10 @@ private:
|
||||
public:
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
|
||||
[[nodiscard]] auto
|
||||
group(context::w_t::group_func_t func) -> context::w_t::wn_t;
|
||||
[[nodiscard]] auto group(context::w_t::group_func_t func)
|
||||
-> context::w_t::wn_t;
|
||||
|
||||
[[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t;
|
||||
};
|
||||
|
@ -34,8 +34,6 @@ public:
|
||||
|
||||
bool or_replace{false};
|
||||
std::map<std::string, db_types_t> values;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
@ -55,12 +53,14 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto column_value(std::string column_name,
|
||||
db_types_t value) -> db_insert &;
|
||||
[[nodiscard]] auto column_value(std::string column_name, db_types_t value)
|
||||
|
||||
|
||||
-> db_insert &;
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
};
|
||||
} // namespace repertory::utils::db::sqlite
|
||||
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
|
||||
[[nodiscard]] auto group_by(std::string column_name) -> db_select_op_t;
|
||||
|
||||
@ -44,8 +44,10 @@ public:
|
||||
|
||||
[[nodiscard]] auto offset(std::int32_t value) -> db_select_op_t;
|
||||
|
||||
[[nodiscard]] auto order_by(std::string column_name,
|
||||
bool ascending) -> db_select_op_t;
|
||||
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
|
||||
|
||||
|
||||
-> db_select_op_t;
|
||||
};
|
||||
|
||||
context(sqlite3 *db3_, std::string table_name_)
|
||||
@ -63,12 +65,8 @@ public:
|
||||
std::optional<std::pair<std::string, bool>> order_by;
|
||||
|
||||
std::unique_ptr<wd_t> where_data;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
|
||||
public:
|
||||
db_select(sqlite3 &db3, std::string table_name)
|
||||
: ctx_(std::make_shared<context>(&db3, table_name)) {}
|
||||
@ -81,24 +79,30 @@ private:
|
||||
public:
|
||||
[[nodiscard]] auto column(std::string column_name) -> db_select &;
|
||||
|
||||
[[nodiscard]] auto count(std::string column_name,
|
||||
std::string as_column_name) -> db_select &;
|
||||
[[nodiscard]] auto count(std::string column_name, std::string as_column_name)
|
||||
|
||||
|
||||
-> db_select &;
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
|
||||
[[nodiscard]] auto group_by(std::string column_name) -> db_select &;
|
||||
|
||||
[[nodiscard]] auto
|
||||
group(context::w_t::group_func_t func) -> context::w_t::wn_t;
|
||||
[[nodiscard]] auto group(context::w_t::group_func_t func)
|
||||
|
||||
|
||||
-> context::w_t::wn_t;
|
||||
|
||||
[[nodiscard]] auto limit(std::int32_t value) -> db_select &;
|
||||
|
||||
[[nodiscard]] auto offset(std::int32_t value) -> db_select &;
|
||||
|
||||
[[nodiscard]] auto order_by(std::string column_name,
|
||||
bool ascending) -> db_select &;
|
||||
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
|
||||
|
||||
|
||||
-> db_select &;
|
||||
|
||||
[[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t;
|
||||
};
|
||||
|
@ -39,12 +39,14 @@ public:
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
|
||||
[[nodiscard]] auto limit(std::int32_t value) -> db_update_op_t;
|
||||
|
||||
[[nodiscard]] auto order_by(std::string column_name,
|
||||
bool ascending) -> db_update_op_t;
|
||||
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
|
||||
|
||||
|
||||
-> db_update_op_t;
|
||||
};
|
||||
|
||||
using w_t = db_where_t<context, db_update_op_t>;
|
||||
@ -55,8 +57,7 @@ public:
|
||||
std::optional<std::pair<std::string, bool>> order_by;
|
||||
|
||||
std::unique_ptr<wd_t> where_data;
|
||||
|
||||
void clear();
|
||||
clear();
|
||||
};
|
||||
|
||||
using row = db_row<context>;
|
||||
@ -71,20 +72,26 @@ private:
|
||||
std::shared_ptr<context> ctx_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto column_value(std::string column_name,
|
||||
db_types_t value) -> db_update &;
|
||||
[[nodiscard]] auto column_value(std::string column_name, db_types_t value)
|
||||
|
||||
|
||||
-> db_update &;
|
||||
|
||||
[[nodiscard]] auto dump() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto go() const -> db_result<context>;
|
||||
[[nodiscard]] auto go() const -> db_result;
|
||||
|
||||
[[nodiscard]] auto
|
||||
group(context::w_t::group_func_t func) -> context::w_t::wn_t;
|
||||
[[nodiscard]] auto group(context::w_t::group_func_t func)
|
||||
|
||||
|
||||
-> context::w_t::wn_t;
|
||||
|
||||
[[nodiscard]] auto limit(std::int32_t value) -> db_update &;
|
||||
|
||||
[[nodiscard]] auto order_by(std::string column_name,
|
||||
bool ascending) -> db_update &;
|
||||
[[nodiscard]] auto order_by(std::string column_name, bool ascending)
|
||||
|
||||
|
||||
-> db_update &;
|
||||
|
||||
[[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t;
|
||||
};
|
||||
|
@ -76,6 +76,49 @@ auto db_column::get_value_as_json() const -> nlohmann::json {
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_JSON)
|
||||
|
||||
db_result::db_result(sqlite3_stmt *stmt, std::int32_t res)
|
||||
: ctx_(std::make_shared<context>()), res_(res) {
|
||||
ctx_->stmt = db3_stmt_t{
|
||||
stmt,
|
||||
sqlite3_statement_deleter(),
|
||||
};
|
||||
|
||||
if (res == SQLITE_OK) {
|
||||
set_res(sqlite3_step(ctx_->stmt.get()));
|
||||
}
|
||||
}
|
||||
|
||||
auto db_result::get_error_str() const -> std::string {
|
||||
auto &&err_msg = sqlite3_errstr(res_);
|
||||
return err_msg == nullptr ? std::to_string(res_) : err_msg;
|
||||
}
|
||||
|
||||
auto db_result::get_row(std::optional<row> &opt_row) const -> bool {
|
||||
opt_row.reset();
|
||||
|
||||
if (not has_row()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
opt_row = db_row<context>{ctx_};
|
||||
set_res(sqlite3_step(ctx_->stmt.get()));
|
||||
return true;
|
||||
}
|
||||
|
||||
auto db_result::has_row() const -> bool { return res_ == SQLITE_ROW; }
|
||||
|
||||
void db_result::next_row() const {
|
||||
if (not has_row()) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_res(sqlite3_step(ctx_->stmt.get()));
|
||||
}
|
||||
|
||||
auto db_result::ok() const -> bool {
|
||||
return res_ == SQLITE_DONE || res_ == SQLITE_ROW;
|
||||
}
|
||||
|
||||
auto create_db(std::string db_path,
|
||||
const std::map<std::string, std::string> &sql_create_tables)
|
||||
-> db3_t {
|
||||
@ -115,8 +158,8 @@ auto create_db(std::string db_path,
|
||||
return db3;
|
||||
}
|
||||
|
||||
auto execute_sql(sqlite3 &db3, const std::string &sql,
|
||||
std::string &err) -> bool {
|
||||
auto execute_sql(sqlite3 &db3, const std::string &sql, std::string &err)
|
||||
-> bool {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
char *err_msg{nullptr};
|
||||
|
@ -24,13 +24,11 @@
|
||||
#include "utils/db/sqlite/db_delete.hpp"
|
||||
|
||||
namespace repertory::utils::db::sqlite {
|
||||
void db_delete::context::clear() { where_data.reset(); }
|
||||
|
||||
auto db_delete::context::db_delete_op_t::dump() const -> std::string {
|
||||
return db_delete{ctx}.dump();
|
||||
}
|
||||
|
||||
auto db_delete::context::db_delete_op_t::go() const -> db_result<context> {
|
||||
auto db_delete::context::db_delete_op_t::go() const -> db_result {
|
||||
return db_delete{ctx}.go();
|
||||
}
|
||||
|
||||
@ -48,22 +46,18 @@ auto db_delete::dump() const -> std::string {
|
||||
return query.str();
|
||||
}
|
||||
|
||||
auto db_delete::go() const -> db_result<context> {
|
||||
auto db_delete::go() const -> db_result {
|
||||
sqlite3_stmt *stmt_ptr{nullptr};
|
||||
auto query_str = dump();
|
||||
auto res =
|
||||
sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr);
|
||||
ctx_->stmt = db3_stmt_t{
|
||||
stmt_ptr,
|
||||
sqlite3_statement_deleter(),
|
||||
};
|
||||
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
if (not ctx_->where_data) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
@ -71,21 +65,21 @@ auto db_delete::go() const -> db_result<context> {
|
||||
idx++) {
|
||||
res = std::visit(
|
||||
overloaded{
|
||||
[this, &idx](std::int64_t data) -> std::int32_t {
|
||||
return sqlite3_bind_int64(ctx_->stmt.get(), idx + 1, data);
|
||||
[&stmt_ptr, &idx](std::int64_t data) -> std::int32_t {
|
||||
return sqlite3_bind_int64(stmt_ptr, idx + 1, data);
|
||||
},
|
||||
[this, &idx](const std::string &data) -> std::int32_t {
|
||||
return sqlite3_bind_text(ctx_->stmt.get(), idx + 1, data.c_str(),
|
||||
-1, nullptr);
|
||||
[&stmt_ptr, &idx](const std::string &data) -> std::int32_t {
|
||||
return sqlite3_bind_text(stmt_ptr, idx + 1, data.c_str(), -1,
|
||||
nullptr);
|
||||
},
|
||||
},
|
||||
ctx_->where_data->values.at(static_cast<std::size_t>(idx)));
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
}
|
||||
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
auto db_delete::group(context::w_t::group_func_t func) -> context::w_t::wn_t {
|
||||
|
@ -24,10 +24,8 @@
|
||||
#include "utils/db/sqlite/db_insert.hpp"
|
||||
|
||||
namespace repertory::utils::db::sqlite {
|
||||
void db_insert::context::clear() { values.clear(); }
|
||||
|
||||
auto db_insert::column_value(std::string column_name,
|
||||
db_types_t value) -> db_insert & {
|
||||
auto db_insert::column_value(std::string column_name, db_types_t value)
|
||||
-> db_insert & {
|
||||
ctx_->values[column_name] = value;
|
||||
return *this;
|
||||
}
|
||||
@ -61,18 +59,14 @@ auto db_insert::dump() const -> std::string {
|
||||
return query.str();
|
||||
}
|
||||
|
||||
auto db_insert::go() const -> db_result<context> {
|
||||
auto db_insert::go() const -> db_result {
|
||||
sqlite3_stmt *stmt_ptr{nullptr};
|
||||
auto query_str = dump();
|
||||
auto res =
|
||||
sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr);
|
||||
ctx_->stmt = db3_stmt_t{
|
||||
stmt_ptr,
|
||||
sqlite3_statement_deleter(),
|
||||
};
|
||||
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
@ -89,11 +83,11 @@ auto db_insert::go() const -> db_result<context> {
|
||||
},
|
||||
std::next(ctx_->values.begin(), idx)->second);
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
}
|
||||
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
} // namespace repertory::utils::db::sqlite
|
||||
|
||||
|
@ -24,21 +24,11 @@
|
||||
#include "utils/db/sqlite/db_select.hpp"
|
||||
|
||||
namespace repertory::utils::db::sqlite {
|
||||
void db_select::context::clear() {
|
||||
columns.clear();
|
||||
count_columns.clear();
|
||||
group_by.clear();
|
||||
limit.reset();
|
||||
offset.reset();
|
||||
order_by.reset();
|
||||
where_data.reset();
|
||||
}
|
||||
|
||||
auto db_select::context::db_select_op_t::dump() const -> std::string {
|
||||
return db_select{ctx}.dump();
|
||||
}
|
||||
|
||||
auto db_select::context::db_select_op_t::go() const -> db_result<context> {
|
||||
auto db_select::context::db_select_op_t::go() const -> db_result {
|
||||
return db_select{ctx}.go();
|
||||
}
|
||||
|
||||
@ -72,8 +62,8 @@ auto db_select::column(std::string column_name) -> db_select & {
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::count(std::string column_name,
|
||||
std::string as_column_name) -> db_select & {
|
||||
auto db_select::count(std::string column_name, std::string as_column_name)
|
||||
-> db_select & {
|
||||
ctx_->count_columns[column_name] = as_column_name;
|
||||
return *this;
|
||||
}
|
||||
@ -142,22 +132,18 @@ auto db_select::dump() const -> std::string {
|
||||
return query.str();
|
||||
}
|
||||
|
||||
auto db_select::go() const -> db_result<context> {
|
||||
auto db_select::go() const -> db_result {
|
||||
sqlite3_stmt *stmt_ptr{nullptr};
|
||||
auto query_str = dump();
|
||||
auto res =
|
||||
sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr);
|
||||
ctx_->stmt = db3_stmt_t{
|
||||
stmt_ptr,
|
||||
sqlite3_statement_deleter(),
|
||||
};
|
||||
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
if (not ctx_->where_data) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
@ -175,11 +161,11 @@ auto db_select::go() const -> db_result<context> {
|
||||
},
|
||||
ctx_->where_data->values.at(static_cast<std::size_t>(idx)));
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
}
|
||||
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
auto db_select::group(context::w_t::group_func_t func) -> context::w_t::wn_t {
|
||||
@ -209,8 +195,8 @@ auto db_select::offset(std::int32_t value) -> db_select & {
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_select::order_by(std::string column_name,
|
||||
bool ascending) -> db_select & {
|
||||
auto db_select::order_by(std::string column_name, bool ascending)
|
||||
-> db_select & {
|
||||
ctx_->order_by = {column_name, ascending};
|
||||
return *this;
|
||||
}
|
||||
|
@ -24,18 +24,11 @@
|
||||
#include "utils/db/sqlite/db_update.hpp"
|
||||
|
||||
namespace repertory::utils::db::sqlite {
|
||||
void db_update::context::clear() {
|
||||
column_values.clear();
|
||||
limit.reset();
|
||||
order_by.reset();
|
||||
where_data.reset();
|
||||
}
|
||||
|
||||
auto db_update::context::db_update_op_t::dump() const -> std::string {
|
||||
return db_update{ctx}.dump();
|
||||
}
|
||||
|
||||
auto db_update::context::db_update_op_t::go() const -> db_result<context> {
|
||||
auto db_update::context::db_update_op_t::go() const -> db_result {
|
||||
return db_update{ctx}.go();
|
||||
}
|
||||
|
||||
@ -52,8 +45,8 @@ auto db_update::context::db_update_op_t::order_by(std::string column_name,
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_update::column_value(std::string column_name,
|
||||
db_types_t value) -> db_update & {
|
||||
auto db_update::column_value(std::string column_name, db_types_t value)
|
||||
-> db_update & {
|
||||
ctx_->column_values[column_name] = value;
|
||||
return *this;
|
||||
}
|
||||
@ -91,18 +84,15 @@ auto db_update::dump() const -> std::string {
|
||||
return query.str();
|
||||
}
|
||||
|
||||
auto db_update::go() const -> db_result<context> {
|
||||
auto db_update::go() const -> db_result {
|
||||
sqlite3_stmt *stmt_ptr{nullptr};
|
||||
|
||||
auto query_str = dump();
|
||||
auto res =
|
||||
sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr);
|
||||
ctx_->stmt = db3_stmt_t{
|
||||
stmt_ptr,
|
||||
sqlite3_statement_deleter(),
|
||||
};
|
||||
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
@ -119,12 +109,12 @@ auto db_update::go() const -> db_result<context> {
|
||||
},
|
||||
std::next(ctx_->column_values.begin(), idx)->second);
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
}
|
||||
|
||||
if (not ctx_->where_data) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
for (std::int32_t idx = 0;
|
||||
@ -149,11 +139,11 @@ auto db_update::go() const -> db_result<context> {
|
||||
},
|
||||
ctx_->where_data->values.at(static_cast<std::size_t>(idx)));
|
||||
if (res != SQLITE_OK) {
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
}
|
||||
|
||||
return {ctx_, res};
|
||||
return {stmt_ptr, res};
|
||||
}
|
||||
|
||||
auto db_update::group(context::w_t::group_func_t func) -> context::w_t::wn_t {
|
||||
@ -173,8 +163,8 @@ auto db_update::limit(std::int32_t value) -> db_update & {
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto db_update::order_by(std::string column_name,
|
||||
bool ascending) -> db_update & {
|
||||
auto db_update::order_by(std::string column_name, bool ascending)
|
||||
-> db_update & {
|
||||
ctx_->order_by = {column_name, ascending};
|
||||
return *this;
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ using namespace ::testing;
|
||||
#include "utils/all.hpp"
|
||||
|
||||
namespace repertory::test {
|
||||
[[nodiscard]] auto
|
||||
create_random_file(std::size_t size) -> utils::file::i_file &;
|
||||
[[nodiscard]] auto create_random_file(std::size_t size)
|
||||
-> utils::file::i_file &;
|
||||
|
||||
[[nodiscard]] auto
|
||||
generate_test_file_name(std::string_view file_name_no_extension) -> std::string;
|
||||
@ -53,6 +53,8 @@ static void decrypt_and_verify(const buffer_t &buffer, std::string_view token,
|
||||
|
||||
auto generate_test_directory() -> utils::file::i_directory &;
|
||||
|
||||
[[nodiscard]] auto get_test_config_dir() -> std::string;
|
||||
|
||||
[[nodiscard]] auto get_test_input_dir() -> std::string;
|
||||
|
||||
[[nodiscard]] auto get_test_output_dir() -> std::string;
|
||||
|
@ -110,10 +110,19 @@ auto generate_test_file_name(std::string_view file_name_no_extension)
|
||||
return generated_files.back()->get_path();
|
||||
}
|
||||
|
||||
auto get_test_config_dir() -> std::string {
|
||||
static auto test_path = ([]() -> std::string {
|
||||
auto dir = utils::get_environment_variable("PROJECT_TEST_CONFIG_DIR");
|
||||
return utils::path::combine(dir.empty() ? "." : dir, {"test_config"});
|
||||
})();
|
||||
|
||||
return test_path;
|
||||
}
|
||||
|
||||
auto get_test_input_dir() -> std::string {
|
||||
static auto test_path = ([]() -> std::string {
|
||||
auto dir = utils::get_environment_variable("PROJECT_TEST_DIR");
|
||||
return utils::path::combine(dir.empty() ? "." : dir, {"test_config"});
|
||||
auto dir = utils::get_environment_variable("PROJECT_TEST_INPUT_DIR");
|
||||
return utils::path::combine(dir.empty() ? "." : dir, {"test_input"});
|
||||
})();
|
||||
|
||||
return test_path;
|
||||
|
@ -89,7 +89,7 @@ static void common_select(sqlite3 &db3, std::string value1, std::string value2,
|
||||
|
||||
std::size_t row_count{};
|
||||
while (res.has_row()) {
|
||||
std::optional<utils::db::sqlite::db_select::row> row;
|
||||
std::optional<utils::db::sqlite::db_result::row> row;
|
||||
EXPECT_TRUE(res.get_row(row));
|
||||
EXPECT_TRUE(row.has_value());
|
||||
if (row.has_value()) {
|
||||
|
Reference in New Issue
Block a user