58 const std::vector<std::uint8_t>& trusted_public_key,
59 const std::filesystem::path& install_base,
bool reject_unknown_kinds =
true) {
60 namespace fs = std::filesystem;
70 const fs::path canon_root = fs::weakly_canonical(source_root, ec);
71 for (
const auto& f : manifest.
files) {
74 const fs::path src = source_root / f.path;
75 if (fs::is_symlink(src, ec) || ec)
77 const fs::path canon = fs::weakly_canonical(src, ec);
78 if (ec || (!canon_root.empty() &&
79 canon.string().rfind(canon_root.string(), 0) != 0))
87 if (fs::exists(dest, ec)) {
90 fs::permissions(dest, fs::perms::owner_all, fs::perm_options::add, ec);
91 fs::remove_all(dest, ec);
97 fs::create_directories(install_base, ec);
99 fs::remove_all(staging, ec);
100 if (!fs::create_directories(staging, ec) && ec)
104 fs::permissions(staging, fs::perms::owner_all, fs::perm_options::add, ec);
105 fs::remove_all(staging, ec);
109 for (
const auto& f : manifest.
files) {
110 const fs::path src = source_root / f.path;
111 const fs::path out = staging / f.path;
112 fs::create_directories(out.parent_path(), ec);
113 std::ifstream in(src, std::ios::binary);
114 if (!in)
return fail_io(
"read " + f.path);
115 std::vector<char> bytes((std::istreambuf_iterator<char>(in)),
116 std::istreambuf_iterator<char>());
117 std::ofstream o(out, std::ios::binary | std::ios::trunc);
118 if (!o)
return fail_io(
"write " + f.path);
119 o.write(bytes.data(),
static_cast<std::streamsize
>(bytes.size()));
121 if (!o)
return fail_io(
"flush " + f.path);
123 fs::permissions(out, fs::perms::owner_read, fs::perm_options::replace, ec);
129 return fail_io(
"staged bytes failed re-verification");
133 fs::rename(staging, dest, ec);
135 if (fs::exists(dest) &&
137 fs::permissions(staging, fs::perms::owner_all, fs::perm_options::add, ec);
138 fs::remove_all(staging, ec);
141 return fail_io(
"publish rename: " + ec.message());
144 fs::permissions(dest, fs::perms::owner_read | fs::perms::owner_exec,
145 fs::perm_options::replace, ec);