diff options
-rw-r--r-- | tests/unit/commands_test.cpp | 20 | ||||
-rw-r--r-- | updater/commands.cpp | 42 | ||||
-rw-r--r-- | updater/include/private/commands.h | 52 |
3 files changed, 113 insertions, 1 deletions
diff --git a/tests/unit/commands_test.cpp b/tests/unit/commands_test.cpp index 9679a9e73..19841d676 100644 --- a/tests/unit/commands_test.cpp +++ b/tests/unit/commands_test.cpp @@ -333,6 +333,25 @@ TEST(CommandsTest, Parse_ZERO) { ASSERT_EQ(PatchInfo(), command.patch()); } +TEST(CommandsTest, Parse_COMPUTE_HASH_TREE) { + const std::string input{ "compute_hash_tree 2,0,1 2,3,4 sha1 unknown-salt unknown-root-hash" }; + std::string err; + Command command = Command::Parse(input, 9, &err); + ASSERT_TRUE(command); + + ASSERT_EQ(Command::Type::COMPUTE_HASH_TREE, command.type()); + ASSERT_EQ(9, command.index()); + ASSERT_EQ(input, command.cmdline()); + + HashTreeInfo expected_info(RangeSet({ { 0, 1 } }), RangeSet({ { 3, 4 } }), "sha1", "unknown-salt", + "unknown-root-hash"); + ASSERT_EQ(expected_info, command.hash_tree_info()); + ASSERT_EQ(TargetInfo(), command.target()); + ASSERT_EQ(SourceInfo(), command.source()); + ASSERT_EQ(StashInfo(), command.stash()); + ASSERT_EQ(PatchInfo(), command.patch()); +} + TEST(CommandsTest, Parse_InvalidNumberOfArgs) { Command::abort_allowed_ = true; @@ -341,6 +360,7 @@ TEST(CommandsTest, Parse_InvalidNumberOfArgs) { std::vector<std::string> inputs{ "abort foo", "bsdiff", + "compute_hash_tree, 2,0,1 2,0,1 unknown-algorithm unknown-salt", "erase", "erase 4,3,5,10,12 hash1", "free", diff --git a/updater/commands.cpp b/updater/commands.cpp index 15a787c51..4a90ea873 100644 --- a/updater/commands.cpp +++ b/updater/commands.cpp @@ -31,6 +31,14 @@ using namespace std::string_literals; bool Command::abort_allowed_ = false; +Command::Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info) + : type_(type), + index_(index), + cmdline_(std::move(cmdline)), + hash_tree_info_(std::move(hash_tree_info)) { + CHECK(type == Type::COMPUTE_HASH_TREE); +} + Command::Type Command::ParseType(const std::string& type_str) { if (type_str == "abort") { if (!abort_allowed_) { @@ -177,7 +185,6 @@ Command Command::Parse(const std::string& line, size_t index, std::string* err) SourceInfo source_info; StashInfo stash_info; - // TODO(xunchang) add the parse code of compute_hash_tree if (op == Type::ZERO || op == Type::NEW || op == Type::ERASE) { // zero/new/erase <rangeset> if (pos + 1 != tokens.size()) { @@ -255,6 +262,39 @@ Command Command::Parse(const std::string& line, size_t index, std::string* err) tokens.size() - pos); return {}; } + } else if (op == Type::COMPUTE_HASH_TREE) { + // <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash> + if (pos + 5 != tokens.size()) { + *err = android::base::StringPrintf("invalid number of args: %zu (expected 5)", + tokens.size() - pos); + return {}; + } + + // Expects the hash_tree data to be contiguous. + RangeSet hash_tree_ranges = RangeSet::Parse(tokens[pos++]); + if (!hash_tree_ranges || hash_tree_ranges.size() != 1) { + *err = "invalid hash tree ranges in: " + line; + return {}; + } + + RangeSet source_ranges = RangeSet::Parse(tokens[pos++]); + if (!source_ranges) { + *err = "invalid source ranges in: " + line; + return {}; + } + + std::string hash_algorithm = tokens[pos++]; + std::string salt_hex = tokens[pos++]; + std::string root_hash = tokens[pos++]; + if (hash_algorithm.empty() || salt_hex.empty() || root_hash.empty()) { + *err = "invalid hash tree arguments in " + line; + return {}; + } + + HashTreeInfo hash_tree_info(std::move(hash_tree_ranges), std::move(source_ranges), + std::move(hash_algorithm), std::move(salt_hex), + std::move(root_hash)); + return Command(op, index, line, std::move(hash_tree_info)); } else { *err = "invalid op"; return {}; diff --git a/updater/include/private/commands.h b/updater/include/private/commands.h index 7f9dc79f4..85b52883b 100644 --- a/updater/include/private/commands.h +++ b/updater/include/private/commands.h @@ -166,6 +166,50 @@ class PatchInfo { size_t length_{ 0 }; }; +// The arguments to build a hash tree from blocks on the block device. +class HashTreeInfo { + public: + HashTreeInfo() = default; + + HashTreeInfo(RangeSet hash_tree_ranges, RangeSet source_ranges, std::string hash_algorithm, + std::string salt_hex, std::string root_hash) + : hash_tree_ranges_(std::move(hash_tree_ranges)), + source_ranges_(std::move(source_ranges)), + hash_algorithm_(std::move(hash_algorithm)), + salt_hex_(std::move(salt_hex)), + root_hash_(std::move(root_hash)) {} + + const RangeSet& hash_tree_ranges() const { + return hash_tree_ranges_; + } + const RangeSet& source_ranges() const { + return source_ranges_; + } + + const std::string& hash_algorithm() const { + return hash_algorithm_; + } + const std::string& salt_hex() const { + return salt_hex_; + } + const std::string& root_hash() const { + return root_hash_; + } + + bool operator==(const HashTreeInfo& other) const { + return hash_tree_ranges_ == other.hash_tree_ranges_ && source_ranges_ == other.source_ranges_ && + hash_algorithm_ == other.hash_algorithm_ && salt_hex_ == other.salt_hex_ && + root_hash_ == other.root_hash_; + } + + private: + RangeSet hash_tree_ranges_; + RangeSet source_ranges_; + std::string hash_algorithm_; + std::string salt_hex_; + std::string root_hash_; +}; + // Command class holds the info for an update command that performs block-based OTA (BBOTA). Each // command consists of one or several args, namely TargetInfo, SourceInfo, StashInfo and PatchInfo. // The currently used BBOTA version is v4. @@ -248,6 +292,8 @@ class Command { source_(std::move(source)), stash_(std::move(stash)) {} + Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info); + // Parses the given command 'line' into a Command object and returns it. The 'index' is specified // by the caller to index the object. On parsing error, it returns an empty Command object that // evaluates to false, and the specific error message will be set in 'err'. @@ -284,6 +330,10 @@ class Command { return stash_; } + const HashTreeInfo& hash_tree_info() const { + return hash_tree_info_; + } + constexpr explicit operator bool() const { return type_ != Type::LAST; } @@ -325,6 +375,8 @@ class Command { // The stash info. Only meaningful for STASH and FREE commands. Note that although SourceInfo may // also load data from stash, such info will be owned and managed by SourceInfo (i.e. in source_). StashInfo stash_; + // The hash_tree info. Only meaningful for COMPUTE_HASH_TREE. + HashTreeInfo hash_tree_info_; }; std::ostream& operator<<(std::ostream& os, const Command& command); |