initial commit
Some checks failed
BlockStorage/repertory_osx/pipeline/head There was a failure building this commit
BlockStorage/repertory_windows/pipeline/head This commit looks good
BlockStorage/repertory_linux_builds/pipeline/head This commit looks good

This commit is contained in:
2022-03-05 00:30:50 -06:00
commit 3ff46723b8
626 changed files with 178600 additions and 0 deletions

View File

@ -0,0 +1,110 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drives/directory_cache.hpp"
#include "drives/directory_iterator.hpp"
#include "events/events.hpp"
#include "events/event_system.hpp"
#include "types/repertory.hpp"
namespace repertory {
bool directory_cache::execute_action(const std::string &api_path, const execute_callback &execute) {
auto found = false;
recur_mutex_lock directory_lock(directory_mutex_);
if ((found = (directory_lookup_.find(api_path) != directory_lookup_.end()))) {
execute(*directory_lookup_[api_path].iterator);
}
return found;
}
void directory_cache::refresh_thread() {
while (not is_shutdown_) {
unique_recur_mutex_lock directory_lock(directory_mutex_);
auto lookup = directory_lookup_;
directory_lock.unlock();
for (const auto &kv : lookup) {
if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() -
kv.second.last_update) >= 120s) {
directory_lock.lock();
directory_lookup_.erase(kv.first);
directory_lock.unlock();
}
}
if (not is_shutdown_) {
unique_mutex_lock shutdown_lock(shutdown_mutex_);
if (not is_shutdown_) {
shutdown_notify_.wait_for(shutdown_lock, 15s);
}
}
}
}
directory_iterator *directory_cache::remove_directory(const std::string &api_path) {
directory_iterator *ret = nullptr;
recur_mutex_lock directory_lock(directory_mutex_);
if (directory_lookup_.find(api_path) != directory_lookup_.end()) {
ret = directory_lookup_[api_path].iterator;
directory_lookup_.erase(api_path);
}
return ret;
}
void directory_cache::remove_directory(directory_iterator *iterator) {
if (iterator) {
recur_mutex_lock directory_lock(directory_mutex_);
const auto it = std::find_if(
directory_lookup_.begin(), directory_lookup_.end(),
[&iterator](const auto &kv) -> bool { return kv.second.iterator == iterator; });
if (it != directory_lookup_.end()) {
directory_lookup_.erase(it->first);
}
}
}
void directory_cache::set_directory(const std::string &api_path, directory_iterator *iterator) {
recur_mutex_lock directory_lock(directory_mutex_);
directory_lookup_[api_path] = {iterator};
}
void directory_cache::start() {
unique_mutex_lock shutdown_lock(shutdown_mutex_);
if (is_shutdown_) {
is_shutdown_ = false;
refresh_thread_ = std::make_unique<std::thread>([this]() { this->refresh_thread(); });
}
}
void directory_cache::stop() {
unique_mutex_lock shutdown_lock(shutdown_mutex_);
if (not is_shutdown_) {
event_system::instance().raise<service_shutdown>("directory_cache");
is_shutdown_ = true;
shutdown_notify_.notify_all();
shutdown_lock.unlock();
refresh_thread_->join();
refresh_thread_.reset();
}
}
} // namespace repertory

View File

@ -0,0 +1,129 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drives/directory_iterator.hpp"
#include "utils/path_utils.hpp"
namespace repertory {
#ifndef _WIN32
int directory_iterator::fill_buffer(const remote::file_offset &offset,
fuse_fill_dir_t filler_function, void *buffer,
populate_stat_callback populate_stat) {
if (offset < items_.size()) {
std::string item_name;
struct stat st {};
struct stat *pst = nullptr;
switch (offset) {
case 0: {
item_name = ".";
} break;
case 1: {
item_name = "..";
} break;
default: {
const auto &item = items_[offset];
item_name = utils::path::strip_to_file_name(item.api_path);
populate_stat(item.api_path, item.size, item.meta, item.directory, &st);
pst = &st;
} break;
}
if (filler_function(buffer, &item_name[0], pst, offset + 1) != 0) {
errno = ENOMEM;
return -1;
}
return 0;
}
errno = 120;
return -1;
}
#endif // !_WIN32
int directory_iterator::get(const std::size_t &offset, std::string &item) {
if (offset < items_.size()) {
item = items_[offset].api_path;
return 0;
}
errno = 120;
return -1;
}
api_error directory_iterator::get_directory_item(const std::size_t &offset, directory_item &di) {
if (offset < items_.size()) {
di = items_[offset];
return api_error::success;
}
return api_error::directory_end_of_files;
}
api_error directory_iterator::get_directory_item(const std::string &api_path, directory_item &di) {
auto iter = std::find_if(items_.begin(), items_.end(),
[&](const auto &item) -> bool { return api_path == item.api_path; });
if (iter != items_.end()) {
di = *iter;
return api_error::success;
}
return api_error::item_not_found;
}
int directory_iterator::get_json(const std::size_t &offset, json &item) {
if (offset < items_.size()) {
item = items_[offset].to_json();
return 0;
}
errno = 120;
return -1;
}
std::size_t directory_iterator::get_next_directory_offset(const std::string &api_path) const {
const auto it = std::find_if(items_.begin(), items_.end(), [&api_path](const auto &di) -> bool {
return api_path == di.api_path;
});
return (it == items_.end()) ? 0 : std::distance(items_.begin(), it) + std::size_t(1u);
}
directory_iterator &directory_iterator::operator=(const directory_iterator &iterator) noexcept {
if (this != &iterator) {
items_ = iterator.items_;
}
return *this;
}
directory_iterator &directory_iterator::operator=(directory_iterator &&iterator) noexcept {
if (this != &iterator) {
items_ = std::move(iterator.items_);
}
return *this;
}
directory_iterator &directory_iterator::operator=(directory_item_list list) noexcept {
if (&items_ != &list) {
items_ = std::move(list);
}
return *this;
}
} // namespace repertory

145
src/drives/eviction.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drives/eviction.hpp"
#include "app_config.hpp"
#include "drives/i_open_file_table.hpp"
#include "providers/i_provider.hpp"
#include "types/repertory.hpp"
#include "utils/file_utils.hpp"
#include "utils/global_data.hpp"
namespace repertory {
void eviction::check_items_thread() {
while (not stop_requested_) {
auto should_evict = true;
// Handle maximum cache size eviction
auto used_bytes = global_data::instance().get_used_cache_space();
if (config_.get_enable_max_cache_size()) {
should_evict = (used_bytes > config_.get_max_cache_size_bytes());
}
// Evict all items if minimum redundancy eviction is enabled; otherwise, evict
// until required space is reclaimed.
if (should_evict) {
// Remove cached source files that don't meet minimum requirements
auto cached_files_list = get_filtered_cached_files();
if (not cached_files_list.empty()) {
while (not stop_requested_ && should_evict && not cached_files_list.empty()) {
std::string api_path;
if (provider_.get_api_path_from_source(cached_files_list.front(), api_path) ==
api_error::success) {
std::string pinned;
provider_.get_item_meta(api_path, META_PINNED, pinned);
api_file file{};
filesystem_item fsi{};
if ((pinned.empty() || not utils::string::to_bool(pinned)) &&
provider_.get_filesystem_item_and_file(api_path, file, fsi) == api_error::success) {
// Only evict files that match expected size
std::uint64_t file_size = 0u;
utils::file::get_file_size(cached_files_list.front(), file_size);
if (file_size == fsi.size) {
// Ensure minimum file redundancy has been met or source path is not being
// used for local recovery
const auto different_source = file.source_path != fsi.source_path;
if (file.recoverable &&
((file.redundancy >= config_.get_minimum_redundancy()) || different_source)) {
// Try to evict file
if (oft_.evict_file(fsi.api_path) && config_.get_enable_max_cache_size()) {
// Restrict number of items evicted if maximum cache size is enabled
used_bytes -= file_size;
should_evict = (used_bytes > config_.get_max_cache_size_bytes());
}
}
}
}
}
cached_files_list.pop_front();
}
}
}
if (not stop_requested_) {
unique_mutex_lock l(eviction_mutex_);
if (not stop_requested_) {
stop_notify_.wait_for(l, 30s);
}
}
}
}
bool eviction::check_minimum_requirements(const std::string &file_path) {
auto ret = false;
// Only evict cachedFileList that are > 0
std::uint64_t file_size = 0u;
utils::file::get_file_size(file_path, file_size);
if (file_size) {
// Check modified/accessed date/time
std::uint64_t reference_time = 0u;
if ((ret = config_.get_eviction_uses_accessed_time()
? utils::file::get_accessed_time(file_path, reference_time)
: utils::file::get_modified_time(file_path, reference_time))) {
#ifdef _WIN32
const auto now = std::chrono::system_clock::now();
const auto delay = std::chrono::minutes(config_.get_eviction_delay_mins());
ret = ((std::chrono::system_clock::from_time_t(reference_time) + delay) <= now);
#else
const auto now = utils::get_time_now();
const auto delay = (config_.get_eviction_delay_mins() * 60L) * NANOS_PER_SECOND;
ret = ((reference_time + delay) <= now);
#endif
}
}
return ret;
}
std::deque<std::string> eviction::get_filtered_cached_files() {
auto list = utils::file::get_directory_files(config_.get_cache_directory(), true);
list.erase(std::remove_if(list.begin(), list.end(),
[this](const std::string &path) -> bool {
return not this->check_minimum_requirements(path);
}),
list.end());
return list;
}
void eviction::start() {
mutex_lock l(start_stop_mutex_);
if (not eviction_thread_) {
stop_requested_ = false;
eviction_thread_ = std::make_unique<std::thread>([this] { this->check_items_thread(); });
}
}
void eviction::stop() {
mutex_lock l(start_stop_mutex_);
if (eviction_thread_) {
event_system::instance().raise<service_shutdown>("eviction");
stop_requested_ = true;
{
mutex_lock l2(eviction_mutex_);
stop_notify_.notify_all();
}
eviction_thread_->join();
eviction_thread_.reset();
}
}
} // namespace repertory

View File

