2.0.0-rc (#9)
Some checks failed
BlockStorage/repertory_osx/pipeline/head This commit looks good
BlockStorage/repertory_windows/pipeline/head This commit looks good
BlockStorage/repertory/pipeline/head There was a failure building this commit
BlockStorage/repertory_linux_builds/pipeline/head This commit looks good
BlockStorage/repertory_osx_builds/pipeline/head There was a failure building this commit

### Issues

* \#1 \[bug\] Unable to mount S3 due to 'item_not_found' exception
* \#2 Require bucket name for S3 mounts
* \#3 \[bug\] File size is not being updated in S3 mount
* \#4 Upgrade to libfuse-3.x.x
* \#5 Switch to renterd for Sia support
* \#6 Switch to cpp-httplib to further reduce dependencies
* \#7 Remove global_data and calculate used disk space per provider
* \#8 Switch to libcurl for S3 mount support

### Changes from v1.x.x

* Added read-only encrypt provider
  * Pass-through mount point that transparently encrypts source data using `XChaCha20-Poly1305`
* Added S3 encryption support via `XChaCha20-Poly1305`
* Added replay protection to remote mounts
* Added support base64 writes in remote FUSE
* Created static linked Linux binaries for `amd64` and `aarch64` using `musl-libc`
* Removed legacy Sia renter support
* Removed Skynet support
* Fixed multiple remote mount WinFSP API issues on \*NIX servers
* Implemented chunked read and write
  * Writes for non-cached files are performed in chunks of 8Mib
* Removed `repertory-ui` support
* Removed `FreeBSD` support
* Switched to `libsodium` over `CryptoPP`
* Switched to `XChaCha20-Poly1305` for remote mounts
* Updated `GoogleTest` to v1.14.0
* Updated `JSON for Modern C++` to v3.11.2
* Updated `OpenSSL` to v1.1.1w
* Updated `RocksDB` to v8.5.3
* Updated `WinFSP` to 2023
* Updated `boost` to v1.78.0
* Updated `cURL` to v8.3.0
* Updated `zlib` to v1.3
* Use `upload_manager` for all providers
  * Adds a delay to uploads to prevent excessive API calls
  * Supports re-upload after mount restart for incomplete uploads
  * NOTE: Uploads for all providers are full file (no resume support)
    * Multipart upload support is planned for S3

Reviewed-on: #9
This commit is contained in:
2023-10-29 06:55:59 +00:00
parent 3ff46723b8
commit f43c41f88a
839 changed files with 98214 additions and 92959 deletions

View File

@ -1,63 +1,42 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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 "events/events.hpp"
#include "types/repertory.hpp"
namespace repertory {
bool directory_cache::execute_action(const std::string &api_path, const execute_callback &execute) {
auto found = false;
void directory_cache::execute_action(const std::string &api_path,
const execute_callback &execute) {
recur_mutex_lock directory_lock(directory_mutex_);
if ((found = (directory_lookup_.find(api_path) != directory_lookup_.end()))) {
if ((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) {
auto directory_cache::remove_directory(const std::string &api_path)
-> directory_iterator * {
directory_iterator *ret = nullptr;
recur_mutex_lock directory_lock(directory_mutex_);
@ -72,39 +51,42 @@ directory_iterator *directory_cache::remove_directory(const std::string &api_pat
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; });
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) {
void directory_cache::service_function() {
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 get_stop_requested()) {
unique_mutex_lock shutdown_lock(get_mutex());
if (not get_stop_requested()) {
get_notify().wait_for(shutdown_lock, 15s);
}
}
}
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

@ -1,53 +1,70 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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/error_utils.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) {
auto directory_iterator::fill_buffer(const remote::file_offset &offset,
fuse_fill_dir_t filler_function,
void *buffer,
populate_stat_callback populate_stat)
-> int {
if (offset < items_.size()) {
std::string item_name;
struct stat st {};
struct stat *pst = nullptr;
switch (offset) {
case 0: {
item_name = ".";
} break;
try {
std::string item_name;
struct stat st {};
struct stat *pst = nullptr;
switch (offset) {
case 0: {
item_name = ".";
} break;
case 1: {
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;
}
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;
#if FUSE_USE_VERSION >= 30
if (filler_function(buffer, &item_name[0], pst, offset + 1,
FUSE_FILL_DIR_PLUS) != 0) {
#else
if (filler_function(buffer, &item_name[0], pst, offset + 1) != 0) {
#endif
errno = ENOMEM;
return -1;
}
} catch (const std::exception &e) {
utils::error::raise_error(__FUNCTION__, e,
"failed to fill fuse directory buffer");
}
return 0;
@ -58,7 +75,7 @@ int directory_iterator::fill_buffer(const remote::file_offset &offset,
}
#endif // !_WIN32
int directory_iterator::get(const std::size_t &offset, std::string &item) {
auto directory_iterator::get(std::size_t offset, std::string &item) -> int {
if (offset < items_.size()) {
item = items_[offset].api_path;
return 0;
@ -68,7 +85,8 @@ int directory_iterator::get(const std::size_t &offset, std::string &item) {
return -1;
}
api_error directory_iterator::get_directory_item(const std::size_t &offset, directory_item &di) {
auto directory_iterator::get_directory_item(std::size_t offset,
directory_item &di) -> api_error {
if (offset < items_.size()) {
di = items_[offset];
return api_error::success;
@ -77,9 +95,12 @@ api_error directory_iterator::get_directory_item(const std::size_t &offset, dire
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; });
auto directory_iterator::get_directory_item(const std::string &api_path,
directory_item &di) -> api_error {
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;
@ -88,7 +109,7 @@ api_error directory_iterator::get_directory_item(const std::string &api_path, di
return api_error::item_not_found;
}
int directory_iterator::get_json(const std::size_t &offset, json &item) {
auto directory_iterator::get_json(std::size_t offset, json &item) -> int {
if (offset < items_.size()) {
item = items_[offset].to_json();
return 0;
@ -98,29 +119,35 @@ int directory_iterator::get_json(const std::size_t &offset, json &item) {
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;
});
auto directory_iterator::get_next_directory_offset(
const std::string &api_path) const -> std::size_t {
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);
return (it == items_.end())
? 0
: std::distance(items_.begin(), it) + std::size_t(1u);
}
directory_iterator &directory_iterator::operator=(const directory_iterator &iterator) noexcept {
auto directory_iterator::operator=(const directory_iterator &iterator) noexcept
-> directory_iterator & {
if (this != &iterator) {
items_ = iterator.items_;
}
return *this;
}
directory_iterator &directory_iterator::operator=(directory_iterator &&iterator) noexcept {
auto directory_iterator::operator=(directory_iterator &&iterator) noexcept
-> directory_iterator & {
if (this != &iterator) {
items_ = std::move(iterator.items_);
}
return *this;
}
directory_iterator &directory_iterator::operator=(directory_item_list list) noexcept {
auto directory_iterator::operator=(directory_item_list list) noexcept
-> directory_iterator & {
if (&items_ != &list) {
items_ = std::move(list);
}

View File

@ -1,108 +1,62 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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 "file_manager/i_file_manager.hpp"
#include "providers/i_provider.hpp"
#include "types/repertory.hpp"
#include "utils/error_utils.hpp"
#include "utils/file_utils.hpp"
#include "utils/global_data.hpp"
#include "utils/unix/unix_utils.hpp"
#include "utils/utils.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);
}
}
auto eviction::check_minimum_requirements(const std::string &file_path)
-> bool {
std::uint64_t file_size{};
if (not utils::file::get_file_size(file_path, file_size)) {
utils::error::raise_error(__FUNCTION__, utils::get_last_error_code(),
file_path, "failed to get file size");
return false;
}
}
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))) {
std::uint64_t reference_time{};
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);
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;
const auto delay =
(config_.get_eviction_delay_mins() * 60L) * NANOS_PER_SECOND;
ret = ((reference_time + delay) <= now);
#endif
}
@ -111,8 +65,9 @@ bool eviction::check_minimum_requirements(const std::string &file_path) {
return ret;
}
std::deque<std::string> eviction::get_filtered_cached_files() {
auto list = utils::file::get_directory_files(config_.get_cache_directory(), true);
auto eviction::get_filtered_cached_files() -> std::deque<std::string> {
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);
@ -121,25 +76,66 @@ std::deque<std::string> eviction::get_filtered_cached_files() {
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::service_function() {
auto should_evict = true;
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();
// Handle maximum cache size eviction
auto used_bytes =
utils::file::calculate_used_space(config_.get_cache_directory(), false);
if (config_.get_enable_max_cache_size()) {
should_evict = (used_bytes > config_.get_max_cache_size_bytes());
}
if (should_evict) {
// Remove cached source files that don't meet minimum requirements
auto cached_files_list = get_filtered_cached_files();
while (not get_stop_requested() && should_evict &&
not cached_files_list.empty()) {
try {
std::string api_path;
if (provider_.get_api_path_from_source(
cached_files_list.front(), api_path) == api_error::success) {
api_file file{};
filesystem_item fsi{};
if (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{};
if (utils::file::get_file_size(cached_files_list.front(),
file_size)) {
if (file_size == fsi.size) {
// Try to evict file
if (fm_.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());
}
}
} else {
utils::error::raise_api_path_error(
__FUNCTION__, file.api_path, file.source_path,
utils::get_last_error_code(), "failed to get file size");
}
}
}
} catch (const std::exception &ex) {
utils::error::raise_error(__FUNCTION__, ex,
"failed to process cached file|sp|" +
cached_files_list.front());
}
cached_files_list.pop_front();
}
}
if (not get_stop_requested()) {
unique_mutex_lock lock(get_mutex());
if (not get_stop_requested()) {
get_notify().wait_for(lock, 30s);
}
eviction_thread_->join();
eviction_thread_.reset();
}
}
} // namespace repertory

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,353 @@
/*
Copyright <2018-2023> <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_drive_base.hpp"
#include "providers/i_provider.hpp"
namespace repertory {
auto fuse_drive_base::access_impl(std::string api_path, int mask) -> api_error {
return check_access(api_path, mask);
}
auto fuse_drive_base::check_access(const std::string &api_path, int mask) const
-> api_error {
api_meta_map meta;
const auto res = get_item_meta(api_path, meta);
if (res != api_error::success) {
return res;
}
// Always allow root
auto current_uid = get_current_uid();
if (current_uid != 0) {
// Always allow forced user
if (not forced_uid_.has_value() || (current_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 (current_uid == effective_uid) {
active_mask |= S_IRWXU;
}
if (get_current_gid() == effective_gid) {
active_mask |= S_IRWXG;
}
if (utils::is_uid_member_of_group(current_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;
}
auto fuse_drive_base::check_and_perform(
const std::string &api_path, int parent_mask,
const std::function<api_error(api_meta_map &meta)> &action) -> api_error {
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);
}
auto fuse_drive_base::check_open_flags(int flags, int mask,
const api_error &fail_error)
-> api_error {
return ((flags & mask) ? fail_error : api_error::success);
}
auto fuse_drive_base::check_owner(const std::string &api_path) const
-> api_error {
api_meta_map meta{};
auto ret = get_item_meta(api_path, meta);
if (ret == api_error::success) {
ret = check_owner(meta);
}
return ret;
}
auto fuse_drive_base::check_owner(const api_meta_map &meta) const -> api_error {
// Always allow root
auto current_uid = get_current_uid();
if ((current_uid != 0) &&
// Always allow forced UID
(not forced_uid_.has_value() || (current_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;
}
auto fuse_drive_base::check_parent_access(const std::string &api_path,
int mask) const -> api_error {
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;
}
auto fuse_drive_base::check_readable(int flags, const api_error &fail_error)
-> api_error {
const auto mode = (flags & O_ACCMODE);
return ((mode == O_WRONLY) ? fail_error : api_error::success);
}
auto fuse_drive_base::check_writeable(int flags, const api_error &fail_error)
-> api_error {
return ((flags & O_ACCMODE) ? api_error::success : fail_error);
}
auto fuse_drive_base::get_current_gid() const -> gid_t {
auto *ctx = fuse_get_context();
return ctx ? ctx->gid : getgid();
}
auto fuse_drive_base::get_current_uid() const -> uid_t {
auto *ctx = fuse_get_context();
return ctx ? ctx->uid : getuid();
}
auto fuse_drive_base::get_effective_gid() const -> gid_t {
return forced_gid_.has_value() ? forced_gid_.value() : get_current_gid();
}
auto fuse_drive_base::get_effective_uid() const -> uid_t {
return forced_uid_.has_value() ? forced_uid_.value() : get_current_uid();
}
#ifdef __APPLE__
auto fuse_drive_base::get_flags_from_meta(const api_meta_map &meta)
-> __uint32_t {
return utils::string::to_uint32(meta.at(META_OSXFLAGS));
}
#endif // __APPLE__
auto fuse_drive_base::get_gid_from_meta(const api_meta_map &meta) -> gid_t {
return static_cast<gid_t>(utils::string::to_uint32(meta.at(META_GID)));
}
auto fuse_drive_base::get_mode_from_meta(const api_meta_map &meta) -> mode_t {
return static_cast<mode_t>(utils::string::to_uint32(meta.at(META_MODE)));
}
void fuse_drive_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;
}
auto fuse_drive_base::get_uid_from_meta(const api_meta_map &meta) -> uid_t {
return static_cast<uid_t>(utils::string::to_uint32(meta.at(META_UID)));
}
#ifdef __APPLE__
auto fuse_drive_base::parse_xattr_parameters(const char *name,
const uint32_t &position,
std::string &attribute_name,
const std::string &api_path)
-> api_error {
#else
auto fuse_drive_base::parse_xattr_parameters(const char *name,
std::string &attribute_name,
const std::string &api_path)
-> api_error {
#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::invalid_operation;
}
#endif
return api_error::success;
}
#ifdef __APPLE__
auto fuse_drive_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) -> api_error {
auto res = parse_xattr_parameters(name, position, attribute_name, api_path);
#else
auto fuse_drive_base::parse_xattr_parameters(const char *name,
const char *value, size_t size,
std::string &attribute_name,
const std::string &api_path)
-> api_error {
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_drive_base::populate_stat(const std::string &api_path,
std::uint64_t size_or_count,
const api_meta_map &meta, 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 block_size_stat = static_cast<std::uint64_t>(512u);
static const auto block_size = static_cast<std::uint64_t>(4096u);
const auto size = utils::divide_with_ceiling(
static_cast<std::uint64_t>(st->st_size), block_size) *
block_size;
st->st_blocks = std::max(block_size / block_size_stat,
utils::divide_with_ceiling(size, block_size_stat));
}
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_drive_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;
}
} // namespace repertory
#endif // _WIN32

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,258 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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 "events/events.hpp"
#include "platform/platform.hpp"
#include "rpc/server/server.hpp"
#include "types/remote.hpp"
#include "utils/error_utils.hpp"
#include "utils/file_utils.hpp"
#include "utils/path_utils.hpp"
#include "utils/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_;
auto remote_fuse_drive::access_impl(std::string api_path, int mask)
-> api_error {
return utils::to_api_error(
remote_instance_->fuse_access(api_path.c_str(), mask));
}
void remote_fuse_drive::remote_fuse_impl::tear_down(const int &ret) {
#ifdef __APPLE__
api_error remote_fuse_drive::chflags_impl(std::string api_path,
uint32_t flags) {
return utils::to_api_error(
remote_instance_->fuse_chflags(api_path.c_str(), flags));
}
#endif // __APPLE__
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode,
struct fuse_file_info * /*fi*/)
-> api_error {
#else
auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode)
-> api_error {
#endif
return utils::to_api_error(
remote_instance_->fuse_chmod(api_path.c_str(), mode));
}
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
struct fuse_file_info * /*fi*/)
-> api_error {
#else
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
-> api_error {
#endif
return utils::to_api_error(
remote_instance_->fuse_chown(api_path.c_str(), uid, gid));
}
auto remote_fuse_drive::create_impl(std::string api_path, mode_t mode,
struct fuse_file_info *fi) -> api_error {
return utils::to_api_error(remote_instance_->fuse_create(
api_path.c_str(), mode, remote::create_open_flags(fi->flags), fi->fh));
}
void remote_fuse_drive::destroy_impl(void * /*ptr*/) {
event_system::instance().raise<drive_unmount_pending>(get_mount_location());
if (server_) {
server_->stop();
server_.reset();
}
if (remote_instance_) {
const auto res = remote_instance_->fuse_destroy();
if (res != 0) {
utils::error::raise_error(__FUNCTION__,
"remote fuse_destroy() failed|err|" +
std::to_string(res));
}
remote_instance_.reset();
}
if (not lock_data_.set_mount_state(false, "", -1)) {
utils::error::raise_error(__FUNCTION__, "failed to set mount state");
}
event_system::instance().raise<drive_unmounted>(get_mount_location());
}
auto remote_fuse_drive::fgetattr_impl(std::string api_path, struct stat *st,
struct fuse_file_info *fi) -> api_error {
remote::stat r{};
auto directory = false;
const auto res =
remote_instance_->fuse_fgetattr(api_path.c_str(), r, directory, fi->fh);
if (res == 0) {
populate_stat(r, directory, *st);
}
return utils::to_api_error(res);
}
#ifdef __APPLE__
api_error remote_fuse_drive::fsetattr_x_impl(std::string api_path,
struct setattr_x *attr,
struct fuse_file_info *fi) {
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 utils::to_api_error(
remote_instance_->fuse_fsetattr_x(api_path.c_str(), attributes, fi->fh));
}
#endif
auto remote_fuse_drive::fsync_impl(std::string api_path, int datasync,
struct fuse_file_info *fi) -> api_error {
return utils::to_api_error(
remote_instance_->fuse_fsync(api_path.c_str(), datasync, fi->fh));
}
#if FUSE_USE_VERSION < 30
auto remote_fuse_drive::ftruncate_impl(std::string api_path, off_t size,
struct fuse_file_info *fi) -> api_error {
return utils::to_api_error(
remote_instance_->fuse_ftruncate(api_path.c_str(), size, fi->fh));
}
#endif
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *st,
struct fuse_file_info * /*fi*/)
-> api_error {
#else
auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *st)
-> api_error {
#endif
bool directory = false;
remote::stat r{};
const auto res =
remote_instance_->fuse_getattr(api_path.c_str(), r, directory);
if (res == 0) {
populate_stat(r, directory, *st);
}
return utils::to_api_error(res);
}
#ifdef __APPLE__
api_error remote_fuse_drive::getxtimes_impl(std::string api_path,
struct timespec *bkuptime,
struct timespec *crtime) {
if (not(bkuptime && crtime)) {
return utils::to_api_error(-EFAULT);
}
remote::file_time repertory_bkuptime = 0u;
remote::file_time repertory_crtime = 0u;
const auto res = remote_instance_->fuse_getxtimes(
api_path.c_str(), repertory_bkuptime, repertory_crtime);
if (res == 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 utils::to_api_error(res);
}
#endif // __APPLE__
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn,
struct fuse_config *cfg) -> void * {
#else
auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * {
#endif
utils::file::change_to_process_directory();
was_mounted_ = true;
if (console_enabled_) {
console_consumer_ = std::make_shared<console_consumer>();
}
logging_consumer_ = std::make_shared<logging_consumer>(
config_.get_log_directory(), config_.get_event_level());
event_system::instance().start();
if (not lock_data_.set_mount_state(true, get_mount_location(), getpid())) {
utils::error::raise_error(__FUNCTION__, "failed to set mount state");
}
remote_instance_ = factory_();
remote_instance_->set_fuse_uid_gid(getuid(), getgid());
if (remote_instance_->fuse_init() != 0) {
utils::error::raise_error(__FUNCTION__,
"failed to connect to remote server");
event_system::instance().raise<unmount_requested>();
} else {
server_ = std::make_shared<server>(config_);
server_->start();
event_system::instance().raise<drive_mounted>(get_mount_location());
}
#if FUSE_USE_VERSION >= 30
return fuse_base::init_impl(conn, cfg);
#else
return fuse_base::init_impl(conn);
#endif
}
auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode)
-> api_error {
return utils::to_api_error(
remote_instance_->fuse_mkdir(api_path.c_str(), mode));
}
void remote_fuse_drive::notify_fuse_main_exit(int &ret) {
if (was_mounted_) {
event_system::instance().raise<drive_mount_result>(std::to_string(ret));
event_system::instance().stop();
@ -55,8 +261,21 @@ void remote_fuse_drive::remote_fuse_impl::tear_down(const int &ret) {
}
}
void remote_fuse_drive::remote_fuse_impl::populate_stat(const remote::stat &r,
const bool &directory, struct stat &st) {
auto remote_fuse_drive::open_impl(std::string api_path,
struct fuse_file_info *fi) -> api_error {
return utils::to_api_error(remote_instance_->fuse_open(
api_path.c_str(), remote::create_open_flags(fi->flags), fi->fh));
}
auto remote_fuse_drive::opendir_impl(std::string api_path,
struct fuse_file_info *fi) -> api_error {
return utils::to_api_error(
remote_instance_->fuse_opendir(api_path.c_str(), fi->fh));
}
void remote_fuse_drive::populate_stat(const remote::stat &r, bool directory,
struct stat &st) {
memset(&st, 0, sizeof(struct stat));
#ifdef __APPLE__
@ -88,12 +307,13 @@ void remote_fuse_drive::remote_fuse_impl::populate_stat(const remote::stat &r,
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));
const auto block_size_stat = static_cast<std::uint64_t>(512u);
const auto block_size = static_cast<std::uint64_t>(4096u);
const auto size = utils::divide_with_ceiling(
static_cast<std::uint64_t>(st.st_size), block_size) *
block_size;
st.st_blocks = std::max(block_size / block_size_stat,
utils::divide_with_ceiling(size, block_size_stat));
}
st.st_gid = r.st_gid;
@ -104,316 +324,168 @@ void remote_fuse_drive::remote_fuse_impl::populate_stat(const remote::stat &r,
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);
auto remote_fuse_drive::read_impl(std::string api_path, char *buffer,
size_t read_size, off_t read_offset,
struct fuse_file_info *fi,
std::size_t &bytes_read) -> api_error {
auto res = remote_instance_->fuse_read(api_path.c_str(), buffer, read_size,
read_offset, fi->fh);
if (res >= 0) {
bytes_read = res;
return api_error::success;
}
return utils::to_api_error(res);
}
#ifdef __APPLE__
int remote_fuse_drive::remote_fuse_impl::repertory_chflags(const char *path, uint32_t flags) {
return remote_instance_->fuse_chflags(path, flags);
}
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
fuse_fill_dir_t fuse_fill_dir,
off_t offset, struct fuse_file_info *fi,
fuse_readdir_flags /*flags*/)
-> api_error {
#else
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
fuse_fill_dir_t fuse_fill_dir,
off_t offset, struct fuse_file_info *fi)
-> api_error {
#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) {
int res = 0;
while ((res = remote_instance_->fuse_readdir(api_path.c_str(), 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) {
#if FUSE_USE_VERSION >= 30
if (fuse_fill_dir(buf, item_path.c_str(), nullptr, ++offset,
static_cast<fuse_fill_dir_flags>(0)) != 0) {
#else
if (fuse_fill_dir(buf, item_path.c_str(), nullptr, ++offset) != 0) {
#endif
break;
}
}
if (ret == -120) {
ret = 0;
if (res == -120) {
res = 0;
}
return ret;
return utils::to_api_error(res);
}
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);
auto remote_fuse_drive::release_impl(std::string api_path,
struct fuse_file_info *fi) -> api_error {
return utils::to_api_error(
remote_instance_->fuse_release(api_path.c_str(), 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);
auto remote_fuse_drive::releasedir_impl(std::string api_path,
struct fuse_file_info *fi)
-> api_error {
return utils::to_api_error(
remote_instance_->fuse_releasedir(api_path.c_str(), 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);
}
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::rename_impl(std::string from_api_path,
std::string to_api_path,
unsigned int /*flags*/) -> api_error {
#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);
}
auto remote_fuse_drive::rename_impl(std::string from_api_path,
std::string to_api_path) -> api_error {
#endif
return utils::to_api_error(remote_instance_->fuse_rename(
from_api_path.c_str(), to_api_path.c_str()));
}
#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);
}
auto remote_fuse_drive::rmdir_impl(std::string api_path) -> api_error {
return utils::to_api_error(remote_instance_->fuse_rmdir(api_path.c_str()));
}
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) {
api_error remote_fuse_drive::setattr_x_impl(std::string api_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.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);
return utils::to_api_error(
remote_instance_->fuse_setattr_x(api_path.c_str(), attributes));
}
int remote_fuse_drive::remote_fuse_impl::repertory_setbkuptime(const char *path,
const struct timespec *bkuptime) {
api_error remote_fuse_drive::setbkuptime_impl(std::string api_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);
return utils::to_api_error(
remote_instance_->fuse_setbkuptime(api_path.c_str(), 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);
api_error remote_fuse_drive::setchgtime_impl(std::string api_path,
const struct timespec *chgtime) {
remote::file_time repertory_chgtime =
((chgtime->tv_sec * NANOS_PER_SECOND) + chgtime->tv_nsec);
return utils::to_api_error(
remote_instance_->fuse_setchgtime(api_path.c_str(), 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);
api_error remote_fuse_drive::setcrtime_impl(std::string api_path,
const struct timespec *crtime) {
remote::file_time repertory_crtime =
((crtime->tv_sec * NANOS_PER_SECOND) + crtime->tv_nsec);
return utils::to_api_error(
remote_instance_->fuse_setcrtime(api_path.c_str(), repertory_crtime));
}
int remote_fuse_drive::remote_fuse_impl::repertory_setvolname(const char *volname) {
return remote_instance_->fuse_setvolname(volname);
api_error remote_fuse_drive::setvolname_impl(const char *volname) {
return utils::to_api_error(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) {
api_error remote_fuse_drive::statfs_x_impl(std::string api_path,
struct statfs *stbuf) {
auto res = statfs(config_.get_data_directory().c_str(), stbuf);
if (res == 0) {
remote::statfs_x r{};
if ((ret = remote_instance_->fuse_statfs_x(path, stbuf->f_bsize, r)) == 0) {
if ((res = remote_instance_->fuse_statfs_x(api_path.c_str(), 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);
strncpy(&stbuf->f_mntonname[0u], get_mount_location().c_str(), MNAMELEN);
strncpy(&stbuf->f_mntfromname[0u], &r.f_mntfromname[0], MNAMELEN);
}
} else {
ret = -errno;
res = -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) {
return utils::to_api_error(res);
}
#else // __APPLE__
auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf)
-> api_error {
auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
if (res == 0) {
remote::statfs r{};
if ((ret = remote_instance_->fuse_statfs(path, stbuf->f_frsize, r)) == 0) {
if ((res = remote_instance_->fuse_statfs(api_path.c_str(), stbuf->f_frsize,
r)) == 0) {
stbuf->f_blocks = r.f_blocks;
stbuf->f_bavail = r.f_bavail;
stbuf->f_bfree = r.f_bfree;
@ -422,195 +494,61 @@ int remote_fuse_drive::remote_fuse_impl::repertory_statfs(const char *path, stru
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;
}
}
}
}
}
res = -errno;
}
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;
return utils::to_api_error(res);
}
#endif // __APPLE__
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";
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size,
struct fuse_file_info * /*fi*/)
-> api_error {
#else
const auto unmount = "fusermount -u \"" + mount_location + "\" >/dev/null 2>&1";
auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size)
-> api_error {
#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);
}
return utils::to_api_error(
remote_instance_->fuse_truncate(api_path.c_str(), size));
}
auto remote_fuse_drive::unlink_impl(std::string api_path) -> api_error {
return utils::to_api_error(remote_instance_->fuse_unlink(api_path.c_str()));
}
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::utimens_impl(std::string api_path,
const struct timespec tv[2],
struct fuse_file_info * /*fi*/)
-> api_error {
#else
auto remote_fuse_drive::utimens_impl(std::string api_path,
const struct timespec tv[2]) -> api_error {
#endif
remote::file_time rtv[2u] = {0};
if (tv) {
rtv[0u] = tv[0u].tv_nsec + (tv[0u].tv_sec * NANOS_PER_SECOND);
rtv[1u] = tv[1u].tv_nsec + (tv[1u].tv_sec * NANOS_PER_SECOND);
}
if (ret != 0) {
ret = kill(getpid(), SIGINT);
return utils::to_api_error(remote_instance_->fuse_utimens(
api_path.c_str(), rtv, tv ? tv[0u].tv_nsec : 0u,
tv ? tv[1u].tv_nsec : 0u));
}
auto remote_fuse_drive::write_impl(std::string api_path, const char *buffer,
size_t write_size, off_t write_offset,
struct fuse_file_info *fi,
std::size_t &bytes_written) -> api_error {
const auto res = remote_instance_->fuse_write(
api_path.c_str(), buffer, write_size, write_offset, fi->fh);
if (res >= 0) {
bytes_written = res;
return api_error::success;
}
event_system::instance().raise<unmount_result>(mount_location, std::to_string(ret));
return utils::to_api_error(res);
}
} // namespace repertory::remote_fuse

View File

@ -1,51 +0,0 @@
/*
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

@ -1,27 +1,34 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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 "events/event_system.hpp"
#include "events/events.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_);
void remote_open_file_table::add_directory(const std::string &client_id,
void *dir) {
recur_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);
@ -29,16 +36,16 @@ void remote_open_file_table::add_directory(const std::string &client_id, void *d
}
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_);
std::vector<remote::file_handle> compat_handles;
unique_recur_mutex_lock compat_lock(compat_mutex_);
for (auto &kv : compat_lookup_) {
if (kv.second.client_id == client_id) {
compatHandles.emplace_back(kv.first);
compat_handles.emplace_back(kv.first);
}
}
compat_lock.unlock();
for (auto &handle : compatHandles) {
for (auto &handle : compat_handles) {
#ifdef _WIN32
_close(static_cast<int>(handle));
#else
@ -47,8 +54,8 @@ void remote_open_file_table::close_all(const std::string &client_id) {
remove_compat_open_info(handle);
}
std::vector<OSHandle> handles;
unique_mutex_lock file_lock(file_mutex_);
std::vector<native_handle> handles;
unique_recur_mutex_lock file_lock(file_mutex_);
for (auto &kv : file_lookup_) {
if (kv.second.client_id == client_id) {
handles.emplace_back(kv.first);
@ -66,7 +73,7 @@ void remote_open_file_table::close_all(const std::string &client_id) {
}
std::vector<void *> dirs;
unique_mutex_lock directory_lock(directory_mutex_);
unique_recur_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());
@ -80,8 +87,9 @@ void remote_open_file_table::close_all(const std::string &client_id) {
}
#ifdef _WIN32
bool remote_open_file_table::get_directory_buffer(const OSHandle &handle, PVOID *&buffer) {
mutex_lock file_lock(file_mutex_);
auto remote_open_file_table::get_directory_buffer(const native_handle &handle,
PVOID *&buffer) -> bool {
recur_mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) != file_lookup_.end()) {
buffer = &file_lookup_[handle].directory_buffer;
return true;
@ -90,8 +98,31 @@ bool remote_open_file_table::get_directory_buffer(const OSHandle &handle, PVOID
}
#endif
bool remote_open_file_table::get_open_info(const OSHandle &handle, open_info &oi) {
mutex_lock file_lock(file_mutex_);
auto remote_open_file_table::get_open_file_count(
const std::string &file_path) const -> std::size_t {
unique_recur_mutex_lock file_lock(file_mutex_);
const auto count = std::accumulate(
file_lookup_.cbegin(), file_lookup_.cend(), std::size_t(0U),
[&file_path](std::size_t total, const auto &kv) -> std::size_t {
if (kv.second.path == file_path) {
return ++total;
}
return total;
});
return std::accumulate(
compat_lookup_.cbegin(), compat_lookup_.cend(), count,
[&file_path](std::size_t total, const auto &kv) -> std::size_t {
if (kv.second.path == file_path) {
return ++total;
}
return total;
});
}
auto remote_open_file_table::get_open_info(const native_handle &handle,
open_info &oi) -> bool {
recur_mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) != file_lookup_.end()) {
oi = file_lookup_[handle];
return true;
@ -99,8 +130,9 @@ bool remote_open_file_table::get_open_info(const OSHandle &handle, open_info &oi
return false;
}
std::string remote_open_file_table::get_open_file_path(const OSHandle &handle) {
mutex_lock file_lock(file_mutex_);
auto remote_open_file_table::get_open_file_path(const native_handle &handle)
-> std::string {
recur_mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) != file_lookup_.end()) {
return file_lookup_[handle].path;
}
@ -108,34 +140,72 @@ std::string remote_open_file_table::get_open_file_path(const OSHandle &handle) {
return "";
}
bool remote_open_file_table::has_open_directory(const std::string &client_id, void *dir) {
unique_mutex_lock directory_lock(directory_mutex_);
auto remote_open_file_table::has_open_directory(const std::string &client_id,
void *dir) -> bool {
recur_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);
auto remote_open_file_table::has_compat_open_info(
const remote::file_handle &handle, int error_return) -> int {
recur_mutex_lock compat_lock(compat_mutex_);
const auto res =
((compat_lookup_.find(handle) == compat_lookup_.end()) ? -1 : 0);
if (res == -1) {
errno = errorReturn;
errno = error_return;
}
return res;
}
void remote_open_file_table::remove_compat_open_info(const remote::file_handle &handle) {
mutex_lock compat_lock(compat_mutex_);
void remote_open_file_table::remove_all(const std::string &file_path) {
unique_recur_mutex_lock file_lock(file_mutex_);
const auto open_list = std::accumulate(
file_lookup_.begin(), file_lookup_.end(), std::vector<native_handle>(),
[&file_path](std::vector<native_handle> v,
const auto &kv) -> std::vector<native_handle> {
if (kv.second.path == file_path) {
v.emplace_back(kv.first);
}
return v;
});
const auto compat_open_list = std::accumulate(
compat_lookup_.begin(), compat_lookup_.end(),
std::vector<remote::file_handle>(),
[&file_path](std::vector<remote::file_handle> v,
const auto &kv) -> std::vector<remote::file_handle> {
if (kv.second.path == file_path) {
v.emplace_back(kv.first);
}
return v;
});
file_lock.unlock();
for (auto &handle : open_list) {
remove_open_info(handle);
}
for (auto &handle : compat_open_list) {
remove_compat_open_info(handle);
}
}
void remote_open_file_table::remove_compat_open_info(
const remote::file_handle &handle) {
recur_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 remote_open_file_table::remove_directory(const std::string &client_id,
void *dir) -> bool {
recur_mutex_lock directory_lock(directory_mutex_);
auto &list = directory_lookup_[client_id];
if (utils::collection_includes(list, dir)) {
utils::remove_element_from(list, dir);
@ -148,42 +218,46 @@ bool remote_open_file_table::remove_directory(const std::string &client_id, void
return false;
}
void remote_open_file_table::remove_open_info(const OSHandle &handle) {
mutex_lock file_lock(file_mutex_);
void remote_open_file_table::remove_open_info(const native_handle &handle) {
recur_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);
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_);
void remote_open_file_table::set_compat_client_id(
const remote::file_handle &handle, const std::string &client_id) {
recur_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_);
void remote_open_file_table::set_client_id(const native_handle &handle,
const std::string &client_id) {
recur_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_);
void remote_open_file_table::set_compat_open_info(
const remote::file_handle &handle, const std::string &file_path) {
recur_mutex_lock compat_lock(compat_mutex_);
if (compat_lookup_.find(handle) == compat_lookup_.end()) {
compat_lookup_[handle] = {0, ""};
compat_lookup_[handle] = {0, "", file_path};
}
compat_lookup_[handle].count++;
}
void remote_open_file_table::set_open_info(const OSHandle &handle, open_info oi) {
mutex_lock file_lock(file_mutex_);
void remote_open_file_table::set_open_info(const native_handle &handle,
open_info oi) {
recur_mutex_lock file_lock(file_mutex_);
if (file_lookup_.find(handle) == file_lookup_.end()) {
file_lookup_[handle] = std::move(oi);
}

View File

@ -1,52 +1,59 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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 "events/events.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))) \
#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,
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_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) {
auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
-> packet::error_type {
packet request;
request.encode(file_desc);
request.encode(file_name);
@ -54,18 +61,21 @@ packet::error_type remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_
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);
__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) {
auto remote_client::json_create_directory_snapshot(const std::string &path,
json &json_data)
-> packet::error_type {
packet request;
request.encode(path);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
auto ret =
packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = packet::decode_json(response, json_data);
}
@ -74,10 +84,9 @@ packet::error_type remote_client::json_create_directory_snapshot(const std::stri
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) {
auto remote_client::json_read_directory_snapshot(
const std::string &path, const remote::file_handle &handle,
std::uint32_t page, json &json_data) -> packet::error_type {
packet request;
request.encode(path);
request.encode(handle);
@ -85,7 +94,8 @@ packet::error_type remote_client::json_read_directory_snapshot(const std::string
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
auto ret =
packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == 0) {
ret = packet::decode_json(response, json_data);
}
@ -94,9 +104,9 @@ packet::error_type remote_client::json_read_directory_snapshot(const std::string
return ret;
}
packet::error_type
remote_client::json_release_directory_snapshot(const std::string &path,
const remote::file_handle &handle) {
auto remote_client::json_release_directory_snapshot(
const std::string &path, const remote::file_handle &handle)
-> packet::error_type {
packet request;
request.encode(path);
request.encode(handle);
@ -108,9 +118,11 @@ remote_client::json_release_directory_snapshot(const std::string &path,
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));
auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name,
UINT32 flags, BOOLEAN &was_closed)
-> packet::error_type {
auto handle = to_handle(file_desc);
const auto file_path = get_open_file_path(handle);
was_closed = 0;
packet request;
@ -120,35 +132,41 @@ packet::error_type remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_nam
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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));
remove_all(file_path);
}
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));
auto remote_client::winfsp_close(PVOID file_desc) -> packet::error_type {
auto handle = to_handle(file_desc);
if (has_open_info(handle, STATUS_INVALID_HANDLE) == STATUS_SUCCESS) {
const auto file_path = get_open_file_path(handle);
packet request;
request.encode(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));
std::uint32_t service_flags = 0u;
const auto ret = packet_client_.send(__FUNCTION__, request, service_flags);
if ((ret == STATUS_SUCCESS) || (ret == STATUS_INVALID_HANDLE)) {
remove_open_info(handle);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, file_path, ret);
}
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, file_path, ret);
return ret;
return 0;
}
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) {
auto 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::error_type {
packet request;
request.encode(file_name);
request.encode(create_options);
@ -158,7 +176,8 @@ packet::error_type remote_client::winfsp_create(PWSTR file_name, UINT32 create_o
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
auto ret =
packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == STATUS_SUCCESS) {
HANDLE handle;
DECODE_OR_IGNORE(&response, handle);
@ -167,8 +186,9 @@ packet::error_type remote_client::winfsp_create(PWSTR file_name, UINT32 create_o
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)});
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);
@ -177,57 +197,70 @@ packet::error_type remote_client::winfsp_create(PWSTR file_name, UINT32 create_o
}
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, get_open_file_path(to_handle(*file_desc)), ret);
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) {
auto remote_client::winfsp_flush(PVOID file_desc, remote::file_info *file_info)
-> packet::error_type {
packet request;
request.encode(file_desc);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
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) {
auto remote_client::winfsp_get_dir_buffer([[maybe_unused]] PVOID file_desc,
[[maybe_unused]] PVOID *&ptr)
-> packet::error_type {
#ifdef _WIN32
if (get_directory_buffer(reinterpret_cast<OSHandle>(file_desc), ptr)) {
if (get_directory_buffer(reinterpret_cast<native_handle>(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) {
auto remote_client::winfsp_get_file_info(PVOID file_desc,
remote::file_info *file_info)
-> packet::error_type {
packet request;
request.encode(file_desc);
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
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) {
auto remote_client::winfsp_get_security_by_name(PWSTR file_name,
PUINT32 attributes,
std::uint64_t *descriptor_size,
std::wstring &string_descriptor)
-> packet::error_type {
packet request;
request.encode(file_name);
request.encode(static_cast<std::uint64_t>(descriptor_size ? *descriptor_size : 0));
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);
auto ret =
packet_client_.send(__FUNCTION__, request, response, service_flags);
string_descriptor.clear();
DECODE_OR_IGNORE(&response, string_descriptor);
@ -239,16 +272,20 @@ packet::error_type remote_client::winfsp_get_security_by_name(PWSTR file_name, P
DECODE_OR_IGNORE(&response, *attributes);
}
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, utils::string::to_utf8(file_name), ret);
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) {
auto remote_client::winfsp_get_volume_info(UINT64 &total_size,
UINT64 &free_size,
std::string &volume_label)
-> packet::error_type {
packet request;
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
@ -256,24 +293,26 @@ packet::error_type remote_client::winfsp_get_volume_info(UINT64 &total_size, UIN
return ret;
}
packet::error_type remote_client::winfsp_mounted(const std::wstring &location) {
auto remote_client::winfsp_mounted(const std::wstring &location)
-> packet::error_type {
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);
const auto mount_location = utils::string::to_utf8(location);
event_system::instance().raise<drive_mounted>(mount_location);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, mountLocation, ret);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(__FUNCTION__, mount_location, 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) {
auto 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::error_type {
packet request;
request.encode(file_name);
request.encode(create_options);
@ -281,7 +320,8 @@ packet::error_type remote_client::winfsp_open(PWSTR file_name, UINT32 create_opt
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
auto ret =
packet_client_.send(__FUNCTION__, request, response, service_flags);
if (ret == STATUS_SUCCESS) {
HANDLE handle;
DECODE_OR_IGNORE(&response, handle);
@ -290,19 +330,22 @@ packet::error_type remote_client::winfsp_open(PWSTR file_name, UINT32 create_opt
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)});
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);
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) {
auto remote_client::winfsp_overwrite(PVOID file_desc, UINT32 attributes,
BOOLEAN replace_attributes,
UINT64 allocation_size,
remote::file_info *file_info)
-> packet::error_type {
packet request;
request.encode(file_desc);
request.encode(attributes);
@ -311,15 +354,18 @@ packet::error_type remote_client::winfsp_overwrite(PVOID file_desc, UINT32 attri
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
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) {
auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
UINT32 length, PUINT32 bytes_transferred)
-> packet::error_type {
packet request;
request.encode(file_desc);
request.encode(offset);
@ -327,26 +373,30 @@ packet::error_type remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UIN
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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))) {
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);
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) {
auto remote_client::winfsp_read_directory(PVOID file_desc, PWSTR pattern,
PWSTR marker, json &item_list)
-> packet::error_type {
packet request;
request.encode(file_desc);
request.encode(pattern);
@ -354,17 +404,21 @@ packet::error_type remote_client::winfsp_read_directory(PVOID file_desc, PWSTR p
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
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) {
auto remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name,
PWSTR new_file_name,
BOOLEAN replace_if_exists)
-> packet::error_type {
packet request;
request.encode(file_desc);
request.encode(file_name);
@ -381,11 +435,10 @@ packet::error_type remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name
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) {
auto 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::error_type {
packet request;
request.encode(file_desc);
request.encode(attributes);
@ -396,16 +449,19 @@ packet::error_type remote_client::winfsp_set_basic_info(PVOID file_desc, UINT32
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
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) {
auto remote_client::winfsp_set_file_size(PVOID file_desc, UINT64 new_size,
BOOLEAN set_allocation_size,
remote::file_info *file_info)
-> packet::error_type {
packet request;
request.encode(file_desc);
request.encode(new_size);
@ -413,14 +469,17 @@ packet::error_type remote_client::winfsp_set_file_size(PVOID file_desc, UINT64 n
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
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) {
auto remote_client::winfsp_unmounted(const std::wstring &location)
-> packet::error_type {
const auto mount_location = utils::string::to_utf8(location);
event_system::instance().raise<drive_unmount_pending>(mount_location);
packet request;
@ -434,10 +493,12 @@ packet::error_type remote_client::winfsp_unmounted(const std::wstring &location)
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) {
auto 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::error_type {
packet request;
request.encode(file_desc);
request.encode(length);
@ -450,13 +511,21 @@ packet::error_type remote_client::winfsp_write(PVOID file_desc, PVOID buffer, UI
packet response;
std::uint32_t service_flags = 0u;
auto ret = packet_client_.send(__FUNCTION__, request, response, service_flags);
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);
RAISE_REMOTE_WINFSP_CLIENT_EVENT(
__FUNCTION__, get_open_file_path(to_handle(file_desc)), ret);
}
return ret;
}
#ifndef _WIN32
native_handle remote_client::to_handle(PVOID file_desc) {
return static_cast<native_handle>(reinterpret_cast<std::uint64_t>(file_desc));
}
#endif
} // namespace repertory::remote_winfsp

File diff suppressed because it is too large Load Diff

View File

@ -1,144 +1,177 @@
/*
Copyright <2018-2022> <scott.e.graves@protonmail.com>
Copyright <2018-2023> <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
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 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.
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 <utility>
#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/error_utils.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]),
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 remote_winfsp_drive::winfsp_service::OnStart(ULONG, PWSTR *) -> NTSTATUS {
const auto mount_location = utils::string::to_lower(
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]);
if (config_.get_enable_mount_manager()) {
unicode_mount_location =
std::wstring(L"\\\\.\\") + unicode_mount_location[0u] + L":";
}
ret = host_.Mount(&unicode_mount_location[0u]);
} else {
std::cerr << (drive_letter ? "Mount location in use: " : "Mount location not supported: ")
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);
event_system::instance().raise<drive_mount_failed>(mount_location,
std::to_string(ret));
if (not lock_.set_mount_state(false, "", -1)) {
utils::error::raise_error(__FUNCTION__, "failed to set mount state");
}
}
return ret;
}
NTSTATUS remote_winfsp_drive::winfsp_service::OnStop() {
auto remote_winfsp_drive::winfsp_service::OnStop() -> NTSTATUS {
host_.Unmount();
lock_.set_mount_state(false, "", -1);
if (not lock_.set_mount_state(false, "", -1)) {
utils::error::raise_error(__FUNCTION__, "failed to set mount state");
}
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();
});
remote_winfsp_drive::remote_winfsp_drive(app_config &config,
remote_instance_factory factory,
lock_data &lock)
: FileSystemBase(),
config_(config),
lock_(lock),
factory_(std::move(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) {
auto remote_winfsp_drive::CanDelete(PVOID /*file_node*/, PVOID file_desc,
PWSTR file_name) -> NTSTATUS {
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) {
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) {
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) {
auto 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)
-> NTSTATUS {
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);
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));
set_file_info(ofi->FileInfo, fi);
const auto file_path = utils::string::from_utf8(normalized_name);
wcsncpy(ofi->NormalizedName, &file_path[0], wcslen(&file_path[0]));
ofi->NormalizedNameSize = (UINT16)(wcslen(&file_path[0]) * sizeof(WCHAR));
}
return ret;
}
NTSTATUS remote_winfsp_drive::Flush(PVOID file_node, PVOID file_desc, FileInfo *file_info) {
auto remote_winfsp_drive::Flush(PVOID /*file_node*/, PVOID file_desc,
FileInfo *file_info) -> NTSTATUS {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_flush(file_desc, &fi);
SetFileInfo(*file_info, fi);
set_file_info(*file_info, fi);
return ret;
}
NTSTATUS remote_winfsp_drive::GetFileInfo(PVOID file_node, PVOID file_desc, FileInfo *file_info) {
auto remote_winfsp_drive::GetFileInfo(PVOID /*file_node*/, PVOID file_desc,
FileInfo *file_info) -> NTSTATUS {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_get_file_info(file_desc, &fi);
SetFileInfo(*file_info, fi);
set_file_info(*file_info, fi);
return ret;
}
NTSTATUS remote_winfsp_drive::GetSecurityByName(PWSTR file_name, PUINT32 attributes,
PSECURITY_DESCRIPTOR descriptor,
SIZE_T *descriptor_size) {
auto remote_winfsp_drive::GetSecurityByName(PWSTR file_name, PUINT32 attributes,
PSECURITY_DESCRIPTOR descriptor,
SIZE_T *descriptor_size)
-> NTSTATUS {
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);
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 (::ConvertStringSecurityDescriptorToSecurityDescriptorW(
&string_descriptor[0u], SDDL_REVISION_1, &sd, &sz2)) {
if (sz2 > *descriptor_size) {
ret = STATUS_BUFFER_TOO_SMALL;
} else {
@ -153,22 +186,28 @@ NTSTATUS remote_winfsp_drive::GetSecurityByName(PWSTR file_name, PUINT32 attribu
return ret;
}
NTSTATUS remote_winfsp_drive::GetVolumeInfo(VolumeInfo *volume_info) {
auto remote_winfsp_drive::GetVolumeInfo(VolumeInfo *volume_info) -> NTSTATUS {
std::string volume_label;
const auto ret = remote_instance_->winfsp_get_volume_info(volume_info->TotalSize,
volume_info->FreeSize, 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);
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 remote_winfsp_drive::Init(PVOID host) -> NTSTATUS {
auto *file_system_host = reinterpret_cast<FileSystemHost *>(host);
file_system_host->SetPrefix(
&(L"\\repertory\\" + std::wstring(file_system_host->FileSystemName()).substr(0, 1))[0]);
if (not config_.get_enable_mount_manager()) {
file_system_host->SetPrefix(
&(L"\\repertory\\" +
std::wstring(file_system_host->FileSystemName()).substr(0, 1))[0u]);
}
file_system_host->SetFileSystemName(REPERTORY_W);
file_system_host->SetFlushAndPurgeOnCleanup(TRUE);
file_system_host->SetReparsePoints(FALSE);
@ -188,7 +227,8 @@ NTSTATUS remote_winfsp_drive::Init(PVOID host) {
return STATUS_SUCCESS;
}
int remote_winfsp_drive::mount(const std::vector<std::string> &drive_args) {
auto remote_winfsp_drive::mount(const std::vector<std::string> &drive_args)
-> int {
std::vector<std::string> parsed_drive_args;
const auto force_no_console = utils::collection_includes(drive_args, "-nc");
@ -210,50 +250,61 @@ int remote_winfsp_drive::mount(const std::vector<std::string> &drive_args) {
c = std::make_unique<console_consumer>();
}
event_system::instance().start();
const auto ret = winfsp_service(lock_, *this, parsed_drive_args, config_).Run();
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 remote_winfsp_drive::Mounted(PVOID host) -> NTSTATUS {
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());
if (not lock_.set_mount_state(true, mount_location_,
::GetCurrentProcessId())) {
utils::error::raise_error(__FUNCTION__, "failed to set mount state");
}
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) {
auto remote_winfsp_drive::Open(PWSTR file_name, UINT32 create_options,
UINT32 granted_access, PVOID * /*file_node*/,
PVOID *file_desc, OpenFileInfo *ofi)
-> NTSTATUS {
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);
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));
set_file_info(ofi->FileInfo, fi);
const auto file_path = utils::string::from_utf8(normalize_name);
wcsncpy(ofi->NormalizedName, &file_path[0], wcslen(&file_path[0]));
ofi->NormalizedNameSize = (UINT16)(wcslen(&file_path[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) {
auto remote_winfsp_drive::Overwrite(PVOID /*file_node*/, PVOID file_desc,
UINT32 attributes,
BOOLEAN replace_attributes,
UINT64 allocation_size, FileInfo *file_info)
-> NTSTATUS {
remote::file_info fi{};
const auto ret = remote_instance_->winfsp_overwrite(file_desc, attributes, replace_attributes,
allocation_size, &fi);
SetFileInfo(*file_info, fi);
const auto ret = remote_instance_->winfsp_overwrite(
file_desc, attributes, replace_attributes, allocation_size, &fi);
set_file_info(*file_info, fi);
return ret;
}
void remote_winfsp_drive::PopulateFileInfo(const json &item, FSP_FSCTL_FILE_INFO &file_info) {
void remote_winfsp_drive::populate_file_info(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 =
@ -270,28 +321,33 @@ void remote_winfsp_drive::PopulateFileInfo(const json &item, FSP_FSCTL_FILE_INFO
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));
auto remote_winfsp_drive::Read(PVOID /*file_node*/, PVOID file_desc,
PVOID buffer, UINT64 offset, ULONG length,
PULONG bytes_transferred) -> NTSTATUS {
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);
auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
PWSTR pattern, PWSTR marker,
PVOID buffer, ULONG buffer_length,
PULONG bytes_transferred) -> NTSTATUS {
json item_list;
NTSTATUS ret = remote_instance_->winfsp_read_directory(file_desc, pattern,
marker, item_list);
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)) {
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) {
for (const auto &item : item_list) {
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));
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 {
@ -304,15 +360,19 @@ NTSTATUS remote_winfsp_drive::ReadDirectory(PVOID file_node, PVOID file_desc, PW
::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)));
(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 (not item["meta"].empty() ||
((item_path != ".") && (item_path != ".."))) {
populate_file_info(item, directory_info->FileInfo);
}
if (ret == STATUS_SUCCESS) {
::wcscpy_s(&directory_info->FileNameBuf[0], MAX_PATH, &display_name[0]);
::wcscpy_s(&directory_info->FileNameBuf[0], MAX_PATH,
&display_name[0]);
FspFileSystemFillDirectoryBuffer(directory_buffer, directory_info, &ret);
FspFileSystemFillDirectoryBuffer(directory_buffer,
directory_info, &ret);
if (ret != STATUS_SUCCESS) {
break;
}
@ -327,8 +387,9 @@ NTSTATUS remote_winfsp_drive::ReadDirectory(PVOID file_node, PVOID file_desc, PW
}
if ((ret == STATUS_SUCCESS) || (ret == STATUS_NO_MORE_FILES)) {
FspFileSystemReadDirectoryBuffer(directory_buffer, marker, buffer, buffer_length,
reinterpret_cast<PULONG>(bytes_transferred));
FspFileSystemReadDirectoryBuffer(
directory_buffer, marker, buffer, buffer_length,
reinterpret_cast<PULONG>(bytes_transferred));
ret = STATUS_SUCCESS;
}
}
@ -337,23 +398,29 @@ NTSTATUS remote_winfsp_drive::ReadDirectory(PVOID file_node, PVOID file_desc, PW
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);
auto remote_winfsp_drive::Rename(PVOID /*file_node*/, PVOID file_desc,
PWSTR file_name, PWSTR new_file_name,
BOOLEAN replace_if_exists) -> NTSTATUS {
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) {
auto 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)
-> NTSTATUS {
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);
file_desc, attributes, creation_time, last_access_time, last_write_time,
change_time, &fi);
set_file_info(*file_info, fi);
return ret;
}
void remote_winfsp_drive::SetFileInfo(FileInfo &dest, const remote::file_info &src) {
void remote_winfsp_drive::set_file_info(FileInfo &dest,
const remote::file_info &src) {
dest.FileAttributes = src.FileAttributes;
dest.ReparseTag = src.ReparseTag;
dest.AllocationSize = src.AllocationSize;
@ -367,33 +434,39 @@ void remote_winfsp_drive::SetFileInfo(FileInfo &dest, const remote::file_info &s
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) {
auto remote_winfsp_drive::SetFileSize(PVOID /*file_node*/, PVOID file_desc,
UINT64 new_size,
BOOLEAN set_allocation_size,
FileInfo *file_info) -> NTSTATUS {
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);
const auto ret = remote_instance_->winfsp_set_file_size(
file_desc, new_size, set_allocation_size, &fi);
set_file_info(*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());
auto *file_system_host = reinterpret_cast<FileSystemHost *>(host);
if (not lock_.set_mount_state(false, "", -1)) {
utils::error::raise_error(__FUNCTION__, "failed to set mount state");
}
remote_instance_->winfsp_unmounted(file_system_host->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) {
auto 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)
-> NTSTATUS {
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);
set_file_info(*file_info, fi);
return ret;
}
} // namespace repertory::remote_winfsp

File diff suppressed because it is too large Load Diff