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
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:
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
353
src/drives/fuse/fuse_drive_base.cpp
Normal file
353
src/drives/fuse/fuse_drive_base.cpp
Normal 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
@ -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
|
||||
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
Reference in New Issue
Block a user