// Copyright 2021 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_software_update/config.h" #define PW_LOG_LEVEL PW_SOFTWARE_UPDATE_CONFIG_LOG_LEVEL #include #include #include "pw_log/log.h" #include "pw_protobuf/message.h" #include "pw_result/result.h" #include "pw_software_update/update_bundle.h" #include "pw_software_update/update_bundle.pwpb.h" #include "pw_stream/interval_reader.h" #include "pw_stream/memory_stream.h" namespace pw::software_update { namespace { constexpr std::string_view kTopLevelTargetsName = "targets"; } Status UpdateBundle::OpenAndVerify(const Manifest&) { PW_TRY(bundle_.Init()); PW_TRY(bundle_reader_.Open()); decoder_ = protobuf::Message(bundle_reader_, bundle_reader_.ConservativeReadLimit()); (void)backend_; // TODO(pw_bug/456): Implement verification logic. return OkStatus(); } // Get the target element corresponding to `target_file` stream::IntervalReader UpdateBundle::GetTargetPayload( std::string_view target_file_name) { protobuf::StringToBytesMap target_payloads = decoder_.AsStringToBytesMap(static_cast( pw_software_update::UpdateBundle::Fields::TARGET_PAYLOADS)); PW_TRY(target_payloads.status()); protobuf::Bytes payload = target_payloads[target_file_name]; PW_TRY(payload.status()); return payload.GetBytesReader(); } Result UpdateBundle::IsTargetPayloadIncluded( std::string_view target_file_name) { // TODO(pwbug/456): Perform personalization check first. If the target // is personalized out. Don't need to proceed. protobuf::StringToMessageMap signed_targets_metadata_map = decoder_.AsStringToMessageMap(static_cast( pw_software_update::UpdateBundle::Fields::TARGETS_METADATA)); PW_TRY(signed_targets_metadata_map.status()); // There should only be one element in the map, which is the top-level // targets metadata. protobuf::Message signed_targets_metadata = signed_targets_metadata_map[kTopLevelTargetsName]; PW_TRY(signed_targets_metadata.status()); protobuf::Message metadata = signed_targets_metadata.AsMessage( static_cast(pw_software_update::SignedTargetsMetadata::Fields:: SERIALIZED_TARGETS_METADATA)); PW_TRY(metadata.status()); protobuf::RepeatedMessages target_files = metadata.AsRepeatedMessages(static_cast( pw_software_update::TargetsMetadata::Fields::TARGET_FILES)); PW_TRY(target_files.status()); for (protobuf::Message target_file : target_files) { protobuf::String name = target_file.AsString(static_cast( pw_software_update::TargetFile::Fields::FILE_NAME)); PW_TRY(name.status()); Result file_name_matches = name.Equal(target_file_name); PW_TRY(file_name_matches.status()); if (file_name_matches.value()) { return true; } } return false; } Status UpdateBundle::WriteManifest(stream::Writer& staged_manifest_writer) { protobuf::StringToMessageMap signed_targets_metadata_map = decoder_.AsStringToMessageMap(static_cast( pw_software_update::UpdateBundle::Fields::TARGETS_METADATA)); PW_TRY(signed_targets_metadata_map.status()); // There should only be one element in the map, which is the top-level // targets metadata. protobuf::Message signed_targets_metadata = signed_targets_metadata_map[kTopLevelTargetsName]; PW_TRY(signed_targets_metadata.status()); protobuf::Bytes metadata = signed_targets_metadata.AsBytes( static_cast(pw_software_update::SignedTargetsMetadata::Fields:: SERIALIZED_TARGETS_METADATA)); PW_TRY(metadata.status()); stream::MemoryReader name_reader( std::as_bytes(std::span(kTopLevelTargetsName))); stream::IntervalReader metadata_reader = metadata.GetBytesReader(); std::byte stream_pipe_buffer[WRITE_MANIFEST_STREAM_PIPE_BUFFER_SIZE]; return protobuf::WriteProtoStringToBytesMapEntry( static_cast( pw_software_update::Manifest::Fields::TARGETS_METADATA), name_reader, kTopLevelTargetsName.size(), metadata_reader, metadata_reader.interval_size(), stream_pipe_buffer, staged_manifest_writer); } Status UpdateBundle::Close() { // TODO(pwbug/456): To be implemented. return bundle_reader_.Close(); } } // namespace pw::software_update