delta_diff_generator.h revision fffd23e1ed1903beeb893640c611001175380186
1// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_ 6#define UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_ 7 8#include <set> 9#include <string> 10#include <vector> 11 12#include <base/macros.h> 13#include <chromeos/secure_blob.h> 14 15#include "update_engine/payload_constants.h" 16#include "update_engine/payload_generator/graph_types.h" 17#include "update_engine/payload_generator/graph_utils.h" 18#include "update_engine/update_metadata.pb.h" 19 20// There is one function in DeltaDiffGenerator of importance to users 21// of the class: GenerateDeltaUpdateFile(). Before calling it, 22// the old and new images must be mounted. Call GenerateDeltaUpdateFile() 23// with both the mount-points of the images in addition to the paths of 24// the images (both old and new). A delta from old to new will be 25// generated and stored in output_path. 26 27namespace chromeos_update_engine { 28 29extern const char* const kEmptyPath; 30extern const size_t kBlockSize; 31extern const size_t kRootFSPartitionSize; 32 33// The minor version used by the in-place delta generator algorithm. 34extern const uint32_t kInPlaceMinorPayloadVersion; 35 36// The minor version used by the A to B delta generator algorithm. 37extern const uint32_t kSourceMinorPayloadVersion; 38 39// This struct stores all relevant info for an edge that is cut between 40// nodes old_src -> old_dst by creating new vertex new_vertex. The new 41// relationship is: 42// old_src -(read before)-> new_vertex <-(write before)- old_dst 43// new_vertex is a MOVE operation that moves some existing blocks into 44// temp space. The temp extents are, by necessity, stored in new_vertex 45// (as dst extents) and old_dst (as src extents), but they are also broken 46// out into tmp_extents, as the nodes themselves may contain many more 47// extents. 48struct CutEdgeVertexes { 49 Vertex::Index new_vertex; 50 Vertex::Index old_src; 51 Vertex::Index old_dst; 52 std::vector<Extent> tmp_extents; 53}; 54 55class DeltaDiffGenerator { 56 public: 57 // Represents a disk block on the install partition. 58 struct Block { 59 // During install, each block on the install partition will be written 60 // and some may be read (in all likelihood, many will be read). 61 // The reading and writing will be performed by InstallOperations, 62 // each of which has a corresponding vertex in a graph. 63 // A Block object tells which vertex will read or write this block 64 // at install time. 65 // Generally, there will be a vector of Block objects whose length 66 // is the number of blocks on the install partition. 67 Block() : reader(Vertex::kInvalidIndex), writer(Vertex::kInvalidIndex) {} 68 Vertex::Index reader; 69 Vertex::Index writer; 70 }; 71 72 // This is the only function that external users of the class should call. 73 // old_image and new_image are paths to two image files. They should be 74 // mounted read-only at paths old_root and new_root respectively. 75 // {old,new}_kernel_part are paths to the old and new kernel partition 76 // images, respectively. 77 // private_key_path points to a private key used to sign the update. 78 // Pass empty string to not sign the update. 79 // output_path is the filename where the delta update should be written. 80 // If |chunk_size| is not -1, the delta payload is generated based on 81 // |chunk_size| chunks rather than whole files. 82 // This method computes scratch space based on |rootfs_partition_size|. 83 // |minor_version| indicates the payload minor version for a delta update. 84 // Returns true on success. Also writes the size of the metadata into 85 // |metadata_size|. 86 static bool GenerateDeltaUpdateFile(const std::string& old_root, 87 const std::string& old_image, 88 const std::string& new_root, 89 const std::string& new_image, 90 const std::string& old_kernel_part, 91 const std::string& new_kernel_part, 92 const std::string& output_path, 93 const std::string& private_key_path, 94 off_t chunk_size, 95 size_t rootfs_partition_size, 96 uint32_t minor_version, 97 const ImageInfo* old_image_info, 98 const ImageInfo* new_image_info, 99 uint64_t* metadata_size); 100 101 // These functions are public so that the unit tests can access them: 102 103 // For a given regular file which must exist at new_root + path, and 104 // may exist at old_root + path, creates a new InstallOperation and 105 // adds it to the graph. Also, populates the |blocks| array as 106 // necessary, if |blocks| is non-null. Also, writes the data 107 // necessary to send the file down to the client into data_fd, which 108 // has length *data_file_size. *data_file_size is updated 109 // appropriately. If |existing_vertex| is no kInvalidIndex, use that 110 // rather than allocating a new vertex. Returns true on success. 111 static bool DeltaReadFile(Graph* graph, 112 Vertex::Index existing_vertex, 113 std::vector<Block>* blocks, 114 const std::string& old_root, 115 const std::string& new_root, 116 const std::string& path, 117 off_t chunk_offset, 118 off_t chunk_size, 119 int data_fd, 120 off_t* data_file_size, 121 bool src_ops_allowed); 122 123 // Reads old_filename (if it exists) and a new_filename and determines 124 // the smallest way to encode this file for the diff. It stores 125 // necessary data in out_data and fills in out_op. 126 // If there's no change in old and new files, it creates a MOVE 127 // operation. If there is a change, or the old file doesn't exist, 128 // the smallest of REPLACE, REPLACE_BZ, or BSDIFF wins. 129 // new_filename must contain at least one byte. 130 // |new_filename| is read starting at |chunk_offset|. 131 // If |chunk_size| is not -1, only up to |chunk_size| bytes are diffed. 132 // If |src_ops_allowed| is true, it will emit SOURCE_COPY and SOURCE_BSDIFF 133 // operations instead of MOVE and BSDIFF, respectively. 134 // Returns true on success. 135 static bool ReadFileToDiff(const std::string& old_filename, 136 const std::string& new_filename, 137 off_t chunk_offset, 138 off_t chunk_size, 139 bool bsdiff_allowed, 140 chromeos::Blob* out_data, 141 DeltaArchiveManifest_InstallOperation* out_op, 142 bool gather_extents, 143 bool src_ops_allowed); 144 145 // Stores all Extents in 'extents' into 'out'. 146 static void StoreExtents(const std::vector<Extent>& extents, 147 google::protobuf::RepeatedPtrField<Extent>* out); 148 149 // Install operations in the manifest may reference data blobs, which 150 // are in data_blobs_path. This function creates a new data blobs file 151 // with the data blobs in the same order as the referencing install 152 // operations in the manifest. E.g. if manifest[0] has a data blob 153 // "X" at offset 1, manifest[1] has a data blob "Y" at offset 0, 154 // and data_blobs_path's file contains "YX", new_data_blobs_path 155 // will set to be a file that contains "XY". 156 static bool ReorderDataBlobs(DeltaArchiveManifest* manifest, 157 const std::string& data_blobs_path, 158 const std::string& new_data_blobs_path); 159 160 // Computes a SHA256 hash of the given buf and sets the hash value in the 161 // operation so that update_engine could verify. This hash should be set 162 // for all operations that have a non-zero data blob. One exception is the 163 // dummy operation for signature blob because the contents of the signature 164 // blob will not be available at payload creation time. So, update_engine will 165 // gracefully ignore the dummy signature operation. 166 static bool AddOperationHash(DeltaArchiveManifest_InstallOperation* op, 167 const chromeos::Blob& buf); 168 169 170 // Returns true if |op| is a no-op operation that doesn't do any useful work 171 // (e.g., a move operation that copies blocks onto themselves). 172 static bool IsNoopOperation(const DeltaArchiveManifest_InstallOperation& op); 173 174 static bool InitializePartitionInfo(bool is_kernel, 175 const std::string& partition, 176 PartitionInfo* info); 177 178 // Runs the bsdiff tool on two files and returns the resulting delta in 179 // |out|. Returns true on success. 180 static bool BsdiffFiles(const std::string& old_file, 181 const std::string& new_file, 182 chromeos::Blob* out); 183 184 // Adds to |manifest| a dummy operation that points to a signature blob 185 // located at the specified offset/length. 186 static void AddSignatureOp(uint64_t signature_blob_offset, 187 uint64_t signature_blob_length, 188 DeltaArchiveManifest* manifest); 189 190 // Takes |graph| and returns a vertex order with the vertex indices of 191 // |graph|, in the order they appear. Returns |true| on success. 192 static std::vector<Vertex::Index> OrderIndices(const Graph& graph); 193 194 // Takes a collection (vector or RepeatedPtrField) of Extent and 195 // returns a vector of the blocks referenced, in order. 196 template<typename T> 197 static std::vector<uint64_t> ExpandExtents(const T& extents) { 198 std::vector<uint64_t> ret; 199 for (size_t i = 0, e = static_cast<size_t>(extents.size()); i != e; ++i) { 200 const Extent extent = graph_utils::GetElement(extents, i); 201 if (extent.start_block() == kSparseHole) { 202 ret.resize(ret.size() + extent.num_blocks(), kSparseHole); 203 } else { 204 for (uint64_t block = extent.start_block(); 205 block < (extent.start_block() + extent.num_blocks()); block++) { 206 ret.push_back(block); 207 } 208 } 209 } 210 return ret; 211 } 212 213 static void CheckGraph(const Graph& graph); 214 215 private: 216 // This should never be constructed. 217 DISALLOW_IMPLICIT_CONSTRUCTORS(DeltaDiffGenerator); 218}; 219 220}; // namespace chromeos_update_engine 221 222#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_ 223