Compare commits
11 Commits
d83de7bb91
...
1236bf1829
Author | SHA1 | Date | |
---|---|---|---|
1236bf1829 | |||
aa9c7d1ec1 | |||
c5d3453c1f | |||
71112d4977 | |||
ba3c6d78cb | |||
eb3ad67819 | |||
cc51ae61e4 | |||
b1fd78ebe3 | |||
7d0af3fb04 | |||
f8e9176538 | |||
734dab801d |
5
.clangd
Normal file
5
.clangd
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"CompileFlags": {
|
||||
"Remove": ["-flarge-source-files"]
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
_lseeki64
|
||||
aarch64
|
||||
advapi32
|
||||
armv8
|
||||
@ -22,6 +23,8 @@ crypto_aead_xchacha20poly1305_ietf_npubbytes
|
||||
cstdint
|
||||
cxxflags
|
||||
cxxstd
|
||||
d_largefile64_source
|
||||
d_largefile_source
|
||||
d_ndebug
|
||||
dbackward_shared
|
||||
dbghelp
|
||||
|
@ -59,7 +59,6 @@ list(APPEND PROJECT_CFLAGS_LIST
|
||||
|
||||
list(APPEND PROJECT_CXXFLAGS_LIST
|
||||
${PROJECT_COMMON_FLAG_LIST}
|
||||
-fext-numeric-literals
|
||||
-std=gnu++${CMAKE_CXX_STANDARD}
|
||||
)
|
||||
|
||||
|
@ -21,10 +21,13 @@ set(GTKMM_VERSION 3.0)
|
||||
set(ICU_VERSION 75-1)
|
||||
set(JSON_VERSION 3.11.3)
|
||||
set(LIBBITCOIN_SYSTEM_VERSION 3.8.0)
|
||||
set(LIBDSM_VERSION 0.4.3)
|
||||
set(LIBEVENT_VERSION 2.1.12)
|
||||
set(LIBJPEG_TURBO_VERSION 3.0.3)
|
||||
set(LIBPNG_VERSION 1.6.43)
|
||||
set(LIBSODIUM_VERSION 1.0.20)
|
||||
set(LIBTASN_VERSION 4.19.0)
|
||||
set(LIBICONV_VERSION 1.17)
|
||||
set(MESA_VERSION 23.3.3)
|
||||
set(MINGW_VERSION 11.0.1)
|
||||
set(NANA_VERSION 1.7.4)
|
||||
@ -41,6 +44,7 @@ set(SFML_VERSION 2.6.1)
|
||||
set(SPDLOG_VERSION 1.14.1)
|
||||
set(SQLITE_VERSION 3460000)
|
||||
set(STDUUID_VERSION 1.2.3)
|
||||
set(VLC_VERSION 3.0)
|
||||
set(VORBIS_VERSION 1.3.7)
|
||||
set(WXWIDGETS_VERSION 3.2.5)
|
||||
set(ZLIB_VERSION 1.3.1)
|
||||
|
@ -10,6 +10,7 @@ RUN apk add \
|
||||
bash \
|
||||
binutils \
|
||||
binutils-dev \
|
||||
bison \
|
||||
boost-dev \
|
||||
bzip2-static \
|
||||
cmake \
|
||||
|
@ -10,6 +10,7 @@ RUN apk add \
|
||||
bash \
|
||||
binutils \
|
||||
binutils-dev \
|
||||
bison \
|
||||
boost-dev \
|
||||
bzip2-static \
|
||||
cmake \
|
||||
|
@ -1004,6 +1004,58 @@ RUN if [ -f "/3rd_party/sdl-${MY_SDL_VERSION}.tar.gz" ]; then \
|
||||
&& rm -r SDL-release-${MY_SDL_VERSION} \
|
||||
; fi
|
||||
|
||||
ARG LIBTASN_VERSION
|
||||
ENV MY_LIBTASN_VERSION=${LIBTASN_VERSION}
|
||||
RUN if [ -f "/3rd_party/libtasn1-${MY_LIBTASN_VERSION}.tar.gz" ]; then \
|
||||
tar xvzf /3rd_party/libtasn1-${MY_LIBTASN_VERSION}.tar.gz \
|
||||
&& cd libtasn1-${MY_LIBTASN_VERSION} \
|
||||
&& ./configure \
|
||||
--disable-doc \
|
||||
--enable-static=yes \
|
||||
--enable-shared=no \
|
||||
--host=${MY_MINGW_PREFIX} \
|
||||
--prefix=${MY_MINGW_DIR} \
|
||||
&& make -j${MY_NUM_JOBS} \
|
||||
&& make install \
|
||||
&& cd ${MY_WORKDIR} \
|
||||
&& rm -r libtasn1-${MY_LIBTASN_VERSION} \
|
||||
; fi
|
||||
|
||||
ARG LIBICONV_VERSION
|
||||
ENV MY_LIBICONV_VERSION=${LIBICONV_VERSION}
|
||||
RUN if [ -f "/3rd_party/libiconv-${MY_LIBICONV_VERSION}.tar.gz" ]; then \
|
||||
tar xvzf /3rd_party/libiconv-${MY_LIBICONV_VERSION}.tar.gz \
|
||||
&& cd libiconv-${MY_LIBICONV_VERSION} \
|
||||
&& ./configure \
|
||||
--enable-static=yes \
|
||||
--enable-shared=no \
|
||||
--host=${MY_MINGW_PREFIX} \
|
||||
--prefix=${MY_MINGW_DIR} \
|
||||
&& make -j${MY_NUM_JOBS} \
|
||||
&& make install \
|
||||
&& cd ${MY_WORKDIR} \
|
||||
&& rm -r libiconv-${MY_LIBICONV_VERSION} \
|
||||
; fi
|
||||
|
||||
ARG LIBDSM_VERSION
|
||||
ENV MY_LIBDSM_VERSION=${LIBDSM_VERSION}
|
||||
RUN if [ -f "/3rd_party/libdsm-${MY_LIBDSM_VERSION}.tar.gz" ]; then \
|
||||
tar xvxf /3rd_party/libdsm-${MY_LIBDSM_VERSION}.tar.gz \
|
||||
&& cd libdsm-${MY_LIBDSM_VERSION} \
|
||||
&& meson setup \
|
||||
--cross-file ${MY_TOOLCHAIN_FILE_MESON} \
|
||||
--prefix=${MY_MINGW_DIR} \
|
||||
-Dbinaries=false \
|
||||
-Ddefault_library=static \
|
||||
_build \
|
||||
&& meson compile \
|
||||
-C _build \
|
||||
&& meson install \
|
||||
-C _build \
|
||||
&& cd ${MY_WORKDIR} \
|
||||
&& rm -r libdsm-${MY_LIBDSM_VERSION} \
|
||||
; fi
|
||||
|
||||
RUN (mv ${MY_MINGW_DIR}/lib/*.dll ${MY_MINGW_DIR}/bin || echo "no dll's found") \
|
||||
&& chmod 0777 -R ${MY_MINGW_DIR} \
|
||||
&& rm -rf /3rd_party
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "comm/i_http_comm.hpp"
|
||||
#include "events/event_system.hpp"
|
||||
#include "events/events.hpp"
|
||||
#include "utils/encrypt.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory {
|
||||
@ -92,32 +92,31 @@ public:
|
||||
const auto key =
|
||||
utils::encryption::generate_key<utils::encryption::hash_256_t>(
|
||||
request.decryption_token.value());
|
||||
const auto result = utils::encryption::read_encrypted_range(
|
||||
request.range.value(), key,
|
||||
[&](data_buffer &ct, std::uint64_t start_offset,
|
||||
std::uint64_t end_offset) -> api_error {
|
||||
auto encrypted_request = request;
|
||||
encrypted_request.decryption_token = std::nullopt;
|
||||
encrypted_request.range = {{start_offset, end_offset}};
|
||||
encrypted_request.response_handler = [&ct](const auto &encrypted_data,
|
||||
long /*response_code*/) {
|
||||
ct = encrypted_data;
|
||||
};
|
||||
encrypted_request.total_size = std::nullopt;
|
||||
if (not utils::encryption::read_encrypted_range(
|
||||
request.range.value(), key,
|
||||
[&](data_buffer &ct, std::uint64_t start_offset,
|
||||
std::uint64_t end_offset) -> bool {
|
||||
auto encrypted_request = request;
|
||||
encrypted_request.decryption_token = std::nullopt;
|
||||
encrypted_request.range = {{start_offset, end_offset}};
|
||||
encrypted_request.response_handler =
|
||||
[&ct](const auto &encrypted_data, long /*response_code*/) {
|
||||
ct = encrypted_data;
|
||||
};
|
||||
encrypted_request.total_size = std::nullopt;
|
||||
|
||||
if (not make_request(cfg, encrypted_request, response_code,
|
||||
stop_requested)) {
|
||||
return api_error::comm_error;
|
||||
}
|
||||
if (not make_request(cfg, encrypted_request, response_code,
|
||||
stop_requested)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (response_code != 200) {
|
||||
return api_error::comm_error;
|
||||
}
|
||||
if (response_code != 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return api_error::success;
|
||||
},
|
||||
request.total_size.value(), data);
|
||||
if (result != api_error::success) {
|
||||
return true;
|
||||
},
|
||||
request.total_size.value(), data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ struct http_request_base {
|
||||
std::optional<std::string> decryption_token{};
|
||||
http_headers headers{};
|
||||
std::string path{};
|
||||
query_parameters query{};
|
||||
http_query_parameters query{};
|
||||
std::optional<http_range> range{};
|
||||
std::optional<response_callback> response_handler;
|
||||
std::optional<http_headers> response_headers;
|
||||
|
@ -263,16 +263,6 @@ from_json(const json &j, host_config &hc) {
|
||||
j.at("TimeoutMs").get_to(hc.timeout_ms);
|
||||
}
|
||||
|
||||
struct http_range {
|
||||
std::uint64_t begin;
|
||||
std::uint64_t end;
|
||||
};
|
||||
|
||||
struct encrypt_config {
|
||||
std::string encryption_token;
|
||||
std::string path;
|
||||
};
|
||||
|
||||
struct s3_config {
|
||||
std::string access_key;
|
||||
std::string bucket;
|
||||
@ -290,11 +280,7 @@ using api_file_list = std::vector<api_file>;
|
||||
using api_file_provider_callback = std::function<void(api_file &)>;
|
||||
using api_item_added_callback = std::function<api_error(bool, api_file &)>;
|
||||
using directory_item_list = std::vector<directory_item>;
|
||||
using http_headers = std::unordered_map<std::string, std::string>;
|
||||
using http_parameters = std::unordered_map<std::string, std::string>;
|
||||
using http_ranges = std::vector<http_range>;
|
||||
using meta_provider_callback = std::function<void(directory_item &)>;
|
||||
using query_parameters = std::map<std::string, std::string>;
|
||||
} // namespace repertory
|
||||
|
||||
#endif // INCLUDE_TYPES_REPERTORY_HPP_
|
||||
|
@ -465,14 +465,16 @@ auto remote_server::fuse_read(
|
||||
res = -1;
|
||||
errno = ERANGE;
|
||||
} else if ((res = has_compat_open_info(handle, EBADF)) == 0) {
|
||||
res = lseek(handle, read_offset, SEEK_SET);
|
||||
res = _lseeki64(static_cast<int>(handle), static_cast<__int64>(read_offset),
|
||||
SEEK_SET);
|
||||
if (res != -1) {
|
||||
data.resize(read_size);
|
||||
res = read(handle, data.data(), data.size());
|
||||
res = read(static_cast<int>(handle), data.data(),
|
||||
static_cast<unsigned int>(data.size()));
|
||||
if (res == -1) {
|
||||
data.resize(0U);
|
||||
} else if (data.size() != res) {
|
||||
data.resize(res);
|
||||
} else if (data.size() != static_cast<std::size_t>(res)) {
|
||||
data.resize(static_cast<std::size_t>(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -517,11 +519,13 @@ auto remote_server::fuse_write(
|
||||
} else {
|
||||
res = has_compat_open_info(handle, EBADF);
|
||||
if (res == 0) {
|
||||
res = lseek(handle, write_offset, SEEK_SET);
|
||||
res = _lseeki64(static_cast<int>(handle),
|
||||
static_cast<__int64>(write_offset), SEEK_SET);
|
||||
if (res != -1) {
|
||||
res = write(handle, buffer, write_size);
|
||||
if (res >= -1) {
|
||||
bytes_written = res;
|
||||
res = write(static_cast<int>(handle), buffer,
|
||||
static_cast<unsigned int>(write_size));
|
||||
if (res != -1) {
|
||||
bytes_written = static_cast<std::size_t>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,8 @@
|
||||
#include "events/events.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/collection.hpp"
|
||||
#include "utils/encrypt.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
#include "utils/polling.hpp"
|
||||
@ -181,13 +181,10 @@ auto encrypt_provider::do_fs_operation(
|
||||
callback) const -> api_error {
|
||||
auto cfg = config_.get_encrypt_config();
|
||||
std::string source_path{api_path};
|
||||
if (api_path != "/") {
|
||||
auto res =
|
||||
utils::encryption::decrypt_file_path(cfg.encryption_token, source_path);
|
||||
if (res != api_error::success) {
|
||||
return directory ? api_error::directory_not_found
|
||||
: api_error::item_not_found;
|
||||
}
|
||||
if (api_path != "/" && not utils::encryption::decrypt_file_path(
|
||||
cfg.encryption_token, source_path)) {
|
||||
return directory ? api_error::directory_not_found
|
||||
: api_error::item_not_found;
|
||||
}
|
||||
|
||||
source_path = utils::path::combine(cfg.path, {source_path});
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include "types/s3.hpp"
|
||||
#include "types/startup_exception.hpp"
|
||||
#include "utils/collection.hpp"
|
||||
#include "utils/encrypt.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
#include "utils/error_utils.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
@ -190,10 +190,9 @@ auto s3_provider::decrypt_object_name(std::string &object_name) const
|
||||
-> api_error {
|
||||
auto parts = utils::string::split(object_name, '/', false);
|
||||
for (auto &part : parts) {
|
||||
auto err = utils::encryption::decrypt_file_name(
|
||||
get_config().get_s3_config().encryption_token, part);
|
||||
if (err != api_error::success) {
|
||||
return err;
|
||||
if (not utils::encryption::decrypt_file_name(
|
||||
get_config().get_s3_config().encryption_token, part)) {
|
||||
return api_error::decryption_error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,10 +312,9 @@ auto s3_provider::get_directory_items_impl(
|
||||
std::string child_object_name;
|
||||
if (is_encrypted) {
|
||||
child_object_name = child_api_path;
|
||||
ret = utils::encryption::decrypt_file_path(cfg.encryption_token,
|
||||
child_api_path);
|
||||
if (ret != api_error::success) {
|
||||
return ret;
|
||||
if (not utils::encryption::decrypt_file_path(cfg.encryption_token,
|
||||
child_api_path)) {
|
||||
return api_error::decryption_error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -732,18 +730,25 @@ auto s3_provider::read_file_bytes(const std::string &api_path, std::size_t size,
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
}
|
||||
const auto total_size = utils::string::to_uint64(temp);
|
||||
|
||||
return utils::encryption::read_encrypted_range(
|
||||
{offset, offset + size - 1U},
|
||||
utils::encryption::generate_key<utils::encryption::hash_256_t>(
|
||||
cfg.encryption_token),
|
||||
[&](data_buffer &ct_buffer, std::uint64_t start_offset,
|
||||
std::uint64_t end_offset) -> api_error {
|
||||
return read_bytes((end_offset - start_offset + 1U), start_offset,
|
||||
ct_buffer);
|
||||
},
|
||||
total_size, data);
|
||||
auto total_size = utils::string::to_uint64(temp);
|
||||
|
||||
res = api_error::success;
|
||||
if (utils::encryption::read_encrypted_range(
|
||||
{offset, offset + size - 1U},
|
||||
utils::encryption::generate_key<utils::encryption::hash_256_t>(
|
||||
cfg.encryption_token),
|
||||
[&](data_buffer &ct_buffer, std::uint64_t start_offset,
|
||||
std::uint64_t end_offset) -> bool {
|
||||
res = read_bytes((end_offset - start_offset + 1U), start_offset,
|
||||
ct_buffer);
|
||||
return res == api_error::success;
|
||||
},
|
||||
total_size, data)) {
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
return res == api_error::success ? api_error::decryption_error : res;
|
||||
}
|
||||
|
||||
return read_bytes(size, offset, data);
|
||||
|
@ -166,9 +166,8 @@ const auto decrypt_parts = [](const repertory::app_config &cfg,
|
||||
continue;
|
||||
}
|
||||
|
||||
EXPECT_EQ(repertory::api_error::success,
|
||||
repertory::utils::encryption::decrypt_file_name(
|
||||
cfg.get_encrypt_config().encryption_token, part));
|
||||
EXPECT_EQ(true, repertory::utils::encryption::decrypt_file_name(
|
||||
cfg.get_encrypt_config().encryption_token, part));
|
||||
}
|
||||
path = repertory::utils::string::join(parts, '/');
|
||||
}
|
||||
|
@ -151,6 +151,10 @@ if [ "${PROJECT_IS_MINGW}" == "1" ] && [ "${PROJECT_ENABLE_WINFSP}" == "ON" ]; t
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${PROJECT_IS_MINGW}" == "1" ] && [ "${PROJECT_ENABLE_VLC}" == "ON" ]; then
|
||||
rsync -av --progress ${PROJECT_3RD_PARTY_DIR}/vlc/ "${PROJECT_DIST_DIR}/vlc/"
|
||||
fi
|
||||
|
||||
for PROJECT_DEPENDENCY in "${PROJECT_MINGW64_COPY_DEPENDENCIES[@]}"; do
|
||||
rsync -av --progress ${PROJECT_DEPENDENCY} "${PROJECT_DIST_DIR}/"
|
||||
done
|
||||
|
@ -222,6 +222,11 @@ else
|
||||
PROJECT_BUILD_SHARED_LIBS=ON
|
||||
fi
|
||||
|
||||
if [ "${PROJECT_ENABLE_LIBDSM}" == "ON" ]; then
|
||||
PROJECT_ENABLE_LIBICONV=ON
|
||||
PROJECT_ENABLE_LIBTASN=ON
|
||||
fi
|
||||
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_3RD_PARTY_DIR=${PROJECT_3RD_PARTY_DIR} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_ARCH=${PROJECT_BUILD_ARCH} ${PROJECT_CMAKE_OPTS}"
|
||||
PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_DIR=${PROJECT_BUILD_DIR} ${PROJECT_CMAKE_OPTS}"
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "utils/config.hpp"
|
||||
|
||||
#include "utils/error.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace repertory::utils::collection {
|
||||
@ -69,24 +70,75 @@ inline auto includes(const col_t &collection,
|
||||
collection.end();
|
||||
}
|
||||
|
||||
template <typename val_t, typename string_t>
|
||||
[[nodiscard]] inline auto
|
||||
from_hex_string_t(std::basic_string_view<typename string_t::value_type> str,
|
||||
val_t &val) -> bool {
|
||||
template <typename val_t>
|
||||
[[nodiscard]] inline auto from_hex_string_t(std::string_view str,
|
||||
val_t &val) -> bool {
|
||||
static constexpr const auto base16{16};
|
||||
|
||||
val.clear();
|
||||
if (not(str.length() % 2U)) {
|
||||
for (std::size_t i = 0U; i < str.length(); i += 2U) {
|
||||
val.emplace_back(static_cast<typename val_t::value_type>(
|
||||
std::strtol(string_t{str.substr(i, 2U)}.c_str(), nullptr, base16)));
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
val.clear();
|
||||
|
||||
std::string fmt_val{str};
|
||||
utils::string::trim(fmt_val);
|
||||
if (fmt_val.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fmt_val = utils::string::to_lower(fmt_val);
|
||||
if (utils::string::begins_with(fmt_val, "0x")) {
|
||||
fmt_val = fmt_val.substr(2U);
|
||||
}
|
||||
|
||||
if (fmt_val.empty()) {
|
||||
throw std::runtime_error("hex string is invalid|" + std::string{str});
|
||||
}
|
||||
|
||||
if (fmt_val.length() % 2U) {
|
||||
fmt_val = '0' + fmt_val;
|
||||
}
|
||||
|
||||
auto iter = std::find_if_not(
|
||||
fmt_val.begin(), fmt_val.end(), [](auto cur_char) -> bool {
|
||||
auto check = static_cast<std::uint32_t>(cur_char);
|
||||
return ((check >= 48U && check <= 57U) ||
|
||||
(check >= 97U && check <= 102U));
|
||||
});
|
||||
if (iter != fmt_val.end()) {
|
||||
auto invalid_idx{std::distance(fmt_val.begin(), iter)};
|
||||
throw std::range_error(
|
||||
"invalid character in hex string|" + std::to_string(invalid_idx) +
|
||||
'|' + std::string(1U, str.at(invalid_idx)) + '|' + std::string{str});
|
||||
}
|
||||
|
||||
val.resize(fmt_val.length() / 2U);
|
||||
for (std::size_t idx = 0U; idx < fmt_val.length(); idx += 2U) {
|
||||
val.at(idx / 2U) = static_cast<typename val_t::value_type>(
|
||||
std::strtoul(fmt_val.substr(idx, 2U).c_str(), nullptr, base16));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
val.clear();
|
||||
return false;
|
||||
}
|
||||
template <typename val_t>
|
||||
inline auto from_hex_string(std::string_view str, val_t &val) -> bool {
|
||||
return from_hex_string_t<val_t>(str, val);
|
||||
}
|
||||
|
||||
template <typename val_t>
|
||||
inline auto from_hex_string(std::wstring_view str, val_t &val) -> bool {
|
||||
return from_hex_string_t<val_t>(utils::string::to_utf8(str), val);
|
||||
}
|
||||
|
||||
template <typename col_t>
|
||||
inline auto remove_element(col_t &collection,
|
||||
@ -96,16 +148,6 @@ inline auto remove_element(col_t &collection,
|
||||
return collection;
|
||||
}
|
||||
|
||||
template <typename val_t>
|
||||
inline auto from_hex_string(std::string_view str, val_t &val) -> bool {
|
||||
return from_hex_string_t<val_t, std::string>(str, val);
|
||||
}
|
||||
|
||||
template <typename val_t>
|
||||
inline auto from_hex_string(std::wstring_view str, val_t &val) -> bool {
|
||||
return from_hex_string_t<val_t, std::wstring>(str, val);
|
||||
}
|
||||
|
||||
template <typename col_t>
|
||||
inline auto to_hex_string(const col_t &collection) -> std::string {
|
||||
static_assert(sizeof(typename col_t::value_type) == 1U,
|
||||
|
@ -165,6 +165,50 @@ extern "C" {
|
||||
#endif // defined(__cplusplus)
|
||||
#endif // defined(PROJECT_ENABLE_FZF)
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif // defined(__cplusplus)
|
||||
#include "bdsm/bdsm.h"
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
struct netbios_ns_deleter final {
|
||||
void operator()(netbios_ns *ns) {
|
||||
if (ns != nullptr) {
|
||||
netbios_ns_destroy(ns);
|
||||
}
|
||||
}
|
||||
};
|
||||
using netbios_ns_t = std::unique_ptr<netbios_ns, netbios_ns_deleter>;
|
||||
|
||||
inline const auto smb_session_deleter = [](smb_session *session) {
|
||||
if (session != nullptr) {
|
||||
smb_session_destroy(session);
|
||||
}
|
||||
};
|
||||
using smb_session_t = std::shared_ptr<smb_session>;
|
||||
|
||||
struct smb_stat_deleter final {
|
||||
void operator()(smb_stat st) {
|
||||
if (st != nullptr) {
|
||||
smb_stat_destroy(st);
|
||||
}
|
||||
}
|
||||
};
|
||||
using smb_stat_t = std::unique_ptr<smb_file, smb_stat_deleter>;
|
||||
|
||||
struct smb_stat_list_deleter final {
|
||||
void operator()(smb_file *list) {
|
||||
if (list != nullptr) {
|
||||
smb_stat_list_destroy(list);
|
||||
}
|
||||
}
|
||||
};
|
||||
using smb_stat_list_t = std::unique_ptr<smb_file, smb_stat_list_deleter>;
|
||||
#endif // defined(__cplusplus)
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBEVENT)
|
||||
#include "event2/buffer.h"
|
||||
#include "event2/bufferevent.h"
|
||||
@ -173,20 +217,68 @@ extern "C" {
|
||||
#include "event2/util.h"
|
||||
#endif // defined(PROJECT_ENABLE_LIBEVENT)
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
#include "sodium.h"
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
|
||||
#if defined(PROJECT_ENABLE_SDL)
|
||||
#include "SDL.h"
|
||||
#include "SDL_gamecontroller.h"
|
||||
#include "SDL_joystick.h"
|
||||
#endif // defined(PROJECT_ENABLE_SDL)
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
#include "sodium.h"
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
|
||||
#if defined(PROJECT_ENABLE_SQLITE)
|
||||
#include "sqlite3.h"
|
||||
#endif // defined(PROJECT_ENABLE_SQLITE)
|
||||
|
||||
#if defined(PROJECT_ENABLE_VLC)
|
||||
#include <vlc/vlc.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
[[nodiscard]] inline auto get_libvlc_error_msg() -> std::string {
|
||||
const auto *msg = libvlc_errmsg();
|
||||
return msg == nullptr ? "none" : msg;
|
||||
}
|
||||
|
||||
struct vlc_deleter final {
|
||||
void operator()(libvlc_instance_t *inst) {
|
||||
if (inst != nullptr) {
|
||||
libvlc_release(inst);
|
||||
}
|
||||
}
|
||||
};
|
||||
using vlc_t = std::unique_ptr<libvlc_instance_t, vlc_deleter>;
|
||||
|
||||
struct vlc_media_deleter final {
|
||||
void operator()(libvlc_media_t *media) {
|
||||
if (media != nullptr) {
|
||||
libvlc_media_release(media);
|
||||
}
|
||||
}
|
||||
};
|
||||
using vlc_media_t = std::unique_ptr<libvlc_media_t, vlc_media_deleter>;
|
||||
|
||||
struct vlc_media_list_deleter final {
|
||||
void operator()(libvlc_media_list_t *media_list) {
|
||||
if (media_list != nullptr) {
|
||||
libvlc_media_list_release(media_list);
|
||||
}
|
||||
}
|
||||
};
|
||||
using vlc_media_list_t =
|
||||
std::unique_ptr<libvlc_media_list_t, vlc_media_list_deleter>;
|
||||
|
||||
struct vlc_string_deleter final {
|
||||
void operator()(char *str) {
|
||||
if (str != nullptr) {
|
||||
libvlc_free(str);
|
||||
}
|
||||
}
|
||||
};
|
||||
using vlc_string_t = std::unique_ptr<char, vlc_string_deleter>;
|
||||
#endif // defined(__cplusplus)
|
||||
#endif // defined(PROJECT_ENABLE_VLC)
|
||||
|
||||
#if !defined(fstat64)
|
||||
#define fstat64 fstat
|
||||
#endif // !defined(fstat64)
|
||||
@ -348,6 +440,22 @@ struct file_deleter final {
|
||||
}
|
||||
};
|
||||
using file_t = std::unique_ptr<FILE, file_deleter>;
|
||||
|
||||
#if defined(PROJECT_ENABLE_CURL)
|
||||
struct http_range final {
|
||||
std::uint64_t begin{};
|
||||
std::uint64_t end{};
|
||||
};
|
||||
|
||||
using http_headers = std::unordered_map<std::string, std::string>;
|
||||
using http_query_parameters = std::map<std::string, std::string>;
|
||||
using http_ranges = std::vector<http_range>;
|
||||
|
||||
struct encrypt_config {
|
||||
std::string encryption_token;
|
||||
std::string path;
|
||||
};
|
||||
#endif // defined(PROJECT_ENABLE_CURL)
|
||||
} // namespace repertory
|
||||
#endif // defined(__cplusplus)
|
||||
|
||||
|
@ -34,7 +34,7 @@ class encrypting_reader final {
|
||||
public:
|
||||
encrypting_reader(std::string_view file_name, std::string_view source_path,
|
||||
stop_type &stop_requested, std::string_view token,
|
||||
std::optional<std::string_view> relative_parent_path,
|
||||
std::optional<std::string> relative_parent_path,
|
||||
std::size_t error_return = 0U);
|
||||
|
||||
encrypting_reader(std::string_view encrypted_file_path,
|
||||
|
@ -46,6 +46,12 @@ inline auto generate_key(
|
||||
default_create_hash<hash_t>()) -> hash_t;
|
||||
|
||||
#if defined(PROJECT_ENABLE_BOOST)
|
||||
[[nodiscard]] auto decrypt_file_name(std::string_view encryption_token,
|
||||
std::string &file_name) -> bool;
|
||||
|
||||
[[nodiscard]] auto decrypt_file_path(std::string_view encryption_token,
|
||||
std::string &file_path) -> bool;
|
||||
|
||||
template <typename result_t, typename arr_t, std::size_t arr_size>
|
||||
[[nodiscard]] inline auto decrypt_data(const std::array<arr_t, arr_size> &key,
|
||||
const unsigned char *buffer,
|
||||
@ -172,6 +178,18 @@ encrypt_data(const std::array<unsigned char,
|
||||
reinterpret_cast<const unsigned char *>(buf.data()),
|
||||
buf.size(), res);
|
||||
}
|
||||
|
||||
#if defined(PROJECT_ENABLE_CURL)
|
||||
using reader_func_t =
|
||||
std::function<bool(data_buffer &cypher_text, std::uint64_t start_offset,
|
||||
std::uint64_t end_offset)>;
|
||||
|
||||
[[nodiscard]] auto
|
||||
read_encrypted_range(const http_range &range,
|
||||
const utils::encryption::hash_256_t &key,
|
||||
reader_func_t reader_func, std::uint64_t total_size,
|
||||
data_buffer &data) -> bool;
|
||||
#endif // defined(PROJECT_ENABLE_CURL)
|
||||
#endif // defined(PROJECT_ENABLE_BOOST)
|
||||
|
||||
template <typename hash_t>
|
||||
|
@ -42,11 +42,33 @@ protected:
|
||||
i_exception_handler() = default;
|
||||
};
|
||||
|
||||
struct iostream_exception_handler final : i_exception_handler {
|
||||
void handle_exception(std::string_view function_name) const override {
|
||||
std::cerr << function_name << "|exception|unknown" << std::endl;
|
||||
}
|
||||
|
||||
void handle_exception(std::string_view function_name,
|
||||
const std::exception &ex) const override {
|
||||
std::cerr << function_name << "|exception|"
|
||||
<< (ex.what() == nullptr ? "unknown" : ex.what()) << std::endl;
|
||||
}
|
||||
};
|
||||
inline const iostream_exception_handler default_exception_handler{};
|
||||
|
||||
extern std::atomic<const i_exception_handler *> exception_handler;
|
||||
|
||||
#if defined(PROJECT_ENABLE_TESTING)
|
||||
[[nodiscard]] inline auto
|
||||
get_exception_handler() -> const i_exception_handler * {
|
||||
return exception_handler;
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_TESTING)
|
||||
|
||||
void handle_exception(std::string_view function_name);
|
||||
|
||||
void handle_exception(std::string_view function_name, const std::exception &ex);
|
||||
|
||||
void set_exception_handler(i_exception_handler *handler);
|
||||
void set_exception_handler(const i_exception_handler *handler);
|
||||
} // namespace repertory::utils::error
|
||||
|
||||
#endif // REPERTORY_INCLUDE_UTILS_ERROR_HPP_
|
||||
|
@ -25,31 +25,106 @@
|
||||
#include "utils/config.hpp"
|
||||
|
||||
#include "utils/path.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace repertory::utils::file {
|
||||
struct i_file {
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
[[nodiscard]] auto
|
||||
smb_create_and_validate_relative_path(std::string_view smb_path,
|
||||
std::string_view rel_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto
|
||||
smb_create_relative_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto
|
||||
smb_create_search_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto
|
||||
smb_create_smb_path(std::string_view smb_path,
|
||||
std::string_view rel_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto
|
||||
smb_get_parent_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto smb_get_root_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto smb_get_unc_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto smb_get_uri_path(std::string_view smb_path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto smb_get_uri_path(std::string_view smb_path,
|
||||
std::string_view user,
|
||||
std::string_view password) -> std::string;
|
||||
|
||||
[[nodiscard]] auto smb_parent_is_same(std::string_view smb_path1,
|
||||
std::string_view smb_path2) -> bool;
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
||||
|
||||
struct i_fs_item {
|
||||
using fs_item_t = std::unique_ptr<i_fs_item>;
|
||||
enum class time_types {
|
||||
access,
|
||||
creation,
|
||||
modified,
|
||||
write,
|
||||
};
|
||||
|
||||
virtual ~i_fs_item() = default;
|
||||
|
||||
[[nodiscard]] virtual auto exists() const -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_path() const -> std::string = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_time(time_types type) const -> std::uint64_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto is_directory_item() const -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto move_to(std::string_view new_path) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto move_to(std::wstring_view new_path) -> bool {
|
||||
return move_to(utils::string::to_utf8(new_path));
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual auto remove() -> bool = 0;
|
||||
|
||||
public:
|
||||
[[nodiscard]] virtual operator bool() const = 0;
|
||||
|
||||
protected:
|
||||
i_fs_item() noexcept = default;
|
||||
|
||||
i_fs_item(const i_fs_item &) noexcept = default;
|
||||
|
||||
i_fs_item(i_fs_item &&) noexcept = default;
|
||||
|
||||
auto operator=(i_fs_item &&) noexcept -> i_fs_item & = default;
|
||||
|
||||
auto operator=(const i_fs_item &) noexcept -> i_fs_item & = default;
|
||||
};
|
||||
|
||||
struct i_file : public i_fs_item {
|
||||
using fs_file_t = std::unique_ptr<i_file>;
|
||||
|
||||
virtual ~i_file() = default;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
[[nodiscard]] virtual auto exists() const -> bool = 0;
|
||||
|
||||
virtual void flush() const = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_handle() const -> native_handle = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_path() const -> std::string = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_read_buffer_size() const -> std::uint32_t = 0;
|
||||
|
||||
[[nodiscard]] auto is_directory_item() const -> bool override {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual auto is_read_only() const -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto move_to(std::string_view new_path) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
read(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool = 0;
|
||||
[[nodiscard]] virtual auto read(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool {
|
||||
return read(data.data(), data.size(), offset, total_read);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
read(unsigned char *data, std::size_t to_read, std::uint64_t offset,
|
||||
@ -57,64 +132,59 @@ struct i_file {
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
read_all(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto remove() -> bool = 0;
|
||||
std::size_t *total_read = nullptr) -> bool;
|
||||
|
||||
virtual auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto size() const -> std::uint64_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto truncate() -> bool = 0;
|
||||
[[nodiscard]] virtual auto truncate() -> bool { return truncate(0U); }
|
||||
|
||||
[[nodiscard]] virtual auto truncate(std::size_t size) -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
write(const data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool = 0;
|
||||
std::size_t *total_written = nullptr) -> bool {
|
||||
return write(data.data(), data.size(), offset, total_written);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool = 0;
|
||||
|
||||
public:
|
||||
[[nodiscard]] virtual operator bool() const = 0;
|
||||
|
||||
protected:
|
||||
i_file() noexcept = default;
|
||||
|
||||
i_file(const i_file &) noexcept = delete;
|
||||
i_file(const i_file &) noexcept = default;
|
||||
|
||||
i_file(i_file &&) noexcept = delete;
|
||||
i_file(i_file &&) noexcept = default;
|
||||
|
||||
auto operator=(i_file &&) noexcept -> i_file & = delete;
|
||||
auto operator=(i_file &&) noexcept -> i_file & = default;
|
||||
|
||||
auto operator=(const i_file &) noexcept -> i_file & = delete;
|
||||
auto operator=(const i_file &) noexcept -> i_file & = default;
|
||||
};
|
||||
|
||||
class file final : public i_file {
|
||||
public:
|
||||
// [[nodiscard]] static auto
|
||||
// attach_file(native_handle handle,
|
||||
// bool read_only = false) -> std::unique_ptr<i_file>;
|
||||
// bool read_only = false) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_file(std::string_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file>;
|
||||
[[nodiscard]] static auto open_file(std::string_view path,
|
||||
bool read_only = false) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_file(std::wstring_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file> {
|
||||
[[nodiscard]] static auto open_file(std::wstring_view path,
|
||||
bool read_only = false) -> fs_file_t {
|
||||
return open_file(utils::string::to_utf8(path), read_only);
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_or_create_file(std::string_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file>;
|
||||
bool read_only = false) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_or_create_file(std::wstring_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file> {
|
||||
bool read_only = false) -> fs_file_t {
|
||||
return open_or_create_file(utils::string::to_utf8(path), read_only);
|
||||
}
|
||||
|
||||
@ -179,23 +249,18 @@ public:
|
||||
return read_buffer_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto is_read_only() const -> bool override {
|
||||
return read_only_;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto read(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
read_all(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove() -> bool override;
|
||||
|
||||
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
|
||||
@ -205,14 +270,8 @@ public:
|
||||
|
||||
[[nodiscard]] auto size() const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto truncate() -> bool override { return truncate(0U); }
|
||||
|
||||
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
write(const data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool override;
|
||||
@ -236,53 +295,26 @@ public:
|
||||
[[nodiscard]] operator bool() const override { return file_ != nullptr; }
|
||||
};
|
||||
|
||||
class thread_file final : public i_file {
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
class enc_file final : public i_file {
|
||||
public:
|
||||
// [[nodiscard]] static auto
|
||||
// attach_file(native_handle handle,
|
||||
// bool read_only = false) -> std::unique_ptr<i_file>;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_file(std::string_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file>;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_file(std::wstring_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file> {
|
||||
return open_file(utils::string::to_utf8(path), read_only);
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_or_create_file(std::string_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file>;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_or_create_file(std::wstring_view path,
|
||||
bool read_only = false) -> std::unique_ptr<i_file> {
|
||||
return open_or_create_file(utils::string::to_utf8(path), read_only);
|
||||
}
|
||||
[[nodiscard]] static auto attach_file(fs_file_t file) -> fs_file_t;
|
||||
|
||||
public:
|
||||
thread_file() noexcept = default;
|
||||
|
||||
thread_file(std::string_view path) : file_(new file(path)) {}
|
||||
|
||||
thread_file(std::wstring_view path)
|
||||
: file_(new file(utils::string::to_utf8(path))) {}
|
||||
enc_file() noexcept = default;
|
||||
|
||||
protected:
|
||||
thread_file(std::unique_ptr<i_file> file);
|
||||
enc_file(fs_file_t file);
|
||||
|
||||
public:
|
||||
thread_file(const thread_file &) = delete;
|
||||
enc_file(const enc_file &) = delete;
|
||||
|
||||
thread_file(thread_file &&move_file) noexcept
|
||||
: file_(std::move(move_file.file_)) {}
|
||||
enc_file(enc_file &&move_file) noexcept : file_(std::move(move_file.file_)) {}
|
||||
|
||||
~thread_file() override { close(); }
|
||||
~enc_file() override { close(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<i_file> file_;
|
||||
fs_file_t file_;
|
||||
|
||||
public:
|
||||
void close() override;
|
||||
@ -303,23 +335,18 @@ public:
|
||||
return file_->get_read_buffer_size();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto is_read_only() const -> bool override {
|
||||
return file_->is_read_only();
|
||||
};
|
||||
|
||||
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto read(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
read_all(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove() -> bool override;
|
||||
|
||||
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
|
||||
@ -328,14 +355,118 @@ public:
|
||||
|
||||
[[nodiscard]] auto size() const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto truncate() -> bool override { return truncate(0U); }
|
||||
|
||||
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
write(const data_buffer &data, std::uint64_t offset,
|
||||
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool override;
|
||||
|
||||
public:
|
||||
[[nodiscard]] operator bool() const override {
|
||||
return static_cast<bool>(*file_);
|
||||
}
|
||||
|
||||
auto operator=(const file &) noexcept -> enc_file & = delete;
|
||||
|
||||
auto operator=(enc_file &&move_file) noexcept -> enc_file & {
|
||||
if (&move_file != this) {
|
||||
file_ = std::move(move_file.file_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
|
||||
class thread_file final : public i_file {
|
||||
public:
|
||||
// [[nodiscard]] static auto
|
||||
// attach_file(native_handle handle,
|
||||
// bool read_only = false) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto attach_file(fs_file_t file) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto open_file(std::string_view path,
|
||||
bool read_only = false) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto open_file(std::wstring_view path,
|
||||
bool read_only = false) -> fs_file_t {
|
||||
return open_file(utils::string::to_utf8(path), read_only);
|
||||
}
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_or_create_file(std::string_view path,
|
||||
bool read_only = false) -> fs_file_t;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open_or_create_file(std::wstring_view path,
|
||||
bool read_only = false) -> fs_file_t {
|
||||
return open_or_create_file(utils::string::to_utf8(path), read_only);
|
||||
}
|
||||
|
||||
public:
|
||||
thread_file() noexcept = default;
|
||||
|
||||
thread_file(std::string_view path) : file_(new file(path)) {}
|
||||
|
||||
thread_file(std::wstring_view path)
|
||||
: file_(new file(utils::string::to_utf8(path))) {}
|
||||
|
||||
protected:
|
||||
thread_file(fs_file_t file);
|
||||
|
||||
public:
|
||||
thread_file(const thread_file &) = delete;
|
||||
|
||||
thread_file(thread_file &&move_file) noexcept
|
||||
: file_(std::move(move_file.file_)) {}
|
||||
|
||||
~thread_file() override { close(); }
|
||||
|
||||
private:
|
||||
fs_file_t file_;
|
||||
|
||||
public:
|
||||
void close() override;
|
||||
|
||||
[[nodiscard]] auto exists() const -> bool override { return file_->exists(); }
|
||||
|
||||
void flush() const override;
|
||||
|
||||
[[nodiscard]] auto get_handle() const -> native_handle override {
|
||||
return file_->get_handle();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_path() const -> std::string override {
|
||||
return file_->get_path();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override {
|
||||
return file_->get_read_buffer_size();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto is_read_only() const -> bool override {
|
||||
return file_->is_read_only();
|
||||
};
|
||||
|
||||
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove() -> bool override;
|
||||
|
||||
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
|
||||
return file_->set_read_buffer_size(size);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto size() const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool override;
|
||||
@ -356,6 +487,372 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct i_directory : public i_fs_item {
|
||||
using fs_directory_t = std::unique_ptr<i_directory>;
|
||||
using fs_file_t = i_file::fs_file_t;
|
||||
|
||||
virtual ~i_directory() = default;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
count(bool recursive = false) const -> std::uint64_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
create_directory(std::string_view path) const -> fs_directory_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto create_file(std::string_view file_name,
|
||||
bool read_only) const -> fs_file_t = 0;
|
||||
|
||||
[[nodiscard]] auto is_directory_item() const -> bool override { return true; }
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_directory(std::string_view path) const -> fs_directory_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_directories() const -> std::vector<fs_directory_t> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
get_file(std::string_view path) const -> fs_file_t = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_files() const -> std::vector<fs_file_t> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto get_items() const -> std::vector<fs_item_t> = 0;
|
||||
|
||||
[[nodiscard]] virtual auto remove_recursively() -> bool = 0;
|
||||
|
||||
[[nodiscard]] virtual auto
|
||||
size(bool recursive = false) const -> std::uint64_t = 0;
|
||||
|
||||
protected:
|
||||
i_directory() noexcept = default;
|
||||
|
||||
i_directory(const i_directory &) noexcept = default;
|
||||
|
||||
i_directory(i_directory &&) noexcept = default;
|
||||
|
||||
auto operator=(i_directory &&) noexcept -> i_directory & = default;
|
||||
|
||||
auto operator=(const i_directory &) noexcept -> i_directory & = default;
|
||||
};
|
||||
|
||||
class directory final : public i_directory {
|
||||
public:
|
||||
using directory_t = std::unique_ptr<directory>;
|
||||
|
||||
directory() noexcept = default;
|
||||
|
||||
directory(std::string_view path) : path_(utils::path::absolute(path)) {}
|
||||
|
||||
directory(std::wstring_view path)
|
||||
: path_(utils::path::absolute(utils::string::to_utf8(path))) {}
|
||||
|
||||
directory(const directory &) noexcept = delete;
|
||||
|
||||
directory(directory &&move_dir) noexcept = default;
|
||||
|
||||
~directory() override = default;
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto
|
||||
count(bool recursive = false) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
create_directory(std::string_view path) const -> fs_directory_t override;
|
||||
|
||||
[[nodiscard]] auto create_file(std::string_view file_name,
|
||||
bool read_only) const -> fs_file_t override;
|
||||
|
||||
[[nodiscard]] auto exists() const -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_directory(std::string_view path) const -> fs_directory_t override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_directories() const -> std::vector<fs_directory_t> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_file(std::string_view path) const -> fs_file_t override;
|
||||
|
||||
[[nodiscard]] auto get_files() const -> std::vector<fs_file_t> override;
|
||||
|
||||
[[nodiscard]] auto get_items() const -> std::vector<fs_item_t> override;
|
||||
|
||||
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
|
||||
|
||||
[[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove() -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove_recursively() -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
size(bool recursive = false) const -> std::uint64_t override;
|
||||
|
||||
public:
|
||||
auto operator=(const directory &) noexcept -> directory & = delete;
|
||||
|
||||
auto operator=(directory &&move_dir) noexcept -> directory & = default;
|
||||
|
||||
[[nodiscard]] operator bool() const override { return exists(); }
|
||||
};
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
#define SMB_MOD_RW2 \
|
||||
(SMB_MOD_READ | SMB_MOD_WRITE | SMB_MOD_READ_EXT | SMB_MOD_WRITE_EXT | \
|
||||
SMB_MOD_READ_ATTR | SMB_MOD_WRITE_ATTR | SMB_MOD_READ_CTL)
|
||||
|
||||
class smb_file final : public i_file {
|
||||
public:
|
||||
smb_file() = default;
|
||||
|
||||
smb_file(std::uint64_t access_time, std::uint64_t creation_time,
|
||||
std::optional<smb_fd> fd, std::uint64_t modified_time,
|
||||
std::string path, smb_session_t session, std::string_view share_name,
|
||||
smb_tid tid, std::uint64_t size, std::uint64_t write_time)
|
||||
: access_time_(access_time),
|
||||
creation_time_(creation_time),
|
||||
fd_(std::move(fd)),
|
||||
modified_time_(modified_time),
|
||||
path_(std::move(path)),
|
||||
session_(std::move(session)),
|
||||
share_name_(share_name),
|
||||
size_(size),
|
||||
tid_(tid),
|
||||
write_time_(write_time) {}
|
||||
|
||||
smb_file(const smb_file &) = delete;
|
||||
|
||||
smb_file(smb_file &&f) noexcept
|
||||
: access_time_(f.access_time_),
|
||||
creation_time_(f.creation_time_),
|
||||
fd_(std::move(f.fd_)),
|
||||
modified_time_(f.modified_time_),
|
||||
path_(std::move(f.path_)),
|
||||
read_buffer_size(f.get_read_buffer_size()),
|
||||
read_only_(f.read_only_),
|
||||
session_(std::move(f.session_)),
|
||||
share_name_(std::move(f.share_name_)),
|
||||
size_(f.size_),
|
||||
tid_(f.tid_),
|
||||
write_time_(f.write_time_) {}
|
||||
|
||||
~smb_file() override { close(); }
|
||||
|
||||
private:
|
||||
std::uint64_t access_time_;
|
||||
std::uint64_t creation_time_;
|
||||
std::optional<smb_fd> fd_;
|
||||
std::uint64_t modified_time_;
|
||||
std::string path_;
|
||||
std::atomic_uint32_t read_buffer_size{65536U};
|
||||
bool read_only_;
|
||||
smb_session_t session_;
|
||||
std::string share_name_;
|
||||
std::uint64_t size_;
|
||||
smb_tid tid_;
|
||||
std::uint64_t write_time_;
|
||||
|
||||
public:
|
||||
void close() override;
|
||||
|
||||
[[nodiscard]] auto exists() const -> bool override;
|
||||
|
||||
void flush() const override;
|
||||
|
||||
[[nodiscard]] auto get_handle() const -> native_handle override {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
|
||||
|
||||
[[nodiscard]] auto get_read_buffer_size() const -> std::uint32_t override {
|
||||
return read_buffer_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override {
|
||||
switch (type) {
|
||||
case time_types::access:
|
||||
return access_time_;
|
||||
|
||||
case time_types::creation:
|
||||
return creation_time_;
|
||||
|
||||
case time_types::modified:
|
||||
return modified_time_;
|
||||
|
||||
case time_types::write:
|
||||
return write_time_;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_unc_path() const -> std::string {
|
||||
return smb_get_unc_path(path_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_uri_path() const -> std::string {
|
||||
return smb_get_uri_path(path_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_uri_path(std::string_view user,
|
||||
std::string_view password) const -> std::string {
|
||||
return smb_get_uri_path(path_, user, password);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto is_read_only() const -> bool override {
|
||||
return read_only_;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto open(bool read_only) -> bool;
|
||||
|
||||
[[nodiscard]] auto read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset,
|
||||
std::size_t *total_read = nullptr) -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove() -> bool override;
|
||||
|
||||
auto set_read_buffer_size(std::uint32_t size) -> std::uint32_t override {
|
||||
read_buffer_size = size;
|
||||
return read_buffer_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto size() const -> std::uint64_t override { return size_; }
|
||||
|
||||
[[nodiscard]] auto truncate(std::size_t size) -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
write(const unsigned char *data, std::size_t to_write, std::size_t offset,
|
||||
std::size_t *total_written = nullptr) -> bool override;
|
||||
|
||||
public:
|
||||
auto operator=(const smb_file &) noexcept -> smb_file & = delete;
|
||||
|
||||
auto operator=(smb_file &&move_file) noexcept -> smb_file & {
|
||||
if (this != &move_file) {
|
||||
access_time_ = move_file.access_time_;
|
||||
creation_time_ = move_file.creation_time_;
|
||||
fd_ = std::move(move_file.fd_);
|
||||
modified_time_ = move_file.modified_time_;
|
||||
path_ = std::move(move_file.path_);
|
||||
read_buffer_size = move_file.get_read_buffer_size();
|
||||
read_only_ = move_file.read_only_;
|
||||
session_ = std::move(move_file.session_);
|
||||
share_name_ = std::move(move_file.share_name_);
|
||||
size_ = move_file.size_;
|
||||
tid_ = move_file.tid_;
|
||||
write_time_ = move_file.write_time_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator bool() const override { return fd_.has_value(); }
|
||||
};
|
||||
|
||||
class smb_directory final : public i_directory {
|
||||
public:
|
||||
using smb_directory_t = std::unique_ptr<smb_directory>;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open(std::string_view host, std::string_view user, std::string_view password,
|
||||
std::string_view share_name) -> smb_directory_t;
|
||||
|
||||
[[nodiscard]] static auto
|
||||
open(std::wstring_view host, std::wstring_view user,
|
||||
std::wstring_view password,
|
||||
std::wstring_view share_name) -> smb_directory_t;
|
||||
|
||||
public:
|
||||
smb_directory() noexcept = default;
|
||||
|
||||
smb_directory(const smb_directory &) noexcept = delete;
|
||||
|
||||
smb_directory(smb_directory &&) noexcept = default;
|
||||
|
||||
~smb_directory() override = default;
|
||||
|
||||
private:
|
||||
smb_directory(std::string path, smb_session_t session,
|
||||
std::string_view share_name, smb_tid tid)
|
||||
: path_(std::move(path)),
|
||||
session_(std::move(session)),
|
||||
share_name_(share_name),
|
||||
tid_(tid) {}
|
||||
|
||||
private:
|
||||
std::string path_{};
|
||||
smb_session_t session_{};
|
||||
std::string share_name_{};
|
||||
smb_tid tid_{};
|
||||
|
||||
public:
|
||||
[[nodiscard]] auto
|
||||
count(bool recursive = false) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
create_directory(std::string_view path) const -> fs_directory_t override;
|
||||
|
||||
[[nodiscard]] auto create_file(std::string_view file_name,
|
||||
bool read_only) const -> fs_file_t override;
|
||||
|
||||
[[nodiscard]] auto exists() const -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_directory(std::string_view path) const -> fs_directory_t override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_directories() const -> std::vector<fs_directory_t> override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_file(std::string_view path) const -> fs_file_t override;
|
||||
|
||||
[[nodiscard]] auto get_files() const -> std::vector<fs_file_t> override;
|
||||
|
||||
[[nodiscard]] auto get_items() const -> std::vector<fs_item_t> override;
|
||||
|
||||
[[nodiscard]] auto get_path() const -> std::string override { return path_; }
|
||||
|
||||
[[nodiscard]] auto get_time(time_types type) const -> std::uint64_t override;
|
||||
|
||||
[[nodiscard]] auto get_unc_path() const -> std::string {
|
||||
return smb_get_unc_path(path_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_uri_path() const -> std::string {
|
||||
return smb_get_uri_path(path_);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto
|
||||
get_uri_path(std::string_view user,
|
||||
std::string_view password) const -> std::string {
|
||||
return smb_get_uri_path(path_, user, password);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto move_to(std::string_view new_path) -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove() -> bool override;
|
||||
|
||||
[[nodiscard]] auto remove_recursively() -> bool override;
|
||||
|
||||
[[nodiscard]] auto
|
||||
size(bool recursive = false) const -> std::uint64_t override;
|
||||
|
||||
public:
|
||||
auto operator=(const smb_directory &) noexcept -> smb_directory & = delete;
|
||||
|
||||
auto
|
||||
operator=(smb_directory &&move_dir) noexcept -> smb_directory & = default;
|
||||
|
||||
[[nodiscard]] operator bool() const override { return session_ != nullptr; }
|
||||
};
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
||||
|
||||
[[nodiscard]] auto create_directories(std::string_view path) -> bool;
|
||||
|
||||
[[nodiscard]] auto create_directories(std::wstring_view path) -> bool;
|
||||
|
@ -192,6 +192,10 @@ combine(std::string_view path,
|
||||
combine(std::wstring_view path,
|
||||
const std::vector<std::wstring_view> &paths) -> std::wstring;
|
||||
|
||||
[[nodiscard]] auto contains_trash_directory(std::string_view path) -> bool;
|
||||
|
||||
[[nodiscard]] auto contains_trash_directory(std::wstring_view path) -> bool;
|
||||
|
||||
[[nodiscard]] auto inline create_api_path(std::string_view path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto inline create_api_path(std::wstring_view path)
|
||||
@ -224,10 +228,6 @@ get_parent_api_path(std::wstring_view path) -> std::wstring;
|
||||
|
||||
[[nodiscard]] auto get_parent_directory(std::wstring_view path) -> std::wstring;
|
||||
|
||||
[[nodiscard]] auto is_trash_directory(std::string_view path) -> bool;
|
||||
|
||||
[[nodiscard]] auto is_trash_directory(std::wstring_view path) -> bool;
|
||||
|
||||
[[nodiscard]] auto make_file_uri(std::string_view path) -> std::string;
|
||||
|
||||
[[nodiscard]] auto make_file_uri(std::wstring_view path) -> std::wstring;
|
||||
|
@ -171,8 +171,7 @@ const std::size_t encrypting_reader::encrypted_chunk_size_ =
|
||||
encrypting_reader::encrypting_reader(
|
||||
std::string_view file_name, std::string_view source_path,
|
||||
stop_type &stop_requested, std::string_view token,
|
||||
std::optional<std::string_view> relative_parent_path,
|
||||
std::size_t error_return)
|
||||
std::optional<std::string> relative_parent_path, std::size_t error_return)
|
||||
: key_(utils::encryption::generate_key<utils::encryption::hash_256_t>(
|
||||
token)),
|
||||
stop_requested_(stop_requested),
|
||||
|
@ -1,117 +1,117 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "utils/encrypt.hpp"
|
||||
|
||||
#include "events/event_system.hpp"
|
||||
#include "events/events.hpp"
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/collection.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
namespace repertory::utils::encryption {
|
||||
auto decrypt_file_path(std::string_view encryption_token,
|
||||
std::string &file_path) -> api_error {
|
||||
std::string decrypted_file_path{};
|
||||
for (const auto &part : std::filesystem::path(file_path)) {
|
||||
auto file_name = part.string();
|
||||
if (file_name == "/") {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto res = decrypt_file_name(encryption_token, file_name);
|
||||
if (res != api_error::success) {
|
||||
return res;
|
||||
}
|
||||
|
||||
decrypted_file_path += '/' + file_name;
|
||||
}
|
||||
|
||||
file_path = decrypted_file_path;
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto decrypt_file_name(std::string_view encryption_token,
|
||||
std::string &file_name) -> api_error {
|
||||
data_buffer buffer;
|
||||
if (not utils::collection::from_hex_string(file_name, buffer)) {
|
||||
return api_error::error;
|
||||
}
|
||||
|
||||
file_name.clear();
|
||||
if (not utils::encryption::decrypt_data(encryption_token, buffer,
|
||||
file_name)) {
|
||||
return api_error::decryption_error;
|
||||
}
|
||||
|
||||
return api_error::success;
|
||||
}
|
||||
|
||||
auto read_encrypted_range(const http_range &range,
|
||||
const utils::encryption::hash_256_t &key,
|
||||
reader_func reader, std::uint64_t total_size,
|
||||
data_buffer &data) -> api_error {
|
||||
const auto encrypted_chunk_size =
|
||||
utils::encryption::encrypting_reader::get_encrypted_chunk_size();
|
||||
const auto data_chunk_size =
|
||||
utils::encryption::encrypting_reader::get_data_chunk_size();
|
||||
|
||||
const auto start_chunk =
|
||||
static_cast<std::size_t>(range.begin / data_chunk_size);
|
||||
const auto end_chunk = static_cast<std::size_t>(range.end / data_chunk_size);
|
||||
auto remain = range.end - range.begin + 1U;
|
||||
auto source_offset = static_cast<std::size_t>(range.begin % data_chunk_size);
|
||||
|
||||
for (std::size_t chunk = start_chunk; chunk <= end_chunk; chunk++) {
|
||||
data_buffer cypher;
|
||||
const auto start_offset = chunk * encrypted_chunk_size;
|
||||
const auto end_offset = std::min(
|
||||
start_offset + (total_size - (chunk * data_chunk_size)) +
|
||||
encryption_header_size - 1U,
|
||||
static_cast<std::uint64_t>(start_offset + encrypted_chunk_size - 1U));
|
||||
|
||||
const auto result = reader(cypher, start_offset, end_offset);
|
||||
if (result != api_error::success) {
|
||||
return result;
|
||||
}
|
||||
|
||||
data_buffer source_buffer;
|
||||
if (not utils::encryption::decrypt_data(key, cypher, source_buffer)) {
|
||||
return api_error::decryption_error;
|
||||
}
|
||||
cypher.clear();
|
||||
|
||||
const auto data_size = static_cast<std::size_t>(std::min(
|
||||
remain, static_cast<std::uint64_t>(data_chunk_size - source_offset)));
|
||||
std::copy(std::next(source_buffer.begin(),
|
||||
static_cast<std::int64_t>(source_offset)),
|
||||
std::next(source_buffer.begin(),
|
||||
static_cast<std::int64_t>(source_offset + data_size)),
|
||||
std::back_inserter(data));
|
||||
remain -= data_size;
|
||||
source_offset = 0U;
|
||||
}
|
||||
|
||||
return api_error::success;
|
||||
}
|
||||
} // namespace repertory::utils::encryption
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "utils/encryption.hpp"
|
||||
|
||||
#include "utils/collection.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
|
||||
namespace repertory::utils::encryption {
|
||||
auto decrypt_file_path(std::string_view encryption_token,
|
||||
std::string &file_path) -> bool {
|
||||
std::string decrypted_file_path{};
|
||||
for (const auto &part : std::filesystem::path(file_path)) {
|
||||
auto file_name = part.string();
|
||||
if (file_name == "/") {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto res = decrypt_file_name(encryption_token, file_name);
|
||||
if (not res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
decrypted_file_path += '/' + file_name;
|
||||
}
|
||||
|
||||
file_path = decrypted_file_path;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto decrypt_file_name(std::string_view encryption_token,
|
||||
std::string &file_name) -> bool {
|
||||
data_buffer buffer;
|
||||
if (not utils::collection::from_hex_string(file_name, buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file_name.clear();
|
||||
if (not utils::encryption::decrypt_data(encryption_token, buffer,
|
||||
file_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(PROJECT_ENABLE_CURL)
|
||||
auto read_encrypted_range(const http_range &range,
|
||||
const utils::encryption::hash_256_t &key,
|
||||
reader_func_t reader_func, std::uint64_t total_size,
|
||||
data_buffer &data) -> bool {
|
||||
const auto encrypted_chunk_size =
|
||||
utils::encryption::encrypting_reader::get_encrypted_chunk_size();
|
||||
const auto data_chunk_size =
|
||||
utils::encryption::encrypting_reader::get_data_chunk_size();
|
||||
|
||||
const auto start_chunk =
|
||||
static_cast<std::size_t>(range.begin / data_chunk_size);
|
||||
const auto end_chunk = static_cast<std::size_t>(range.end / data_chunk_size);
|
||||
auto remain = range.end - range.begin + 1U;
|
||||
auto source_offset = static_cast<std::size_t>(range.begin % data_chunk_size);
|
||||
|
||||
for (std::size_t chunk = start_chunk; chunk <= end_chunk; chunk++) {
|
||||
data_buffer cypher;
|
||||
const auto start_offset = chunk * encrypted_chunk_size;
|
||||
const auto end_offset = std::min(
|
||||
start_offset + (total_size - (chunk * data_chunk_size)) +
|
||||
encryption_header_size - 1U,
|
||||
static_cast<std::uint64_t>(start_offset + encrypted_chunk_size - 1U));
|
||||
|
||||
if (not reader_func(cypher, start_offset, end_offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_buffer source_buffer;
|
||||
if (not utils::encryption::decrypt_data(key, cypher, source_buffer)) {
|
||||
return false;
|
||||
}
|
||||
cypher.clear();
|
||||
|
||||
const auto data_size = static_cast<std::size_t>(std::min(
|
||||
remain, static_cast<std::uint64_t>(data_chunk_size - source_offset)));
|
||||
std::copy(std::next(source_buffer.begin(),
|
||||
static_cast<std::int64_t>(source_offset)),
|
||||
std::next(source_buffer.begin(),
|
||||
static_cast<std::int64_t>(source_offset + data_size)),
|
||||
std::back_inserter(data));
|
||||
remain -= data_size;
|
||||
source_offset = 0U;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_CURL)
|
||||
} // namespace repertory::utils::encryption
|
||||
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined (PROJECT_ENABLE_BOOST)
|
@ -21,51 +21,32 @@
|
||||
*/
|
||||
#include "utils/error.hpp"
|
||||
|
||||
namespace {
|
||||
struct default_exception_handler final
|
||||
: repertory::utils::error::i_exception_handler {
|
||||
void handle_exception(std::string_view function_name) const override {
|
||||
std::cerr << function_name << "|exception|unknown" << std::endl;
|
||||
}
|
||||
|
||||
void handle_exception(std::string_view function_name,
|
||||
const std::exception &ex) const override {
|
||||
std::cerr << function_name << "|exception|"
|
||||
<< (ex.what() == nullptr ? "unknown" : ex.what()) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
static default_exception_handler default_handler{};
|
||||
|
||||
static std::atomic<repertory::utils::error::i_exception_handler *>
|
||||
exception_handler{
|
||||
&default_handler,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace repertory::utils::error {
|
||||
std::atomic<const i_exception_handler *> exception_handler{
|
||||
&default_exception_handler};
|
||||
|
||||
void handle_exception(std::string_view function_name) {
|
||||
i_exception_handler *handler{exception_handler};
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
handler->handle_exception(function_name);
|
||||
return;
|
||||
}
|
||||
|
||||
default_handler.handle_exception(function_name);
|
||||
default_exception_handler.handle_exception(function_name);
|
||||
}
|
||||
|
||||
void handle_exception(std::string_view function_name,
|
||||
const std::exception &ex) {
|
||||
i_exception_handler *handler{exception_handler};
|
||||
const i_exception_handler *handler{exception_handler};
|
||||
if (handler != nullptr) {
|
||||
handler->handle_exception(function_name, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
default_handler.handle_exception(function_name, ex);
|
||||
default_exception_handler.handle_exception(function_name, ex);
|
||||
}
|
||||
|
||||
void set_exception_handler(i_exception_handler *handler) {
|
||||
void set_exception_handler(const i_exception_handler *handler) {
|
||||
exception_handler = handler;
|
||||
}
|
||||
} // namespace repertory::utils::error
|
||||
|
@ -77,10 +77,43 @@ namespace {
|
||||
} // namespace
|
||||
|
||||
namespace repertory::utils::file {
|
||||
auto i_file::read_all(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read) -> bool {
|
||||
data_buffer buffer;
|
||||
buffer.resize(get_read_buffer_size());
|
||||
|
||||
std::size_t current_read{};
|
||||
while (read(reinterpret_cast<unsigned char *>(buffer.data()),
|
||||
buffer.size() * sizeof(data_buffer::value_type), offset,
|
||||
¤t_read)) {
|
||||
if (total_read != nullptr) {
|
||||
*total_read += current_read;
|
||||
}
|
||||
|
||||
if (current_read != 0U) {
|
||||
offset += current_read;
|
||||
|
||||
data.insert(
|
||||
data.end(), buffer.begin(),
|
||||
std::next(buffer.begin(),
|
||||
static_cast<std::int64_t>(
|
||||
current_read / sizeof(data_buffer::value_type))));
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto create_directories(std::string_view path) -> bool {
|
||||
if (is_directory(path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
return is_directory(path) ||
|
||||
(::SHCreateDirectory(
|
||||
return (::SHCreateDirectory(
|
||||
nullptr,
|
||||
utils::string::from_utf8(utils::path::absolute(path)).c_str()) ==
|
||||
ERROR_SUCCESS);
|
||||
@ -332,4 +365,170 @@ auto write_json_file(std::wstring_view path,
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
#endif // defined(PROJECT_ENABLE_JSON)
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
static constexpr const auto validate_smb_path =
|
||||
[](std::string_view path) -> bool {
|
||||
return (not utils::string::begins_with(path, "///") &&
|
||||
utils::string::begins_with(path, "//") &&
|
||||
not utils::string::contains(path, " ") &&
|
||||
std::count(path.begin(), path.end(), '/') >= 3U);
|
||||
};
|
||||
|
||||
auto smb_create_smb_path(std::string_view smb_path,
|
||||
std::string_view rel_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
std::string path{rel_path};
|
||||
utils::path::format_path(path, "/", "\\");
|
||||
utils::string::left_trim(path, '/');
|
||||
|
||||
auto old_parts =
|
||||
repertory::utils::string::split(smb_path.substr(2U), '/', false);
|
||||
old_parts.erase(std::next(old_parts.begin(), 2U), old_parts.end());
|
||||
|
||||
auto new_parts = repertory::utils::string::split(path, '/', false);
|
||||
old_parts.insert(old_parts.end(), new_parts.begin(), new_parts.end());
|
||||
|
||||
path = utils::string::join(old_parts, '/');
|
||||
path = "//" + utils::path::format_path(path, "/", "\\");
|
||||
|
||||
if (not validate_smb_path(path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{path});
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
auto smb_create_and_validate_relative_path(
|
||||
std::string_view smb_path, std::string_view path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
std::string dir_path;
|
||||
if (utils::string::begins_with(path, "//")) {
|
||||
if (not utils::file::smb_parent_is_same(smb_path, path)) {
|
||||
throw std::runtime_error("failed to validate path|" +
|
||||
std::string{smb_path} + '|' + std::string{path} +
|
||||
"|parent paths are not the same");
|
||||
}
|
||||
|
||||
return utils::file::smb_create_relative_path(path);
|
||||
}
|
||||
|
||||
return utils::file::smb_create_relative_path(std::string{smb_path} + '/' +
|
||||
std::string{path});
|
||||
}
|
||||
|
||||
auto smb_create_relative_path(std::string_view smb_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
std::string path{smb_path};
|
||||
utils::path::format_path(path, "\\", "/");
|
||||
utils::string::left_trim(path, '\\');
|
||||
|
||||
auto parts = repertory::utils::string::split(path, '\\', false);
|
||||
parts.erase(parts.begin(), std::next(parts.begin(), 2U));
|
||||
return "\\" + utils::string::join(parts, '\\');
|
||||
}
|
||||
|
||||
auto smb_create_search_path(std::string_view smb_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
std::string path{smb_path};
|
||||
utils::string::left_trim(path, '/');
|
||||
|
||||
auto parts = repertory::utils::string::split(path, '/', false);
|
||||
parts.erase(parts.begin(), std::next(parts.begin(), 2U));
|
||||
|
||||
auto search_path = repertory::utils::string::join(parts, '\\');
|
||||
return search_path.empty() ? "\\*" : "\\" + search_path + "\\*";
|
||||
}
|
||||
|
||||
auto smb_get_parent_path(std::string_view smb_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
auto parts = repertory::utils::string::split(smb_path.substr(2U), '/', false);
|
||||
if (parts.size() > 2U) {
|
||||
parts.erase(std::prev(parts.end()), parts.end());
|
||||
}
|
||||
|
||||
auto parent_smb_path = "//" + utils::string::join(parts, '/');
|
||||
if (not validate_smb_path(parent_smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + parent_smb_path);
|
||||
}
|
||||
|
||||
return parent_smb_path;
|
||||
}
|
||||
|
||||
auto smb_get_root_path(std::string_view smb_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
auto parts = repertory::utils::string::split(smb_path.substr(2U), '/', false);
|
||||
if (parts.size() > 2U) {
|
||||
parts.erase(std::next(parts.begin(), 2U), parts.end());
|
||||
}
|
||||
|
||||
return "//" + utils::string::join(parts, '/');
|
||||
}
|
||||
|
||||
auto smb_get_unc_path(std::string_view smb_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
std::string unc_path{smb_path};
|
||||
utils::path::format_path(unc_path, "\\", "/");
|
||||
return '\\' + unc_path;
|
||||
}
|
||||
|
||||
auto smb_get_uri_path(std::string_view smb_path) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
return "smb:" + std::string{smb_path};
|
||||
}
|
||||
|
||||
auto smb_get_uri_path(std::string_view smb_path, std::string_view user,
|
||||
std::string_view password) -> std::string {
|
||||
if (not validate_smb_path(smb_path)) {
|
||||
throw std::runtime_error("invalid smb path|" + std::string{smb_path});
|
||||
}
|
||||
|
||||
return "smb://" + std::string{user} + ':' + std::string{password} + '@' +
|
||||
std::string{smb_path.substr(2U)};
|
||||
}
|
||||
|
||||
auto smb_parent_is_same(std::string_view smb_path1,
|
||||
std::string_view smb_path2) -> bool {
|
||||
if (not(validate_smb_path(smb_path1) && validate_smb_path(smb_path2))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto parts1 = utils::string::split(smb_path1.substr(2U), "/", false);
|
||||
auto parts2 = utils::string::split(smb_path2.substr(2U), "/", false);
|
||||
if (parts1.size() < 2U || parts2.size() < 2U) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parts2.at(1U).empty() || parts1.at(1U).empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::equal(parts1.begin(), std::next(parts1.begin(), 2U),
|
||||
parts2.begin());
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
||||
} // namespace repertory::utils::file
|
||||
|
@ -1,53 +1,55 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/encrypting_reader.hpp"
|
||||
#include "utils/file_utils.hpp"
|
||||
#include "utils/path.hpp"
|
||||
|
||||
namespace repertory {
|
||||
/* TEST(encrypting_reader, get_encrypted_file_name) {
|
||||
const auto source_file_name = get_source_file_name();
|
||||
ASSERT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
|
||||
const auto token = std::string("moose");
|
||||
auto &source_file = create_random_file(source_file_name, 1024UL);
|
||||
EXPECT_TRUE(source_file != nullptr);
|
||||
if (source_file) {
|
||||
stop_type stop_requested = false;
|
||||
utils::encryption::encrypting_reader reader(
|
||||
"test.dat", source_file_name, stop_requested, token, std::nullopt);
|
||||
|
||||
auto file_name = reader.get_encrypted_file_name();
|
||||
|
||||
EXPECT_EQ(api_error::success,
|
||||
utils::encryption::decrypt_file_name(token, file_name));
|
||||
EXPECT_STREQ("test.dat", file_name.c_str());
|
||||
|
||||
source_file->close();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(utils::file::retry_delete_file(source_file_name));
|
||||
} */
|
||||
} // namespace repertory
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "utils/file.hpp"
|
||||
|
||||
namespace repertory::utils::file {
|
||||
auto directory::count(bool recursive) const -> std::uint64_t { return 0U; }
|
||||
|
||||
auto directory::create_directory(std::string_view path) const
|
||||
-> fs_directory_t {}
|
||||
|
||||
auto directory::exists() const -> bool { return false; }
|
||||
|
||||
auto directory::get_directory(std::string_view path) const -> fs_directory_t {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto directory::get_directories() const -> std::vector<fs_directory_t> {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto directory::get_time(time_types type) const -> std::uint64_t {}
|
||||
|
||||
auto directory::get_file(std::string_view path) const -> fs_file_t {}
|
||||
|
||||
auto directory::get_files() const -> std::vector<fs_file_t> { return {}; }
|
||||
|
||||
auto directory::get_items() const -> std::vector<fs_item_t> { return {}; }
|
||||
|
||||
auto directory::move_to(std::string_view new_path) -> bool { return false; }
|
||||
|
||||
auto directory::remove() -> bool { return false; }
|
||||
|
||||
auto directory::remove_recursively() -> bool { return false; }
|
||||
|
||||
auto directory::size(bool recursive) const -> std::uint64_t { return 0U; }
|
||||
} // namespace repertory::utils::file
|
@ -1,46 +1,52 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef INCLUDE_UTILS_ENCRYPT_HPP_
|
||||
#define INCLUDE_UTILS_ENCRYPT_HPP_
|
||||
|
||||
#include "types/repertory.hpp"
|
||||
#include "utils/encryption.hpp"
|
||||
|
||||
namespace repertory::utils::encryption {
|
||||
using reader_func = std::function<api_error(data_buffer &cypher_text,
|
||||
std::uint64_t start_offset,
|
||||
std::uint64_t end_offset)>;
|
||||
// Prototypes
|
||||
[[nodiscard]] auto decrypt_file_path(std::string_view encryption_token,
|
||||
std::string &file_path) -> api_error;
|
||||
|
||||
[[nodiscard]] auto decrypt_file_name(std::string_view encryption_token,
|
||||
std::string &file_name) -> api_error;
|
||||
|
||||
[[nodiscard]] auto
|
||||
read_encrypted_range(const http_range &range,
|
||||
const utils::encryption::hash_256_t &key,
|
||||
reader_func reader, std::uint64_t total_size,
|
||||
data_buffer &data) -> api_error;
|
||||
} // namespace repertory::utils::encryption
|
||||
|
||||
#endif // INCLUDE_UTILS_ENCRYPT_HPP_
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "utils/file.hpp"
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
|
||||
namespace repertory::utils::file {
|
||||
auto enc_file::attach_file(fs_file_t file) -> fs_file_t {}
|
||||
|
||||
enc_file::enc_file(fs_file_t file) : file_(std::move(file)) {}
|
||||
|
||||
void enc_file::close() {}
|
||||
|
||||
void enc_file::flush() const {}
|
||||
|
||||
auto enc_file::get_time(time_types type) const -> std::uint64_t {}
|
||||
|
||||
auto enc_file::move_to(std::string_view path) -> bool {}
|
||||
|
||||
auto enc_file::read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset, std::size_t *total_read) -> bool {}
|
||||
|
||||
auto enc_file::remove() -> bool {}
|
||||
|
||||
auto enc_file::truncate(std::size_t size) -> bool {}
|
||||
|
||||
auto enc_file::write(const unsigned char *data, std::size_t to_write,
|
||||
std::size_t offset, std::size_t *total_written) -> bool {}
|
||||
|
||||
auto enc_file::size() const -> std::uint64_t {}
|
||||
} // namespace repertory::utils::file
|
||||
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
@ -25,10 +25,11 @@
|
||||
#include "utils/error.hpp"
|
||||
#include "utils/path.hpp"
|
||||
#include "utils/string.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
namespace repertory::utils::file {
|
||||
// auto file::attach_file(native_handle handle,
|
||||
// bool read_only) -> std::unique_ptr<i_file> {
|
||||
// bool read_only) -> fs_file_t {
|
||||
// static constexpr const std::string_view function_name{
|
||||
// static_cast<const char *>(__FUNCTION__),
|
||||
// };
|
||||
@ -64,7 +65,7 @@ namespace repertory::utils::file {
|
||||
// auto *ptr = fdopen(handle, read_only ? "rb" : "rb+");
|
||||
// #endif // defined(_WIN32)
|
||||
//
|
||||
// return std::unique_ptr<i_file>(new file{
|
||||
// return fs_file_t(new file{
|
||||
// file_t{ptr},
|
||||
// utils::path::absolute(path),
|
||||
// read_only,
|
||||
@ -90,8 +91,7 @@ void file::open() {
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
|
||||
auto file::open_file(std::string_view path,
|
||||
bool read_only) -> std::unique_ptr<i_file> {
|
||||
auto file::open_file(std::string_view path, bool read_only) -> fs_file_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
@ -101,7 +101,7 @@ auto file::open_file(std::string_view path,
|
||||
utils::path::absolute(path),
|
||||
read_only,
|
||||
};
|
||||
auto new_file = std::unique_ptr<i_file>(ptr);
|
||||
auto new_file = fs_file_t(ptr);
|
||||
|
||||
try {
|
||||
ptr->open();
|
||||
@ -115,7 +115,7 @@ auto file::open_file(std::string_view path,
|
||||
}
|
||||
|
||||
auto file::open_or_create_file(std::string_view path,
|
||||
bool read_only) -> std::unique_ptr<i_file> {
|
||||
bool read_only) -> fs_file_t {
|
||||
auto abs_path = utils::path::absolute(path);
|
||||
if (not is_file(abs_path)) {
|
||||
#if defined(_WIN32)
|
||||
@ -188,6 +188,68 @@ auto file::get_handle() const -> native_handle {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
auto file::get_time(time_types type) const -> std::uint64_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
recur_mutex_lock lock{*mtx_};
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
try {
|
||||
#if defined(_WIN32)
|
||||
#else // !defined(_WIN32)
|
||||
struct stat st {};
|
||||
stat(path_.c_str(), &st);
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
switch (type) {
|
||||
case time_types::access:
|
||||
#if defined(_WIN32)
|
||||
break;
|
||||
#else // !defined(_WIN32)
|
||||
return static_cast<std::uint64_t>(st.st_atim.tv_nsec +
|
||||
st.st_atim.tv_sec *
|
||||
utils::time::NANOS_PER_SECOND);
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
case time_types::creation:
|
||||
#if defined(_WIN32)
|
||||
break;
|
||||
#else // !defined(_WIN32)
|
||||
return static_cast<std::uint64_t>(st.st_ctim.tv_nsec +
|
||||
st.st_ctim.tv_sec *
|
||||
utils::time::NANOS_PER_SECOND);
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
case time_types::modified:
|
||||
#if defined(_WIN32)
|
||||
break;
|
||||
#else // !defined(_WIN32)
|
||||
return static_cast<std::uint64_t>(st.st_mtim.tv_nsec +
|
||||
st.st_mtim.tv_sec *
|
||||
utils::time::NANOS_PER_SECOND);
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
case time_types::write:
|
||||
#if defined(_WIN32)
|
||||
break;
|
||||
#else // !defined(_WIN32)
|
||||
return static_cast<std::uint64_t>(st.st_mtim.tv_nsec +
|
||||
st.st_mtim.tv_sec *
|
||||
utils::time::NANOS_PER_SECOND);
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto file::move_to(std::string_view path) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
@ -233,59 +295,6 @@ auto file::move_to(std::string_view path) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto file::read_all(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read) -> bool {
|
||||
#if defined(_WIN32)
|
||||
recur_mutex_lock lock{*mtx_};
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
data_buffer buffer;
|
||||
buffer.resize(read_buffer_size);
|
||||
|
||||
std::size_t current_read{};
|
||||
while (read(reinterpret_cast<unsigned char *>(buffer.data()),
|
||||
buffer.size() * sizeof(data_buffer::value_type), offset,
|
||||
¤t_read)) {
|
||||
if (total_read != nullptr) {
|
||||
*total_read += current_read;
|
||||
}
|
||||
|
||||
if (current_read != 0U) {
|
||||
offset += current_read;
|
||||
|
||||
data.insert(
|
||||
data.end(), buffer.begin(),
|
||||
std::next(buffer.begin(),
|
||||
static_cast<std::int64_t>(
|
||||
current_read / sizeof(data_buffer::value_type))));
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto file::read(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read) -> bool {
|
||||
#if defined(_WIN32)
|
||||
recur_mutex_lock lock{*mtx_};
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
std::size_t bytes_read{};
|
||||
auto ret =
|
||||
read(reinterpret_cast<unsigned char *>(data.data()),
|
||||
data.size() * sizeof(data_buffer::value_type), offset, &bytes_read);
|
||||
data.resize(bytes_read / sizeof(data_buffer::value_type));
|
||||
|
||||
if (total_read != nullptr) {
|
||||
(*total_read) = bytes_read;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto file::read(unsigned char *data, std::size_t to_read, std::uint64_t offset,
|
||||
std::size_t *total_read) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
@ -310,9 +319,18 @@ auto file::read(unsigned char *data, std::size_t to_read, std::uint64_t offset,
|
||||
throw std::runtime_error("failed to seek before read");
|
||||
}
|
||||
|
||||
auto bytes_read = fread(data, 1U, to_read, file_.get());
|
||||
if (not feof(file_.get()) && ferror(file_.get())) {
|
||||
throw std::runtime_error("failed to read file bytes");
|
||||
std::size_t bytes_read{0U};
|
||||
while (bytes_read != to_read) {
|
||||
res = fread(&data[bytes_read], 1U, to_read - bytes_read, file_.get());
|
||||
if (not feof(file_.get()) && ferror(file_.get())) {
|
||||
throw std::runtime_error("failed to read file bytes");
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
bytes_read += static_cast<std::size_t>(res);
|
||||
}
|
||||
|
||||
if (total_read != nullptr) {
|
||||
@ -407,10 +425,19 @@ auto file::write(const unsigned char *data, std::size_t to_write,
|
||||
throw std::runtime_error("failed to seek before write");
|
||||
}
|
||||
|
||||
auto bytes_written =
|
||||
fwrite(reinterpret_cast<const char *>(data), 1U, to_write, file_.get());
|
||||
if (not feof(file_.get()) && ferror(file_.get())) {
|
||||
throw std::runtime_error("failed to write file bytes");
|
||||
std::size_t bytes_written{0U};
|
||||
while (bytes_written != to_write) {
|
||||
res = fwrite(reinterpret_cast<const char *>(&data[bytes_written]), 1U,
|
||||
to_write - bytes_written, file_.get());
|
||||
if (not feof(file_.get()) && ferror(file_.get())) {
|
||||
throw std::runtime_error("failed to write file bytes");
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
bytes_written += static_cast<std::size_t>(res);
|
||||
}
|
||||
|
||||
flush();
|
||||
@ -466,11 +493,4 @@ 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<const unsigned char *>(data.data()),
|
||||
data.size() * sizeof(data_buffer::value_type), offset,
|
||||
total_written);
|
||||
}
|
||||
} // namespace repertory::utils::file
|
||||
|
610
support/src/utils/file_smb_directory.cpp
Normal file
610
support/src/utils/file_smb_directory.cpp
Normal file
@ -0,0 +1,610 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "utils/file.hpp"
|
||||
|
||||
#include "utils/error.hpp"
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
namespace repertory::utils::file {
|
||||
auto smb_directory::open(std::string_view host, std::string_view user,
|
||||
std::string_view password,
|
||||
std::string_view share_name) -> smb_directory_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
smb_session_t session{smb_session_new(), smb_session_deleter};
|
||||
netbios_ns_t ns{netbios_ns_new()};
|
||||
|
||||
sockaddr_in addr{};
|
||||
|
||||
auto res = netbios_ns_resolve(
|
||||
ns.get(), std::string{host}.c_str(), NETBIOS_FILESERVER,
|
||||
reinterpret_cast<std::uint32_t *>(&addr.sin_addr.s_addr));
|
||||
if (res != DSM_SUCCESS) {
|
||||
res = inet_pton(AF_INET, std::string{host}.c_str(), &addr.sin_addr);
|
||||
if (res != 1) {
|
||||
throw std::runtime_error("failed to resolve host|" + std::string{host} +
|
||||
'|' + std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
res = smb_session_connect(session.get(), std::string{host}.c_str(),
|
||||
static_cast<std::uint32_t>(addr.sin_addr.s_addr),
|
||||
SMB_TRANSPORT_TCP);
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to connect to host|" +
|
||||
std::string{host} + '|' + std::to_string(res));
|
||||
}
|
||||
|
||||
smb_session_set_creds(session.get(), std::string{host}.c_str(),
|
||||
std::string{user}.c_str(),
|
||||
std::string{password}.c_str());
|
||||
res = smb_session_login(session.get());
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to logon to host|" + std::string{host} +
|
||||
'|' + std::string{user} + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
smb_tid tid{};
|
||||
res =
|
||||
smb_tree_connect(session.get(), std::string{share_name}.c_str(), &tid);
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to connect to share|" +
|
||||
std::string{share_name} + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
return smb_directory_t{
|
||||
new smb_directory{
|
||||
"//" + std::string{host} + "/" + std::string{share_name},
|
||||
session,
|
||||
share_name,
|
||||
tid,
|
||||
},
|
||||
};
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto smb_directory::open(std::wstring_view host, std::wstring_view user,
|
||||
std::wstring_view password,
|
||||
std::wstring_view share_name) -> smb_directory_t {
|
||||
return open(utils::string::to_utf8(host), utils::string::to_utf8(user),
|
||||
utils::string::to_utf8(password),
|
||||
utils::string::to_utf8(share_name));
|
||||
}
|
||||
|
||||
auto smb_directory::count(bool recursive) const -> std::uint64_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
smb_stat_list_t list{
|
||||
smb_find(session_.get(), tid_, smb_create_search_path(path_).c_str())};
|
||||
auto count = smb_stat_list_count(list.get());
|
||||
|
||||
if (not recursive) {
|
||||
return count;
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to get directory count recursively|" +
|
||||
path_ + "|not implemented");
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
auto smb_directory::create_directory(std::string_view path) const
|
||||
-> fs_directory_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
auto dir = get_directory(path);
|
||||
if (dir) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
auto res = smb_directory_create(
|
||||
session_.get(), tid_,
|
||||
smb_create_and_validate_relative_path(path_, path).c_str());
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to create directory|" + path_ + '/' +
|
||||
std::string{path} + '|' + std::to_string(res));
|
||||
}
|
||||
|
||||
return get_directory(path);
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto smb_directory::create_file(std::string_view file_name,
|
||||
bool read_only) const -> fs_file_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
auto fs_file = get_file(file_name);
|
||||
if (fs_file) {
|
||||
if (not dynamic_cast<smb_file *>(fs_file.get())->open(read_only)) {
|
||||
throw std::runtime_error("failed to open existing file|" +
|
||||
std::string{file_name});
|
||||
}
|
||||
|
||||
return fs_file;
|
||||
}
|
||||
|
||||
auto rel_path = smb_create_and_validate_relative_path(path_, file_name);
|
||||
|
||||
smb_fd fd{};
|
||||
auto res =
|
||||
smb_fopen(session_.get(), tid_, rel_path.c_str(), SMB_MOD_RW, &fd);
|
||||
if (res != DSM_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
smb_fclose(session_.get(), fd);
|
||||
|
||||
res = smb_fopen(session_.get(), tid_, rel_path.c_str(),
|
||||
read_only ? SMB_MOD_RO : SMB_MOD_RW2, &fd);
|
||||
if (res != DSM_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
smb_stat_t st{smb_fstat(session_.get(), tid_, rel_path.c_str())};
|
||||
if (not st) {
|
||||
smb_fclose(session_.get(), fd);
|
||||
throw std::runtime_error("failed to stat file|" + rel_path);
|
||||
}
|
||||
|
||||
return std::make_unique<smb_file>(
|
||||
smb_stat_get(st.get(), SMB_STAT_ATIME),
|
||||
smb_stat_get(st.get(), SMB_STAT_CTIME), fd,
|
||||
smb_stat_get(st.get(), SMB_STAT_MTIME),
|
||||
smb_create_smb_path(path_, std::string{rel_path}), session_,
|
||||
share_name_, smb_stat_get(st.get(), SMB_STAT_SIZE), tid_,
|
||||
smb_stat_get(st.get(), SMB_STAT_WTIME));
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
auto smb_directory::exists() const -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
smb_stat_t st{smb_fstat(session_.get(), tid_,
|
||||
smb_create_relative_path(path_).c_str())};
|
||||
if (not st) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return smb_stat_get(st.get(), SMB_STAT_ISDIR) != 0U;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_directory::get_directory(std::string_view path) const
|
||||
-> fs_directory_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
auto rel_path = smb_create_and_validate_relative_path(path_, path);
|
||||
smb_stat_t st{smb_fstat(session_.get(), tid_, rel_path.c_str())};
|
||||
if (not st) {
|
||||
throw std::runtime_error("failed to stat directory|" + rel_path);
|
||||
}
|
||||
|
||||
bool is_dir{smb_stat_get(st.get(), SMB_STAT_ISDIR) != 0U};
|
||||
if (not is_dir) {
|
||||
throw std::runtime_error("path is not a directory|" + rel_path);
|
||||
}
|
||||
|
||||
return smb_directory_t{
|
||||
new smb_directory{
|
||||
smb_create_smb_path(path_, rel_path),
|
||||
session_,
|
||||
share_name_,
|
||||
tid_,
|
||||
},
|
||||
};
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto smb_directory::get_directories() const -> std::vector<fs_directory_t> {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
smb_stat_list_t list{
|
||||
smb_find(session_.get(), tid_, smb_create_search_path(path_).c_str())};
|
||||
if (not list) {
|
||||
throw std::runtime_error("failed to get directory list|" + path_);
|
||||
}
|
||||
|
||||
std::vector<fs_directory_t> ret{};
|
||||
|
||||
auto count = smb_stat_list_count(list.get());
|
||||
for (std::size_t idx = 0U; idx < count; ++idx) {
|
||||
auto st = smb_stat_list_at(list.get(), idx);
|
||||
|
||||
bool is_dir{smb_stat_get(st, SMB_STAT_ISDIR) != 0U};
|
||||
if (not is_dir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name{smb_stat_name(st)};
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.emplace_back(smb_directory_t{
|
||||
new smb_directory{
|
||||
smb_create_smb_path(path_, name),
|
||||
session_,
|
||||
share_name_,
|
||||
tid_,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto smb_directory::get_file(std::string_view path) const -> fs_file_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
auto rel_path = smb_create_and_validate_relative_path(path_, path);
|
||||
smb_stat_t st{smb_fstat(session_.get(), tid_, rel_path.c_str())};
|
||||
if (not st) {
|
||||
throw std::runtime_error("failed to stat file|" + rel_path);
|
||||
}
|
||||
|
||||
bool is_dir{smb_stat_get(st.get(), SMB_STAT_ISDIR) != 0U};
|
||||
if (is_dir) {
|
||||
throw std::runtime_error("path is not a file|" + rel_path);
|
||||
}
|
||||
|
||||
return std::make_unique<smb_file>(
|
||||
smb_stat_get(st.get(), SMB_STAT_ATIME),
|
||||
smb_stat_get(st.get(), SMB_STAT_CTIME), std::nullopt,
|
||||
smb_stat_get(st.get(), SMB_STAT_MTIME),
|
||||
smb_create_smb_path(path_, std::string{rel_path}), session_,
|
||||
share_name_, smb_stat_get(st.get(), SMB_STAT_SIZE), tid_,
|
||||
smb_stat_get(st.get(), SMB_STAT_WTIME));
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto smb_directory::get_files() const -> std::vector<fs_file_t> {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
smb_stat_list_t list{
|
||||
smb_find(session_.get(), tid_, smb_create_search_path(path_).c_str())};
|
||||
if (not list) {
|
||||
throw std::runtime_error("failed to get file list|" + path_);
|
||||
}
|
||||
|
||||
std::vector<fs_file_t> ret{};
|
||||
|
||||
auto count = smb_stat_list_count(list.get());
|
||||
for (std::size_t idx = 0U; idx < count; ++idx) {
|
||||
auto st = smb_stat_list_at(list.get(), idx);
|
||||
bool is_dir{smb_stat_get(st, SMB_STAT_ISDIR) != 0U};
|
||||
if (is_dir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name{smb_stat_name(st)};
|
||||
ret.emplace_back(std::make_unique<smb_file>(
|
||||
smb_stat_get(st, SMB_STAT_ATIME), smb_stat_get(st, SMB_STAT_CTIME),
|
||||
std::nullopt, smb_stat_get(st, SMB_STAT_MTIME),
|
||||
smb_create_smb_path(path_, name), session_, share_name_,
|
||||
smb_stat_get(st, SMB_STAT_SIZE), tid_,
|
||||
smb_stat_get(st, SMB_STAT_WTIME)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto smb_directory::get_items() const -> std::vector<fs_item_t> {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
smb_stat_list_t list{
|
||||
smb_find(session_.get(), tid_, smb_create_search_path(path_).c_str())};
|
||||
if (not list) {
|
||||
throw std::runtime_error("failed to get item list|" + path_);
|
||||
}
|
||||
std::vector<fs_item_t> ret{};
|
||||
|
||||
auto count = smb_stat_list_count(list.get());
|
||||
for (std::size_t idx = 0U; idx < count; ++idx) {
|
||||
auto st = smb_stat_list_at(list.get(), idx);
|
||||
|
||||
bool is_dir{smb_stat_get(st, SMB_STAT_ISDIR) != 0U};
|
||||
std::string name{smb_stat_name(st)};
|
||||
|
||||
if (is_dir) {
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.emplace_back(smb_directory_t{
|
||||
new smb_directory{
|
||||
path_ + '/' + name,
|
||||
session_,
|
||||
share_name_,
|
||||
tid_,
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.emplace_back(std::make_unique<smb_file>(
|
||||
smb_stat_get(st, SMB_STAT_ATIME), smb_stat_get(st, SMB_STAT_CTIME),
|
||||
std::nullopt, smb_stat_get(st, SMB_STAT_MTIME),
|
||||
smb_create_smb_path(path_, name), session_, share_name_, tid_,
|
||||
smb_stat_get(st, SMB_STAT_SIZE), smb_stat_get(st, SMB_STAT_WTIME)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto smb_directory::get_time(time_types type) const -> std::uint64_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
auto rel_path = smb_create_relative_path(path_);
|
||||
smb_stat_t st{smb_fstat(session_.get(), tid_, rel_path.c_str())};
|
||||
if (not st) {
|
||||
throw std::runtime_error("failed to stat directory|" + rel_path);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case time_types::access:
|
||||
return smb_stat_get(st.get(), SMB_STAT_ATIME);
|
||||
|
||||
case time_types::creation:
|
||||
return smb_stat_get(st.get(), SMB_STAT_CTIME);
|
||||
|
||||
case time_types::modified:
|
||||
return smb_stat_get(st.get(), SMB_STAT_MTIME);
|
||||
|
||||
case time_types::write:
|
||||
return smb_stat_get(st.get(), SMB_STAT_WTIME);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
auto smb_directory::move_to(std::string_view new_path) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to move directory|" + path_ + '|' +
|
||||
std::string{new_path} + "|not implemented");
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_directory::remove() -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
auto res = smb_directory_rm(session_.get(), tid_,
|
||||
smb_create_relative_path(path_).c_str());
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to remove directory|" + path_ + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_directory::remove_recursively() -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to remove directory recursively|" + path_ +
|
||||
"|not implemented");
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_directory::size(bool /* recursive */) const -> std::uint64_t {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to get directory size|" + path_ +
|
||||
"|not implemented");
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace repertory::utils::file
|
||||
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
336
support/src/utils/file_smb_file.cpp
Normal file
336
support/src/utils/file_smb_file.cpp
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "utils/file.hpp"
|
||||
|
||||
#include "utils/error.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
|
||||
namespace repertory::utils::file {
|
||||
void smb_file::close() {
|
||||
if (fd_.has_value()) {
|
||||
smb_fclose(session_.get(), *fd_);
|
||||
fd_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
auto smb_file::exists() const -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (not session_) {
|
||||
throw std::runtime_error("session not found|" + path_);
|
||||
}
|
||||
|
||||
smb_stat_t st{smb_fstat(session_.get(), tid_,
|
||||
smb_create_relative_path(path_).c_str())};
|
||||
if (not st) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return smb_stat_get(st.get(), SMB_STAT_ISDIR) == 0U;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void smb_file::flush() const {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
throw std::runtime_error("failed to flush file|" + path_ +
|
||||
"|not implemented");
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
}
|
||||
|
||||
auto smb_file::move_to(std::string_view new_path) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (utils::string::begins_with(new_path, "//")) {
|
||||
throw std::runtime_error("failed to move file|" + path_ + '|' +
|
||||
std::string{new_path} +
|
||||
"|new path must be in same share");
|
||||
}
|
||||
|
||||
auto from_path = smb_create_relative_path(path_);
|
||||
auto to_path = smb_create_and_validate_relative_path(
|
||||
utils::string::begins_with(new_path, "/") ? smb_get_root_path(path_)
|
||||
: smb_get_parent_path(path_),
|
||||
new_path);
|
||||
|
||||
auto was_open{false};
|
||||
if (fd_.has_value()) {
|
||||
close();
|
||||
was_open = true;
|
||||
}
|
||||
|
||||
auto res = smb_tree_connect(session_.get(), share_name_.c_str(), &tid_);
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to connect to share|" + share_name_ +
|
||||
'|' + std::to_string(res));
|
||||
}
|
||||
|
||||
res = smb_file_mv(session_.get(), tid_, from_path.c_str(), to_path.c_str());
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to move file|" + path_ + '|' +
|
||||
from_path + '|' + to_path + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
path_ = smb_create_smb_path(path_, to_path);
|
||||
if (was_open) {
|
||||
return open(read_only_);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_file::open(bool read_only) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (fd_.has_value()) {
|
||||
if (read_only == read_only_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
auto rel_path = smb_create_relative_path(path_);
|
||||
|
||||
auto res = smb_tree_connect(session_.get(), share_name_.c_str(), &tid_);
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to connect to share|" + share_name_ +
|
||||
'|' + std::to_string(res));
|
||||
}
|
||||
|
||||
smb_fd fd{};
|
||||
res = smb_fopen(session_.get(), tid_, rel_path.c_str(),
|
||||
read_only ? SMB_MOD_RO : SMB_MOD_RW2, &fd);
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to open file|" + path_ + '|' + rel_path +
|
||||
'|' + utils::string::from_bool(read_only) + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
fd_ = fd;
|
||||
read_only_ = read_only;
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_file::read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset, std::size_t *total_read) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (total_read != nullptr) {
|
||||
(*total_read) = 0U;
|
||||
}
|
||||
|
||||
if (not fd_.has_value()) {
|
||||
throw std::runtime_error("failed to read file|" + path_ +
|
||||
"|file not open");
|
||||
}
|
||||
|
||||
auto res = smb_fseek(session_.get(), *fd_, static_cast<off_t>(offset),
|
||||
SMB_SEEK_SET);
|
||||
if (res == -1) {
|
||||
throw std::runtime_error("failed to seek file|" + path_ + '|' +
|
||||
std::to_string(offset) + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
std::size_t bytes_read{0U};
|
||||
while (bytes_read != to_read) {
|
||||
res = smb_fread(session_.get(), *fd_, &data[bytes_read],
|
||||
to_read - bytes_read);
|
||||
if (res == -1) {
|
||||
throw std::runtime_error("failed to read file|" + path_ + '|' +
|
||||
std::to_string(to_read) + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
bytes_read += static_cast<std::size_t>(res);
|
||||
}
|
||||
|
||||
if (total_read != nullptr) {
|
||||
(*total_read) = bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_file::remove() -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
close();
|
||||
|
||||
auto res = smb_tree_connect(session_.get(), share_name_.c_str(), &tid_);
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error("failed to connect to share|" + share_name_ +
|
||||
'|' + std::to_string(res));
|
||||
}
|
||||
|
||||
auto rel_path = smb_create_relative_path(path_);
|
||||
res = smb_file_rm(session_.get(), tid_, rel_path.c_str());
|
||||
if (res != DSM_SUCCESS) {
|
||||
throw std::runtime_error(
|
||||
"failed to remove file|" + path_ + '|' + rel_path + '|' +
|
||||
std::to_string(res) + '|' +
|
||||
std::to_string(smb_session_get_nt_status(session_.get())));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_file::truncate(std::size_t size) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
throw std::runtime_error("failed to truncate file|" + path_ + '|' +
|
||||
std::to_string(size) + "|not implemented");
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto smb_file::write(const unsigned char *data, std::size_t to_write,
|
||||
std::size_t offset, std::size_t *total_written) -> bool {
|
||||
static constexpr const std::string_view function_name{
|
||||
static_cast<const char *>(__FUNCTION__),
|
||||
};
|
||||
|
||||
try {
|
||||
if (total_written != nullptr) {
|
||||
(*total_written) = 0U;
|
||||
}
|
||||
|
||||
if (not fd_.has_value()) {
|
||||
throw std::runtime_error("failed to write file|" + path_ +
|
||||
"|file not open");
|
||||
}
|
||||
|
||||
auto res = smb_fseek(session_.get(), *fd_, static_cast<off_t>(offset),
|
||||
SMB_SEEK_SET);
|
||||
if (res == -1) {
|
||||
throw std::runtime_error("failed to seek file|" + path_ + '|' +
|
||||
std::to_string(offset) + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
std::size_t bytes_written{0U};
|
||||
while (bytes_written != to_write) {
|
||||
res = smb_fwrite(session_.get(), *fd_,
|
||||
const_cast<unsigned char *>(&data[bytes_written]),
|
||||
to_write - bytes_written);
|
||||
if (res == -1) {
|
||||
throw std::runtime_error("failed to write file|" + path_ + '|' +
|
||||
std::to_string(to_write) + '|' +
|
||||
std::to_string(res));
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
bytes_written += static_cast<std::size_t>(res);
|
||||
}
|
||||
|
||||
if (total_written != nullptr) {
|
||||
(*total_written) = bytes_written;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
utils::error::handle_exception(function_name, e);
|
||||
} catch (...) {
|
||||
utils::error::handle_exception(function_name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace repertory::utils::file
|
||||
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
@ -23,29 +23,26 @@
|
||||
|
||||
namespace repertory::utils::file {
|
||||
// auto thread_file::attach_file(native_handle handle,
|
||||
// bool read_only) -> std::unique_ptr<i_file> {}
|
||||
// bool read_only) -> fs_file_t {}
|
||||
|
||||
auto thread_file::attach_file(fs_file_t file) -> fs_file_t {}
|
||||
|
||||
auto thread_file::open_file(std::string_view path,
|
||||
bool read_only) -> std::unique_ptr<i_file> {}
|
||||
bool read_only) -> fs_file_t {}
|
||||
|
||||
auto thread_file::open_or_create_file(std::string_view path, bool read_only)
|
||||
-> std::unique_ptr<i_file> {}
|
||||
auto thread_file::open_or_create_file(std::string_view path,
|
||||
bool read_only) -> fs_file_t {}
|
||||
|
||||
thread_file::thread_file(std::unique_ptr<i_file> file)
|
||||
: file_(std::move(file)) {}
|
||||
thread_file::thread_file(fs_file_t file) : file_(std::move(file)) {}
|
||||
|
||||
void thread_file::close() {}
|
||||
|
||||
void thread_file::flush() const {}
|
||||
|
||||
auto thread_file::get_time(time_types type) const -> std::uint64_t {}
|
||||
|
||||
auto thread_file::move_to(std::string_view path) -> bool {}
|
||||
|
||||
auto thread_file::read_all(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read) -> bool {}
|
||||
|
||||
auto thread_file::read(data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_read) -> bool {}
|
||||
|
||||
auto thread_file::read(unsigned char *data, std::size_t to_read,
|
||||
std::uint64_t offset, std::size_t *total_read) -> bool {}
|
||||
|
||||
@ -58,7 +55,4 @@ auto thread_file::write(const unsigned char *data, std::size_t to_write,
|
||||
std::size_t *total_written) -> bool {}
|
||||
|
||||
auto thread_file::size() const -> std::uint64_t {}
|
||||
|
||||
auto thread_file::write(const data_buffer &data, std::uint64_t offset,
|
||||
std::size_t *total_written) -> bool {}
|
||||
} // namespace repertory::utils::file
|
||||
|
@ -182,17 +182,18 @@ auto get_parent_directory(std::wstring_view path) -> std::wstring {
|
||||
get_parent_directory(utils::string::to_utf8(path)));
|
||||
}
|
||||
|
||||
auto is_trash_directory(std::string_view path) -> bool {
|
||||
std::string dir_sep_t{get_directory_seperator<char>()};
|
||||
auto contains_trash_directory(std::string_view path) -> bool {
|
||||
auto parts = utils::string::split(utils::string::to_lower(absolute(path)),
|
||||
get_directory_seperator<char>(), false);
|
||||
|
||||
auto trash_path = utils::string::to_lower(absolute(path));
|
||||
return utils::string::begins_with(trash_path, dir_sep_t + ".trash-") ||
|
||||
utils::string::begins_with(trash_path, dir_sep_t + ".trashes") ||
|
||||
utils::string::begins_with(trash_path, dir_sep_t + "$recycle.bin");
|
||||
return std::find_if(parts.begin(), parts.end(), [](auto &&part) -> bool {
|
||||
return utils::string::begins_with(part, ".trash-") ||
|
||||
part == ".trashes" || part == "$recycle.bin";
|
||||
}) != parts.end();
|
||||
}
|
||||
|
||||
auto is_trash_directory(std::wstring_view path) -> bool {
|
||||
return is_trash_directory(utils::string::to_utf8(path));
|
||||
auto contains_trash_directory(std::wstring_view path) -> bool {
|
||||
return contains_trash_directory(utils::string::to_utf8(path));
|
||||
}
|
||||
|
||||
auto make_file_uri(std::string_view path) -> std::string {
|
||||
|
@ -97,7 +97,7 @@ auto time64_to_unix_time(const __time64_t &time) -> std::uint64_t {
|
||||
|
||||
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
||||
auto unix_time_to_filetime(std::uint64_t unix_time) -> FILETIME {
|
||||
const auto win_time = (unix_time / 100ULL) + 116444736000000000ULL;
|
||||
auto win_time = (unix_time / 100ULL) + 116444736000000000ULL;
|
||||
FILETIME file_time{};
|
||||
file_time.dwHighDateTime = static_cast<DWORD>(win_time >> 32U);
|
||||
file_time.dwLowDateTime = win_time & 0xFFFFFFFF;
|
||||
|
250
support/test/src/utils/collection_test.cpp
Normal file
250
support/test/src/utils/collection_test.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "test.hpp"
|
||||
|
||||
namespace repertory {
|
||||
TEST(utils_collection, excludes) {
|
||||
auto data = {"cow", "moose", "dog", "chicken"};
|
||||
EXPECT_FALSE(utils::collection::excludes(data, "chicken"));
|
||||
EXPECT_FALSE(utils::collection::excludes(data, "cow"));
|
||||
EXPECT_FALSE(utils::collection::excludes(data, "dog"));
|
||||
EXPECT_FALSE(utils::collection::excludes(data, "moose"));
|
||||
EXPECT_TRUE(utils::collection::excludes(data, "mouse"));
|
||||
}
|
||||
|
||||
TEST(utils_collection, includes) {
|
||||
auto data = {"cow", "moose", "dog", "chicken"};
|
||||
EXPECT_FALSE(utils::collection::includes(data, "mice"));
|
||||
EXPECT_TRUE(utils::collection::includes(data, "chicken"));
|
||||
EXPECT_TRUE(utils::collection::includes(data, "cow"));
|
||||
EXPECT_TRUE(utils::collection::includes(data, "dog"));
|
||||
EXPECT_TRUE(utils::collection::includes(data, "moose"));
|
||||
}
|
||||
|
||||
TEST(utils_collection, from_hex_string) {
|
||||
{
|
||||
auto data = "0xABCDEF10";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(4U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = " 0xABCDEF10 ";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(4U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = "ABCDEF10";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(4U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = "ACDEF";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(3U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = " ACDEF ";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(3U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = "";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"0xABCDEF10";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(4U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L" 0xABCDEF10 ";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(4U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"ABCDEF10";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(4U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"ACDEF";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(3U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L" ACDEF ";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_EQ(3U, val.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_TRUE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(utils_collection, from_hex_string_fails) {
|
||||
{
|
||||
auto data = "ABCDEF1Z";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = "ABC DEF1";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = "0x";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = " 0x ";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"ABCDEF1Z";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"ABC DEF1";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L"0x";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto data = L" 0x";
|
||||
std::vector<std::uint8_t> val{};
|
||||
EXPECT_FALSE(utils::collection::from_hex_string(data, val));
|
||||
EXPECT_TRUE(val.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(utils_collection, to_hex_string) {
|
||||
{
|
||||
std::array<std::int8_t, 2U> col{
|
||||
static_cast<std::int8_t>(0xFF),
|
||||
static_cast<std::int8_t>(0xEE),
|
||||
};
|
||||
|
||||
auto str = utils::collection::to_hex_string(col);
|
||||
EXPECT_STREQ("ffee", str.c_str());
|
||||
|
||||
auto w_str = utils::collection::to_hex_wstring(col);
|
||||
EXPECT_STREQ(L"ffee", w_str.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
std::array<std::uint8_t, 2U> col{
|
||||
static_cast<std::uint8_t>(0xFF),
|
||||
static_cast<std::uint8_t>(0xEE),
|
||||
};
|
||||
|
||||
auto str = utils::collection::to_hex_string(col);
|
||||
EXPECT_STREQ("ffee", str.c_str());
|
||||
|
||||
auto w_str = utils::collection::to_hex_wstring(col);
|
||||
EXPECT_STREQ(L"ffee", w_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(utils_collection, remove_element) {
|
||||
{
|
||||
std::vector<std::uint8_t> col{
|
||||
static_cast<std::uint8_t>(0xFF),
|
||||
static_cast<std::uint8_t>(0xEE),
|
||||
};
|
||||
|
||||
utils::collection::remove_element(col, 0xFF);
|
||||
EXPECT_EQ(1U, col.size());
|
||||
EXPECT_EQ(static_cast<std::uint8_t>(0xEE), col.at(0U));
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::uint8_t> col{
|
||||
static_cast<std::uint8_t>(0xFF),
|
||||
static_cast<std::uint8_t>(0xEE),
|
||||
};
|
||||
|
||||
utils::collection::remove_element(col, 0xEE);
|
||||
EXPECT_EQ(1U, col.size());
|
||||
EXPECT_EQ(static_cast<std::uint8_t>(0xFF), col.at(0U));
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::uint8_t> col{
|
||||
static_cast<std::uint8_t>(0xFF),
|
||||
static_cast<std::uint8_t>(0xEE),
|
||||
};
|
||||
|
||||
utils::collection::remove_element(col, 0xEF);
|
||||
EXPECT_EQ(2U, col.size());
|
||||
EXPECT_EQ(static_cast<std::uint8_t>(0xFF), col.at(0U));
|
||||
EXPECT_EQ(static_cast<std::uint8_t>(0xEE), col.at(1U));
|
||||
}
|
||||
}
|
||||
} // namespace repertory
|
@ -22,6 +22,7 @@
|
||||
#include "test.hpp"
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
|
||||
namespace repertory {
|
||||
TEST(utils_encrypting_reader, read_file_data) {
|
||||
const auto token = std::string("moose");
|
||||
|
@ -24,8 +24,8 @@
|
||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
||||
|
||||
namespace repertory {
|
||||
static const std::string token{"moose"};
|
||||
static const std::wstring token_w{L"moose"};
|
||||
static constexpr const std::string_view token{"moose"};
|
||||
static constexpr const std::wstring_view token_w{L"moose"};
|
||||
|
||||
TEST(utils_encryption, generate_key) {
|
||||
auto key1 =
|
||||
@ -244,6 +244,39 @@ TEST(utils_encryption, decryption_failure) {
|
||||
std::string data;
|
||||
EXPECT_FALSE(utils::encryption::decrypt_data(key, result, data));
|
||||
}
|
||||
|
||||
TEST(utils_encryption, decrypt_file_name) {
|
||||
auto &source_file = test::create_random_file(
|
||||
8U * utils::encryption::encrypting_reader::get_data_chunk_size());
|
||||
EXPECT_TRUE(source_file);
|
||||
if (source_file) {
|
||||
stop_type stop_requested{false};
|
||||
utils::encryption::encrypting_reader reader(
|
||||
"test.dat", source_file.get_path(), stop_requested, token,
|
||||
std::nullopt);
|
||||
|
||||
auto file_name = reader.get_encrypted_file_name();
|
||||
|
||||
EXPECT_EQ(true, utils::encryption::decrypt_file_name(token, file_name));
|
||||
EXPECT_STREQ("test.dat", file_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(utils_encryption, decrypt_file_path) {
|
||||
auto &source_file = test::create_random_file(
|
||||
8U * utils::encryption::encrypting_reader::get_data_chunk_size());
|
||||
EXPECT_TRUE(source_file);
|
||||
if (source_file) {
|
||||
stop_type stop_requested{false};
|
||||
utils::encryption::encrypting_reader reader(
|
||||
"test.dat", source_file.get_path(), stop_requested, token, "moose/cow");
|
||||
|
||||
auto file_path = reader.get_encrypted_file_path();
|
||||
|
||||
EXPECT_EQ(true, utils::encryption::decrypt_file_path(token, file_path));
|
||||
EXPECT_STREQ("/moose/cow/test.dat", file_path.c_str());
|
||||
}
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_BOOST)
|
||||
} // namespace repertory
|
||||
|
||||
|
65
support/test/src/utils/error_test.cpp
Normal file
65
support/test/src/utils/error_test.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright <2018-2024> <scott.e.graves@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "test.hpp"
|
||||
|
||||
namespace repertory {
|
||||
template <typename T, typename U>
|
||||
constexpr bool is_decay_equ = std::is_same_v<std::decay_t<T>, U>;
|
||||
|
||||
TEST(utils_error, check_default_exception_handler) {
|
||||
EXPECT_EQ(&utils::error::default_exception_handler,
|
||||
utils::error::get_exception_handler());
|
||||
|
||||
auto default_handler_is_iostream =
|
||||
is_decay_equ<decltype(utils::error::default_exception_handler),
|
||||
utils::error::iostream_exception_handler>;
|
||||
EXPECT_TRUE(default_handler_is_iostream);
|
||||
}
|
||||
|
||||
TEST(utils_error, can_override_exception_handler) {
|
||||
struct my_exc_handler : public utils::error::i_exception_handler {
|
||||
MOCK_METHOD(void, handle_exception, (std::string_view function_name),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(void, handle_exception,
|
||||
(std::string_view function_name, const std::exception &ex),
|
||||
(const, override));
|
||||
};
|
||||
|
||||
my_exc_handler handler{};
|
||||
utils::error::set_exception_handler(&handler);
|
||||
|
||||
EXPECT_CALL(handler, handle_exception("test_func")).WillOnce(Return());
|
||||
utils::error::handle_exception("test_func");
|
||||
|
||||
auto ex = std::runtime_error("moose");
|
||||
EXPECT_CALL(handler, handle_exception(_, _))
|
||||
.WillOnce(
|
||||
[&ex](std::string_view function_name, const std::exception &ex2) {
|
||||
EXPECT_EQ("test_func_ex", function_name);
|
||||
EXPECT_STREQ(ex.what(), ex2.what());
|
||||
});
|
||||
utils::error::handle_exception("test_func_ex", ex);
|
||||
|
||||
utils::error::set_exception_handler(&utils::error::default_exception_handler);
|
||||
}
|
||||
} // namespace repertory
|
@ -140,4 +140,125 @@ TEST(utils_file, read_and_write_json_file_encrypted) {
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST)
|
||||
#endif // defined(PROJECT_ENABLE_JSON)
|
||||
|
||||
#if defined(PROJECT_ENABLE_LIBDSM)
|
||||
TEST(utils_file, smb_create_smb_path) {
|
||||
auto path = "//server/share";
|
||||
auto rel_path = "test/test.txt";
|
||||
auto smb_path = utils::file::smb_create_smb_path(path, rel_path);
|
||||
EXPECT_STREQ("//server/share/test/test.txt", smb_path.c_str());
|
||||
|
||||
rel_path = "/test/test.txt";
|
||||
smb_path = utils::file::smb_create_smb_path(path, rel_path);
|
||||
EXPECT_STREQ("//server/share/test/test.txt", smb_path.c_str());
|
||||
|
||||
rel_path = "test\\test.txt";
|
||||
smb_path = utils::file::smb_create_smb_path(path, rel_path);
|
||||
EXPECT_STREQ("//server/share/test/test.txt", smb_path.c_str());
|
||||
|
||||
rel_path = "\\test\\test.txt";
|
||||
smb_path = utils::file::smb_create_smb_path(path, rel_path);
|
||||
EXPECT_STREQ("//server/share/test/test.txt", smb_path.c_str());
|
||||
}
|
||||
|
||||
TEST(utils_file, smb_create_relative_path) {
|
||||
auto path = "//server/share/test.txt";
|
||||
auto rel_path = utils::file::smb_create_relative_path(path);
|
||||
EXPECT_STREQ("\\test.txt", rel_path.c_str());
|
||||
|
||||
path = "//server/share/test";
|
||||
rel_path = utils::file::smb_create_relative_path(path);
|
||||
EXPECT_STREQ("\\test", rel_path.c_str());
|
||||
|
||||
path = "//server/share/test/";
|
||||
rel_path = utils::file::smb_create_relative_path(path);
|
||||
EXPECT_STREQ("\\test", rel_path.c_str());
|
||||
|
||||
path = "//server/share/test/";
|
||||
rel_path = utils::file::smb_create_relative_path(path);
|
||||
EXPECT_STREQ("\\test", rel_path.c_str());
|
||||
}
|
||||
|
||||
TEST(utils_file, smb_create_search_path) {
|
||||
auto path = "//server/share";
|
||||
auto search_path = utils::file::smb_create_search_path(path);
|
||||
EXPECT_STREQ("\\*", search_path.c_str());
|
||||
|
||||
path = "//server/share/";
|
||||
search_path = utils::file::smb_create_search_path(path);
|
||||
EXPECT_STREQ("\\*", search_path.c_str());
|
||||
|
||||
path = "//server/share/folder";
|
||||
search_path = utils::file::smb_create_search_path(path);
|
||||
EXPECT_STREQ("\\folder\\*", search_path.c_str());
|
||||
|
||||
path = "//server/share/folder/";
|
||||
search_path = utils::file::smb_create_search_path(path);
|
||||
EXPECT_STREQ("\\folder\\*", search_path.c_str());
|
||||
|
||||
path = "//server/share/folder/next";
|
||||
search_path = utils::file::smb_create_search_path(path);
|
||||
EXPECT_STREQ("\\folder\\next\\*", search_path.c_str());
|
||||
|
||||
path = "//server/share/folder/next/";
|
||||
search_path = utils::file::smb_create_search_path(path);
|
||||
EXPECT_STREQ("\\folder\\next\\*", search_path.c_str());
|
||||
}
|
||||
|
||||
TEST(utils_file, smb_parent_is_same) {
|
||||
auto path1 = "//server/share";
|
||||
auto path2 = "//server/share";
|
||||
EXPECT_TRUE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server/share/";
|
||||
path2 = "//server/share/";
|
||||
EXPECT_TRUE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server/share/one";
|
||||
path2 = "//server/share/two";
|
||||
EXPECT_TRUE(utils::file::smb_parent_is_same(path1, path2));
|
||||
}
|
||||
|
||||
TEST(utils_file, smb_parent_is_not_same) {
|
||||
auto path1 = "server/share";
|
||||
auto path2 = "//server/share";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "server/share/";
|
||||
path2 = "server/share/";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server1/share/one";
|
||||
path2 = "//server/share/two";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server/share";
|
||||
path2 = "//server/share2";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server/share/";
|
||||
path2 = "//server/share2/";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server/share/one";
|
||||
path2 = "//server/share2/two";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server";
|
||||
path2 = "//server/share/two";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server/";
|
||||
path2 = "//server/";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "//server";
|
||||
path2 = "//server";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
|
||||
path1 = "// server/cow";
|
||||
path2 = "// server/cow";
|
||||
EXPECT_FALSE(utils::file::smb_parent_is_same(path1, path2));
|
||||
}
|
||||
#endif // defined(PROJECT_ENABLE_LIBDSM)
|
||||
} // namespace repertory
|
||||
|
@ -393,4 +393,128 @@ TEST(utils_path, absolute_can_resolve_path_variables) {
|
||||
EXPECT_STREQ(home.c_str(), expanded_str.c_str());
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
|
||||
TEST(utils_path, get_parent_directory) {
|
||||
#if defined(_WIN32)
|
||||
{
|
||||
auto dir = R"(c:\test)";
|
||||
auto parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ("c:", parent.c_str());
|
||||
|
||||
dir = R"(c:\test\file.txt)";
|
||||
parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ(R"(c:\test)", parent.c_str());
|
||||
|
||||
dir = "c:";
|
||||
parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ("c:", parent.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
auto dir = LR"(c:\test)";
|
||||
auto parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ(L"c:", parent.c_str());
|
||||
|
||||
dir = LR"(c:\test\file.txt)";
|
||||
parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ(LR"(c:\test)", parent.c_str());
|
||||
|
||||
dir = L"c:";
|
||||
parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ(L"c:", parent.c_str());
|
||||
}
|
||||
#else // !defined(_WIN32)
|
||||
{
|
||||
auto dir = "/test";
|
||||
auto parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ("/", parent.c_str());
|
||||
|
||||
dir = "/test/test";
|
||||
parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ("/test", parent.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
auto dir = L"/test";
|
||||
auto parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ(L"/", parent.c_str());
|
||||
|
||||
dir = L"/test/test";
|
||||
parent = utils::path::get_parent_directory(dir);
|
||||
EXPECT_STREQ(L"/test", parent.c_str());
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
|
||||
TEST(utils_path, contains_trash_directory) {
|
||||
#if defined(_WIN32)
|
||||
{
|
||||
auto dir = R"(c:\$recycle.bin)";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = R"(c:\$recycle.bin\moose.txt)";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
|
||||
{
|
||||
auto dir = LR"(c:\$recycle.bin)";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = LR"(c:\$recycle.bin\moose.txt)";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
#else // !defined(_WIN32)
|
||||
{
|
||||
auto dir = "/$recycle.bin";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = "/$recycle.bin/moose.txt";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
|
||||
{
|
||||
auto dir = L"/$recycle.bin";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = L"/$recycle.bin/moose.txt";
|
||||
EXPECT_TRUE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
|
||||
TEST(utils_path, does_not_contain_trash_directory) {
|
||||
#if defined(_WIN32)
|
||||
{
|
||||
auto dir = R"(c:\recycle.bin)";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = R"(c:\recycle.bin\moose.txt)";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
|
||||
{
|
||||
auto dir = LR"(c:\recycle.bin)";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = LR"(c:\recycle.bin\moose.txt)";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
#else // !defined(_WIN32)
|
||||
{
|
||||
auto dir = "/recycle.bin";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = "/recycle.bin/moose.txt)";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
|
||||
{
|
||||
auto dir = L"/recycle.bin";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
|
||||
dir = L"/recycle.bin/moose.txt)";
|
||||
EXPECT_FALSE(utils::path::contains_trash_directory(dir));
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
} // namespace repertory
|
||||
|
Reference in New Issue
Block a user