payload_generation_config.cc revision a4073ef63482fd08c3678982f7d153360b088094
1// 2// Copyright (C) 2015 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "update_engine/payload_generator/payload_generation_config.h" 18 19#include <base/logging.h> 20 21#include "update_engine/common/utils.h" 22#include "update_engine/payload_consumer/delta_performer.h" 23#include "update_engine/payload_generator/delta_diff_generator.h" 24#include "update_engine/payload_generator/delta_diff_utils.h" 25#include "update_engine/payload_generator/ext2_filesystem.h" 26#include "update_engine/payload_generator/raw_filesystem.h" 27 28namespace chromeos_update_engine { 29 30bool PostInstallConfig::IsEmpty() const { 31 return run == false && path.empty() && filesystem_type.empty(); 32} 33 34bool PartitionConfig::ValidateExists() const { 35 TEST_AND_RETURN_FALSE(!path.empty()); 36 TEST_AND_RETURN_FALSE(utils::FileExists(path.c_str())); 37 TEST_AND_RETURN_FALSE(size > 0); 38 // The requested size is within the limits of the file. 39 TEST_AND_RETURN_FALSE(static_cast<off_t>(size) <= 40 utils::FileSize(path.c_str())); 41 return true; 42} 43 44bool PartitionConfig::OpenFilesystem() { 45 if (path.empty()) 46 return true; 47 fs_interface.reset(); 48 if (diff_utils::IsExtFilesystem(path)) { 49 fs_interface = Ext2Filesystem::CreateFromFile(path); 50 // TODO(deymo): The delta generator algorithm doesn't support a block size 51 // different than 4 KiB. Remove this check once that's fixed. b/26972455 52 if (fs_interface) 53 TEST_AND_RETURN_FALSE(fs_interface->GetBlockSize() == kBlockSize); 54 } 55 56 if (!fs_interface) { 57 // Fall back to a RAW filesystem. 58 TEST_AND_RETURN_FALSE(size % kBlockSize == 0); 59 fs_interface = RawFilesystem::Create( 60 "<" + name + "-partition>", 61 kBlockSize, 62 size / kBlockSize); 63 } 64 return true; 65} 66 67bool ImageConfig::ValidateIsEmpty() const { 68 TEST_AND_RETURN_FALSE(ImageInfoIsEmpty()); 69 return partitions.empty(); 70} 71 72bool ImageConfig::LoadImageSize() { 73 for (PartitionConfig& part : partitions) { 74 if (part.path.empty()) 75 continue; 76 part.size = utils::FileSize(part.path); 77 } 78 return true; 79} 80 81bool ImageConfig::LoadPostInstallConfig(const brillo::KeyValueStore& store) { 82 bool found_postinstall = false; 83 for (PartitionConfig& part : partitions) { 84 bool run_postinstall; 85 if (!store.GetBoolean("RUN_POSTINSTALL_" + part.name, &run_postinstall) || 86 !run_postinstall) 87 continue; 88 found_postinstall = true; 89 part.postinstall.run = true; 90 store.GetString("POSTINSTALL_PATH_" + part.name, &part.postinstall.path); 91 store.GetString("FILESYSTEM_TYPE_" + part.name, 92 &part.postinstall.filesystem_type); 93 } 94 if (!found_postinstall) { 95 LOG(ERROR) << "No valid postinstall config found."; 96 return false; 97 } 98 return true; 99} 100 101bool ImageConfig::ImageInfoIsEmpty() const { 102 return image_info.board().empty() 103 && image_info.key().empty() 104 && image_info.channel().empty() 105 && image_info.version().empty() 106 && image_info.build_channel().empty() 107 && image_info.build_version().empty(); 108} 109 110PayloadVersion::PayloadVersion(uint64_t major_version, uint32_t minor_version) { 111 major = major_version; 112 minor = minor_version; 113} 114 115bool PayloadVersion::Validate() const { 116 TEST_AND_RETURN_FALSE(major == kChromeOSMajorPayloadVersion || 117 major == kBrilloMajorPayloadVersion); 118 TEST_AND_RETURN_FALSE(minor == kFullPayloadMinorVersion || 119 minor == kInPlaceMinorPayloadVersion || 120 minor == kSourceMinorPayloadVersion || 121 minor == kOpSrcHashMinorPayloadVersion || 122 minor == kImgdiffMinorPayloadVersion); 123 return true; 124} 125 126bool PayloadVersion::OperationAllowed(InstallOperation_Type operation) const { 127 switch (operation) { 128 // Full operations: 129 case InstallOperation::REPLACE: 130 case InstallOperation::REPLACE_BZ: 131 // These operations were included in the original payload format. 132 return true; 133 134 case InstallOperation::ZERO: 135 case InstallOperation::DISCARD: 136 case InstallOperation::REPLACE_XZ: 137 // These operations are included in the major version used in Brillo, but 138 // can also be used with minor version 3 or newer. 139 return major == kBrilloMajorPayloadVersion || 140 minor >= kOpSrcHashMinorPayloadVersion; 141 142 // Delta operations: 143 case InstallOperation::MOVE: 144 case InstallOperation::BSDIFF: 145 // MOVE and BSDIFF were replaced by SOURCE_COPY and SOURCE_BSDIFF and 146 // should not be used in newer delta versions, since the idempotent checks 147 // were removed. 148 return minor == kInPlaceMinorPayloadVersion; 149 150 case InstallOperation::SOURCE_COPY: 151 case InstallOperation::SOURCE_BSDIFF: 152 return minor >= kSourceMinorPayloadVersion; 153 154 case InstallOperation::IMGDIFF: 155 return minor >= kImgdiffMinorPayloadVersion && imgdiff_allowed; 156 } 157 return false; 158} 159 160bool PayloadVersion::IsDelta() const { 161 return minor != kFullPayloadMinorVersion; 162} 163 164bool PayloadVersion::InplaceUpdate() const { 165 return minor == kInPlaceMinorPayloadVersion; 166} 167 168bool PayloadGenerationConfig::Validate() const { 169 TEST_AND_RETURN_FALSE(version.Validate()); 170 TEST_AND_RETURN_FALSE(version.IsDelta() == is_delta); 171 if (is_delta) { 172 for (const PartitionConfig& part : source.partitions) { 173 if (!part.path.empty()) { 174 TEST_AND_RETURN_FALSE(part.ValidateExists()); 175 TEST_AND_RETURN_FALSE(part.size % block_size == 0); 176 } 177 // Source partition should not have postinstall. 178 TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty()); 179 } 180 181 // If new_image_info is present, old_image_info must be present. 182 TEST_AND_RETURN_FALSE(source.ImageInfoIsEmpty() == 183 target.ImageInfoIsEmpty()); 184 } else { 185 // All the "source" image fields must be empty for full payloads. 186 TEST_AND_RETURN_FALSE(source.ValidateIsEmpty()); 187 } 188 189 // In all cases, the target image must exists. 190 for (const PartitionConfig& part : target.partitions) { 191 TEST_AND_RETURN_FALSE(part.ValidateExists()); 192 TEST_AND_RETURN_FALSE(part.size % block_size == 0); 193 if (version.minor == kInPlaceMinorPayloadVersion && 194 part.name == kLegacyPartitionNameRoot) 195 TEST_AND_RETURN_FALSE(rootfs_partition_size >= part.size); 196 if (version.major == kChromeOSMajorPayloadVersion) 197 TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty()); 198 } 199 200 TEST_AND_RETURN_FALSE(hard_chunk_size == -1 || 201 hard_chunk_size % block_size == 0); 202 TEST_AND_RETURN_FALSE(soft_chunk_size % block_size == 0); 203 204 TEST_AND_RETURN_FALSE(rootfs_partition_size % block_size == 0); 205 206 return true; 207} 208 209} // namespace chromeos_update_engine 210