delta_diff_generator.cc revision dcbc0ae6a5c48b40a1bc7d3c2ed62ec2a9fe7748
1// 2// Copyright (C) 2012 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/delta_diff_generator.h" 18 19#include <errno.h> 20#include <fcntl.h> 21#include <inttypes.h> 22#include <sys/stat.h> 23#include <sys/types.h> 24 25#include <algorithm> 26#include <memory> 27#include <string> 28#include <utility> 29#include <vector> 30 31#include <base/logging.h> 32 33#include "update_engine/common/utils.h" 34#include "update_engine/payload_consumer/delta_performer.h" 35#include "update_engine/payload_consumer/payload_constants.h" 36#include "update_engine/payload_generator/ab_generator.h" 37#include "update_engine/payload_generator/blob_file_writer.h" 38#include "update_engine/payload_generator/delta_diff_utils.h" 39#include "update_engine/payload_generator/full_update_generator.h" 40#include "update_engine/payload_generator/inplace_generator.h" 41#include "update_engine/payload_generator/payload_file.h" 42 43using std::string; 44using std::unique_ptr; 45using std::vector; 46 47namespace chromeos_update_engine { 48 49// bytes 50const size_t kRootFSPartitionSize = static_cast<size_t>(2) * 1024 * 1024 * 1024; 51const size_t kBlockSize = 4096; // bytes 52 53bool GenerateUpdatePayloadFile( 54 const PayloadGenerationConfig& config, 55 const string& output_path, 56 const string& private_key_path, 57 uint64_t* metadata_size) { 58 59 // Create empty payload file object. 60 PayloadFile payload; 61 TEST_AND_RETURN_FALSE(payload.Init(config)); 62 63 const string kTempFileTemplate("CrAU_temp_data.XXXXXX"); 64 string temp_file_path; 65 int data_file_fd; 66 TEST_AND_RETURN_FALSE( 67 utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &data_file_fd)); 68 ScopedPathUnlinker temp_file_unlinker(temp_file_path); 69 TEST_AND_RETURN_FALSE(data_file_fd >= 0); 70 71 { 72 off_t data_file_size = 0; 73 ScopedFdCloser data_file_fd_closer(&data_file_fd); 74 BlobFileWriter blob_file(data_file_fd, &data_file_size); 75 if (config.is_delta) { 76 TEST_AND_RETURN_FALSE(config.source.partitions.size() == 77 config.target.partitions.size()); 78 } 79 PartitionConfig empty_part(""); 80 for (size_t i = 0; i < config.target.partitions.size(); i++) { 81 const PartitionConfig& old_part = 82 config.is_delta ? config.source.partitions[i] : empty_part; 83 const PartitionConfig& new_part = config.target.partitions[i]; 84 LOG(INFO) << "Partition name: " << new_part.name; 85 LOG(INFO) << "Partition size: " << new_part.size; 86 LOG(INFO) << "Block count: " << new_part.size / config.block_size; 87 88 // Select payload generation strategy based on the config. 89 unique_ptr<OperationsGenerator> strategy; 90 // We don't efficiently support deltas on squashfs. For now, we will 91 // produce full operations in that case. 92 if (!old_part.path.empty() && 93 !diff_utils::IsSquashfs4Filesystem(new_part.path)) { 94 // Delta update. 95 if (diff_utils::IsExtFilesystem(new_part.path)) { 96 LOG_IF(WARNING, old_part.size != new_part.size) 97 << "Old and new filesystems have different size."; 98 // TODO(deymo): Our tools only support growing the filesystem size 99 // during an update. Remove this check when that's fixed. 100 // crbug.com/192136 101 LOG_IF(FATAL, old_part.size > new_part.size) 102 << "Shirking the filesystem size is not supported at the moment."; 103 } 104 if (config.minor_version == kInPlaceMinorPayloadVersion) { 105 LOG(INFO) << "Using generator InplaceGenerator()."; 106 strategy.reset(new InplaceGenerator()); 107 } else if (config.minor_version == kSourceMinorPayloadVersion || 108 config.minor_version == kOpSrcHashMinorPayloadVersion || 109 config.minor_version == kImgdiffMinorPayloadVersion) { 110 LOG(INFO) << "Using generator ABGenerator()."; 111 strategy.reset(new ABGenerator()); 112 } else { 113 LOG(ERROR) << "Unsupported minor version given for delta payload: " 114 << config.minor_version; 115 return false; 116 } 117 } else { 118 LOG(INFO) << "Using generator FullUpdateGenerator()."; 119 strategy.reset(new FullUpdateGenerator()); 120 } 121 122 vector<AnnotatedOperation> aops; 123 // Generate the operations using the strategy we selected above. 124 TEST_AND_RETURN_FALSE(strategy->GenerateOperations(config, 125 old_part, 126 new_part, 127 &blob_file, 128 &aops)); 129 130 // Filter the no-operations. OperationsGenerators should not output this 131 // kind of operations normally, but this is an extra step to fix that if 132 // happened. 133 diff_utils::FilterNoopOperations(&aops); 134 135 TEST_AND_RETURN_FALSE(payload.AddPartition(old_part, new_part, aops)); 136 } 137 } 138 139 LOG(INFO) << "Writing payload file..."; 140 // Write payload file to disk. 141 TEST_AND_RETURN_FALSE(payload.WritePayload(output_path, temp_file_path, 142 private_key_path, metadata_size)); 143 144 LOG(INFO) << "All done. Successfully created delta file with " 145 << "metadata size = " << *metadata_size; 146 return true; 147} 148 149}; // namespace chromeos_update_engine 150