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 if (!config.version.Validate()) { 59 LOG(ERROR) << "Unsupported major.minor version: " << config.version.major 60 << "." << config.version.minor; 61 return false; 62 } 63 64 // Create empty payload file object. 65 PayloadFile payload; 66 TEST_AND_RETURN_FALSE(payload.Init(config)); 67 68 const string kTempFileTemplate("CrAU_temp_data.XXXXXX"); 69 string temp_file_path; 70 int data_file_fd; 71 TEST_AND_RETURN_FALSE( 72 utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &data_file_fd)); 73 ScopedPathUnlinker temp_file_unlinker(temp_file_path); 74 TEST_AND_RETURN_FALSE(data_file_fd >= 0); 75 76 { 77 off_t data_file_size = 0; 78 ScopedFdCloser data_file_fd_closer(&data_file_fd); 79 BlobFileWriter blob_file(data_file_fd, &data_file_size); 80 if (config.is_delta) { 81 TEST_AND_RETURN_FALSE(config.source.partitions.size() == 82 config.target.partitions.size()); 83 } 84 PartitionConfig empty_part(""); 85 for (size_t i = 0; i < config.target.partitions.size(); i++) { 86 const PartitionConfig& old_part = 87 config.is_delta ? config.source.partitions[i] : empty_part; 88 const PartitionConfig& new_part = config.target.partitions[i]; 89 LOG(INFO) << "Partition name: " << new_part.name; 90 LOG(INFO) << "Partition size: " << new_part.size; 91 LOG(INFO) << "Block count: " << new_part.size / config.block_size; 92 93 // Select payload generation strategy based on the config. 94 unique_ptr<OperationsGenerator> strategy; 95 // We don't efficiently support deltas on squashfs. For now, we will 96 // produce full operations in that case. 97 if (!old_part.path.empty() && 98 !utils::IsSquashfsFilesystem(new_part.path)) { 99 // Delta update. 100 if (config.version.minor == kInPlaceMinorPayloadVersion) { 101 LOG(INFO) << "Using generator InplaceGenerator()."; 102 strategy.reset(new InplaceGenerator()); 103 } else { 104 LOG(INFO) << "Using generator ABGenerator()."; 105 strategy.reset(new ABGenerator()); 106 } 107 } else { 108 LOG(INFO) << "Using generator FullUpdateGenerator()."; 109 strategy.reset(new FullUpdateGenerator()); 110 } 111 112 vector<AnnotatedOperation> aops; 113 // Generate the operations using the strategy we selected above. 114 TEST_AND_RETURN_FALSE(strategy->GenerateOperations(config, 115 old_part, 116 new_part, 117 &blob_file, 118 &aops)); 119 120 // Filter the no-operations. OperationsGenerators should not output this 121 // kind of operations normally, but this is an extra step to fix that if 122 // happened. 123 diff_utils::FilterNoopOperations(&aops); 124 125 TEST_AND_RETURN_FALSE(payload.AddPartition(old_part, new_part, aops)); 126 } 127 } 128 129 LOG(INFO) << "Writing payload file..."; 130 // Write payload file to disk. 131 TEST_AND_RETURN_FALSE(payload.WritePayload(output_path, temp_file_path, 132 private_key_path, metadata_size)); 133 134 LOG(INFO) << "All done. Successfully created delta file with " 135 << "metadata size = " << *metadata_size; 136 return true; 137} 138 139}; // namespace chromeos_update_engine 140