// The platform-independent half of fs.hpp. AI-authored (Claude). #include "fs.hpp" #include #include #include #include #include #include #include #include namespace packutils::fs { std::string join(std::string_view a, std::string_view b) { std::string out(a); const bool ends = !out.empty() && (out.back() == '/' || out.back() == separator); if (!out.empty() && !ends && !b.empty()) { out.push_back(separator); } out += b; return out; } void pause(std::uint32_t milliseconds) { std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); } namespace { constexpr std::uint32_t mount_point_tag = 0xA0000003U; /// The tag, length and reserved fields, then four name offsets and lengths. constexpr std::size_t mount_point_header = 8 + 8; constexpr std::size_t max_reparse_bytes = std::size_t{16} * 1024; void put16(std::vector &out, std::size_t at, std::size_t value) { out.at(at) = static_cast(value & 0xFFU); out.at(at + 1) = static_cast((value >> 8U) & 0xFFU); } } // namespace std::optional> junction_buffer(const std::u16string &substitute, const std::u16string &print) { const std::size_t path_bytes = (substitute.size() + 1 + print.size() + 1) * 2; const std::size_t total = mount_point_header + path_bytes; if (total > max_reparse_bytes || total - 8 > 0xFFFFU) { return std::nullopt; } std::vector out(total, 0); put16(out, 0, mount_point_tag & 0xFFFFU); put16(out, 2, mount_point_tag >> 16U); put16(out, 4, total - 8); put16(out, 6, 0); put16(out, 8, 0); put16(out, 10, substitute.size() * 2); put16(out, 12, (substitute.size() + 1) * 2); put16(out, 14, print.size() * 2); std::size_t at = mount_point_header; for (const std::u16string *name : {&substitute, &print}) { for (const char16_t unit : *name) { put16(out, at, unit); at += 2; } at += 2; // The NUL, already zero. } return out; } bool same_path(std::string_view a, std::string_view b) { const auto trim = [](std::string_view path) { if (path.size() > 1 && (path.back() == '/' || path.back() == '\\')) { path.remove_suffix(1); } return path; }; const std::string_view x = trim(a); const std::string_view y = trim(b); #ifdef _WIN32 if (x.size() != y.size()) { return false; } const auto lower = [](char c) { return c >= 'A' && c <= 'Z' ? static_cast(c + 32) : c; }; for (std::size_t i = 0; i < x.size(); ++i) { const bool separators = (x[i] == '/' || x[i] == '\\') && (y[i] == '/' || y[i] == '\\'); if (!separators && lower(x[i]) != lower(y[i])) { return false; } } return true; #else return x == y; #endif } } // namespace packutils::fs