mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-13 22:23:45 +00:00
depot_download: option for unverified downloads
This patch equips the depot_download subsystem with the option to explicitly skip the signature verification for downloads by specifying the attribute 'verify="no"' for an <installation> item. This is useful in scenarios where the lack of integrity of downloaded content does not pose a risk, e.g., for untrusted applications that are rigidly sandboxed, or during development. Note that this option does not entirely discarge the signature checking. Whenever an download has dependencies that are verifyable - for which the public key exists in the depot - the dependencies are still verified. This allows untrusted content to depend of verifyable content while protecting the integrity the verifyable content. Issue #4804
This commit is contained in:
parent
b6bb338011
commit
f8fd202a1c
@ -58,11 +58,18 @@ void Depot_download_manager::gen_depot_query_start_content(Xml_generator &xml,
|
||||
fn(node); });
|
||||
};
|
||||
|
||||
auto propagate_verify_attr = [&] (Xml_generator &xml, Xml_node const &node)
|
||||
{
|
||||
if (node.attribute_value("verify", true) == false)
|
||||
xml.attribute("require_verify", "no");
|
||||
};
|
||||
|
||||
for_each_install_sub_node("archive", [&] (Xml_node const &archive) {
|
||||
xml.node("dependencies", [&] () {
|
||||
xml.attribute("path", archive.attribute_value("path", Archive::Path()));
|
||||
xml.attribute("source", archive.attribute_value("source", true));
|
||||
xml.attribute("binary", archive.attribute_value("binary", true));
|
||||
propagate_verify_attr(xml, archive);
|
||||
});
|
||||
});
|
||||
|
||||
@ -75,6 +82,7 @@ void Depot_download_manager::gen_depot_query_start_content(Xml_generator &xml,
|
||||
xml.node("index", [&] () {
|
||||
xml.attribute("user", Archive::user(path));
|
||||
xml.attribute("version", Archive::_path_element<Archive::Version>(path, 2));
|
||||
propagate_verify_attr(xml, index);
|
||||
});
|
||||
});
|
||||
|
||||
@ -87,6 +95,7 @@ void Depot_download_manager::gen_depot_query_start_content(Xml_generator &xml,
|
||||
xml.node("image", [&] () {
|
||||
xml.attribute("user", Archive::user(path));
|
||||
xml.attribute("name", Archive::name(path));
|
||||
propagate_verify_attr(xml, image);
|
||||
});
|
||||
});
|
||||
|
||||
@ -97,7 +106,9 @@ void Depot_download_manager::gen_depot_query_start_content(Xml_generator &xml,
|
||||
return;
|
||||
}
|
||||
xml.node("image_index", [&] () {
|
||||
xml.attribute("user", Archive::user(path)); });
|
||||
xml.attribute("user", Archive::user(path));
|
||||
propagate_verify_attr(xml, image_index);
|
||||
});
|
||||
});
|
||||
|
||||
if (next_user.valid())
|
||||
|
@ -55,7 +55,7 @@ void Depot_download_manager::gen_extract_start_content(Xml_generator &xml,
|
||||
});
|
||||
});
|
||||
|
||||
import.for_each_verified_archive([&] (Archive::Path const &path) {
|
||||
import.for_each_verified_or_blessed_archive([&] (Archive::Path const &path) {
|
||||
|
||||
typedef String<160> Path;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
void Depot_download_manager::gen_fetchurl_start_content(Xml_generator &xml,
|
||||
Import const &import,
|
||||
Url const ¤t_user_url,
|
||||
Pubkey_known pubkey_known,
|
||||
Fetchurl_version version)
|
||||
{
|
||||
xml.attribute("version", version.value);
|
||||
@ -23,40 +24,40 @@ void Depot_download_manager::gen_fetchurl_start_content(Xml_generator &xml,
|
||||
gen_common_start_content(xml, "fetchurl",
|
||||
Cap_quota{500}, Ram_quota{8*1024*1024});
|
||||
|
||||
xml.node("config", [&] () {
|
||||
xml.node("libc", [&] () {
|
||||
xml.node("config", [&] {
|
||||
xml.node("libc", [&] {
|
||||
xml.attribute("stdout", "/dev/log");
|
||||
xml.attribute("stderr", "/dev/log");
|
||||
xml.attribute("rtc", "/dev/rtc");
|
||||
xml.attribute("socket", "/socket");
|
||||
});
|
||||
xml.node("report", [&] () {
|
||||
xml.node("report", [&] {
|
||||
xml.attribute("progress", "yes");
|
||||
xml.attribute("delay_ms", 250);
|
||||
});
|
||||
xml.node("vfs", [&] () {
|
||||
xml.node("dir", [&] () {
|
||||
xml.node("vfs", [&] {
|
||||
xml.node("dir", [&] {
|
||||
xml.attribute("name", "download");
|
||||
xml.node("fs", [&] () {
|
||||
xml.node("fs", [&] {
|
||||
xml.attribute("buffer_size", 144u << 10);
|
||||
xml.attribute("label", "download"); });
|
||||
});
|
||||
xml.node("dir", [&] () {
|
||||
xml.node("dir", [&] {
|
||||
xml.attribute("name", "dev");
|
||||
xml.node("log", [&] () { });
|
||||
xml.node("null", [&] () { });
|
||||
xml.node("inline", [&] () {
|
||||
xml.node("log", [&] { });
|
||||
xml.node("null", [&] { });
|
||||
xml.node("inline", [&] {
|
||||
xml.attribute("name", "rtc");
|
||||
String<64> date("2000-01-01 00:00");
|
||||
xml.append(date.string());
|
||||
});
|
||||
xml.node("inline", [&] () {
|
||||
xml.node("inline", [&] {
|
||||
xml.attribute("name", "random");
|
||||
String<64> entropy("01234567890123456789");
|
||||
xml.append(entropy.string());
|
||||
});
|
||||
});
|
||||
xml.node("fs", [&] () {
|
||||
xml.node("fs", [&] {
|
||||
xml.attribute("label", "tcpip"); });
|
||||
});
|
||||
|
||||
@ -69,29 +70,31 @@ void Depot_download_manager::gen_fetchurl_start_content(Xml_generator &xml,
|
||||
Remote const remote (current_user_url, "/", file_path);
|
||||
Local const local ("/download/", file_path);
|
||||
|
||||
xml.node("fetch", [&] () {
|
||||
xml.node("fetch", [&] {
|
||||
xml.attribute("url", remote);
|
||||
xml.attribute("path", local);
|
||||
});
|
||||
|
||||
xml.node("fetch", [&] () {
|
||||
xml.attribute("url", Remote(remote, ".sig"));
|
||||
xml.attribute("path", Local (local, ".sig"));
|
||||
});
|
||||
if (pubkey_known.value) {
|
||||
xml.node("fetch", [&] {
|
||||
xml.attribute("url", Remote(remote, ".sig"));
|
||||
xml.attribute("path", Local (local, ".sig"));
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
xml.node("route", [&] () {
|
||||
xml.node("service", [&] () {
|
||||
xml.node("route", [&] {
|
||||
xml.node("service", [&] {
|
||||
xml.attribute("name", File_system::Session::service_name());
|
||||
xml.attribute("label", "download");
|
||||
xml.node("parent", [&] () {
|
||||
xml.node("parent", [&] {
|
||||
xml.attribute("label", "public_rw"); });
|
||||
});
|
||||
xml.node("service", [&] () {
|
||||
xml.node("service", [&] {
|
||||
xml.attribute("name", File_system::Session::service_name());
|
||||
xml.attribute("label", "tcpip");
|
||||
xml.node("parent", [&] () {
|
||||
xml.node("parent", [&] {
|
||||
xml.attribute("label", "tcpip"); });
|
||||
});
|
||||
gen_parent_unscoped_rom_route(xml, "fetchurl");
|
||||
|
@ -63,12 +63,15 @@ class Depot_download_manager::Import
|
||||
|
||||
Archive::Path const path;
|
||||
|
||||
bool const require_verify;
|
||||
|
||||
enum State { DOWNLOAD_IN_PROGRESS,
|
||||
DOWNLOAD_COMPLETE,
|
||||
DOWNLOAD_UNAVAILABLE,
|
||||
VERIFICATION_IN_PROGRESS,
|
||||
VERIFIED,
|
||||
VERIFICATION_FAILED,
|
||||
BLESSED, /* verification deliberately skipped */
|
||||
UNPACKED };
|
||||
|
||||
State state = DOWNLOAD_IN_PROGRESS;
|
||||
@ -78,12 +81,15 @@ class Depot_download_manager::Import
|
||||
return state == DOWNLOAD_IN_PROGRESS
|
||||
|| state == DOWNLOAD_COMPLETE
|
||||
|| state == VERIFICATION_IN_PROGRESS
|
||||
|| state == VERIFIED;
|
||||
|| state == VERIFIED
|
||||
|| state == BLESSED;
|
||||
}
|
||||
|
||||
Item(Registry<Item> ®istry, Archive::Path const &path)
|
||||
Item(Registry<Item> ®istry, Archive::Path const &path,
|
||||
Require_verify require_verify)
|
||||
:
|
||||
_element(registry, *this), path(path)
|
||||
_element(registry, *this), path(path),
|
||||
require_verify(require_verify.value)
|
||||
{ }
|
||||
|
||||
char const *state_text() const
|
||||
@ -95,6 +101,7 @@ class Depot_download_manager::Import
|
||||
case VERIFICATION_IN_PROGRESS: return "verify";
|
||||
case VERIFIED: return "extract";
|
||||
case VERIFICATION_FAILED: return "corrupted";
|
||||
case BLESSED: return "extract";
|
||||
case UNPACKED: return "done";
|
||||
};
|
||||
return "";
|
||||
@ -103,6 +110,8 @@ class Depot_download_manager::Import
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
bool const _pubkey_known;
|
||||
|
||||
Registry<Item> _items { };
|
||||
|
||||
template <typename FN>
|
||||
@ -155,16 +164,16 @@ class Depot_download_manager::Import
|
||||
FN const &fn)
|
||||
{
|
||||
dependencies.for_each_sub_node("missing", [&] (Xml_node const &item) {
|
||||
fn(_depdendency_path(item)); });
|
||||
fn(_depdendency_path(item), Require_verify::from_xml(item)); });
|
||||
|
||||
index.for_each_sub_node("missing", [&] (Xml_node const &item) {
|
||||
fn(_index_path(item)); });
|
||||
fn(_index_path(item), Require_verify::from_xml(item)); });
|
||||
|
||||
image.for_each_sub_node("missing", [&] (Xml_node const &item) {
|
||||
fn(_image_path(item)); });
|
||||
fn(_image_path(item), Require_verify::from_xml(item)); });
|
||||
|
||||
image_index.for_each_sub_node("missing", [&] (Xml_node const &item) {
|
||||
fn(_image_index_path(item)); });
|
||||
fn(_image_index_path(item), Require_verify::from_xml(item)); });
|
||||
}
|
||||
|
||||
public:
|
||||
@ -200,18 +209,20 @@ class Depot_download_manager::Import
|
||||
* items that match the 'user'. The remaining sub nodes are imported in
|
||||
* a future iteration.
|
||||
*/
|
||||
Import(Allocator &alloc, Archive::User const &user,
|
||||
Xml_node const &dependencies,
|
||||
Xml_node const &index,
|
||||
Xml_node const &image,
|
||||
Xml_node const &image_index)
|
||||
Import(Allocator &alloc,
|
||||
Archive::User const &user,
|
||||
Pubkey_known const pubkey_known,
|
||||
Xml_node const &dependencies,
|
||||
Xml_node const &index,
|
||||
Xml_node const &image,
|
||||
Xml_node const &image_index)
|
||||
:
|
||||
_alloc(alloc)
|
||||
_alloc(alloc), _pubkey_known(pubkey_known.value)
|
||||
{
|
||||
_for_each_missing_depot_path(dependencies, index, image, image_index,
|
||||
[&] (Archive::Path const &path) {
|
||||
[&] (Archive::Path const &path, Require_verify require_verify) {
|
||||
if (Archive::user(path) == user)
|
||||
new (alloc) Item(_items, path); });
|
||||
new (alloc) Item(_items, path, require_verify); });
|
||||
}
|
||||
|
||||
~Import()
|
||||
@ -234,9 +245,10 @@ class Depot_download_manager::Import
|
||||
return _item_state_exists(Item::VERIFICATION_IN_PROGRESS);
|
||||
}
|
||||
|
||||
bool verified_archives_available() const
|
||||
bool verified_or_blessed_archives_available() const
|
||||
{
|
||||
return _item_state_exists(Item::VERIFIED);
|
||||
return _item_state_exists(Item::VERIFIED)
|
||||
|| _item_state_exists(Item::BLESSED);
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
@ -252,9 +264,10 @@ class Depot_download_manager::Import
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
void for_each_verified_archive(FN const &fn) const
|
||||
void for_each_verified_or_blessed_archive(FN const &fn) const
|
||||
{
|
||||
_for_each_item(Item::VERIFIED, fn);
|
||||
_for_each_item(Item::BLESSED, fn);
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
@ -277,11 +290,23 @@ class Depot_download_manager::Import
|
||||
item.state = Item::DOWNLOAD_COMPLETE; });
|
||||
}
|
||||
|
||||
void verify_all_downloaded_archives()
|
||||
void verify_or_bless_all_downloaded_archives()
|
||||
{
|
||||
_items.for_each([&] (Item &item) {
|
||||
if (item.state == Item::DOWNLOAD_COMPLETE)
|
||||
item.state = Item::VERIFICATION_IN_PROGRESS; });
|
||||
if (item.state == Item::DOWNLOAD_COMPLETE) {
|
||||
|
||||
/*
|
||||
* If verification is not required, still verify whenever
|
||||
* a depot user's public key exists. This way, verifiable
|
||||
* archives referred to by non-verified archives end up in
|
||||
* verified form in the depot.
|
||||
*/
|
||||
if (item.require_verify || _pubkey_known)
|
||||
item.state = Item::VERIFICATION_IN_PROGRESS;
|
||||
else
|
||||
item.state = Item::BLESSED;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void apply_download_progress(Download_progress const &progress)
|
||||
@ -319,10 +344,10 @@ class Depot_download_manager::Import
|
||||
item.state = Item::VERIFICATION_FAILED; });
|
||||
}
|
||||
|
||||
void all_verified_archives_extracted()
|
||||
void all_verified_or_blessed_archives_extracted()
|
||||
{
|
||||
_items.for_each([&] (Item &item) {
|
||||
if (item.state == Item::VERIFIED)
|
||||
if (item.state == Item::VERIFIED || item.state == Item::BLESSED)
|
||||
item.state = Item::UNPACKED; });
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,11 @@ struct Depot_download_manager::Main : Import::Download_progress
|
||||
return _current_user.xml().attribute_value("name", Archive::User());
|
||||
}
|
||||
|
||||
Pubkey_known _current_user_has_pubkey() const
|
||||
{
|
||||
return Pubkey_known { _current_user.xml().has_sub_node("pubkey") };
|
||||
}
|
||||
|
||||
Path _current_user_path() const
|
||||
{
|
||||
return Path("/depot/", _current_user_name());
|
||||
@ -326,7 +331,9 @@ void Depot_download_manager::Main::_generate_init_config(Xml_generator &xml)
|
||||
if (fetchurl_running) {
|
||||
try {
|
||||
xml.node("start", [&] () {
|
||||
gen_fetchurl_start_content(xml, *_import, _current_user_url(),
|
||||
gen_fetchurl_start_content(xml, *_import,
|
||||
_current_user_url(),
|
||||
_current_user_has_pubkey(),
|
||||
_fetchurl_count); });
|
||||
}
|
||||
catch (Invalid_download_url) {
|
||||
@ -338,7 +345,7 @@ void Depot_download_manager::Main::_generate_init_config(Xml_generator &xml)
|
||||
xml.node("start", [&] () {
|
||||
gen_verify_start_content(xml, *_import, _current_user_path()); });
|
||||
|
||||
if (_import.constructed() && _import->verified_archives_available()) {
|
||||
if (_import.constructed() && _import->verified_or_blessed_archives_available()) {
|
||||
|
||||
xml.node("start", [&] () {
|
||||
gen_chroot_start_content(xml, _current_user_name()); });
|
||||
@ -370,8 +377,7 @@ void Depot_download_manager::Main::_handle_query_result()
|
||||
|
||||
Archive::User const name = user.attribute_value("name", Archive::User());
|
||||
|
||||
bool const user_info_complete = user.has_sub_node("url")
|
||||
&& user.has_sub_node("pubkey");
|
||||
bool const user_info_complete = user.has_sub_node("url");
|
||||
|
||||
if (name.valid() && !user_info_complete) {
|
||||
|
||||
@ -397,6 +403,8 @@ void Depot_download_manager::Main::_handle_query_result()
|
||||
Xml_node const image = _image.xml();
|
||||
Xml_node const image_index = _image_index.xml();
|
||||
|
||||
log("query result index: ", index);
|
||||
|
||||
/* mark jobs referring to existing depot content as unneccessary */
|
||||
Import::for_each_present_depot_path(dependencies, index, image, image_index,
|
||||
[&] (Archive::Path const &path) {
|
||||
@ -458,7 +466,7 @@ void Depot_download_manager::Main::_handle_query_result()
|
||||
}
|
||||
|
||||
/* start new import */
|
||||
_import.construct(_heap, _current_user_name(),
|
||||
_import.construct(_heap, _current_user_name(), _current_user_has_pubkey(),
|
||||
dependencies, index, image, image_index);
|
||||
|
||||
/* mark imported jobs as started */
|
||||
@ -514,7 +522,7 @@ void Depot_download_manager::Main::_handle_init_state()
|
||||
}
|
||||
|
||||
if (!import.downloads_in_progress() && import.completed_downloads_available()) {
|
||||
import.verify_all_downloaded_archives();
|
||||
import.verify_or_bless_all_downloaded_archives();
|
||||
reconfigure_init = true;
|
||||
}
|
||||
|
||||
@ -545,7 +553,7 @@ void Depot_download_manager::Main::_handle_init_state()
|
||||
});
|
||||
}
|
||||
|
||||
if (import.verified_archives_available()) {
|
||||
if (import.verified_or_blessed_archives_available()) {
|
||||
|
||||
Child_exit_state const extract_state(_init_state.xml(), "extract");
|
||||
|
||||
@ -553,7 +561,7 @@ void Depot_download_manager::Main::_handle_init_state()
|
||||
error("extract failed with exit code ", extract_state.code);
|
||||
|
||||
if (extract_state.exited && extract_state.code == 0)
|
||||
import.all_verified_archives_extracted();
|
||||
import.all_verified_or_blessed_archives_extracted();
|
||||
}
|
||||
|
||||
/* flag failed jobs to prevent re-attempts in subsequent import iterations */
|
||||
|
@ -28,8 +28,33 @@ namespace Depot_download_manager {
|
||||
|
||||
struct Depot_query_version { unsigned value; };
|
||||
struct Fetchurl_version { unsigned value; };
|
||||
|
||||
struct Require_verify;
|
||||
|
||||
struct Pubkey_known { bool value; };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Argument type for propagating 'verify' install attributes to imports
|
||||
*/
|
||||
struct Depot_download_manager::Require_verify
|
||||
{
|
||||
bool value;
|
||||
|
||||
static Require_verify from_xml(Xml_node const &node)
|
||||
{
|
||||
return Require_verify { node.attribute_value("require_verify", true) };
|
||||
}
|
||||
|
||||
void gen_attr(Xml_generator &xml) const
|
||||
{
|
||||
if (!value)
|
||||
xml.attribute("require_verify", "no");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
|
@ -89,7 +89,7 @@ namespace Depot_download_manager {
|
||||
List_model<Job> const &);
|
||||
|
||||
void gen_fetchurl_start_content(Xml_generator &, Import const &, Url const &,
|
||||
Fetchurl_version);
|
||||
Pubkey_known, Fetchurl_version);
|
||||
|
||||
void gen_verify_start_content(Xml_generator &, Import const &, Path const &);
|
||||
|
||||
|
@ -191,6 +191,7 @@ void Depot_query::Main::_query_blueprint(Directory::Path const &pkg_path, Xml_ge
|
||||
|
||||
void Depot_query::Main::_collect_source_dependencies(Archive::Path const &path,
|
||||
Dependencies &dependencies,
|
||||
Require_verify require_verify,
|
||||
Recursion_limit recursion_limit)
|
||||
{
|
||||
try { Archive::type(path); }
|
||||
@ -199,14 +200,15 @@ void Depot_query::Main::_collect_source_dependencies(Archive::Path const &path,
|
||||
return;
|
||||
}
|
||||
|
||||
dependencies.record(path);
|
||||
dependencies.record(path, require_verify);
|
||||
|
||||
switch (Archive::type(path)) {
|
||||
|
||||
case Archive::PKG: {
|
||||
_with_file_content(path, "archives", [&] (File_content const &archives) {
|
||||
archives.for_each_line<Archive::Path>([&] (Archive::Path const &path) {
|
||||
_collect_source_dependencies(path, dependencies, recursion_limit); }); });
|
||||
_collect_source_dependencies(path, dependencies, require_verify,
|
||||
recursion_limit); }); });
|
||||
break;
|
||||
}
|
||||
|
||||
@ -214,7 +216,8 @@ void Depot_query::Main::_collect_source_dependencies(Archive::Path const &path,
|
||||
typedef String<160> Api;
|
||||
_with_file_content(path, "used_apis", [&] (File_content const &used_apis) {
|
||||
used_apis.for_each_line<Archive::Path>([&] (Api const &api) {
|
||||
dependencies.record(Archive::Path(Archive::user(path), "/api/", api)); }); });
|
||||
dependencies.record(Archive::Path(Archive::user(path), "/api/", api),
|
||||
require_verify); }); });
|
||||
break;
|
||||
}
|
||||
|
||||
@ -227,6 +230,7 @@ void Depot_query::Main::_collect_source_dependencies(Archive::Path const &path,
|
||||
|
||||
void Depot_query::Main::_collect_binary_dependencies(Archive::Path const &path,
|
||||
Dependencies &dependencies,
|
||||
Require_verify require_verify,
|
||||
Recursion_limit recursion_limit)
|
||||
{
|
||||
try { Archive::type(path); }
|
||||
@ -238,22 +242,23 @@ void Depot_query::Main::_collect_binary_dependencies(Archive::Path const &path,
|
||||
switch (Archive::type(path)) {
|
||||
|
||||
case Archive::PKG:
|
||||
dependencies.record(path);
|
||||
dependencies.record(path, require_verify);
|
||||
|
||||
_with_file_content(path, "archives", [&] (File_content const &archives) {
|
||||
archives.for_each_line<Archive::Path>([&] (Archive::Path const &archive_path) {
|
||||
_collect_binary_dependencies(archive_path, dependencies, recursion_limit); }); });
|
||||
_collect_binary_dependencies(archive_path, dependencies,
|
||||
require_verify, recursion_limit); }); });
|
||||
break;
|
||||
|
||||
case Archive::SRC:
|
||||
dependencies.record(Archive::Path(Archive::user(path), "/bin/",
|
||||
_architecture, "/",
|
||||
Archive::name(path), "/",
|
||||
Archive::version(path)));
|
||||
Archive::version(path)), require_verify);
|
||||
break;
|
||||
|
||||
case Archive::RAW:
|
||||
dependencies.record(path);
|
||||
dependencies.record(path, require_verify);
|
||||
break;
|
||||
|
||||
case Archive::IMAGE:
|
||||
@ -363,13 +368,16 @@ void Depot_query::Main::_gen_index_for_arch(Xml_generator &xml,
|
||||
|
||||
void Depot_query::Main::_query_index(Archive::User const &user,
|
||||
Archive::Version const &version,
|
||||
bool const content, Xml_generator &xml)
|
||||
bool const content,
|
||||
Require_verify const require_verify,
|
||||
Xml_generator &xml)
|
||||
{
|
||||
Directory::Path const index_path("depot/", user, "/index/", version);
|
||||
if (!_root.file_exists(index_path)) {
|
||||
xml.node("missing", [&] () {
|
||||
xml.attribute("user", user);
|
||||
xml.attribute("version", version);
|
||||
require_verify.gen_attr(xml);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -377,6 +385,7 @@ void Depot_query::Main::_query_index(Archive::User const &user,
|
||||
xml.node("index", [&] () {
|
||||
xml.attribute("user", user);
|
||||
xml.attribute("version", version);
|
||||
require_verify.gen_attr(xml);
|
||||
|
||||
if (content) {
|
||||
try {
|
||||
@ -392,9 +401,10 @@ void Depot_query::Main::_query_index(Archive::User const &user,
|
||||
}
|
||||
|
||||
|
||||
void Depot_query::Main::_query_image(Archive::User const &user,
|
||||
Archive::Name const &name,
|
||||
Xml_generator &xml)
|
||||
void Depot_query::Main::_query_image(Archive::User const &user,
|
||||
Archive::Name const &name,
|
||||
Require_verify const require_verify,
|
||||
Xml_generator &xml)
|
||||
{
|
||||
Directory::Path const image_path("depot/", user, "/image/", name);
|
||||
char const *node_type = _root.directory_exists(image_path)
|
||||
@ -402,6 +412,7 @@ void Depot_query::Main::_query_image(Archive::User const &user,
|
||||
xml.node(node_type, [&] () {
|
||||
xml.attribute("user", user);
|
||||
xml.attribute("name", name);
|
||||
require_verify.gen_attr(xml);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ namespace Depot_query {
|
||||
|
||||
typedef String<64> Rom_label;
|
||||
|
||||
struct Require_verify;
|
||||
struct Directory_cache;
|
||||
struct Recursion_limit;
|
||||
struct Dependencies;
|
||||
@ -39,6 +40,26 @@ namespace Depot_query {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Argument type for propagating 'require_verify' query attributes to results
|
||||
*/
|
||||
struct Depot_query::Require_verify
|
||||
{
|
||||
bool value;
|
||||
|
||||
static Require_verify from_xml(Xml_node const &node)
|
||||
{
|
||||
return Require_verify { node.attribute_value("require_verify", true) };
|
||||
}
|
||||
|
||||
void gen_attr(Xml_generator &xml) const
|
||||
{
|
||||
if (!value)
|
||||
xml.attribute("require_verify", "no");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Depot_query::Directory_cache : Noncopyable
|
||||
{
|
||||
Allocator &_alloc;
|
||||
@ -165,11 +186,28 @@ class Depot_query::Dependencies
|
||||
{
|
||||
private:
|
||||
|
||||
using Path = Archive::Path;
|
||||
|
||||
struct Collection : Noncopyable
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
typedef Registered_no_delete<Archive::Path> Entry;
|
||||
struct Dependency
|
||||
{
|
||||
Path path;
|
||||
Require_verify require_verify;
|
||||
|
||||
Dependency(Path const &path, Require_verify require_verify)
|
||||
: path(path), require_verify(require_verify) { }
|
||||
|
||||
void gen_attr(Xml_generator &xml) const
|
||||
{
|
||||
xml.attribute("path", path);
|
||||
require_verify.gen_attr(xml);
|
||||
}
|
||||
};
|
||||
|
||||
using Entry = Registered_no_delete<Dependency>;
|
||||
|
||||
Registry<Entry> _entries { };
|
||||
|
||||
@ -180,20 +218,20 @@ class Depot_query::Dependencies
|
||||
_entries.for_each([&] (Entry &e) { destroy(_alloc, &e); });
|
||||
}
|
||||
|
||||
bool known(Archive::Path const &path) const
|
||||
bool known(Path const &path) const
|
||||
{
|
||||
bool result = false;
|
||||
_entries.for_each([&] (Entry const &entry) {
|
||||
if (path == entry)
|
||||
if (path == entry.path)
|
||||
result = true; });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void insert(Archive::Path const &path)
|
||||
void insert(Path const &path, Require_verify require_verify)
|
||||
{
|
||||
if (!known(path))
|
||||
new (_alloc) Entry(_entries, path);
|
||||
new (_alloc) Entry(_entries, path, require_verify);
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
@ -212,26 +250,26 @@ class Depot_query::Dependencies
|
||||
_depot(depot), _present(alloc), _missing(alloc)
|
||||
{ }
|
||||
|
||||
bool known(Archive::Path const &path) const
|
||||
bool known(Path const &path) const
|
||||
{
|
||||
return _present.known(path) || _missing.known(path);
|
||||
}
|
||||
|
||||
void record(Archive::Path const &path)
|
||||
void record(Path const &path, Require_verify require_verify)
|
||||
{
|
||||
if (_depot.directory_exists(path))
|
||||
_present.insert(path);
|
||||
_present.insert(path, require_verify);
|
||||
else
|
||||
_missing.insert(path);
|
||||
_missing.insert(path, require_verify);
|
||||
}
|
||||
|
||||
void xml(Xml_generator &xml) const
|
||||
{
|
||||
_present.for_each([&] (Archive::Path const &path) {
|
||||
xml.node("present", [&] () { xml.attribute("path", path); }); });
|
||||
_present.for_each([&] (Collection::Entry const &entry) {
|
||||
xml.node("present", [&] () { entry.gen_attr(xml); }); });
|
||||
|
||||
_missing.for_each([&] (Archive::Path const &path) {
|
||||
xml.node("missing", [&] () { xml.attribute("path", path); }); });
|
||||
_missing.for_each([&] (Collection::Entry const &entry) {
|
||||
xml.node("missing", [&] () { entry.gen_attr(xml); }); });
|
||||
}
|
||||
};
|
||||
|
||||
@ -336,15 +374,15 @@ struct Depot_query::Main
|
||||
void _gen_inherited_rom_path_nodes(Xml_generator &, Xml_node const &,
|
||||
Archive::Path const &, Recursion_limit);
|
||||
void _query_blueprint(Directory::Path const &, Xml_generator &);
|
||||
void _collect_source_dependencies(Archive::Path const &, Dependencies &, Recursion_limit);
|
||||
void _collect_binary_dependencies(Archive::Path const &, Dependencies &, Recursion_limit);
|
||||
void _collect_source_dependencies(Archive::Path const &, Dependencies &, Require_verify, Recursion_limit);
|
||||
void _collect_binary_dependencies(Archive::Path const &, Dependencies &, Require_verify, Recursion_limit);
|
||||
void _scan_user(Archive::User const &, Xml_generator &);
|
||||
void _query_user(Archive::User const &, Xml_generator &);
|
||||
void _gen_index_node_rec(Xml_generator &, Xml_node const &, unsigned) const;
|
||||
void _gen_index_for_arch(Xml_generator &, Xml_node const &) const;
|
||||
void _query_index(Archive::User const &, Archive::Version const &, bool, Xml_generator &);
|
||||
void _query_image(Archive::User const &, Archive::Name const &, Xml_generator &);
|
||||
void _query_image_index(Xml_node const &, Xml_generator &);
|
||||
void _query_index(Archive::User const &, Archive::Version const &, bool, Require_verify, Xml_generator &);
|
||||
void _query_image(Archive::User const &, Archive::Name const &, Require_verify, Xml_generator &);
|
||||
void _query_image_index(Xml_node const &, Require_verify, Xml_generator &);
|
||||
|
||||
void _handle_config()
|
||||
{
|
||||
@ -431,13 +469,16 @@ struct Depot_query::Main
|
||||
Dependencies dependencies(_heap, _depot_dir);
|
||||
query.for_each_sub_node("dependencies", [&] (Xml_node node) {
|
||||
|
||||
Archive::Path const path = node.attribute_value("path", Archive::Path());
|
||||
Archive::Path const path = node.attribute_value("path", Archive::Path());
|
||||
Require_verify const require_verify = Require_verify::from_xml(node);
|
||||
|
||||
if (node.attribute_value("source", false))
|
||||
_collect_source_dependencies(path, dependencies, Recursion_limit{8});
|
||||
_collect_source_dependencies(path, dependencies, require_verify,
|
||||
Recursion_limit{8});
|
||||
|
||||
if (node.attribute_value("binary", false))
|
||||
_collect_binary_dependencies(path, dependencies, Recursion_limit{8});
|
||||
_collect_binary_dependencies(path, dependencies, require_verify,
|
||||
Recursion_limit{8});
|
||||
});
|
||||
dependencies.xml(xml);
|
||||
});
|
||||
@ -457,17 +498,19 @@ struct Depot_query::Main
|
||||
_query_index(node.attribute_value("user", Archive::User()),
|
||||
node.attribute_value("version", Archive::Version()),
|
||||
node.attribute_value("content", false),
|
||||
Require_verify::from_xml(node),
|
||||
xml); }); });
|
||||
|
||||
_gen_versioned_report(_image_reporter, version, [&] (Xml_generator &xml) {
|
||||
query.for_each_sub_node("image", [&] (Xml_node node) {
|
||||
_query_image(node.attribute_value("user", Archive::User()),
|
||||
node.attribute_value("name", Archive::Name()),
|
||||
Require_verify::from_xml(node),
|
||||
xml); }); });
|
||||
|
||||
_gen_versioned_report(_image_index_reporter, version, [&] (Xml_generator &xml) {
|
||||
query.for_each_sub_node("image_index", [&] (Xml_node node) {
|
||||
_query_image_index(node, xml); }); });
|
||||
_query_image_index(node, Require_verify::from_xml(node), xml); }); });
|
||||
}
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
|
||||
void Depot_query::Main::_query_image_index(Xml_node const &index_query,
|
||||
Require_verify require_verify,
|
||||
Xml_generator &xml)
|
||||
{
|
||||
using User = Archive::User;
|
||||
@ -150,7 +151,9 @@ void Depot_query::Main::_query_image_index(Xml_node const &index_query,
|
||||
* file.
|
||||
*/
|
||||
xml.node(index_exists ? "present" : "missing", [&] () {
|
||||
xml.attribute("user", user); });
|
||||
xml.attribute("user", user);
|
||||
require_verify.gen_attr(xml);
|
||||
});
|
||||
|
||||
/*
|
||||
* Report aggregated image information with the newest version first.
|
||||
|
Loading…
x
Reference in New Issue
Block a user