updated build system

This commit is contained in:
2024-08-20 08:48:29 -05:00
parent d83de7bb91
commit 734dab801d
26 changed files with 2440 additions and 277 deletions

View File

@ -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),

View File

@ -0,0 +1,67 @@
/*
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"
#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;
}
} // namespace repertory::utils::encryption
#endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined (PROJECT_ENABLE_BOOST)

View File

@ -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,
&current_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

View File

@ -0,0 +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 "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

View File

@ -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,
&current_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{
@ -466,11 +475,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

View 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)

View File

@ -0,0 +1,308 @@
/*
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 (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));
}
res = smb_fread(session_.get(), *fd_, data, to_read);
if (res == -1) {
throw std::runtime_error("failed to read file|" + path_ + '|' +
std::to_string(to_read) + '|' +
std::to_string(res));
}
if (total_read != nullptr) {
(*total_read) = static_cast<std::uint64_t>(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_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 (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));
}
res = smb_fwrite(session_.get(), *fd_, const_cast<unsigned char *>(data),
to_write);
if (res == -1) {
throw std::runtime_error("failed to write file|" + path_ + '|' +
std::to_string(to_write) + '|' +
std::to_string(res));
}
if (total_written != nullptr) {
(*total_written) = static_cast<std::uint64_t>(res);
}
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)

View File

@ -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