diff --git a/repertory/librepertory/include/utils/file_utils.hpp b/repertory/librepertory/include/utils/file_utils.hpp index ccf97db4..709ad525 100644 --- a/repertory/librepertory/include/utils/file_utils.hpp +++ b/repertory/librepertory/include/utils/file_utils.hpp @@ -22,22 +22,13 @@ #ifndef INCLUDE_UTILS_FILE_UTILS_HPP_ #define INCLUDE_UTILS_FILE_UTILS_HPP_ -#include "types/repertory.hpp" #include "utils/file.hpp" namespace repertory::utils::file { -void change_to_process_directory(); - [[nodiscard]] auto -get_directory_files(std::string path, bool oldest_first, +get_directory_files(std::string_view path, bool oldest_first, bool recursive = false) -> std::deque; -[[nodiscard]] auto -get_free_drive_space(const std::string &path) -> std::uint64_t; - -[[nodiscard]] auto -get_total_drive_space(const std::string &path) -> std::uint64_t; - [[nodiscard]] auto read_file_lines(const std::string &path) -> std::vector; diff --git a/repertory/librepertory/src/app_config.cpp b/repertory/librepertory/src/app_config.cpp index 5e32d98e..ecc6652b 100644 --- a/repertory/librepertory/src/app_config.cpp +++ b/repertory/librepertory/src/app_config.cpp @@ -317,11 +317,12 @@ auto app_config::get_json() const -> json { } auto app_config::get_max_cache_size_bytes() const -> std::uint64_t { - const auto max_space = + auto max_space = std::max(static_cast(100ULL * 1024ULL * 1024ULL), max_cache_size_bytes_); - return std::min(utils::file::get_free_drive_space(get_cache_directory()), - max_space); + auto free_space = utils::file::get_free_drive_space(get_cache_directory()); + return free_space.has_value() ? std::min(free_space.value(), max_space) + : max_space; } auto app_config::get_provider_display_name(const provider_type &prov) diff --git a/repertory/librepertory/src/drives/fuse/fuse_base.cpp b/repertory/librepertory/src/drives/fuse/fuse_base.cpp index ef128bfa..4bb52800 100644 --- a/repertory/librepertory/src/drives/fuse/fuse_base.cpp +++ b/repertory/librepertory/src/drives/fuse/fuse_base.cpp @@ -393,31 +393,34 @@ auto fuse_base::init_(struct fuse_conn_info *conn) -> void * { #if FUSE_USE_VERSION >= 30 auto fuse_base::init_impl([[maybe_unused]] struct fuse_conn_info *conn, struct fuse_config *cfg) -> void * { -#else +#else // FUSE_USE_VERSION < 30 auto fuse_base::init_impl(struct fuse_conn_info *conn) -> void * { -#endif +#endif // FUSE_USE_VERSION >= 30 static constexpr const std::string_view function_name{ static_cast(__FUNCTION__), }; - utils::file::change_to_process_directory(); - if (not console_enabled_) { - if (not repertory::project_initialize()) { - utils::error::raise_error(function_name, - "failed to initialize repertory"); - event_system::instance().raise(); - } - } - #if defined(__APPLE__) conn->want |= FUSE_CAP_VOL_RENAME; conn->want |= FUSE_CAP_XTIMES; -#endif // __APPLE__ +#endif // defined(__APPLE__) #if FUSE_USE_VERSION >= 30 cfg->nullpath_ok = 0; cfg->hard_remove = 1; -#endif +#endif // FUSE_USE_VERSION >= 30 + + if (not utils::file::change_to_process_directory()) { + utils::error::raise_error(function_name, + "failed to change to process directory"); + event_system::instance().raise(); + return this; + } + + if (not console_enabled_ && not repertory::project_initialize()) { + utils::error::raise_error(function_name, "failed to initialize repertory"); + event_system::instance().raise(); + } return this; } diff --git a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp index b9358bbc..62f86bfb 100644 --- a/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp +++ b/repertory/librepertory/src/drives/winfsp/winfsp_drive.cpp @@ -623,7 +623,9 @@ auto winfsp_drive::Mounted(PVOID host) -> NTSTATUS { }; auto ret = STATUS_SUCCESS; - utils::file::change_to_process_directory(); + if (not utils::file::change_to_process_directory()) { + return utils::get_last_error_code(); + } auto *file_system_host = reinterpret_cast(host); polling::instance().start(&config_); diff --git a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp index 6ea62f11..6990b973 100644 --- a/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp +++ b/repertory/librepertory/src/providers/encrypt/encrypt_provider.cpp @@ -628,8 +628,9 @@ auto encrypt_provider::get_item_meta(const std::string &api_path, } auto encrypt_provider::get_total_drive_space() const -> std::uint64_t { - const auto cfg = config_.get_encrypt_config(); - return utils::file::get_total_drive_space(cfg.path); + auto total_space = + utils::file::get_total_drive_space(config_.get_encrypt_config().path); + return total_space.value_or(0U); } auto encrypt_provider::get_total_item_count() const -> std::uint64_t { @@ -646,8 +647,10 @@ auto encrypt_provider::get_total_item_count() const -> std::uint64_t { } auto encrypt_provider::get_used_drive_space() const -> std::uint64_t { - const auto cfg = config_.get_encrypt_config(); - return get_total_drive_space() - utils::file::get_free_drive_space(cfg.path); + auto free_space = + utils::file::get_free_drive_space(config_.get_encrypt_config().path); + return free_space.has_value() ? get_total_drive_space() - free_space.value() + : 0U; } auto encrypt_provider::is_directory(const std::string &api_path, diff --git a/repertory/librepertory/src/utils/file_utils.cpp b/repertory/librepertory/src/utils/file_utils.cpp index e69c95e6..66849eb8 100644 --- a/repertory/librepertory/src/utils/file_utils.cpp +++ b/repertory/librepertory/src/utils/file_utils.cpp @@ -31,121 +31,70 @@ #include "utils/utils.hpp" namespace repertory::utils::file { -void change_to_process_directory() { -#if defined(_WIN32) - std::string file_name; - file_name.resize(MAX_PATH); - ::GetModuleFileNameA(nullptr, &file_name[0U], - static_cast(file_name.size())); - - std::string path = file_name.c_str(); - ::PathRemoveFileSpecA(&path[0U]); - ::SetCurrentDirectoryA(&path[0U]); -#else - std::string path; - path.resize(PATH_MAX + 1); -#if defined(__APPLE__) - proc_pidpath(getpid(), &path[0U], path.size()); -#else - readlink("/proc/self/exe", &path[0U], path.size()); -#endif - path = utils::path::get_parent_path(path); - chdir(path.c_str()); -#endif -} - -auto get_free_drive_space(const std::string &path) -> std::uint64_t { -#if defined(_WIN32) - ULARGE_INTEGER li{}; - ::GetDiskFreeSpaceEx(path.c_str(), &li, nullptr, nullptr); - return li.QuadPart; -#endif -#if defined(__linux__) - std::uint64_t ret = 0; - struct statfs64 st {}; - if (statfs64(path.c_str(), &st) == 0) { - ret = st.f_bfree * st.f_bsize; - } - return ret; -#endif -#if defined(__APPLE__) - struct statvfs st {}; - statvfs(path.c_str(), &st); - return st.f_bfree * st.f_frsize; -#endif -} - -auto get_total_drive_space(const std::string &path) -> std::uint64_t { -#if defined(_WIN32) - ULARGE_INTEGER li{}; - ::GetDiskFreeSpaceEx(path.c_str(), nullptr, &li, nullptr); - return li.QuadPart; -#endif -#if defined(__linux__) - std::uint64_t ret = 0; - struct statfs64 st {}; - if (statfs64(path.c_str(), &st) == 0) { - ret = st.f_blocks * st.f_bsize; - } - return ret; -#endif -#if defined(__APPLE__) - struct statvfs st {}; - statvfs(path.c_str(), &st); - return st.f_blocks * st.f_frsize; -#endif -} - -auto get_directory_files(std::string path, bool oldest_first, +auto get_directory_files(std::string_view path, bool oldest_first, bool recursive) -> std::deque { - path = utils::path::absolute(path); + static constexpr const std::string_view function_name{ + static_cast(__FUNCTION__), + }; + + auto abs_path = utils::path::absolute(path); std::deque ret; std::unordered_map lookup; #if defined(_WIN32) WIN32_FIND_DATA fd{}; - const auto search = utils::path::combine(path, {"*.*"}); + auto search = utils::path::combine(abs_path, {"*.*"}); auto find = ::FindFirstFile(search.c_str(), &fd); if (find != INVALID_HANDLE_VALUE) { - do { - const auto full_path = utils::path::combine(path, {fd.cFileName}); - if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == - FILE_ATTRIBUTE_DIRECTORY) { - if (recursive) { - const auto sub_files = - get_directory_files(full_path, oldest_first, recursive); - ret.insert(ret.end(), sub_files.begin(), sub_files.end()); - } else { - ULARGE_INTEGER li{}; - li.HighPart = fd.ftLastWriteTime.dwHighDateTime; - li.LowPart = fd.ftLastWriteTime.dwLowDateTime; - lookup[full_path] = li.QuadPart; - ret.emplace_back(full_path); + try { + do { + auto full_path = utils::path::combine(abs_path, {fd.cFileName}); + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == + FILE_ATTRIBUTE_DIRECTORY) { + if (recursive) { + auto sub_files = + get_directory_files(full_path, oldest_first, recursive); + ret.insert(ret.end(), sub_files.begin(), sub_files.end()); + } else { + ULARGE_INTEGER li{}; + li.HighPart = fd.ftLastWriteTime.dwHighDateTime; + li.LowPart = fd.ftLastWriteTime.dwLowDateTime; + lookup[full_path] = li.QuadPart; + ret.emplace_back(full_path); + } } - } - } while (::FindNextFile(find, &fd) != 0); + } while (::FindNextFile(find, &fd) != 0); + } catch (const std::exception &e) { + utils::error::raise_error(function_name, e, + "failed to get directory files"); + } ::FindClose(find); - std::sort(ret.begin(), ret.end(), - [&](const auto &p1, const auto &p2) -> bool { - return (oldest_first != 0) == (lookup[p1] < lookup[p2]); - }); + std::sort(ret.begin(), ret.end(), [&](auto &&path1, auto &&path2) -> bool { + return (oldest_first != 0) == (lookup[path1] < lookup[path2]); + }); } -#else - auto *root = opendir(path.c_str()); +#else // !defined(_WIN32) + auto *root = opendir(abs_path.c_str()); if (root) { - struct dirent *de{}; - while ((de = readdir(root)) != nullptr) { - if (de->d_type == DT_DIR) { - if (recursive) { - const auto sub_files = - get_directory_files(utils::path::combine(path, {de->d_name}), - oldest_first, recursive); - ret.insert(ret.end(), sub_files.begin(), sub_files.end()); + try { + struct dirent *de{}; + while ((de = readdir(root)) != nullptr) { + if (de->d_type == DT_DIR) { + if (recursive) { + auto sub_files = get_directory_files( + utils::path::combine(abs_path, {de->d_name}), oldest_first, + recursive); + ret.insert(ret.end(), sub_files.begin(), sub_files.end()); + } + } else { + ret.emplace_back(utils::path::combine(abs_path, {de->d_name})); } - } else { - ret.emplace_back(utils::path::combine(path, {de->d_name})); } + } catch (const std::exception &e) { + utils::error::raise_error(function_name, e, + "failed to get directory files"); } + closedir(root); const auto add_to_lookup = [&](const std::string &lookup_path) { @@ -153,25 +102,26 @@ auto get_directory_files(std::string path, bool oldest_first, struct stat st {}; stat(lookup_path.c_str(), &st); #if defined(__APPLE__) - lookup[lookup_path] = static_cast( - (st.st_mtimespec.tv_sec * utils::time::NANOS_PER_SECOND) + - st.st_mtimespec.tv_nsec); + lookup[lookup_path] = + (static_cast(st.st_mtimespec.tv_sec) * + utils::time::NANOS_PER_SECOND) + + static_cast(st.st_mtimespec.tv_nsec); #else // !defined(__APPLE__) - lookup[lookup_path] = static_cast( - (st.st_mtim.tv_sec * utils::time::NANOS_PER_SECOND) + - st.st_mtim.tv_nsec); + lookup[lookup_path] = (static_cast(st.st_mtim.tv_sec) * + utils::time::NANOS_PER_SECOND) + + static_cast(st.st_mtim.tv_nsec); #endif // defined(__APPLE__) } }; - std::sort(ret.begin(), ret.end(), - [&](const auto &p1, const auto &p2) -> bool { - add_to_lookup(p1); - add_to_lookup(p2); - return (oldest_first != 0) == (lookup[p1] < lookup[p2]); - }); + std::sort(ret.begin(), ret.end(), [&](auto &&path1, auto &&path2) -> bool { + add_to_lookup(path1); + add_to_lookup(path2); + return (oldest_first != 0) == (lookup.at(path1) < lookup.at(path2)); + }); } -#endif +#endif // defined(_WIN32) + return ret; } @@ -190,7 +140,7 @@ auto read_file_lines(const std::string &path) -> std::vector { } auto reset_modified_time(const std::string &path) -> bool { - auto ret = false; + auto ret{false}; #if defined(_WIN32) SYSTEMTIME st{}; ::GetSystemTime(&st); @@ -206,13 +156,14 @@ auto reset_modified_time(const std::string &path) -> bool { ::CloseHandle(handle); } } -#else +#else // !defined(_WIN32) auto fd = open(path.c_str(), O_RDWR); if ((ret = (fd != -1))) { - ret = not futimens(fd, nullptr); + ret = futimens(fd, nullptr) == 0; close(fd); } -#endif +#endif // defined(_WIN32) + return ret; } } // namespace repertory::utils::file diff --git a/support/include/utils/file.hpp b/support/include/utils/file.hpp index 5b55904c..bef78ad4 100644 --- a/support/include/utils/file.hpp +++ b/support/include/utils/file.hpp @@ -56,6 +56,8 @@ struct file_times final { } }; +[[nodiscard]] auto change_to_process_directory() -> bool; + [[nodiscard]] inline auto directory_exists_in_path(std::string_view path, std::string_view sub_directory) -> bool; @@ -71,6 +73,9 @@ file_exists_in_path(std::string_view path, std::string_view file_name) -> bool; file_exists_in_path(std::wstring_view path, std::wstring_view file_name) -> bool; +[[nodiscard]] auto +get_free_drive_space(std::string_view path) -> std::optional; + [[nodiscard]] auto get_time(std::string_view path, time_type type) -> std::optional; @@ -83,6 +88,9 @@ get_times(std::string_view path) -> std::optional; [[nodiscard]] auto get_times(std::wstring_view path) -> std::optional; +[[nodiscard]] auto +get_total_drive_space(std::string_view path) -> std::optional; + #if defined(PROJECT_ENABLE_LIBDSM) [[nodiscard]] auto smb_create_and_validate_relative_path(std::string_view smb_path, diff --git a/support/src/utils/file.cpp b/support/src/utils/file.cpp index ced2f49c..bd5447d9 100644 --- a/support/src/utils/file.cpp +++ b/support/src/utils/file.cpp @@ -26,9 +26,102 @@ #include "utils/path.hpp" #include "utils/string.hpp" #include "utils/time.hpp" +#include "utils/unix.hpp" #include "utils/windows.hpp" namespace repertory::utils::file { +auto change_to_process_directory() -> bool { + static constexpr const std::string_view function_name{ + static_cast(__FUNCTION__), + }; + + try { +#if defined(_WIN32) + std::string file_name; + file_name.resize(MAX_PATH + 1U); + + ::GetModuleFileNameA(nullptr, file_name.data(), + static_cast(file_name.size() - 1U)); + auto path = utils::path::strip_to_file_name(file_name.c_str()); + ::SetCurrentDirectoryA(path.c_str()); +#else // !defined(_WIN32) + std::string path; + path.resize(PATH_MAX + 1); +#if defined(__APPLE__) + proc_pidpath(getpid(), path.c_str(), path.size()); +#else // !defined(__APPLE__) + auto res = readlink("/proc/self/exe", path.data(), path.size()); + if (res == -1) { + throw std::runtime_error("failed to readlink|" + path + '|' + + std::to_string(errno)); + } +#endif // defined(__APPLE__) + path = utils::path::get_parent_path(path); + res = chdir(path.c_str()); + if (res != 0) { + throw std::runtime_error("failed to chdir|" + path + '|' + + std::to_string(errno)); + } +#endif // defined(_WIN32) + + return true; + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } + + return false; +} + +auto get_free_drive_space(std::string_view path) + -> std::optional { + static constexpr const std::string_view function_name{ + static_cast(__FUNCTION__), + }; + + try { +#if defined(_WIN32) + ULARGE_INTEGER li{}; + if (not ::GetDiskFreeSpaceEx(path.c_str(), &li, nullptr, nullptr)) { + throw std::runtime_error("failed to get free disk space|" + + std::string{path} + '|' + + std::to_string(utils::get_last_error_code())); + } + + return li.QuadPart; +#endif // defined(_WIN32) + +#if defined(__linux__) + struct statfs64 st {}; + if (statfs64(std::string{path}.c_str(), &st) != 0) { + throw std::runtime_error("failed to get free disk space|" + + std::string{path} + '|' + + std::to_string(utils::get_last_error_code())); + } + + return st.f_bfree * static_cast(st.f_bsize); +#endif // defined(__linux__) + +#if defined(__APPLE__) + struct statvfs st {}; + if (statvfs(path.c_str(), &st) != 0) { + throw std::runtime_error("failed to get free disk space|" + + std::string{path} + '|' + + std::to_string(utils::get_last_error_code())); + } + + return st.f_bfree * static_cast(st.f_frsize); +#endif // defined(__APPLE__) + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } + + return std::nullopt; +} + auto get_time(std::string_view path, time_type type) -> std::optional { auto times = get_times(path); @@ -111,6 +204,53 @@ auto get_times(std::wstring_view path) -> std::optional { return get_times(utils::string::to_utf8(path)); } +auto get_total_drive_space(std::string_view path) + -> std::optional { + static constexpr const std::string_view function_name{ + static_cast(__FUNCTION__), + }; + + try { +#if defined(_WIN32) + ULARGE_INTEGER li{}; + if (not ::GetDiskFreeSpaceEx(path.c_str(), nullptr, &li, nullptr)) { + throw std::runtime_error("failed to get total disk space|" + + std::string{path} + '|' + + std::to_string(utils::get_last_error_code())); + } + return li.QuadPart; +#endif // defined(_WIN32) + +#if defined(__linux__) + struct statfs64 st {}; + if (statfs64(std::string{path}.c_str(), &st) != 0) { + throw std::runtime_error("failed to get total disk space|" + + std::string{path} + '|' + + std::to_string(utils::get_last_error_code())); + } + + return st.f_blocks * static_cast(st.f_bsize); +#endif // defined(__linux__) + +#if defined(__APPLE__) + struct statvfs st {}; + if (statvfs(path.c_str(), &st) != 0) { + throw std::runtime_error("failed to get total disk space|" + + std::string{path} + '|' + + std::to_string(utils::get_last_error_code())); + } + + return st.f_blocks * static_cast(st.f_frsize); +#endif // defined(__APPLE__) + } catch (const std::exception &e) { + utils::error::handle_exception(function_name, e); + } catch (...) { + utils::error::handle_exception(function_name); + } + + return std::nullopt; +} + auto i_fs_item::get_time(time_type type) const -> std::optional { return utils::file::get_time(get_path(), type); }