v2.0.2-rc (#27)
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
## v2.0.2-rc ### BREAKING CHANGES * Refactored `config.json` - will need to verify configuration settings prior to mounting ### Issues * \#12 \[Unit Test\] Complete all providers unit tests * \#14 \[Unit Test\] SQLite mini-ORM unit tests and cleanup * \#16 Add support for bucket name in Sia provider * \#17 Update to common c++ build system * A single 64-bit Linux Jenkins server is used to build all Linux and Windows versions * All dependency sources are now included * MSVC is no longer supported * MSYS2 is required for building Windows binaries on Windows * OS X support is temporarily disabled * \#19 \[bug\] Rename file is broken for files that are existing * \#23 \[bug\] Incorrect file size displayed while upload is pending * \#24 RocksDB implementations should be transactional * \#25 Writes should block when maximum cache size is reached * \#26 Complete ring buffer and direct download support ### Changes from v2.0.1-rc * Ability to choose between RocksDB and SQLite databases * Added direct reads and implemented download fallback * Corrected file times on S3 and Sia providers * Corrected handling of `chown()` and `chmod()` * Fixed erroneous download of chunks after resize Reviewed-on: #27
This commit is contained in:
315
support/src/utils/path.cpp
Normal file
315
support/src/utils/path.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
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/path.hpp"
|
||||
|
||||
#include "utils/common.hpp"
|
||||
#include "utils/error.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/string.hpp"
|
||||
#include "utils/unix.hpp"
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] auto resolve(std::string path) -> std::string {
|
||||
REPERTORY_USES_FUNCTION_NAME();
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (repertory::utils::string::contains(path, "~\\")) {
|
||||
repertory::utils::string::replace(path, "~\\", "%USERPROFILE%\\");
|
||||
}
|
||||
|
||||
if (repertory::utils::string::contains(path, "~/")) {
|
||||
repertory::utils::string::replace(path, "~/", "%USERPROFILE%\\");
|
||||
}
|
||||
|
||||
if (repertory::utils::string::contains(path, "%")) {
|
||||
auto size = ::ExpandEnvironmentStringsA(path.c_str(), nullptr, 0);
|
||||
|
||||
std::string dest;
|
||||
dest.resize(size);
|
||||
::ExpandEnvironmentStringsA(path.c_str(), dest.data(),
|
||||
static_cast<DWORD>(dest.size()));
|
||||
path = dest.c_str();
|
||||
}
|
||||
#else // !defined (_WIN32)
|
||||
if (repertory::utils::string::contains(path, "~\\")) {
|
||||
repertory::utils::string::replace(path, "~\\", "~/");
|
||||
}
|
||||
|
||||
if (repertory::utils::string::contains(path, "~/")) {
|
||||
std::string home{};
|
||||
auto res =
|
||||
repertory::utils::use_getpwuid(getuid(), [&home](struct passwd *pw) {
|
||||
home = (pw->pw_dir ? pw->pw_dir : "");
|
||||
if (home.empty() ||
|
||||
((home == repertory::utils::path::slash) && (getuid() != 0))) {
|
||||
home = repertory::utils::path::combine("/home", {pw->pw_name});
|
||||
}
|
||||
});
|
||||
if (not res) {
|
||||
throw repertory::utils::error::create_exception(function_name,
|
||||
{
|
||||
"failed to getpwuid",
|
||||
res.reason,
|
||||
});
|
||||
}
|
||||
|
||||
path = repertory::utils::string::replace(path, "~/", home + "/");
|
||||
}
|
||||
#endif // defined (_WIN32)
|
||||
|
||||
return repertory::utils::path::finalize(path);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace repertory::utils::path {
|
||||
auto absolute(std::string_view path) -> std::string {
|
||||
std::string abs_path{path};
|
||||
if (abs_path.empty()) {
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
abs_path = resolve(abs_path);
|
||||
#if defined(_WIN32)
|
||||
if (not utils::string::contains(abs_path, dot)) {
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
std::string temp;
|
||||
temp.resize(repertory::max_path_length + 1U);
|
||||
::GetFullPathNameA(abs_path.c_str(), static_cast<DWORD>(temp.size()),
|
||||
temp.data(), nullptr);
|
||||
#else // !defined(_WIN32)
|
||||
if (not utils::string::contains(abs_path, dot) ||
|
||||
utils::string::begins_with(abs_path, slash)) {
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
auto found{false};
|
||||
std::string tmp{abs_path};
|
||||
do {
|
||||
auto *res = realpath(tmp.c_str(), nullptr);
|
||||
if (res != nullptr) {
|
||||
abs_path =
|
||||
res + std::string{directory_seperator} + abs_path.substr(tmp.size());
|
||||
free(res);
|
||||
found = true;
|
||||
} else if (tmp == dot) {
|
||||
found = true;
|
||||
} else {
|
||||
tmp = dirname(tmp.data());
|
||||
}
|
||||
} while (not found);
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
return finalize(abs_path);
|
||||
}
|
||||
|
||||
auto absolute(std::wstring_view path) -> std::wstring {
|
||||
return utils::string::from_utf8(absolute(utils::string::to_utf8(path)));
|
||||
}
|
||||
|
||||
auto exists(std::string_view path) -> bool {
|
||||
return utils::file::file{path}.exists() ||
|
||||
utils::file::directory{path}.exists();
|
||||
}
|
||||
|
||||
auto exists(std::wstring_view path) -> bool {
|
||||
return exists(utils::string::to_utf8(path));
|
||||
}
|
||||
|
||||
auto find_program_in_path(const std::string &name_without_extension)
|
||||
-> std::string {
|
||||
static std::mutex mtx{};
|
||||
static std::unordered_map<std::string, std::string> found_items{};
|
||||
|
||||
mutex_lock lock(mtx);
|
||||
if (found_items.contains(name_without_extension)) {
|
||||
return found_items.at(name_without_extension);
|
||||
}
|
||||
|
||||
auto path = utils::get_environment_variable("PATH");
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
static constexpr const std::array<std::string_view, 4U> extension_list{
|
||||
".bat",
|
||||
".cmd",
|
||||
".exe",
|
||||
".ps1",
|
||||
};
|
||||
static constexpr const auto split_char = ';';
|
||||
#else // !defined(_WIN32)
|
||||
static constexpr const std::array<std::string_view, 2U> extension_list{
|
||||
"",
|
||||
".sh",
|
||||
};
|
||||
static constexpr const auto split_char = ':';
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
auto search_path_list = utils::string::split(path, split_char, false);
|
||||
for (auto &&search_path : search_path_list) {
|
||||
for (auto &&extension : extension_list) {
|
||||
auto exec_path = combine(
|
||||
search_path, {name_without_extension + std::string{extension}});
|
||||
if (utils::file::file(exec_path).exists()) {
|
||||
found_items[name_without_extension] = exec_path;
|
||||
return exec_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] auto
|
||||
find_program_in_path(std::wstring_view name_without_extension) -> std::wstring {
|
||||
return utils::string::from_utf8(
|
||||
find_program_in_path(utils::string::to_utf8(name_without_extension)));
|
||||
}
|
||||
|
||||
auto get_parent_path(std::string_view path) -> std::string {
|
||||
auto abs_path = absolute(path);
|
||||
|
||||
#if defined(_WIN32)
|
||||
::PathRemoveFileSpecA(abs_path.data());
|
||||
abs_path = abs_path.c_str();
|
||||
#else // !defined(_WIN32)
|
||||
abs_path = std::filesystem::path{abs_path}.parent_path().string();
|
||||
#endif // defined(_WIN32)
|
||||
|
||||
return finalize(abs_path);
|
||||
}
|
||||
|
||||
auto get_parent_path(std::wstring_view path) -> std::wstring {
|
||||
return utils::string::from_utf8(
|
||||
get_parent_path(utils::string::to_utf8(path)));
|
||||
}
|
||||
|
||||
auto get_relative_path(std::string_view path, std::string_view root_path)
|
||||
-> std::string {
|
||||
auto abs_path = absolute(path);
|
||||
auto abs_root_path =
|
||||
absolute(root_path) + std::string{get_directory_seperator<char>()};
|
||||
#if defined(_WIN32)
|
||||
if (utils::string::to_lower(abs_path).starts_with(
|
||||
utils::string::to_lower(abs_root_path))) {
|
||||
#else // !defined(_WIN32)
|
||||
if (abs_path.starts_with(abs_root_path)) {
|
||||
#endif // defined(_WIN32)
|
||||
return abs_path.substr(abs_root_path.size());
|
||||
}
|
||||
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
auto get_relative_path(std::wstring_view path, std::wstring_view root_path)
|
||||
-> std::wstring {
|
||||
return utils::string::from_utf8(get_relative_path(
|
||||
utils::string::to_utf8(path), utils::string::to_utf8(root_path)));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 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 {
|
||||
auto abs_path = absolute(path);
|
||||
#if defined(_WIN32)
|
||||
utils::string::replace(abs_path, backslash, slash);
|
||||
abs_path = std::string{slash} + abs_path;
|
||||
#endif // defined(_WIN32)
|
||||
return "file://" + abs_path;
|
||||
}
|
||||
|
||||
auto make_file_uri(std::wstring_view path) -> std::wstring {
|
||||
return utils::string::from_utf8(make_file_uri(utils::string::to_utf8(path)));
|
||||
}
|
||||
|
||||
auto strip_to_file_name(std::string path) -> std::string {
|
||||
if (path == "." || path == "..") {
|
||||
return path;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
return ::PathFindFileNameA(path.c_str());
|
||||
#else // !defined(_WIN32)
|
||||
return utils::string::contains(path, slash) ? basename(path.data()) : path;
|
||||
#endif // defined(_WIN32)
|
||||
}
|
||||
|
||||
auto strip_to_file_name(std::wstring path) -> std::wstring {
|
||||
return utils::string::from_utf8(
|
||||
strip_to_file_name(utils::string::to_utf8(path)));
|
||||
}
|
||||
|
||||
auto unmake_file_uri(std::string_view uri) -> std::string {
|
||||
static constexpr const std::array<std::string_view, 23U> escape_characters = {
|
||||
{
|
||||
" ", "<", ">", "#", "%", "+", "{", "}", "|", "\\", "^", "~",
|
||||
"[", "]", "`", ";", "/", "?", ":", "@", "=", "&", "$",
|
||||
}};
|
||||
static constexpr const std::array<std::string_view, 23U>
|
||||
escape_sequences_lower = {{
|
||||
"%20", "%3c", "%3e", "%23", "%25", "%2b", "%7b", "%7d",
|
||||
"%7c", "%5c", "%5e", "%7e", "%5b", "%5d", "%60", "%3b",
|
||||
"%2f", "%3f", "%3a", "%40", "%3d", "%26", "%24",
|
||||
}};
|
||||
static constexpr const std::array<std::string_view, 23U>
|
||||
escape_sequences_upper = {{
|
||||
"%20", "%3C", "%3E", "%23", "%25", "%2B", "%7B", "%7D",
|
||||
"%7C", "%5C", "%5E", "%7E", "%5B", "%5D", "%60", "%3B",
|
||||
"%2F", "%3F", "%3A", "%40", "%3D", "%26", "%24",
|
||||
}};
|
||||
|
||||
std::string ret_uri{uri};
|
||||
#if defined(_WIN32)
|
||||
ret_uri = ret_uri.substr(8U);
|
||||
#else
|
||||
ret_uri = ret_uri.substr(7U);
|
||||
#endif
|
||||
|
||||
for (std::size_t idx = 0U; idx < escape_characters.size(); idx++) {
|
||||
utils::string::replace(ret_uri, escape_sequences_lower.at(idx),
|
||||
escape_characters.at(idx));
|
||||
utils::string::replace(ret_uri, escape_sequences_upper.at(idx),
|
||||
escape_characters.at(idx));
|
||||
}
|
||||
|
||||
return absolute(ret_uri);
|
||||
}
|
||||
|
||||
auto unmake_file_uri(std::wstring_view uri) -> std::wstring {
|
||||
return utils::string::from_utf8(unmake_file_uri(utils::string::to_utf8(uri)));
|
||||
}
|
||||
} // namespace repertory::utils::path
|
Reference in New Issue
Block a user