@ -0,0 +1,844 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _WIN32
#include "drives/fuse/fuse_base.hpp"
#include "app_config.hpp"
#include "drives/fuse/events.hpp"
#include "events/events.hpp"
#include "events/event_system.hpp"
#include "providers/i_provider.hpp"
#include "utils/path_utils.hpp"
#include "utils/string_utils.hpp"
#include "utils/utils.hpp"
namespace repertory {
fuse_base &fuse_base::instance() {
return *reinterpret_cast<fuse_base *>(fuse_get_context()->private_data);
}
fuse_base::fuse_base(app_config &config) : config_(config) {
#ifdef __APPLE__
fuse_ops_.chflags = fuse_base::chflags_;
fuse_ops_.fsetattr_x = fuse_base::fsetattr_x_;
fuse_ops_.getxtimes = fuse_base::getxtimes_;
fuse_ops_.setattr_x = fuse_base::setattr_x_;
fuse_ops_.setbkuptime = fuse_base::setbkuptime_;
fuse_ops_.setchgtime = fuse_base::setchgtime_;
fuse_ops_.setcrtime = fuse_base::setcrtime_;
fuse_ops_.setvolname = fuse_base::setvolname_;
fuse_ops_.statfs_x = fuse_base::statfs_x_;
#endif // __APPLE__
E_SUBSCRIBE_EXACT(unmount_requested, [this](const unmount_requested &) {
std::thread([this]() { this->shutdown(); }).detach();
});
}
fuse_base::~fuse_base() { E_CONSUMER_RELEASE(); }
int fuse_base::access_(const char *path, int mask) {
return instance().instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().access_impl(api_path, mask);
});
}
#ifdef __APPLE__
int fuse_base::chflags_(const char *path, uint32_t flags) {
return instance().instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().chflags_impl(api_path, flags);
});
}
#endif // __APPLE__
api_error fuse_base::check_access(const std::string &api_path, int mask) const {
api_meta_map meta;
const auto res = get_item_meta(api_path, meta);
if (res != api_error::success) {
return res;
}
// Always allow root
if (fuse_get_context()->uid != 0) {
// Always allow forced user
if (not forced_uid_.has_value() || (fuse_get_context()->uid != get_effective_uid())) {
// Always allow if checking file exists
if (F_OK != mask) {
const auto effective_uid =
(forced_uid_.has_value() ? forced_uid_.value() : get_uid_from_meta(meta));
const auto effective_gid =
(forced_gid_.has_value() ? forced_gid_.value() : get_gid_from_meta(meta));
// Create file mode
mode_t effective_mode = forced_umask_.has_value()
? ((S_IRWXU | S_IRWXG | S_IRWXO) & (~forced_umask_.value()))
: get_mode_from_meta(meta);
// Create access mask
mode_t active_mask = S_IRWXO;
if (fuse_get_context()->uid == effective_uid) {
active_mask |= S_IRWXU;
}
if (fuse_get_context()->gid == effective_gid) {
active_mask |= S_IRWXG;
}
if (utils::is_uid_member_of_group(fuse_get_context()->uid, effective_gid)) {
active_mask |= S_IRWXG;
}
// Calculate effective file mode
effective_mode &= active_mask;
// Check allow execute
if ((mask & X_OK) == X_OK) {
if ((effective_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) {
return api_error::permission_denied;
}
}
// Check allow write
if ((mask & W_OK) == W_OK) {
if ((effective_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) {
return api_error::access_denied;
}
}
// Check allow read
if ((mask & R_OK) == R_OK) {
if ((effective_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
return api_error::access_denied;
}
}
if (effective_mode == 0) {
// Deny access if effective mode is 0
return api_error::access_denied;
}
}
}
}
return api_error::success;
}
api_error fuse_base::check_and_perform(const std::string &api_path, int parent_mask,
const std::function<api_error(api_meta_map &meta)> &action) {
api_meta_map meta;
auto ret = get_item_meta(api_path, meta);
if (ret != api_error::success) {
return ret;
}
if ((ret = check_parent_access(api_path, parent_mask)) != api_error::success) {
return ret;
}
if ((ret = check_owner(meta)) != api_error::success) {
return ret;
}
return action(meta);
}
api_error fuse_base::check_open_flags(const int &flags, const int &mask,
const api_error &fail_error) {
return ((flags & mask) ? fail_error : api_error::success);
}
api_error fuse_base::check_owner(const api_meta_map &meta) const {
// Always allow root
if ((fuse_get_context()->uid != 0) &&
// Always allow forced UID
(not forced_uid_.has_value() || (fuse_get_context()->uid != get_effective_uid())) &&
// Check if current uid matches file uid
(get_uid_from_meta(meta) != get_effective_uid())) {
return api_error::permission_denied;
}
return api_error::success;
}
api_error fuse_base::check_parent_access(const std::string &api_path, int mask) const {
auto ret = api_error::success;
// Ignore root
if (api_path != "/") {
if ((mask & X_OK) == X_OK) {
for (auto parent = utils::path::get_parent_directory(api_path);
(ret == api_error::success) && not parent.empty();
parent = utils::path::get_parent_directory(parent)) {
if (((ret = check_access(parent, X_OK)) == api_error::success) && (parent == "/")) {
break;
}
}
}
if (ret == api_error::success) {
mask &= (~X_OK);
if (mask != 0) {
ret = check_access(utils::path::get_parent_directory(api_path), mask);
}
}
}
return ret;
}
api_error fuse_base::check_readable(const int &flags, const api_error &fail_error) {
const auto mode = (flags & O_ACCMODE);
return ((mode == O_WRONLY) ? fail_error : api_error::success);
}
api_error fuse_base::check_writeable(const int &flags, const api_error &fail_error) {
return ((flags & O_ACCMODE) ? api_error::success : fail_error);
}
int fuse_base::chmod_(const char *path, mode_t mode) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().chmod_impl(api_path, mode);
});
}
int fuse_base::chown_(const char *path, uid_t uid, gid_t gid) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().chown_impl(api_path, uid, gid);
});
}
int fuse_base::create_(const char *path, mode_t mode, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().create_impl(api_path, mode, fi);
});
}
void fuse_base::destroy_(void *ptr) {
execute_void_callback(__FUNCTION__, [&]() { instance().destroy_impl(ptr); });
}
void fuse_base::display_options(int argc, char *argv[]) {
struct fuse_operations fuse_ops {};
fuse_main(argc, argv, &fuse_ops, nullptr);
std::cout << std::endl;
}
void fuse_base::display_version_information(int argc, char *argv[]) {
struct fuse_operations fuse_ops {};
fuse_main(argc, argv, &fuse_ops, nullptr);
}
int fuse_base::execute_callback(const std::string &function_name, const char *from, const char *to,
const std::function<api_error(const std::string &from_api_file,
const std::string &to_api_path)> &cb,
const bool &disable_logging) {
const auto from_api_file = utils::path::create_api_path(from ? from : "");
const auto to_api_file = utils::path::create_api_path(to ? to : "");
const auto res = utils::translate_api_error(cb(from_api_file, to_api_file));
raise_fuse_event(function_name, "from|" + from_api_file + "|to|" + to_api_file, res,
disable_logging);
return res;
}
int fuse_base::execute_callback(const std::string &function_name, const char *path,
const std::function<api_error(const std::string &api_path)> &cb,
const bool &disable_logging) {
const auto api_path = utils::path::create_api_path(path ? path : "");
const auto res = utils::translate_api_error(cb(api_path));
raise_fuse_event(function_name, api_path, res, disable_logging);
return res;
}
void fuse_base::execute_void_callback(const std::string &function_name,
const std::function<void()> &cb) {
cb();
instance().raise_fuse_event(function_name, "", 0, false);
}
void *fuse_base::execute_void_pointer_callback(const std::string &function_name,
const std::function<void *()> &cb) {
auto *ret = cb();
instance().raise_fuse_event(function_name, "", 0, false);
return ret;
}
int fuse_base::fallocate_(const char *path, int mode, off_t offset, off_t length,
struct fuse_file_info *fi) {
return instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().fallocate_impl(api_path, mode, offset, length, fi);
});
}
int fuse_base::fgetattr_(const char *path, struct stat *st, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().fgetattr_impl(api_path, st, fi);
});
}
#ifdef __APPLE__
int fuse_base::fsetattr_x_(const char *path, struct setattr_x *attr, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().fsetattr_x_impl(api_path, attr, fi);
});
}
#endif // __APPLE__
int fuse_base::fsync_(const char *path, int datasync, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().fsync_impl(api_path, datasync, fi);
});
}
int fuse_base::ftruncate_(const char *path, off_t size, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().ftruncate_impl(api_path, size, fi);
});
}
uid_t fuse_base::get_effective_uid() const {
return forced_uid_.has_value() ? forced_uid_.value() : fuse_get_context()->uid;
}
uid_t fuse_base::get_effective_gid() const {
return forced_gid_.has_value() ? forced_gid_.value() : fuse_get_context()->gid;
}
#ifdef __APPLE__
__uint32_t fuse_base::get_flags_from_meta(const api_meta_map &meta) {
return utils::string::to_uint32(meta.at(META_OSXFLAGS));
}
#endif // __APPLE__
gid_t fuse_base::get_gid_from_meta(const api_meta_map &meta) {
return static_cast<gid_t>(utils::string::to_uint32(meta.at(META_GID)));
}
mode_t fuse_base::get_mode_from_meta(const api_meta_map &meta) {
return static_cast<mode_t>(utils::string::to_uint32(meta.at(META_MODE)));
}
void fuse_base::get_timespec_from_meta(const api_meta_map &meta, const std::string &name,
struct timespec &ts) {
const auto t = utils::string::to_uint64(meta.at(name));
ts.tv_nsec = t % NANOS_PER_SECOND;
ts.tv_sec = t / NANOS_PER_SECOND;
}
uid_t fuse_base::get_uid_from_meta(const api_meta_map &meta) {
return static_cast<uid_t>(utils::string::to_uint32(meta.at(META_UID)));
}
int fuse_base::getattr_(const char *path, struct stat *st) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().getattr_impl(api_path, st);
});
}
#ifdef __APPLE__
int fuse_base::getxtimes_(const char *path, struct timespec *bkuptime, struct timespec *crtime) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().getxtimes_impl(api_path, bkuptime, crtime);
});
}
#endif // __APPLE__
void *fuse_base::init_(struct fuse_conn_info *conn) {
return execute_void_pointer_callback(__FUNCTION__,
[&]() -> void * { return instance().init_impl(conn); });
}
void *fuse_base::init_impl(struct fuse_conn_info *conn) {
#ifdef __APPLE__
conn->want |= FUSE_CAP_VOL_RENAME;
conn->want |= FUSE_CAP_XTIMES;
#endif // __APPLE__
conn->want |= FUSE_CAP_BIG_WRITES;
return this;
}
int fuse_base::mkdir_(const char *path, mode_t mode) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().mkdir_impl(api_path, mode);
});
}
int fuse_base::mount(std::vector<std::string> args) {
auto ret = parse_args(args);
if (ret == 0) {
std::vector<const char *> fuse_argv(args.size());
for (std::size_t i = 0u; i < args.size(); i++) {
fuse_argv[i] = args[i].c_str();
}
{
struct fuse_args fa =
FUSE_ARGS_INIT(static_cast<int>(fuse_argv.size()), (char **)&fuse_argv[0]);
char *mount_location = nullptr;
fuse_parse_cmdline(&fa, &mount_location, nullptr, nullptr);
if (mount_location) {
mount_location_ = mount_location;
free(mount_location);
}
}
notify_fuse_args_parsed(args);
umask(0);
ret = fuse_main(static_cast<int>(fuse_argv.size()), (char **)&fuse_argv[0], &fuse_ops_, this);
notify_fuse_main_exit(ret);
}
return ret;
}
int fuse_base::open_(const char *path, struct fuse_file_info *fi) {
return instance().execute_callback(
__FUNCTION__, path,
[&](const std::string &api_path) -> api_error { return instance().open_impl(api_path, fi); });
}
int fuse_base::opendir_(const char *path, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().opendir_impl(api_path, fi);
});
}
int fuse_base::read_(const char *path, char *buffer, size_t read_size, off_t read_offset,
struct fuse_file_info *fi) {
std::size_t bytes_read{};
const auto res = instance().execute_callback(
__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().read_impl(api_path, buffer, read_size, read_offset, fi, bytes_read);
},
true);
return (res == 0) ? static_cast<int>(bytes_read) : res;
}
int fuse_base::readdir_(const char *path, void *buf, fuse_fill_dir_t fuse_fill_dir, off_t offset,
struct fuse_file_info *fi) {
return instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().readdir_impl(api_path, buf, fuse_fill_dir, offset, fi);
});
}
int fuse_base::release_(const char *path, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().release_impl(api_path, fi);
});
}
int fuse_base::releasedir_(const char *path, struct fuse_file_info *fi) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().releasedir_impl(api_path, fi);
});
}
int fuse_base::rename_(const char *from, const char *to) {
return instance().execute_callback(
__FUNCTION__, from, to,
[&](const std::string &from_api_file, const std::string &to_api_path) -> api_error {
return instance().rename_impl(from_api_file, to_api_path);
});
}
int fuse_base::rmdir_(const char *path) {
return instance().execute_callback(
__FUNCTION__, path,
[&](const std::string &api_path) -> api_error { return instance().rmdir_impl(api_path); });
}
#ifdef HAS_SETXATTR
#ifdef __APPLE__
int fuse_base::getxattr_(const char *path, const char *name, char *value, size_t size,
uint32_t position) {
int attribute_size = 0;
const auto res = instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().getxattr_impl(api_path, name, value, size, position, attribute_size);
});
return res == 0 ? attribute_size : res;
}
#else // __APPLE__
int fuse_base::getxattr_(const char *path, const char *name, char *value, size_t size) {
int attribute_size = 0;
const auto res = instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().getxattr_impl(api_path, name, value, size, attribute_size);
});
return res == 0 ? attribute_size : res;
}
#endif // __APPLE__
int fuse_base::listxattr_(const char *path, char *buffer, size_t size) {
int required_size = 0;
bool return_size = false;
const auto res = instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().listxattr_impl(api_path, buffer, size, required_size, return_size);
});
return return_size ? required_size : res;
}
int fuse_base::parse_args(std::vector<std::string> &args) {
auto force_no_console = false;
for (std::size_t i = 1; !force_no_console && (i < args.size()); i++) {
if (args[i] == "-nc") {
force_no_console = true;
}
}
utils::remove_element_from(args, "-nc");
for (std::size_t i = 1; i < args.size(); i++) {
if (args[i] == "-f") {
console_enabled_ = not force_no_console;
} else if (args[i].find("-o") == 0) {
std::string options = "";
if (args[i].size() == 2) {
if ((i + 1) < args.size()) {
options = args[++i];
}
} else {
options = args[i].substr(2);
}
const auto option_parts = utils::string::split(options, ',');
for (const auto &option : option_parts) {
if (option.find("gid") == 0) {
const auto parts = utils::string::split(option, '=');
if (parts.size() == 2) {
auto gid = getgrnam(parts[1].c_str());
if (not gid) {
gid = getgrgid(utils::string::to_uint32(parts[1]));
}
if ((getgid() != 0) && (gid->gr_gid == 0)) {
std::cerr << "'gid=0' requires running as root" << std::endl;
return -1;
} else {
forced_gid_ = gid->gr_gid;
}
}
} else if (option.find("noatime") == 0) {
atime_enabled_ = false;
} else if (option.find("uid") == 0) {
const auto parts = utils::string::split(option, '=');
if (parts.size() == 2) {
auto uid = getpwnam(parts[1].c_str());
if (not uid) {
uid = getpwuid(utils::string::to_uint32(parts[1]));
}
if ((getuid() != 0) && (uid->pw_uid == 0)) {
std::cerr << "'uid=0' requires running as root" << std::endl;
return -1;
} else {
forced_uid_ = uid->pw_uid;
}
}
} else if (option.find("umask") == 0) {
const auto parts = utils::string::split(option, '=');
if (parts.size() == 2) {
static const auto match_number_regex = std::regex("[0-9]+");
try {
if (not std::regex_match(parts[1], match_number_regex)) {
throw std::runtime_error("invalid syntax");
} else {
forced_umask_ = utils::string::to_uint32(parts[1]);
}
} catch (...) {
std::cerr << ("'" + option + "' invalid syntax") << std::endl;
return -1;
}
}
}
}
}
}
return 0;
}
#ifdef __APPLE__
api_error fuse_base::parse_xattr_parameters(const char *name, const uint32_t &position,
std::string &attribute_name,
const std::string &api_path) {
#else
api_error fuse_base::parse_xattr_parameters(const char *name, std::string &attribute_name,
const std::string &api_path) {
#endif
auto res = api_path.empty() ? api_error::bad_address : api_error::success;
if (res != api_error::success) {
return res;
}
if (not name) {
return api_error::bad_address;
}
attribute_name = std::string(name);
#ifdef __APPLE__
if (attribute_name == A_KAUTH_FILESEC_XATTR) {
char new_name[MAXPATHLEN] = {0};
memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR));
memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1);
attribute_name = new_name;
} else if (attribute_name.empty() ||
((attribute_name != XATTR_RESOURCEFORK_NAME) && (position != 0))) {
return api_error::xattr_osx_invalid;
}
#endif
return api_error::success;
}
#ifdef __APPLE__
api_error fuse_base::parse_xattr_parameters(const char *name, const char *value, size_t size,
const uint32_t &position, std::string &attribute_name,
const std::string &api_path) {
auto res = parse_xattr_parameters(name, position, attribute_name, api_path);
#else
api_error fuse_base::parse_xattr_parameters(const char *name, const char *value, size_t size,
std::string &attribute_name,
const std::string &api_path) {
auto res = parse_xattr_parameters(name, attribute_name, api_path);
#endif
if (res != api_error::success) {
return res;
}
return (value ? api_error::success : (size ? api_error::bad_address : api_error::success));
}
void fuse_base::populate_stat(const std::string &api_path, const std::uint64_t &size_or_count,
const api_meta_map &meta, const bool &directory, i_provider &provider,
struct stat *st) {
memset(st, 0, sizeof(struct stat));
st->st_nlink =
(directory ? 2 + (size_or_count ? size_or_count : provider.get_directory_item_count(api_path))
: 1);
if (directory) {
st->st_blocks = 0;
} else {
st->st_size = size_or_count;
static const auto blockSizeStat = static_cast<std::uint64_t>(512u);
static const auto blockSize = static_cast<std::uint64_t>(4096u);
const auto size =
utils::divide_with_ceiling(static_cast<std::uint64_t>(st->st_size), blockSize) * blockSize;
st->st_blocks =
std::max(blockSize / blockSizeStat, utils::divide_with_ceiling(size, blockSizeStat));
}
st->st_gid = get_gid_from_meta(meta);
st->st_mode = (directory ? S_IFDIR : S_IFREG) | get_mode_from_meta(meta);
st->st_uid = get_uid_from_meta(meta);
#ifdef __APPLE__
st->st_blksize = 0;
st->st_flags = get_flags_from_meta(meta);
set_timespec_from_meta(meta, META_MODIFIED, st->st_mtimespec);
set_timespec_from_meta(meta, META_CREATION, st->st_birthtimespec);
set_timespec_from_meta(meta, META_CHANGED, st->st_ctimespec);
set_timespec_from_meta(meta, META_ACCESSED, st->st_atimespec);
#else // __APPLE__
st->st_blksize = 4096;
set_timespec_from_meta(meta, META_MODIFIED, st->st_mtim);
set_timespec_from_meta(meta, META_CREATION, st->st_ctim);
set_timespec_from_meta(meta, META_ACCESSED, st->st_atim);
#endif // __APPLE__
}
void fuse_base::raise_fuse_event(std::string function_name, const std::string &api_path,
const int &ret, const bool &disable_logging) {
if ((ret >= 0) && disable_logging) {
return;
}
if (not config_.get_enable_drive_events()) {
return;
}
if (((config_.get_event_level() >= fuse_event::level) && (ret != 0)) ||
(config_.get_event_level() >= event_level::verbose)) {
event_system::instance().raise<fuse_event>(utils::string::right_trim(function_name, '_'),
api_path, ret);
}
}
int fuse_base::removexattr_(const char *path, const char *name) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().removexattr_impl(api_path, name);
});
}
void fuse_base::set_timespec_from_meta(const api_meta_map &meta, const std::string &name,
struct timespec &ts) {
const auto t = utils::string::to_uint64(meta.at(name));
ts.tv_nsec = t % NANOS_PER_SECOND;
ts.tv_sec = t / NANOS_PER_SECOND;
}
#ifdef __APPLE__
int fuse_base::setxattr_(const char *path, const char *name, const char *value, size_t size,
int flags, uint32_t position) {
const auto res = instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().setxattr_impl(api_path, name, value, size, flags, position);
});
if (res != 0) {
errno = std::abs(res);
}
return res;
}
#else // __APPLE__
int fuse_base::setxattr_(const char *path, const char *name, const char *value, size_t size,
int flags) {
const auto res = instance().execute_callback(
__FUNCTION__, path, [&](const std::string &api_path) -> api_error {
return instance().setxattr_impl(api_path, name, value, size, flags);
});
if (res != 0) {
errno = std::abs(res);
}
return res;
}
#endif // __APPLE__
#endif // HAS_SETXATTR
int fuse_base::shutdown() {
#if __APPLE__
const auto unmount = "umount \"" + mount_location_ + "\" >/dev/null 2>&1";
#else
const auto unmount = "fusermount -u \"" + mount_location_ + "\" >/dev/null 2>&1";
#endif
return system(unmount.c_str());
}
#ifdef __APPLE__
int fuse_base::setattr_x_(const char *path, struct setattr_x *attr) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().setattr_x_impl(api_path, attr);
});
}
int fuse_base::setbkuptime_(const char *path, const struct timespec *bkuptime) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().setbkuptime_impl(api_path, bkuptime);
});
}
int fuse_base::setchgtime_(const char *path, const struct timespec *chgtime) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().setchgtime_impl(api_path, chgtime);
});
}
int fuse_base::setcrtime_(const char *path, const struct timespec *crtime) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().setcrtime_impl(api_path, crtime);
});
}
int fuse_base::setvolname_(const char *volname) {
return instance().execute_callback(__FUNCTION__, volname,
[&](const std::string &api_path) -> api_error {
return instance().setvolname_impl(volname);
});
}
int fuse_base::statfs_x_(const char *path, struct statfs *stbuf) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().statfs_x_impl(api_path, stbuf);
});
}
#else // __APPLE__
int fuse_base::statfs_(const char *path, struct statvfs *stbuf) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().statfs_impl(api_path, stbuf);
});
}
#endif // __APPLE__
int fuse_base::truncate_(const char *path, off_t size) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().truncate_impl(api_path, size);
});
}
int fuse_base::unlink_(const char *path) {
return instance().execute_callback(
__FUNCTION__, path,
[&](const std::string &api_path) -> api_error { return instance().unlink_impl(api_path); });
}
int fuse_base::utimens_(const char *path, const struct timespec tv[2]) {
return instance().execute_callback(__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().utimens_impl(api_path, tv);
});
}
int fuse_base::write_(const char *path, const char *buffer, size_t write_size, off_t write_offset,
struct fuse_file_info *fi) {
std::size_t bytes_written{};
const auto res = instance().execute_callback(
__FUNCTION__, path,
[&](const std::string &api_path) -> api_error {
return instance().write_impl(api_path, buffer, write_size, write_offset, fi, bytes_written);
},
true);
return (res == 0) ? static_cast<int>(bytes_written) : res;
}
} // namespace repertory
#endif // _WIN32

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,716 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drives/fuse/remotefuse/remote_client.hpp"
#include "comm/packet/packet.hpp"
#include "app_config.hpp"
#include "events/events.hpp"
#include "utils/path_utils.hpp"
namespace repertory::remote_fuse {
// clang-format off
E_SIMPLE3(remote_fuse_client_event, debug, true,
std::string, function, func, E_STRING,
std::string, api_path, ap, E_STRING,
int, result, res, E_FROM_INT32
);
// clang-format on
#define RAISE_REMOTE_CLIENT_FUSE_EVENT(func, file, ret) \
if (config_.get_enable_drive_events() && \
(((config_.get_event_level() >= remote_fuse_client_event::level) && (ret != 0)) || \
(config_.get_event_level() >= event_level::verbose))) \
event_system::instance().raise<remote_fuse_client_event>(func, file, ret)
remote_client::remote_client(const app_config &config)
: config_(config),
packet_client_(config.get_remote_host_name_or_ip(), config.get_remote_max_connections(),
config.get_remote_port(), config.get_remote_receive_timeout_secs(),
config.get_remote_send_timeout_secs(), config.get_remote_token()) {}
packet::error_type remote_client::fuse_access(const char *path, const std::int32_t &mask) {
packet request;
request.encode(path);
request.encode(mask);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_chflags(const char *path, const std::uint32_t &flags) {
packet request;
request.encode(path);
request.encode(flags);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_chmod(const char *path, const remote::file_mode &mode) {
packet request;
request.encode(path);
request.encode(mode);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_chown(const char *path, const remote::user_id &uid,
const remote::group_id &gid) {
packet request;
request.encode(path);
request.encode(uid);
request.encode(gid);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_destroy() {
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, "", ret);
return ret;
}
/*packet::error_type remote_client::fuse_fallocate(const char *path, const std::int32_t &mode,
const remote::file_offset &offset,
const remote::file_offset &length,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(mode);
request.encode(offset);
request.encode(length);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packetClient_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}*/
packet::error_type remote_client::fuse_fgetattr(const char *path, remote::stat &st, bool &directory,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(handle);
request.encode(uid_);
request.encode(gid_);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
if ((ret = response.decode(st)) == 0) {
std::uint8_t d = 0;
if ((ret = response.decode(d)) == 0) {
directory = static_cast<bool>(d);
}
}
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_fsetattr_x(const char *path, const remote::setattr_x &attr,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(attr);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_fsync(const char *path, const std::int32_t &datasync,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(datasync);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_ftruncate(const char *path, const remote::file_offset &size,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(size);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_getattr(const char *path, remote::stat &st,
bool &directory) {
packet request;
request.encode(path);
request.encode(uid_);
request.encode(gid_);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
if ((ret = response.decode(st)) == 0) {
std::uint8_t d = 0;
if ((ret = response.decode(d)) == 0) {
directory = static_cast<bool>(d);
}
}
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
/*packet::error_type remote_client::fuse_getxattr(const char *path, const char *name, char
*value, const remote::file_size &size) { packet::error_type ret = 0; if (size >
std::numeric_limits<std::size_t>::max()) { ret = -ERANGE; } else { packet request;
request.encode(path);
request.encode(name);
request.encode(size);
packet response;
std::uint32_t service_flags = 0;
if ((ret = packetClient_.send(__FUNCTION__, request, response, service_flags)) == 0) {
remote::file_size size2;
if ((ret = response.decode(size2)) == 0) {
if (size2 > std::numeric_limits<std::size_t>::max()) {
ret = -ERANGE;
} else {
memcpy(value, response.CurrentPointer(), static_cast<std::size_t>(size2));
}
}
}
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_getxattr_osx(const char *path, const char *name, char
*value, const remote::file_size &size, const std::uint32_t &position) { packet::error_type ret
= 0; if (size > std::numeric_limits<std::size_t>::max()) { ret = -ERANGE; } else { packet request;
request.encode(path);
request.encode(name);
request.encode(size);
request.encode(position);
packet response;
std::uint32_t service_flags = 0;
if ((ret = packetClient_.send(__FUNCTION__, request, response, service_flags)) == 0) {
remote::file_size size2;
if ((ret = response.decode(size2)) == 0) {
if (size2 > std::numeric_limits<std::size_t>::max()) {
ret = -ERANGE;
} else {
memcpy(value, response.CurrentPointer(), static_cast<std::size_t>(size2));
}
}
}
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}*/
packet::error_type remote_client::fuse_getxtimes(const char *path, remote::file_time &bkuptime,
remote::file_time &crtime) {
packet request;
request.encode(path);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
response.decode(bkuptime);
response.decode(crtime);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_init() {
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, "", ret);
return ret;
}
/*packet::error_type remote_client::fuse_listxattr(const char *path, char *buffer,
const remote::file_size &size) {
packet::error_type ret = 0;
if (size > std::numeric_limits<std::size_t>::max()) {
ret = -ERANGE;
} else {
packet request;
request.encode(path);
request.encode(size);
packet response;
std::uint32_t service_flags = 0;
if ((ret = packetClient_.send(__FUNCTION__, request, response, service_flags)) == 0) {
remote::file_size size2;
if ((ret = response.decode(size2)) == 0) {
if (size2 > std::numeric_limits<std::size_t>::max()) {
ret = -ERANGE;
} else {
memcpy(buffer, response.CurrentPointer(), static_cast<std::size_t>(size2));
}
}
}
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}*/
packet::error_type remote_client::fuse_mkdir(const char *path, const remote::file_mode &mode) {
packet request;
request.encode(path);
request.encode(mode);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_opendir(const char *path, remote::file_handle &handle) {
packet request;
request.encode(path);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = response.decode(handle);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_create(const char *path, const remote::file_mode &mode,
const remote::open_flags &flags,
remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(mode);
request.encode(flags);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = response.decode(handle);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_open(const char *path, const remote::open_flags &flags,
remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(flags);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = response.decode(handle);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_read(const char *path, char *buffer,
const remote::file_size &read_size,
const remote::file_offset &read_offset,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(read_size);
request.encode(read_offset);
request.encode(handle);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret > 0) {
memcpy(buffer, response.current_pointer(), ret);
}
if (ret < 0) {
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
}
return ret;
}
packet::error_type remote_client::fuse_rename(const char *from, const char *to) {
packet request;
request.encode(from);
request.encode(to);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(
__FUNCTION__, utils::path::create_api_path(from) + "|" + utils::path::create_api_path(to),
ret);
return ret;
}
packet::error_type remote_client::fuse_write(const char *path, const char *buffer,
const remote::file_size &write_size,
const remote::file_offset &write_offset,
const remote::file_handle &handle) {
packet::error_type ret = 0;
if (write_size > std::numeric_limits<std::size_t>::max()) {
ret = -ERANGE;
} else {
packet request;
request.encode(path);
request.encode(write_size);
request.encode(buffer, static_cast<std::size_t>(write_size));
request.encode(write_offset);
request.encode(handle);
std::uint32_t service_flags = 0;
ret = packet_client_.send(__FUNCTION__, request, service_flags);
}
if (ret < 0) {
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
}
return ret;
}
packet::error_type remote_client::fuse_write_base64(const char *path, const char *buffer,
const remote::file_size &write_size,
const remote::file_offset &write_offset,
const remote::file_handle &handle) {
packet::error_type ret = 0;
if (write_size > std::numeric_limits<std::size_t>::max()) {
ret = -ERANGE;
} else {
packet request;
request.encode(path);
request.encode(write_size);
request.encode(buffer, static_cast<std::size_t>(write_size));
request.encode(write_offset);
request.encode(handle);
std::uint32_t service_flags = 0;
ret = packet_client_.send(__FUNCTION__, request, service_flags);
}
if (ret < 0) {
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
}
return ret;
}
packet::error_type remote_client::fuse_readdir(const char *path, const remote::file_offset &offset,
const remote::file_handle &handle,
std::string &item_path) {
packet request;
request.encode(path);
request.encode(offset);
request.encode(handle);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
DECODE_OR_IGNORE(&response, item_path);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path),
ret == -120 ? 0 : ret);
return ret;
}
packet::error_type remote_client::fuse_release(const char *path,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_releasedir(const char *path,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
/*packet::error_type remote_client::fuse_removexattr(const char *path, const char *name)
override { packet request; request.encode(path); request.Encode(name);
std::uint32_t service_flags = 0;
const auto ret = packetClient_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}*/
packet::error_type remote_client::fuse_rmdir(const char *path) {
packet request;
request.encode(path);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_setattr_x(const char *path, remote::setattr_x &attr) {
packet request;
request.encode(path);
request.encode(attr);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_setbkuptime(const char *path,
const remote::file_time &bkuptime) {
packet request;
request.encode(path);
request.encode(bkuptime);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_setchgtime(const char *path,
const remote::file_time &chgtime) {
packet request;
request.encode(path);
request.encode(chgtime);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_setcrtime(const char *path,
const remote::file_time &crtime) {
packet request;
request.encode(path);
request.encode(crtime);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_setvolname(const char *volname) {
packet request;
request.encode(volname);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, volname ? volname : "", ret);
return ret;
}
/*packet::error_type remote_client::fuse_setxattr(const char *path, const char *name, const
char *value, const remote::file_size &size, const std::int32_t &flags) { packet::error_type ret
= 0; if (size > std::numeric_limits<std::size_t>::max()) { ret = -ERANGE; } else { packet request;
request.encode(path);
request.encode(name);
request.encode(size);
request.encode(value, static_cast<std::size_t>(size));
request.encode(flags);
std::uint32_t service_flags = 0;
ret = packetClient_.send(__FUNCTION__, request, service_flags);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_setxattr_osx(const char *path, const char *name, const
char *value, const remote::file_size &size, const std::int32_t &flags, const std::uint32_t
&position) override { packet::error_type ret = 0; if (size >
std::numeric_limits<std::size_t>::max()) { ret = -ERANGE; } else { packet request;
request.encode(path); request.Encode(name); request.Encode(size); request.encode(value,
static_cast<std::size_t>(size)); request.encode(flags); request.encode(position);
std::uint32_t service_flags = 0;
ret = packetClient_.send(__FUNCTION__, request, service_flags);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}*/
packet::error_type remote_client::fuse_statfs(const char *path, const std::uint64_t &frsize,
remote::statfs &st) {
packet request;
request.encode(path);
request.encode(frsize);
packet response;
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
response.decode(st);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_statfs_x(const char *path, const std::uint64_t &bsize,
remote::statfs_x &st) {
packet request;
request.encode(path);
request.encode(bsize);
packet response;
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
response.decode(st);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_truncate(const char *path, const remote::file_offset &size) {
packet request;
request.encode(path);
request.encode(size);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_unlink(const char *path) {
packet request;
request.encode(path);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::fuse_utimens(const char *path, const remote::file_time *tv,
const std::uint64_t &op0, const std::uint64_t &op1) {
packet request;
request.encode(path);
request.encode(&tv[0], sizeof(remote::file_time) * 2);
request.encode(op0);
request.encode(op1);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, utils::path::create_api_path(path), ret);
return ret;
}
packet::error_type remote_client::json_create_directory_snapshot(const std::string &path,
json &json_data) {
packet request;
request.encode(path);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = packet::decode_json(response, json_data);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, path, ret);
return ret;
}
packet::error_type remote_client::json_read_directory_snapshot(const std::string &path,
const remote::file_handle &handle,
const std::uint32_t &page,
json &json_data) {
packet request;
request.encode(path);
request.encode(handle);
request.encode(page);
packet response;
std::uint32_t service_flags = 0;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = packet::decode_json(response, json_data);
}
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, path, ret);
return ret;
}
packet::error_type
remote_client::json_release_directory_snapshot(const std::string &path,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(handle);
std::uint32_t service_flags = 0;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_CLIENT_FUSE_EVENT(__FUNCTION__, path, ret);
return ret;
}
void remote_client::set_fuse_uid_gid(const remote::user_id &uid, const remote::group_id &gid) {
uid_ = uid;
gid_ = gid;
}
} // namespace repertory::remote_fuse

View File

@ -0,0 +1,617 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _WIN32
#include "drives/fuse/remotefuse/remote_fuse_drive.hpp"
#include "app_config.hpp"
#include "drives/fuse/events.hpp"
#include "events/consumers/console_consumer.hpp"
#include "events/consumers/logging_consumer.hpp"
#include "events/events.hpp"
#include "events/event_system.hpp"
#include "platform/platform.hpp"
#include "rpc/server/server.hpp"
#include "types/remote.hpp"
#include "utils/file_utils.hpp"
#include "utils/path_utils.hpp"
namespace repertory::remote_fuse {
app_config *remote_fuse_drive::remote_fuse_impl::config_ = nullptr;
lock_data *remote_fuse_drive::remote_fuse_impl::lock_ = nullptr;
std::string *remote_fuse_drive::remote_fuse_impl::mount_location_ = nullptr;
bool remote_fuse_drive::remote_fuse_impl::console_enabled_ = false;
bool remote_fuse_drive::remote_fuse_impl::was_mounted_ = false;
std::optional<gid_t> remote_fuse_drive::remote_fuse_impl::forced_gid_;
std::optional<uid_t> remote_fuse_drive::remote_fuse_impl::forced_uid_;
std::optional<mode_t> remote_fuse_drive::remote_fuse_impl::forced_umask_;
remote_instance_factory *remote_fuse_drive::remote_fuse_impl::factory_ = nullptr;
std::unique_ptr<logging_consumer> remote_fuse_drive::remote_fuse_impl::logging_consumer_;
std::unique_ptr<console_consumer> remote_fuse_drive::remote_fuse_impl::console_consumer_;
std::unique_ptr<i_remote_instance> remote_fuse_drive::remote_fuse_impl::remote_instance_;
std::unique_ptr<server> remote_fuse_drive::remote_fuse_impl::server_;
void remote_fuse_drive::remote_fuse_impl::tear_down(const int &ret) {
if (was_mounted_) {
event_system::instance().raise<drive_mount_result>(std::to_string(ret));
event_system::instance().stop();
logging_consumer_.reset();
console_consumer_.reset();
}
}
void remote_fuse_drive::remote_fuse_impl::populate_stat(const remote::stat &r,
const bool &directory, struct stat &st) {
memset(&st, 0, sizeof(struct stat));
#ifdef __APPLE__
st.st_blksize = 0;
st.st_atimespec.tv_nsec = r.st_atimespec % NANOS_PER_SECOND;
st.st_atimespec.tv_sec = r.st_atimespec / NANOS_PER_SECOND;
st.st_birthtimespec.tv_nsec = r.st_birthtimespec % NANOS_PER_SECOND;
st.st_birthtimespec.tv_sec = r.st_birthtimespec / NANOS_PER_SECOND;
st.st_ctimespec.tv_nsec = r.st_ctimespec % NANOS_PER_SECOND;
st.st_ctimespec.tv_sec = r.st_ctimespec / NANOS_PER_SECOND;
st.st_mtimespec.tv_nsec = r.st_mtimespec % NANOS_PER_SECOND;
st.st_mtimespec.tv_sec = r.st_mtimespec / NANOS_PER_SECOND;
st.st_flags = r.st_flags;
#else
st.st_blksize = 4096;
st.st_atim.tv_nsec = r.st_atimespec % NANOS_PER_SECOND;
st.st_atim.tv_sec = r.st_atimespec / NANOS_PER_SECOND;
st.st_ctim.tv_nsec = r.st_ctimespec % NANOS_PER_SECOND;
st.st_ctim.tv_sec = r.st_ctimespec / NANOS_PER_SECOND;
st.st_mtim.tv_nsec = r.st_mtimespec % NANOS_PER_SECOND;
st.st_mtim.tv_sec = r.st_mtimespec / NANOS_PER_SECOND;
#endif
if (not directory) {
const auto blockSizeStat = static_cast<std::uint64_t>(512);
const auto blockSize = static_cast<std::uint64_t>(4096);
const auto size =
utils::divide_with_ceiling(static_cast<std::uint64_t>(st.st_size), blockSize) * blockSize;
st.st_blocks =
std::max(blockSize / blockSizeStat, utils::divide_with_ceiling(size, blockSizeStat));
}
st.st_gid = r.st_gid;
st.st_mode = (directory ? S_IFDIR : S_IFREG) | r.st_mode;
st.st_nlink = r.st_nlink;
st.st_size = r.st_size;
st.st_uid = r.st_uid;
}
int remote_fuse_drive::remote_fuse_impl::repertory_access(const char *path, int mask) {
return remote_instance_->fuse_access(path, mask);
}
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_chflags(const char *path, uint32_t flags) {
return remote_instance_->fuse_chflags(path, flags);
}
#endif
int remote_fuse_drive::remote_fuse_impl::repertory_chmod(const char *path, mode_t mode) {
return remote_instance_->fuse_chmod(path, mode);
}
int remote_fuse_drive::remote_fuse_impl::repertory_chown(const char *path, uid_t uid, gid_t gid) {
return remote_instance_->fuse_chown(path, uid, gid);
}
int remote_fuse_drive::remote_fuse_impl::repertory_create(const char *path, mode_t mode,
struct fuse_file_info *fi) {
return remote_instance_->fuse_create(path, mode, remote::open_flags(fi->flags), fi->fh);
}
void remote_fuse_drive::remote_fuse_impl::repertory_destroy(void * /*ptr*/) {
event_system::instance().raise<drive_unmount_pending>(*mount_location_);
if (server_) {
server_->stop();
server_.reset();
}
remote_instance_->fuse_destroy();
remote_instance_.reset();
lock_->set_mount_state(false, "", -1);
event_system::instance().raise<drive_mounted>(*mount_location_);
}
/*int remote_fuse_drive::remote_fuse_impl::repertory_fallocate(const char *path, int mode, off_t
offset, off_t length, struct fuse_file_info *fi) { return remote_instance_->fuse_fallocate(path,
mode, offset, length, fi->fh);
}*/
int remote_fuse_drive::remote_fuse_impl::repertory_fgetattr(const char *path, struct stat *st,
struct fuse_file_info *fi) {
remote::stat r{};
bool directory = false;
auto ret = remote_instance_->fuse_fgetattr(path, r, directory, fi->fh);
if (ret == 0) {
populate_stat(r, directory, *st);
}
return ret;
}
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_fsetattr_x(const char *path,
struct setattr_x *attr,
struct fuse_file_info *fi) {
remote::setattr_x attrRepertory{};
attrRepertory.valid = attr->valid;
attrRepertory.mode = attr->mode;
attrRepertory.uid = attr->uid;
attrRepertory.gid = attr->gid;
attrRepertory.size = attr->size;
attrRepertory.acctime = ((attr->acctime.tv_sec * NANOS_PER_SECOND) + attr->acctime.tv_nsec);
attrRepertory.modtime = ((attr->modtime.tv_sec * NANOS_PER_SECOND) + attr->modtime.tv_nsec);
attrRepertory.crtime = ((attr->crtime.tv_sec * NANOS_PER_SECOND) + attr->crtime.tv_nsec);
attrRepertory.chgtime = ((attr->chgtime.tv_sec * NANOS_PER_SECOND) + attr->chgtime.tv_nsec);
attrRepertory.bkuptime = ((attr->bkuptime.tv_sec * NANOS_PER_SECOND) + attr->bkuptime.tv_nsec);
attrRepertory.flags = attr->flags;
return remote_instance_->fuse_fsetattr_x(path, attrRepertory, fi->fh);
}
#endif
int remote_fuse_drive::remote_fuse_impl::repertory_fsync(const char *path, int datasync,
struct fuse_file_info *fi) {
return remote_instance_->fuse_fsync(path, datasync, fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi) {
return remote_instance_->fuse_ftruncate(path, size, fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_getattr(const char *path, struct stat *st) {
bool directory = false;
remote::stat r{};
const auto ret = remote_instance_->fuse_getattr(path, r, directory);
if (ret == 0) {
populate_stat(r, directory, *st);
}
return ret;
}
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_getxtimes(const char *path,
struct timespec *bkuptime,
struct timespec *crtime) {
if (not(bkuptime && crtime)) {
return -EFAULT;
} else {
remote::file_time repertory_bkuptime = 0;
remote::file_time repertory_crtime = 0;
const auto ret = remote_instance_->fuse_getxtimes(path, repertory_bkuptime, repertory_crtime);
if (ret == 0) {
bkuptime->tv_nsec = static_cast<long>(repertory_bkuptime % NANOS_PER_SECOND);
bkuptime->tv_sec = repertory_bkuptime / NANOS_PER_SECOND;
crtime->tv_nsec = static_cast<long>(repertory_crtime % NANOS_PER_SECOND);
crtime->tv_sec = repertory_crtime / NANOS_PER_SECOND;
}
return ret;
}
}
#endif
void *remote_fuse_drive::remote_fuse_impl::repertory_init(struct fuse_conn_info *conn) {
utils::file::change_to_process_directory();
#ifdef __APPLE__
conn->want |= FUSE_CAP_VOL_RENAME;
conn->want |= FUSE_CAP_XTIMES;
#endif
conn->want |= FUSE_CAP_BIG_WRITES;
if (console_enabled_) {
console_consumer_ = std::make_unique<console_consumer>();
}
logging_consumer_ =
std::make_unique<logging_consumer>(config_->get_log_directory(), config_->get_event_level());
event_system::instance().start();
was_mounted_ = true;
lock_->set_mount_state(true, *mount_location_, getpid());
remote_instance_ = (*factory_)();
remote_instance_->set_fuse_uid_gid(getuid(), getgid());
if (remote_instance_->fuse_init() != 0) {
event_system::instance().raise<repertory_exception>(__FUNCTION__,
"Failed to connect to remote server");
event_system::instance().raise<unmount_requested>();
} else {
server_ = std::make_unique<server>(*config_);
server_->start();
event_system::instance().raise<drive_mounted>(*mount_location_);
}
return nullptr;
}
int remote_fuse_drive::remote_fuse_impl::repertory_mkdir(const char *path, mode_t mode) {
return remote_instance_->fuse_mkdir(path, mode);
}
int remote_fuse_drive::remote_fuse_impl::repertory_open(const char *path,
struct fuse_file_info *fi) {
return remote_instance_->fuse_open(path, remote::open_flags(fi->flags), fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_opendir(const char *path,
struct fuse_file_info *fi) {
return remote_instance_->fuse_opendir(path, fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_read(const char *path, char *buffer,
size_t readSize, off_t readOffset,
struct fuse_file_info *fi) {
return remote_instance_->fuse_read(path, buffer, readSize, readOffset, fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_readdir(const char *path, void *buf,
fuse_fill_dir_t fuseFillDir,
off_t offset,
struct fuse_file_info *fi) {
std::string item_path;
int ret = 0;
while ((ret = remote_instance_->fuse_readdir(path, offset, fi->fh, item_path)) == 0) {
if ((item_path != ".") && (item_path != "..")) {
item_path = utils::path::strip_to_file_name(item_path);
}
if (fuseFillDir(buf, &item_path[0], nullptr, ++offset) != 0) {
break;
}
}
if (ret == -120) {
ret = 0;
}
return ret;
}
int remote_fuse_drive::remote_fuse_impl::repertory_release(const char *path,
struct fuse_file_info *fi) {
return remote_instance_->fuse_release(path, fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_releasedir(const char *path,
struct fuse_file_info *fi) {
return remote_instance_->fuse_releasedir(path, fi->fh);
}
int remote_fuse_drive::remote_fuse_impl::repertory_rename(const char *from, const char *to) {
return remote_instance_->fuse_rename(from, to);
}
int remote_fuse_drive::remote_fuse_impl::repertory_rmdir(const char *path) {
return remote_instance_->fuse_rmdir(path);
}
/*
#ifdef HAS_SETXATTR
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_getxattr(const char *path, const char *name,
char *value, size_t size, uint32_t position) { return remote_instance_->fuse_getxattr_osx(path,
name, value, size, position);
}
#else
int remote_fuse_drive::remote_fuse_impl::repertory_getxattr(const char *path, const char *name,
char *value, size_t size) { return remote_instance_->fuse_getxattr(path, name, value, size);
}
#endif
int remote_fuse_drive::remote_fuse_impl::repertory_listxattr(const char *path, char *buffer,
size_t size) { return remote_instance_->fuse_listxattr(path, buffer, size);
}
remote_fuse_drive::remote_fuse_impl::int repertory_removexattr(const char *path, const char
*name) { return remote_instance_->fuse_removexattr(path, name);
}
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_setxattr(const char *path, const char *name,
const char *value, size_t size, int flags, uint32_t position) { return
remote_instance_->fuse_setxattr_osx(path, name, value, size, flags, position);
}
#else
int remote_fuse_drive::remote_fuse_impl::repertory_setxattr(const char *path, const char *name,
const char *value, size_t size, int flags) { return remote_instance_->fuse_setxattr(path, name,
value, size, flags);
}
#endif
#endif
*/
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_setattr_x(const char *path,
struct setattr_x *attr) {
remote::setattr_x attributes{};
attributes.valid = attr->valid;
attributes.mode = attr->mode;
attributes.uid = attr->uid;
attributes.gid = attr->gid;
attributes.size = attr->size;
attributes.acctime = ((attr->acctime.tv_sec * NANOS_PER_SECOND) + attr->acctime.tv_nsec);
attributes.modtime = ((attr->modtime.tv_sec * NANOS_PER_SECOND) + attr->modtime.tv_nsec);
attributes.crtime = ((attr->crtime.tv_sec * NANOS_PER_SECOND) + attr->crtime.tv_nsec);
attributes.chgtime = ((attr->chgtime.tv_sec * NANOS_PER_SECOND) + attr->chgtime.tv_nsec);
attributes.bkuptime = ((attr->bkuptime.tv_sec * NANOS_PER_SECOND) + attr->bkuptime.tv_nsec);
attributes.flags = attr->flags;
return remote_instance_->fuse_setattr_x(path, attributes);
}
int remote_fuse_drive::remote_fuse_impl::repertory_setbkuptime(const char *path,
const struct timespec *bkuptime) {
remote::file_time repertory_bkuptime =
((bkuptime->tv_sec * NANOS_PER_SECOND) + bkuptime->tv_nsec);
return remote_instance_->fuse_setbkuptime(path, repertory_bkuptime);
}
int remote_fuse_drive::remote_fuse_impl::repertory_setchgtime(const char *path,
const struct timespec *chgtime) {
remote::file_time repertory_chgtime = ((chgtime->tv_sec * NANOS_PER_SECOND) + chgtime->tv_nsec);
return remote_instance_->fuse_setchgtime(path, repertory_chgtime);
}
int remote_fuse_drive::remote_fuse_impl::repertory_setcrtime(const char *path,
const struct timespec *crtime) {
remote::file_time repertory_crtime = ((crtime->tv_sec * NANOS_PER_SECOND) + crtime->tv_nsec);
return remote_instance_->fuse_setcrtime(path, repertory_crtime);
}
int remote_fuse_drive::remote_fuse_impl::repertory_setvolname(const char *volname) {
return remote_instance_->fuse_setvolname(volname);
}
int remote_fuse_drive::remote_fuse_impl::repertory_statfs_x(const char *path,
struct statfs *stbuf) {
auto ret = statfs(config_->get_data_directory().c_str(), stbuf);
if (ret == 0) {
remote::statfs_x r{};
if ((ret = remote_instance_->fuse_statfs_x(path, stbuf->f_bsize, r)) == 0) {
stbuf->f_blocks = r.f_blocks;
stbuf->f_bavail = r.f_bavail;
stbuf->f_bfree = r.f_bfree;
stbuf->f_ffree = r.f_ffree;
stbuf->f_files = r.f_files;
stbuf->f_owner = getuid();
strncpy(&stbuf->f_mntonname[0], mount_location_->c_str(), MNAMELEN);
strncpy(&stbuf->f_mntfromname[0], &r.f_mntfromname[0], MNAMELEN);
}
} else {
ret = -errno;
}
return ret;
}
#else
int remote_fuse_drive::remote_fuse_impl::repertory_statfs(const char *path, struct statvfs *stbuf) {
auto ret = statvfs(&config_->get_data_directory()[0], stbuf);
if (ret == 0) {
remote::statfs r{};
if ((ret = remote_instance_->fuse_statfs(path, stbuf->f_frsize, r)) == 0) {
stbuf->f_blocks = r.f_blocks;
stbuf->f_bavail = r.f_bavail;
stbuf->f_bfree = r.f_bfree;
stbuf->f_ffree = r.f_ffree;
stbuf->f_favail = r.f_favail;
stbuf->f_files = r.f_files;
}
} else {
ret = -errno;
}
return ret;
}
#endif
int remote_fuse_drive::remote_fuse_impl::repertory_truncate(const char *path, off_t size) {
return remote_instance_->fuse_truncate(path, size);
}
int remote_fuse_drive::remote_fuse_impl::repertory_unlink(const char *path) {
return remote_instance_->fuse_unlink(path);
}
int remote_fuse_drive::remote_fuse_impl::repertory_utimens(const char *path,
const struct timespec tv[2]) {
remote::file_time rtv[2] = {0};
if (tv) {
rtv[0] = tv[0].tv_nsec + (tv[0].tv_sec * NANOS_PER_SECOND);
rtv[1] = tv[1].tv_nsec + (tv[1].tv_sec * NANOS_PER_SECOND);
}
return remote_instance_->fuse_utimens(path, rtv, tv ? tv[0].tv_nsec : 0, tv ? tv[1].tv_nsec : 0);
}
int remote_fuse_drive::remote_fuse_impl::repertory_write(const char *path, const char *buffer,
size_t writeSize, off_t writeOffset,
struct fuse_file_info *fi) {
return remote_instance_->fuse_write(path, buffer, writeSize, writeOffset, fi->fh);
}
remote_fuse_drive::remote_fuse_drive(app_config &config, lock_data &lock,
remote_instance_factory factory)
: config_(config), lock_(lock), factory_(std::move(factory)) {
E_SUBSCRIBE_EXACT(unmount_requested, [this](const unmount_requested &) {
std::thread([this]() { remote_fuse_drive::shutdown(mount_location_); }).detach();
});
}
int remote_fuse_drive::mount(std::vector<std::string> drive_args) {
remote_fuse_impl::lock_ = &lock_;
remote_fuse_impl::config_ = &config_;
remote_fuse_impl::mount_location_ = &mount_location_;
remote_fuse_impl::factory_ = &factory_;
#ifdef __APPLE__
fuse_ops_.chflags = remote_fuse_impl::repertory_chflags;
fuse_ops_.fsetattr_x = remote_fuse_impl::repertory_fsetattr_x;
fuse_ops_.getxtimes = remote_fuse_impl::repertory_getxtimes;
fuse_ops_.setattr_x = remote_fuse_impl::repertory_setattr_x;
fuse_ops_.setbkuptime = remote_fuse_impl::repertory_setbkuptime;
fuse_ops_.setchgtime = remote_fuse_impl::repertory_setchgtime;
fuse_ops_.setcrtime = remote_fuse_impl::repertory_setcrtime;
fuse_ops_.setvolname = remote_fuse_impl::repertory_setvolname;
fuse_ops_.statfs_x = remote_fuse_impl::repertory_statfs_x;
#endif
auto force_no_console = false;
for (std::size_t i = 1u; !force_no_console && (i < drive_args.size()); i++) {
if (drive_args[i] == "-nc") {
force_no_console = true;
}
}
utils::remove_element_from(drive_args, "-nc");
for (std::size_t i = 1u; i < drive_args.size(); i++) {
if (drive_args[i] == "-f") {
remote_fuse_impl::console_enabled_ = not force_no_console;
} else if (drive_args[i].find("-o") == 0) {
std::string options;
if (drive_args[i].size() == 2u) {
if ((i + 1) < drive_args.size()) {
options = drive_args[++i];
}
} else {
options = drive_args[i].substr(2);
}
const auto option_list = utils::string::split(options, ',');
for (const auto &option : option_list) {
if (option.find("gid") == 0) {
const auto parts = utils::string::split(option, '=');
if (parts.size() == 2u) {
auto gid = getgrnam(parts[1u].c_str());
if (not gid) {
gid = getgrgid(utils::string::to_uint32(parts[1]));
}
if ((getgid() != 0) && (gid->gr_gid == 0)) {
std::cerr << "'gid=0' requires running as root" << std::endl;
return -1;
} else {
remote_fuse_impl::forced_gid_ = gid->gr_gid;
}
}
} else if (option.find("uid") == 0) {
const auto parts = utils::string::split(option, '=');
if (parts.size() == 2u) {
auto uid = getpwnam(parts[1u].c_str());
if (not uid) {
uid = getpwuid(utils::string::to_uint32(parts[1]));
}
if ((getuid() != 0) && (uid->pw_uid == 0)) {
std::cerr << "'uid=0' requires running as root" << std::endl;
return -1;
} else {
remote_fuse_impl::forced_uid_ = uid->pw_uid;
}
}
} else if (option.find("umask") == 0) {
const auto parts = utils::string::split(option, '=');
if (parts.size() == 2u) {
static const auto numeric_regex = std::regex("[0-9]+");
try {
if (not std::regex_match(parts[1u], numeric_regex)) {
throw std::runtime_error("invalid syntax");
} else {
remote_fuse_impl::forced_umask_ = utils::string::to_uint32(parts[1]);
}
} catch (...) {
std::cerr << ("'" + option + "' invalid syntax") << std::endl;
return -1;
}
}
}
}
}
}
std::vector<const char *> fuse_argv(drive_args.size());
for (std::size_t i = 0u; i < drive_args.size(); i++) {
fuse_argv[i] = drive_args[i].c_str();
}
struct fuse_args args =
FUSE_ARGS_INIT(static_cast<int>(fuse_argv.size()), (char **)&fuse_argv[0]);
char *mount_location = nullptr;
fuse_parse_cmdline(&args, &mount_location, nullptr, nullptr);
if (mount_location) {
mount_location_ = mount_location;
free(mount_location);
}
std::string args_string;
for (const auto *arg : fuse_argv) {
if (args_string.empty()) {
args_string += arg;
} else {
args_string += (" " + std::string(arg));
}
}
event_system::instance().raise<fuse_args_parsed>(args_string);
umask(0);
const auto ret = fuse_main(static_cast<int>(fuse_argv.size()), (char **)&fuse_argv[0], &fuse_ops_,
&mount_location);
remote_fuse_impl::tear_down(ret);
return ret;
}
void remote_fuse_drive::display_options(int argc, char *argv[]) {
struct fuse_operations fuse_ops {};
fuse_main(argc, argv, &fuse_ops, nullptr);
std::cout << std::endl;
}
void remote_fuse_drive::display_version_information(int argc, char *argv[]) {
struct fuse_operations fuse_ops {};
fuse_main(argc, argv, &fuse_ops, nullptr);
}
void remote_fuse_drive::shutdown(std::string mount_location) {
#if __APPLE__
const auto unmount = "umount \"" + mount_location + "\" >/dev/null 2>&1";
#else
const auto unmount = "fusermount -u \"" + mount_location + "\" >/dev/null 2>&1";
#endif
int ret;
for (std::uint8_t i = 0u; ((ret = system(unmount.c_str())) != 0) && (i < 10u); i++) {
event_system::instance().raise<unmount_result>(mount_location, std::to_string(ret));
if (i != 9u) {
std::this_thread::sleep_for(1s);
}
}
if (ret != 0) {
ret = kill(getpid(), SIGINT);
}
event_system::instance().raise<unmount_result>(mount_location, std::to_string(ret));
}
} // namespace repertory::remote_fuse
#endif // _WIN32

View File

@ -0,0 +1,51 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _WIN32
#if 0
#include "drives/fuse/remotefuse/remote_fuse_drive2.hpp"
#include "app_config.hpp"
#include "events/consumers/console_consumer.hpp"
#include "events/consumers/logging_consumer.hpp"
#include "events/events.hpp"
#include "events/event_system.hpp"
#include "platform/platform.hpp"
#include "rpc/server/server.hpp"
#include "types/remote.hpp"
#include "utils/file_utils.hpp"
#include "utils/path_utils.hpp"
namespace repertory::remote_fuse {
api_error remote_fuse_drive2::access_impl(std::string api_path, int mask) {
return utils::to_api_error(remote_instance_->fuse_access(api_path.c_str(), mask));
}
#ifdef __APPLE__
api_error remote_fuse_drive2::chflags_impl(std::string api_path, uint32_t flags) {
return utils::to_api_error(remote_instance_->fuse_chflags(path, flags));
}
#endif // __APPLE__
api_error remote_fuse_drive2::chmod_impl(std::string api_path, mode_t mode) {
return utils::to_api_error(remote_instance_->fuse_chmod(path, mode));
}
} // namespace repertory::remote_fuse
#endif // 0
#endif // _WIN32

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,192 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drives/remote/remote_open_file_table.hpp"
#include "utils/utils.hpp"
namespace repertory {
void remote_open_file_table::add_directory(const std::string &client_id, void *dir) {
unique_mutex_lock directory_lock(directory_mutex_);
auto &list = directory_lookup_[client_id];
if (utils::collection_excludes(list, dir)) {
directory_lookup_[client_id].emplace_back(dir);
}
}
void remote_open_file_table::close_all(const std::string &client_id) {
std::vector<remote::file_handle> compatHandles;
unique_mutex_lock compat_lock(compat_mutex_);
for (auto &kv : compat_lookup_) {
if (kv.second.client_id == client_id) {
compatHandles.emplace_back(kv.first);
}
}
compat_lock.unlock();
for (auto &handle : compatHandles) {
#ifdef _WIN32
_close(static_cast<int>(handle));
#else
close(static_cast<int>(handle));
#endif
remove_compat_open_info(handle);
}
std::vector<OSHandle> handles;
unique_mutex_lock file_lock(file_mutex_);
for (auto &kv : file_lookup_) {
if (kv.second.client_id == client_id) {
handles.emplace_back(kv.first);
}
}
file_lock.unlock();
for (auto &handle : handles) {
#ifdef _WIN32
::CloseHandle(handle);
#else
close(handle);
#endif
remove_open_info(handle);
}
std::vector<void *> dirs;
unique_mutex_lock directory_lock(directory_mutex_);
for (auto &kv : directory_lookup_) {
if (kv.first == client_id) {
dirs.insert(dirs.end(), kv.second.begin(), kv.second.end());
}
}
directory_lock.unlock();
for (auto *dir : dirs) {
remove_directory(client_id, dir);
}
}
#ifdef _WIN32
bool remote_open_file_table::get_directory_buffer(const OSHandle &handle, PVOID *&buffer) {
mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) != file_lookup_.end()) {
buffer = &file_lookup_[handle].directory_buffer;
return true;
}
return false;
}
#endif
bool remote_open_file_table::get_open_info(const OSHandle &handle, open_info &oi) {
mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) != file_lookup_.end()) {
oi = file_lookup_[handle];
return true;
}
return false;
}
std::string remote_open_file_table::get_open_file_path(const OSHandle &handle) {
mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) != file_lookup_.end()) {
return file_lookup_[handle].path;
}
return "";
}
bool remote_open_file_table::has_open_directory(const std::string &client_id, void *dir) {
unique_mutex_lock directory_lock(directory_mutex_);
auto &list = directory_lookup_[client_id];
return (utils::collection_includes(list, dir));
}
int remote_open_file_table::has_compat_open_info(const remote::file_handle &handle,
const int &errorReturn) {
mutex_lock compat_lock(compat_mutex_);
const auto res = ((compat_lookup_.find(handle) == compat_lookup_.end()) ? -1 : 0);
if (res == -1) {
errno = errorReturn;
}
return res;
}
void remote_open_file_table::remove_compat_open_info(const remote::file_handle &handle) {
mutex_lock compat_lock(compat_mutex_);
if (compat_lookup_[handle].count > 0) {
compat_lookup_[handle].count--;
}
if (not compat_lookup_[handle].count) {
compat_lookup_.erase(handle);
}
}
bool remote_open_file_table::remove_directory(const std::string &client_id, void *dir) {
unique_mutex_lock directory_lock(directory_mutex_);
auto &list = directory_lookup_[client_id];
if (utils::collection_includes(list, dir)) {
utils::remove_element_from(list, dir);
delete_open_directory(dir);
if (directory_lookup_[client_id].empty()) {
directory_lookup_.erase(client_id);
}
return true;
}
return false;
}
void remote_open_file_table::remove_open_info(const OSHandle &handle) {
mutex_lock file_lock(file_mutex_);
if (file_lookup_[handle].count > 0) {
file_lookup_[handle].count--;
}
if (not file_lookup_[handle].count) {
#ifdef _WIN32
if (file_lookup_[handle].directory_buffer) {
FspFileSystemDeleteDirectoryBuffer(&file_lookup_[handle].directory_buffer);
}
#endif
file_lookup_.erase(handle);
}
}
void remote_open_file_table::set_compat_client_id(const remote::file_handle &handle,
const std::string &client_id) {
mutex_lock compat_lock(compat_mutex_);
compat_lookup_[handle].client_id = client_id;
}
void remote_open_file_table::set_client_id(const OSHandle &handle, const std::string &client_id) {
mutex_lock file_lock(file_mutex_);
file_lookup_[handle].client_id = client_id;
}
void remote_open_file_table::set_compat_open_info(const remote::file_handle &handle) {
mutex_lock compat_lock(compat_mutex_);
if (compat_lookup_.find(handle) == compat_lookup_.end()) {
compat_lookup_[handle] = {0, ""};
}
compat_lookup_[handle].count++;
}
void remote_open_file_table::set_open_info(const OSHandle &handle, open_info oi) {
mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) == file_lookup_.end()) {
file_lookup_[handle] = std::move(oi);
}
file_lookup_[handle].count++;
}
} // namespace repertory

View File

@ -0,0 +1,462 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
#include "app_config.hpp"
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
#include "events/events.hpp"
#include "events/event_system.hpp"
#include "types/repertory.hpp"
#include "utils/path_utils.hpp"
namespace repertory::remote_winfsp {
#define RAISE_REMOTE_WINFSP_CLIENT_EVENT(func, file, ret) \
if (config_.get_enable_drive_events() && \
(((config_.get_event_level() >= remote_winfsp_client_event::level) && \
(ret != STATUS_SUCCESS)) || \
(config_.get_event_level() >= event_level::verbose))) \
event_system::instance().raise<remote_winfsp_client_event>(func, file, ret)
// clang-format off
E_SIMPLE3(remote_winfsp_client_event, debug, true,
std::string, function, func, E_STRING,
std::string, api_path, ap, E_STRING,
packet::error_type, result, res, E_FROM_INT32
);
// clang-format on
remote_client::remote_client(const app_config &config)
: config_(config),
packet_client_(config.get_remote_host_name_or_ip(), config.get_remote_max_connections(),
config.get_remote_port(), config.get_remote_receive_timeout_secs(),
config.get_remote_send_timeout_secs(), config.get_remote_token()) {}
packet::error_type remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name) {
packet request;
request.encode(file_desc);
request.encode(file_name);
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(
__FUNCTION__, utils::path::create_api_path(utils::string::to_utf8(file_name)), ret);
return ret;
}
packet::error_type remote_client::json_create_directory_snapshot(const std::string &path,
json &json_data) {
packet request;
request.encode(path);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = packet::decode_json(response, json_data);
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, path, ret);
return ret;
}
packet::error_type remote_client::json_read_directory_snapshot(const std::string &path,
const remote::file_handle &handle,
const std::uint32_t &page,
json &json_data) {
packet request;
request.encode(path);
request.encode(handle);
request.encode(page);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = packet::decode_json(response, json_data);
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, path, ret);
return ret;
}
packet::error_type
remote_client::json_release_directory_snapshot(const std::string &path,
const remote::file_handle &handle) {
packet request;
request.encode(path);
request.encode(handle);
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, path, ret);
return ret;
}
packet::error_type remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name, UINT32 flags,
BOOLEAN &was_closed) {
const auto file_path = get_open_file_path(to_handle(file_desc));
was_closed = 0;
packet request;
request.encode(file_desc);
request.encode(file_name);
request.encode(flags);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, was_closed);
if (was_closed) {
remove_open_info(to_handle(file_desc));
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, file_path, ret);
return ret;
}
packet::error_type remote_client::winfsp_close(PVOID file_desc) {
const auto file_path = get_open_file_path(to_handle(file_desc));
packet request;
request.encode(file_desc);
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
if (ret == STATUS_SUCCESS) {
remove_open_info(to_handle(file_desc));
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, file_path, ret);
return ret;
}
packet::error_type remote_client::winfsp_create(PWSTR file_name, UINT32 create_options,
UINT32 granted_access, UINT32 attributes,
UINT64 allocation_size, PVOID *file_desc,
remote::file_info *file_info,
std::string &normalized_name, BOOLEAN &exists) {
packet request;
request.encode(file_name);
request.encode(create_options);
request.encode(granted_access);
request.encode(attributes);
request.encode(allocation_size);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == STATUS_SUCCESS) {
HANDLE handle;
DECODE_OR_IGNORE(&response, handle);
DECODE_OR_IGNORE(&response, *file_info);
DECODE_OR_IGNORE(&response, normalized_name);
DECODE_OR_IGNORE(&response, exists);
if (ret == STATUS_SUCCESS) {
*file_desc = reinterpret_cast<PVOID>(handle);
set_open_info(to_handle(*file_desc),
open_info{0, "", nullptr, utils::string::to_utf8(file_name)});
#ifdef _WIN32
if (exists) {
::SetLastError(ERROR_ALREADY_EXISTS);
}
#endif
}
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(*file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_flush(PVOID file_desc, remote::file_info *file_info) {
packet request;
request.encode(file_desc);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *file_info);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_get_dir_buffer(PVOID file_desc, PVOID *&ptr) {
#ifdef _WIN32
if (get_directory_buffer(reinterpret_cast<OSHandle>(file_desc), ptr)) {
return STATUS_SUCCESS;
}
#endif
return STATUS_INVALID_HANDLE;
}
packet::error_type remote_client::winfsp_get_file_info(PVOID file_desc,
remote::file_info *file_info) {
packet request;
request.encode(file_desc);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *file_info);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_get_security_by_name(PWSTR file_name, PUINT32 attributes,
std::uint64_t *descriptor_size,
std::wstring &string_descriptor) {
packet request;
request.encode(file_name);
request.encode(static_cast<std::uint64_t>(descriptor_size ? *descriptor_size : 0));
request.encode(static_cast<std::uint8_t>(attributes != nullptr));
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
string_descriptor.clear();
DECODE_OR_IGNORE(&response, string_descriptor);
if (string_descriptor.empty()) {
string_descriptor = L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)";
}
if (attributes) {
DECODE_OR_IGNORE(&response, *attributes);
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, utils::string::to_utf8(file_name), ret);
return ret;
}
packet::error_type remote_client::winfsp_get_volume_info(UINT64 &total_size, UINT64 &free_size,
std::string &volume_label) {
packet request;
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, total_size);
DECODE_OR_IGNORE(&response, free_size);
DECODE_OR_IGNORE(&response, volume_label);
return ret;
}
packet::error_type remote_client::winfsp_mounted(const std::wstring &location) {
packet request;
request.encode(get_repertory_version());
request.encode(location);
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
const auto mountLocation = utils::string::to_utf8(location);
event_system::instance().raise<drive_mounted>(mountLocation);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, mountLocation, ret);
return ret;
}
packet::error_type remote_client::winfsp_open(PWSTR file_name, UINT32 create_options,
UINT32 granted_access, PVOID *file_desc,
remote::file_info *file_info,
std::string &normalized_name) {
packet request;
request.encode(file_name);
request.encode(create_options);
request.encode(granted_access);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == STATUS_SUCCESS) {
HANDLE handle;
DECODE_OR_IGNORE(&response, handle);
DECODE_OR_IGNORE(&response, *file_info);
DECODE_OR_IGNORE(&response, normalized_name);
if (ret == STATUS_SUCCESS) {
*file_desc = reinterpret_cast<PVOID>(handle);
set_open_info(to_handle(*file_desc),
open_info{0, "", nullptr, utils::string::to_utf8(file_name)});
}
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(*file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_overwrite(PVOID file_desc, UINT32 attributes,
BOOLEAN replace_attributes,
UINT64 allocation_size,
remote::file_info *file_info) {
packet request;
request.encode(file_desc);
request.encode(attributes);
request.encode(replace_attributes);
request.encode(allocation_size);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *file_info);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
UINT32 length, PUINT32 bytes_transferred) {
packet request;
request.encode(file_desc);
request.encode(offset);
request.encode(length);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *bytes_transferred);
if (ret == STATUS_SUCCESS) {
ret = response.decode(buffer, *bytes_transferred);
#ifdef _WIN32
if ((ret == STATUS_SUCCESS) && (not *bytes_transferred || (*bytes_transferred != length))) {
::SetLastError(ERROR_HANDLE_EOF);
}
#endif
}
if (ret != STATUS_SUCCESS) {
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
}
return ret;
}
packet::error_type remote_client::winfsp_read_directory(PVOID file_desc, PWSTR pattern,
PWSTR marker, json &item_list) {
packet request;
request.encode(file_desc);
request.encode(pattern);
request.encode(marker);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == STATUS_SUCCESS) {
ret = packet::decode_json(response, item_list);
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name,
PWSTR new_file_name, BOOLEAN replace_if_exists) {
packet request;
request.encode(file_desc);
request.encode(file_name);
request.encode(new_file_name);
request.encode(replace_if_exists);
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(
__FUNCTION__,
utils::path::create_api_path(utils::string::to_utf8(file_name)) + "|" +
utils::path::create_api_path(utils::string::to_utf8(new_file_name)),
ret);
return ret;
}
packet::error_type remote_client::winfsp_set_basic_info(PVOID file_desc, UINT32 attributes,
UINT64 creation_time,
UINT64 last_access_time,
UINT64 last_write_time, UINT64 change_time,
remote::file_info *file_info) {
packet request;
request.encode(file_desc);
request.encode(attributes);
request.encode(creation_time);
request.encode(last_access_time);
request.encode(last_write_time);
request.encode(change_time);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *file_info);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_set_file_size(PVOID file_desc, UINT64 new_size,
BOOLEAN set_allocation_size,
remote::file_info *file_info) {
packet request;
request.encode(file_desc);
request.encode(new_size);
request.encode(set_allocation_size);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *file_info);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
return ret;
}
packet::error_type remote_client::winfsp_unmounted(const std::wstring &location) {
const auto mount_location = utils::string::to_utf8(location);
event_system::instance().raise<drive_unmount_pending>(mount_location);
packet request;
request.encode(location);
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
event_system::instance().raise<drive_unmounted>(mount_location);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, mount_location, ret);
return ret;
}
packet::error_type remote_client::winfsp_write(PVOID file_desc, PVOID buffer, UINT64 offset,
UINT32 length, BOOLEAN write_to_end,
BOOLEAN constrained_io, PUINT32 bytes_transferred,
remote::file_info *file_info) {
packet request;
request.encode(file_desc);
request.encode(length);
request.encode(offset);
request.encode(write_to_end);
request.encode(constrained_io);
if (length) {
request.encode(buffer, length);
}
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
DECODE_OR_IGNORE(&response, *bytes_transferred);
DECODE_OR_IGNORE(&response, *file_info);
if (ret != STATUS_SUCCESS) {
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
}
return ret;
}
} // namespace repertory::remote_winfsp

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,401 @@
/*
Copyright <2018-2022> <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.
*/
#ifdef _WIN32
#include "drives/winfsp/remotewinfsp/remote_winfsp_drive.hpp"
#include "app_config.hpp"
#include "events/consumers/console_consumer.hpp"
#include "events/consumers/logging_consumer.hpp"
#include "events/events.hpp"
#include "platform/platform.hpp"
#include "rpc/server/server.hpp"
#include "utils/file_utils.hpp"
#include "utils/path_utils.hpp"
#include "utils/utils.hpp"
namespace repertory::remote_winfsp {
remote_winfsp_drive::winfsp_service::winfsp_service(lock_data &lock, remote_winfsp_drive &drive,
std::vector<std::string> drive_args,
app_config &config)
: Service(&(L"RepertoryRemote_" + utils::string::from_utf8(lock.get_unique_id()))[0u]),
config_(config),
lock_(lock),
drive_(drive),
drive_args_(std::move(drive_args)),
host_(drive) {}
NTSTATUS remote_winfsp_drive::winfsp_service::OnStart(ULONG, PWSTR *) {
const auto mount_location =
utils::path::absolute((drive_args_.size() > 1u) ? drive_args_[1u] : "");
const auto drive_letter = ((mount_location.size() == 2u) ||
((mount_location.size() == 3u) && (mount_location[2u] == '\\'))) &&
(mount_location[1u] == ':');
auto ret = drive_letter ? STATUS_DEVICE_BUSY : STATUS_NOT_SUPPORTED;
if ((drive_letter && not utils::file::is_directory(mount_location))) {
auto unicode_mount_location = utils::string::from_utf8(mount_location);
host_.SetFileSystemName(&unicode_mount_location[0u]);
ret = host_.Mount(&unicode_mount_location[0u]);
} else {
std::cerr << (drive_letter ? "Mount location in use: " : "Mount location not supported: ")
<< mount_location << std::endl;
}
if (ret != STATUS_SUCCESS) {
event_system::instance().raise<drive_mount_failed>(mount_location, std::to_string(ret));
lock_.set_mount_state(false, "", -1);
}
return ret;
}
NTSTATUS remote_winfsp_drive::winfsp_service::OnStop() {
host_.Unmount();
lock_.set_mount_state(false, "", -1);
return STATUS_SUCCESS;
}
remote_winfsp_drive::remote_winfsp_drive(app_config &config, lock_data &lockData,
remote_instance_factory factory)
: FileSystemBase(), config_(config), lock_(lockData), factory_(factory) {
E_SUBSCRIBE_EXACT(unmount_requested, [this](const unmount_requested &e) {
std::thread([this]() { this->shutdown(); }).detach();
});
}
NTSTATUS remote_winfsp_drive::CanDelete(PVOID file_node, PVOID file_desc, PWSTR file_name) {
return remote_instance_->winfsp_can_delete(file_desc, file_name);
}
VOID remote_winfsp_drive::Cleanup(PVOID file_node, PVOID file_desc, PWSTR file_name, ULONG flags) {
BOOLEAN was_closed;
remote_instance_->winfsp_cleanup(file_desc, file_name, flags, was_closed);
}
VOID remote_winfsp_drive::Close(PVOID file_node, PVOID file_desc) {
remote_instance_->winfsp_close(file_desc);
}
NTSTATUS remote_winfsp_drive::Create(PWSTR file_name, UINT32 create_options, UINT32 granted_access,
UINT32 attributes, PSECURITY_DESCRIPTOR descriptor,
UINT64 allocation_size, PVOID *file_node, PVOID *file_desc,
OpenFileInfo *ofi) {
remote::file_info fi{};
std::string normalized_name;
BOOLEAN exists = 0;
const auto ret =
remote_instance_->winfsp_create(file_name, create_options, granted_access, attributes,
allocation_size, file_desc, &fi, normalized_name, exists);
if (ret == STATUS_SUCCESS) {
SetFileInfo(ofi->FileInfo, fi);
const auto filePath = utils::string::from_utf8(normalized_name);
wcsncpy(ofi->NormalizedName, &filePath[0], wcslen(&filePath[0]));
ofi->NormalizedNameSize = (UINT16)(wcslen(&filePath[0]) * sizeof(WCHAR));
}
return ret;
}
NTSTATUS remote_winfsp_drive::Flush(PVOID file_node, PVOID file_desc, FileInfo *file_info) {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_flush(file_desc, &fi);
SetFileInfo(*file_info, fi);
return ret;
}
NTSTATUS remote_winfsp_drive::GetFileInfo(PVOID file_node, PVOID file_desc, FileInfo *file_info) {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_get_file_info(file_desc, &fi);
SetFileInfo(*file_info, fi);
return ret;
}
NTSTATUS remote_winfsp_drive::GetSecurityByName(PWSTR file_name, PUINT32 attributes,
PSECURITY_DESCRIPTOR descriptor,
SIZE_T *descriptor_size) {
std::wstring string_descriptor;
std::uint64_t sds = descriptor_size ? *descriptor_size : 0;
auto ret = remote_instance_->winfsp_get_security_by_name(
file_name, attributes, descriptor_size ? &sds : nullptr, string_descriptor);
*descriptor_size = static_cast<SIZE_T>(sds);
if ((ret == STATUS_SUCCESS) && *descriptor_size) {
PSECURITY_DESCRIPTOR sd = nullptr;
ULONG sz2 = 0u;
if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(&string_descriptor[0u],
SDDL_REVISION_1, &sd, &sz2)) {
if (sz2 > *descriptor_size) {
ret = STATUS_BUFFER_TOO_SMALL;
} else {
::CopyMemory(descriptor, sd, sz2);
}
*descriptor_size = sz2;
::LocalFree(sd);
} else {
ret = FspNtStatusFromWin32(::GetLastError());
}
}
return ret;
}
NTSTATUS remote_winfsp_drive::GetVolumeInfo(VolumeInfo *volume_info) {
std::string volume_label;
const auto ret = remote_instance_->winfsp_get_volume_info(volume_info->TotalSize,
volume_info->FreeSize, volume_label);
if (ret == STATUS_SUCCESS) {
const auto byte_size = static_cast<UINT16>(volume_label.size() * sizeof(WCHAR));
wcscpy_s(&volume_info->VolumeLabel[0u], 32, &utils::string::from_utf8(volume_label)[0u]);
volume_info->VolumeLabelLength = std::min(static_cast<UINT16>(64u), byte_size);
}
return ret;
}
NTSTATUS remote_winfsp_drive::Init(PVOID host) {
auto *file_system_host = reinterpret_cast<FileSystemHost *>(host);
file_system_host->SetPrefix(
&(L"\\repertory\\" + std::wstring(file_system_host->FileSystemName()).substr(0, 1))[0]);
file_system_host->SetFileSystemName(REPERTORY_W);
file_system_host->SetFlushAndPurgeOnCleanup(TRUE);
file_system_host->SetReparsePoints(FALSE);
file_system_host->SetReparsePointsAccessCheck(FALSE);
file_system_host->SetSectorSize(WINFSP_ALLOCATION_UNIT);
file_system_host->SetSectorsPerAllocationUnit(1);
file_system_host->SetFileInfoTimeout(1000);
file_system_host->SetCaseSensitiveSearch(FALSE);
file_system_host->SetCasePreservedNames(TRUE);
file_system_host->SetNamedStreams(FALSE);
file_system_host->SetUnicodeOnDisk(TRUE);
file_system_host->SetPersistentAcls(FALSE);
file_system_host->SetPostCleanupWhenModifiedOnly(TRUE);
file_system_host->SetPassQueryDirectoryPattern(FALSE);
file_system_host->SetVolumeCreationTime(utils::get_file_time_now());
file_system_host->SetVolumeSerialNumber(0);
return STATUS_SUCCESS;
}
int remote_winfsp_drive::mount(const std::vector<std::string> &drive_args) {
std::vector<std::string> parsed_drive_args;
const auto force_no_console = utils::collection_includes(drive_args, "-nc");
auto enable_console = false;
for (const auto &arg : drive_args) {
if (arg == "-f") {
if (not force_no_console) {
enable_console = true;
}
} else if (arg != "-nc") {
parsed_drive_args.emplace_back(arg);
}
}
logging_consumer l(config_.get_log_directory(), config_.get_event_level());
std::unique_ptr<console_consumer> c;
if (enable_console) {
c = std::make_unique<console_consumer>();
}
event_system::instance().start();
const auto ret = winfsp_service(lock_, *this, parsed_drive_args, config_).Run();
event_system::instance().raise<drive_mount_result>(std::to_string(ret));
event_system::instance().stop();
c.reset();
return static_cast<int>(ret);
}
NTSTATUS remote_winfsp_drive::Mounted(PVOID host) {
auto *file_system_host = reinterpret_cast<FileSystemHost *>(host);
remote_instance_ = factory_();
server_ = std::make_unique<server>(config_);
server_->start();
mount_location_ = utils::string::to_utf8(file_system_host->MountPoint());
lock_.set_mount_state(true, mount_location_, ::GetCurrentProcessId());
return remote_instance_->winfsp_mounted(file_system_host->MountPoint());
}
NTSTATUS remote_winfsp_drive::Open(PWSTR file_name, UINT32 create_options, UINT32 granted_access,
PVOID *file_node, PVOID *file_desc, OpenFileInfo *ofi) {
remote::file_info fi{};
std::string normalize_name;
const auto ret = remote_instance_->winfsp_open(file_name, create_options, granted_access,
file_desc, &fi, normalize_name);
if (ret == STATUS_SUCCESS) {
SetFileInfo(ofi->FileInfo, fi);
const auto filePath = utils::string::from_utf8(normalize_name);
wcsncpy(ofi->NormalizedName, &filePath[0], wcslen(&filePath[0]));
ofi->NormalizedNameSize = (UINT16)(wcslen(&filePath[0]) * sizeof(WCHAR));
}
return ret;
}
NTSTATUS remote_winfsp_drive::Overwrite(PVOID file_node, PVOID file_desc, UINT32 attributes,
BOOLEAN replace_attributes, UINT64 allocation_size,
FileInfo *file_info) {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_overwrite(file_desc, attributes, replace_attributes,
allocation_size, &fi);
SetFileInfo(*file_info, fi);
return ret;
}
void remote_winfsp_drive::PopulateFileInfo(const json &item, FSP_FSCTL_FILE_INFO &file_info) {
const auto di = directory_item::from_json(item);
file_info.FileSize = di.directory ? 0 : di.size;
file_info.AllocationSize =
utils::divide_with_ceiling(file_info.FileSize, WINFSP_ALLOCATION_UNIT) *
WINFSP_ALLOCATION_UNIT;
file_info.ChangeTime = utils::get_changed_time_from_meta(di.meta);
file_info.CreationTime = utils::get_creation_time_from_meta(di.meta);
file_info.FileAttributes = utils::get_attributes_from_meta(di.meta);
file_info.HardLinks = 0;
file_info.IndexNumber = 0;
file_info.LastAccessTime = utils::get_accessed_time_from_meta(di.meta);
file_info.LastWriteTime = utils::get_written_time_from_meta(di.meta);
file_info.ReparseTag = 0;
file_info.EaSize = 0;
}
NTSTATUS remote_winfsp_drive::Read(PVOID file_node, PVOID file_desc, PVOID buffer, UINT64 offset,
ULONG length, PULONG bytes_transferred) {
return remote_instance_->winfsp_read(file_desc, buffer, offset, length,
reinterpret_cast<PUINT32>(bytes_transferred));
}
NTSTATUS remote_winfsp_drive::ReadDirectory(PVOID file_node, PVOID file_desc, PWSTR pattern,
PWSTR marker, PVOID buffer, ULONG buffer_length,
PULONG bytes_transferred) {
json itemList;
NTSTATUS ret = remote_instance_->winfsp_read_directory(file_desc, pattern, marker, itemList);
if (ret == STATUS_SUCCESS) {
PVOID *directory_buffer = nullptr;
if ((ret = remote_instance_->winfsp_get_dir_buffer(file_desc, directory_buffer)) ==
STATUS_SUCCESS) {
if (FspFileSystemAcquireDirectoryBuffer(directory_buffer,
static_cast<BOOLEAN>(nullptr == marker), &ret)) {
auto item_found = false;
for (const auto &item : itemList) {
const auto item_path = item["path"].get<std::string>();
const auto display_name =
utils::string::from_utf8(utils::path::strip_to_file_name(item_path));
if (not marker || (marker && item_found)) {
if (not utils::path::is_ads_file_path(item_path)) {
union {
UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) +
((MAX_PATH + 1) * sizeof(WCHAR))];
FSP_FSCTL_DIR_INFO D;
} directory_info_buffer;
auto *directory_info = &directory_info_buffer.D;
::ZeroMemory(directory_info, sizeof(*directory_info));
directory_info->Size = static_cast<UINT16>(
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) +
(std::min((size_t)MAX_PATH, display_name.size()) * sizeof(WCHAR)));
if (not item["meta"].empty() || ((item_path != ".") && (item_path != ".."))) {
PopulateFileInfo(item, directory_info->FileInfo);
}
if (ret == STATUS_SUCCESS) {
::wcscpy_s(&directory_info->FileNameBuf[0], MAX_PATH, &display_name[0]);
FspFileSystemFillDirectoryBuffer(directory_buffer, directory_info, &ret);
if (ret != STATUS_SUCCESS) {
break;
}
}
}
} else {
item_found = display_name == std::wstring(marker);
}
}
FspFileSystemReleaseDirectoryBuffer(directory_buffer);
}
if ((ret == STATUS_SUCCESS) || (ret == STATUS_NO_MORE_FILES)) {
FspFileSystemReadDirectoryBuffer(directory_buffer, marker, buffer, buffer_length,
reinterpret_cast<PULONG>(bytes_transferred));
ret = STATUS_SUCCESS;
}
}
}
return ret;
}
NTSTATUS remote_winfsp_drive::Rename(PVOID file_node, PVOID file_desc, PWSTR file_name,
PWSTR new_file_name, BOOLEAN replace_if_exists) {
return remote_instance_->winfsp_rename(file_desc, file_name, new_file_name, replace_if_exists);
}
NTSTATUS remote_winfsp_drive::SetBasicInfo(PVOID file_node, PVOID file_desc, UINT32 attributes,
UINT64 creation_time, UINT64 last_access_time,
UINT64 last_write_time, UINT64 change_time,
FileInfo *file_info) {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_set_basic_info(
file_desc, attributes, creation_time, last_access_time, last_write_time, change_time, &fi);
SetFileInfo(*file_info, fi);
return ret;
}
void remote_winfsp_drive::SetFileInfo(FileInfo &dest, const remote::file_info &src) {
dest.FileAttributes = src.FileAttributes;
dest.ReparseTag = src.ReparseTag;
dest.AllocationSize = src.AllocationSize;
dest.FileSize = src.FileSize;
dest.CreationTime = src.CreationTime;
dest.LastAccessTime = src.LastAccessTime;
dest.LastWriteTime = src.LastWriteTime;
dest.ChangeTime = src.ChangeTime;
dest.IndexNumber = src.IndexNumber;
dest.HardLinks = src.HardLinks;
dest.EaSize = src.EaSize;
}
NTSTATUS remote_winfsp_drive::SetFileSize(PVOID file_node, PVOID file_desc, UINT64 new_size,
BOOLEAN set_allocation_size, FileInfo *file_info) {
remote::file_info fi{};
const auto ret =
remote_instance_->winfsp_set_file_size(file_desc, new_size, set_allocation_size, &fi);
SetFileInfo(*file_info, fi);
return ret;
}
VOID remote_winfsp_drive::Unmounted(PVOID host) {
server_->stop();
server_.reset();
auto *fileSystemHost = reinterpret_cast<FileSystemHost *>(host);
lock_.set_mount_state(false, "", -1);
remote_instance_->winfsp_unmounted(fileSystemHost->MountPoint());
remote_instance_.reset();
mount_location_ = "";
}
NTSTATUS remote_winfsp_drive::Write(PVOID file_node, PVOID file_desc, PVOID buffer, UINT64 offset,
ULONG length, BOOLEAN write_to_end, BOOLEAN constrained_io,
PULONG bytes_transferred, FileInfo *file_info) {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_write(
file_desc, buffer, offset, length, write_to_end, constrained_io,
reinterpret_cast<PUINT32>(bytes_transferred), &fi);
SetFileInfo(*file_info, fi);
return ret;
}
} // namespace repertory::remote_winfsp
#endif // _WIN32

File diff suppressed because it is too large Load Diff