diff --git a/repertory/librepertory/include/utils/native_file.hpp b/repertory/librepertory/include/utils/native_file.hpp deleted file mode 100644 index 5b82e631..00000000 --- a/repertory/librepertory/include/utils/native_file.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright <2018-2024> - - 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 INCLUDE_UTILS_NATIVEFILE_HPP_ -#define INCLUDE_UTILS_NATIVEFILE_HPP_ - -#include "types/repertory.hpp" - -namespace repertory { -class native_file final { -public: - native_file(const native_file &) = delete; - native_file(native_file &&) = delete; - auto operator=(const native_file &) -> native_file & = delete; - auto operator=(native_file &&) -> native_file & = delete; - - using native_file_ptr = std::shared_ptr; - -public: - [[nodiscard]] static auto attach(native_handle handle) -> native_file_ptr { - return std::shared_ptr(new native_file(handle)); - } - - [[nodiscard]] static auto - clone(const native_file_ptr &ptr) -> native_file_ptr; - - [[nodiscard]] static auto create_or_open(std::string_view source_path, - bool read_only, - native_file_ptr &ptr) -> api_error; - - [[nodiscard]] static auto create_or_open(std::string_view source_path, - native_file_ptr &ptr) -> api_error; - - [[nodiscard]] static auto open(std::string_view source_path, - native_file_ptr &ptr) -> api_error; - - [[nodiscard]] static auto open(std::string_view source_path, bool read_only, - native_file_ptr &ptr) -> api_error; - -private: - explicit native_file(const native_handle &handle) : handle_(handle) {} - -public: - ~native_file(); - -private: - native_handle handle_; - -private: - bool auto_close{false}; -#if defined(_WIN32) - std::recursive_mutex read_write_mutex_; -#endif - -public: - [[nodiscard]] auto allocate(std::uint64_t file_size) -> bool; - - void close(); - - [[nodiscard]] auto copy_from(const native_file_ptr &ptr) -> bool; - - [[nodiscard]] auto copy_from(const std::string &path) -> bool; - - void flush(); - - [[nodiscard]] auto get_file_size(std::uint64_t &file_size) -> bool; - - [[nodiscard]] auto get_handle() -> native_handle; - -#if defined(_WIN32) - [[nodiscard]] auto read_bytes(unsigned char *buffer, std::size_t read_size, - std::uint64_t read_offset, - std::size_t &bytes_read) -> bool; -#else - [[nodiscard]] auto read_bytes(unsigned char *buffer, std::size_t read_size, - std::uint64_t read_offset, - std::size_t &bytes_read) -> bool; -#endif - void set_auto_close(bool b) { auto_close = b; } - - [[nodiscard]] auto truncate(std::uint64_t file_size) -> bool; - -#if defined(_WIN32) - [[nodiscard]] auto write_bytes(const unsigned char *buffer, - std::size_t write_size, - std::uint64_t write_offset, - std::size_t &bytes_written) -> bool; -#else - [[nodiscard]] auto write_bytes(const unsigned char *buffer, - std::size_t write_size, - std::uint64_t write_offset, - std::size_t &bytes_written) -> bool; -#endif -}; - -using native_file_ptr = native_file::native_file_ptr; -} // namespace repertory - -#endif // INCLUDE_UTILS_NATIVEFILE_HPP_ diff --git a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp index 5ad4c9d0..e870604d 100644 --- a/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp +++ b/repertory/librepertory/src/drives/winfsp/remotewinfsp/remote_server.cpp @@ -38,8 +38,8 @@ #include "types/remote.hpp" #include "types/repertory.hpp" #include "utils/common.hpp" +#include "utils/file.hpp" #include "utils/file_utils.hpp" -#include "utils/native_file.hpp" #include "utils/path.hpp" #include "utils/time.hpp" @@ -472,21 +472,20 @@ auto remote_server::fuse_read( if (os_handle != INVALID_HANDLE_VALUE) { errno = EFAULT; - auto file = native_file::attach(os_handle); - std::uint64_t file_size{}; - if (file->get_file_size(file_size)) { + auto file = utils::file::file::attach_file(os_handle, true); + if (file) { + auto file_size = file.size(); data.resize(utils::calculate_read_size( file_size, static_cast(read_size), read_offset)); - if (!data.empty()) { + if (data.empty()) { + res = 0; + errno = 0; + } else { std::size_t bytes_read{}; - if (file->read_bytes(data.data(), data.size(), read_offset, - bytes_read)) { + if (file.read(data.data(), data.size(), read_offset, &bytes_read)) { res = 0; errno = 0; } - } else { - res = 0; - errno = 0; } } } @@ -539,10 +538,10 @@ auto remote_server::fuse_write( if (os_handle != INVALID_HANDLE_VALUE) { errno = EFAULT; if ((write_size == 0) || - native_file::attach(os_handle)->write_bytes( + utils::file::file::attach_file(os_handle).write( reinterpret_cast(buffer), static_cast(write_size), write_offset, - bytes_written)) { + &bytes_written)) { res = 0; errno = 0; } diff --git a/repertory/librepertory/src/utils/native_file.cpp b/repertory/librepertory/src/utils/native_file.cpp deleted file mode 100644 index ec56a68e..00000000 --- a/repertory/librepertory/src/utils/native_file.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - Copyright <2018-2024> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ -#include "utils/native_file.hpp" - -#include "platform/platform.hpp" -#include "types/repertory.hpp" -#include "utils/string.hpp" -#include "utils/utils.hpp" - -namespace repertory { -auto native_file::get_handle() -> native_handle { return handle_; } - -native_file::~native_file() { - if (auto_close) { - close(); - } -} - -auto native_file::clone(const native_file_ptr &ptr) -> native_file_ptr { - std::string source_path; - -#if defined(_WIN32) - source_path.resize(MAX_PATH + 1); - ::GetFinalPathNameByHandleA(ptr->get_handle(), source_path.data(), - MAX_PATH + 1, - FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); -#else - source_path.resize(PATH_MAX + 1); -#if defined(__APPLE__) - fcntl(ptr->get_handle(), F_GETPATH, source_path.data()); -#else - readlink(("/proc/self/fd/" + std::to_string(ptr->get_handle())).c_str(), - source_path.data(), source_path.size()); -#endif -#endif - source_path = source_path.c_str(); - - native_file_ptr clone; - auto res = native_file::open(source_path, clone); - if (res != api_error::success) { - throw std::runtime_error("unable to open file|sp|" + source_path + "|err|" + - api_error_to_string(res)); - } - - return clone; -} - -auto native_file::create_or_open(std::string_view source_path, bool read_only, - native_file_ptr &ptr) -> api_error { -#if defined(_WIN32) - auto handle = - read_only ? ::CreateFileA(std::string{source_path}.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, nullptr) - : ::CreateFileA(std::string{source_path}.c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, nullptr); -#else - auto handle = read_only ? ::open(std::string{source_path}.c_str(), - O_CREAT | O_RDONLY | O_CLOEXEC, 0600U) - : ::open(std::string{source_path}.c_str(), - O_CREAT | O_RDWR | O_CLOEXEC, 0600U); - if (not read_only) { - chmod(std::string{source_path}.c_str(), 0600U); - } -#endif - ptr = native_file::attach(handle); - return ((handle == REPERTORY_INVALID_HANDLE) ? api_error::os_error - : api_error::success); -} - -auto native_file::create_or_open(std::string_view source_path, - native_file_ptr &ptr) -> api_error { - return create_or_open(source_path, false, ptr); -} - -auto native_file::open(std::string_view source_path, - native_file_ptr &ptr) -> api_error { - return open(source_path, false, ptr); -} - -auto native_file::open(std::string_view source_path, bool read_only, - native_file_ptr &ptr) -> api_error { -#if defined(_WIN32) - auto handle = - read_only - ? ::CreateFileA(std::string{source_path}.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr) - : ::CreateFileA(std::string{source_path}.c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr); -#else - auto handle = - read_only ? ::open(std::string{source_path}.c_str(), O_RDONLY | O_CLOEXEC) - : ::open(std::string{source_path}.c_str(), O_RDWR | O_CLOEXEC); - if (not read_only) { - chmod(std::string{source_path}.c_str(), 0600U); - } -#endif - ptr = native_file::attach(handle); - return ((handle == REPERTORY_INVALID_HANDLE) ? api_error::os_error - : api_error::success); -} - -auto native_file::allocate(std::uint64_t file_size) -> bool { -#if defined(_WIN32) - LARGE_INTEGER li{}; - li.QuadPart = static_cast(file_size); - return (::SetFilePointerEx(handle_, li, nullptr, FILE_BEGIN) && - ::SetEndOfFile(handle_)); -#endif -#if defined(__linux__) - return (fallocate(handle_, 0, 0, static_cast(file_size)) >= 0); -#endif -#if defined(__APPLE__) - return (ftruncate(handle_, file_size) >= 0); -#endif -} - -void native_file::close() { - if (handle_ != REPERTORY_INVALID_HANDLE) { -#if defined(_WIN32) - ::CloseHandle(handle_); -#else - ::close(handle_); -#endif - handle_ = REPERTORY_INVALID_HANDLE; - } -} - -auto native_file::copy_from(const native_file_ptr &ptr) -> bool { - std::uint64_t file_size{}; - auto ret = ptr->get_file_size(file_size); - if (ret) { - data_buffer buffer; - buffer.resize(65536ULL * 2ULL); - std::uint64_t offset{}; - while (ret && (file_size > 0U)) { - std::size_t bytes_read{}; - ret = ptr->read_bytes(buffer.data(), buffer.size(), offset, bytes_read); - if (ret) { - std::size_t bytes_written{}; - ret = write_bytes(buffer.data(), bytes_read, offset, bytes_written); - file_size -= bytes_read; - offset += bytes_read; - } - } - flush(); - } - - return ret; -} - -auto native_file::copy_from(const std::string &path) -> bool { - auto ret = false; - native_file_ptr ptr; - if (native_file::create_or_open(path, ptr) == api_error ::success) { - ret = copy_from(ptr); - ptr->close(); - } - - return ret; -} - -void native_file::flush() { -#if defined(_WIN32) - recur_mutex_lock l(read_write_mutex_); - ::FlushFileBuffers(handle_); -#else - fsync(handle_); -#endif -} - -auto native_file::get_file_size(std::uint64_t &file_size) -> bool { - auto ret = false; -#if defined(_WIN32) - LARGE_INTEGER li{}; - if ((ret = ::GetFileSizeEx(handle_, &li) && (li.QuadPart >= 0))) { - file_size = static_cast(li.QuadPart); - } -#else -#if defined(__APPLE__) - struct stat unix_st {}; - if (fstat(handle_, &unix_st) >= 0) { -#else - struct stat64 unix_st {}; - if (fstat64(handle_, &unix_st) >= 0) { -#endif - ret = (unix_st.st_size >= 0); - if (ret) { - file_size = static_cast(unix_st.st_size); - } - } -#endif - return ret; -} - -#if defined(_WIN32) -auto native_file::read_bytes(unsigned char *buffer, std::size_t read_size, - std::uint64_t read_offset, - std::size_t &bytes_read) -> bool { - recur_mutex_lock l(read_write_mutex_); - - auto ret = false; - bytes_read = 0u; - LARGE_INTEGER li{}; - li.QuadPart = static_cast(read_offset); - if ((ret = !!::SetFilePointerEx(handle_, li, nullptr, FILE_BEGIN))) { - DWORD current_read = 0u; - do { - current_read = 0u; - ret = !!::ReadFile(handle_, &buffer[bytes_read], - static_cast(read_size - bytes_read), - ¤t_read, nullptr); - bytes_read += current_read; - } while (ret && (bytes_read < read_size) && (current_read != 0)); - } - - if (ret && (read_size != bytes_read)) { - ::SetLastError(ERROR_HANDLE_EOF); - } - - return ret; -} -#else -auto native_file::read_bytes(unsigned char *buffer, std::size_t read_size, - std::uint64_t read_offset, - std::size_t &bytes_read) -> bool { - bytes_read = 0U; - ssize_t result = 0; - do { - result = pread64(handle_, &buffer[bytes_read], read_size - bytes_read, - static_cast(read_offset + bytes_read)); - if (result > 0) { - bytes_read += static_cast(result); - } - } while ((result > 0) && (bytes_read < read_size)); - - return (result >= 0); -} -#endif -auto native_file::truncate(std::uint64_t file_size) -> bool { -#if defined(_WIN32) - recur_mutex_lock l(read_write_mutex_); - LARGE_INTEGER li{}; - li.QuadPart = static_cast(file_size); - return (::SetFilePointerEx(handle_, li, nullptr, FILE_BEGIN) && - ::SetEndOfFile(handle_)); -#else - return (ftruncate(handle_, static_cast(file_size)) >= 0); -#endif -} - -#if defined(_WIN32) -auto native_file::write_bytes(const unsigned char *buffer, - std::size_t write_size, - std::uint64_t write_offset, - std::size_t &bytes_written) -> bool { - recur_mutex_lock l(read_write_mutex_); - - bytes_written = 0u; - auto ret = true; - - LARGE_INTEGER li{}; - li.QuadPart = static_cast(write_offset); - if ((ret = !!::SetFilePointerEx(handle_, li, nullptr, FILE_BEGIN))) { - do { - DWORD current_write = 0u; - ret = !!::WriteFile(handle_, &buffer[bytes_written], - static_cast(write_size - bytes_written), - ¤t_write, nullptr); - bytes_written += current_write; - } while (ret && (bytes_written < write_size)); - } - - return ret; -} -#else -auto native_file::write_bytes(const unsigned char *buffer, - std::size_t write_size, - std::uint64_t write_offset, - std::size_t &bytes_written) -> bool { - bytes_written = 0U; - ssize_t result{}; - do { - result = - pwrite64(handle_, &buffer[bytes_written], write_size - bytes_written, - static_cast(write_offset + bytes_written)); - if (result > 0) { - bytes_written += static_cast(result); - } - } while ((result >= 0) && (bytes_written < write_size)); - - return (bytes_written == write_size); -} -#endif -} // namespace repertory diff --git a/support/include/utils/file.hpp b/support/include/utils/file.hpp index 5ce3881f..e088407a 100644 --- a/support/include/utils/file.hpp +++ b/support/include/utils/file.hpp @@ -27,6 +27,9 @@ namespace repertory::utils::file { class file final { public: + [[nodiscard]] static auto attach_file(native_handle handle, + bool read_only = false) -> file; + [[nodiscard]] static auto open_file(std::filesystem::path path, bool read_only = false) -> file; @@ -103,31 +106,14 @@ public: [[nodiscard]] auto truncate(std::size_t size) -> bool; [[nodiscard]] auto write(const data_buffer &data, std::uint64_t offset, - std::size_t *total_written = nullptr) -> bool { - return write_(reinterpret_cast(data.data()), - data.size() * sizeof(data_buffer::value_type), offset, - total_written); - } + std::size_t *total_written = nullptr) -> bool; - [[nodiscard]] auto write(std::string_view data, std::uint64_t offset, - std::size_t *total_written = nullptr) -> bool { - return write_(reinterpret_cast(data.data()), - data.size(), offset, total_written); - } - - [[nodiscard]] auto write(std::wstring_view data, std::uint64_t offset, - std::size_t *total_written = nullptr) -> bool { - return write_(reinterpret_cast(data.data()), - data.size() * sizeof(wchar_t), offset, total_written); - } + [[nodiscard]] auto write(const unsigned char *data, std::size_t to_write, + std::size_t offset, + std::size_t *total_written = nullptr) -> bool; public: [[nodiscard]] operator bool() const { return file_ != nullptr; } - -private: - [[nodiscard]] auto write_(const unsigned char *data, std::size_t to_write, - std::size_t offset, - std::size_t *total_written) -> bool; }; [[nodiscard]] auto get_file_size(std::string_view path, diff --git a/support/src/utils/file.cpp b/support/src/utils/file.cpp index 4f5b1b03..d0d23f2c 100644 --- a/support/src/utils/file.cpp +++ b/support/src/utils/file.cpp @@ -157,7 +157,9 @@ auto write_json_file(std::string_view path, } #endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) - return file.write(data.dump(), 0U); + auto json_str = data.dump(); + return file.write(reinterpret_cast(json_str.c_str()), + json_str.size(), 0U); } catch (const std::exception &e) { utils::error::handle_exception(function_name, e); } catch (...) { diff --git a/support/src/utils/file_file.cpp b/support/src/utils/file_file.cpp index 8d6ff6ca..12a8798d 100644 --- a/support/src/utils/file_file.cpp +++ b/support/src/utils/file_file.cpp @@ -27,6 +27,55 @@ #include "utils/string.hpp" namespace repertory::utils::file { +auto file::attach_file(native_handle handle, bool read_only) -> file { + static constexpr const std::string_view function_name{ + static_cast(__FUNCTION__), + }; + + try { + std::string path; + +#if defined(_WIN32) + path.resize(MAX_PATH + 1); + + ::GetFinalPathNameByHandleA(handle, path.data(), + static_cast(path.size()), + FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); +#else // !defined(_WIN32) + source_path.resize(PATH_MAX + 1); + +#if defined(__APPLE__) + fcntl(handle, F_GETPATH, source_path.data()); +#else // !defined(__APPLE__) + readlink(("/proc/self/fd/" + std::to_string(handle)).c_str(), + source_path.data(), source_path.size()); +#endif // defined(__APPLE__) +#endif // defined(_WIN32) + + path = path.c_str(); + +#if defined(_WIN32) + auto *ptr = _fdopen( + static_cast(_open_osfhandle(reinterpret_cast(handle), + read_only ? _O_RDONLY : _O_RDWR)), + read_only ? "rb" : "rb+"); +#else // !defined(_WIN32) + auto *ptr = fdopen(handle, read_only ? "rb" : "rb+"); +#endif // defined(_WIN32) + + return file{ + file_t{ptr}, + utils::path::absolute(path), + }; + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } + + return {}; +} + auto file::open_file(std::filesystem::path path, bool read_only) -> file { static constexpr const std::string_view function_name{ static_cast(__FUNCTION__), @@ -285,8 +334,8 @@ auto file::truncate(std::size_t size) -> bool { return ec.value() == 0; } -auto file::write_(const unsigned char *data, std::size_t to_write, - std::size_t offset, std::size_t *total_written) -> bool { +auto file::write(const unsigned char *data, std::size_t to_write, + std::size_t offset, std::size_t *total_written) -> bool { #if defined(_WIN32) recur_mutex_lock lock{mtx_}; #endif // defined(_WIN32) @@ -361,4 +410,11 @@ auto file::size() const -> std::uint64_t { return 0U; } + +auto file::write(const data_buffer &data, std::uint64_t offset, + std::size_t *total_written) -> bool { + return write(reinterpret_cast(data.data()), + data.size() * sizeof(data_buffer::value_type), offset, + total_written); +} } // namespace repertory::utils::file