delta_diff_generator.h revision fdf005161523d9873a281f2a96d51dd4a3261f4f
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/payload_generator/payload_generation_config.h"
19#include "update_engine/update_metadata.pb.h"
20
21// There is one function in DeltaDiffGenerator of importance to users
22// of the class: GenerateDeltaUpdateFile(). Before calling it,
23// the old and new images must be mounted. Call GenerateDeltaUpdateFile()
24// with both the mount-points of the images in addition to the paths of
25// the images (both old and new). A delta from old to new will be
26// generated and stored in output_path.
27
28namespace chromeos_update_engine {
29
30extern const char* const kEmptyPath;
31extern const size_t kBlockSize;
32extern const size_t kRootFSPartitionSize;
33
34// The payload generation strategy prototype. This is the function that does
35// all the work to generate the operations for the rootfs and the kernel.
36// Given the |config|, generates the payload by populating the |graph| with
37// the operations required to update the rootfs when applied in the order
38// specified by |final_order|, and populating |kernel_ops| with the list of
39// kernel operations required to update the kernel.
40// The operations returned will refer to offsets in the file |data_file_fd|,
41// where this function stores the output, but not necessarily in the same
42// order as they appear in the |final_order| and |kernel_ops|.
43// This function stores the amount of data written to |data_file_fd| in
44// |data_file_size|.
45// TODO(deymo): Replace |graph|, |kernel_ops| and |final_order| by two vectors
46// of annotated InstallOperation (InstallOperation plus a name for logging
47// purposes). At this level, there's no need to have a graph.
48// TODO(deymo): Convert this type alias into a base class, so other parameter
49// can be passed to the particular generators while keeping the same interface
50// for operation generation.
51using OperationsGenerator = bool(
52      const PayloadGenerationConfig& /* config */,
53      int /* data_file_fd */,
54      off_t* /* data_file_size */,
55      Graph* /* graph */,
56      std::vector<DeltaArchiveManifest_InstallOperation>* /* kernel_ops */,
57      std::vector<Vertex::Index>* /* final_order */);
58
59
60class DeltaDiffGenerator {
61 public:
62  // Represents a disk block on the install partition.
63  struct Block {
64    // During install, each block on the install partition will be written
65    // and some may be read (in all likelihood, many will be read).
66    // The reading and writing will be performed by InstallOperations,
67    // each of which has a corresponding vertex in a graph.
68    // A Block object tells which vertex will read or write this block
69    // at install time.
70    // Generally, there will be a vector of Block objects whose length
71    // is the number of blocks on the install partition.
72    Block() : reader(Vertex::kInvalidIndex), writer(Vertex::kInvalidIndex) {}
73    Vertex::Index reader;
74    Vertex::Index writer;
75  };
76
77  // This is the only function that external users of the class should call.
78  // The |config| describes the payload generation request, describing both
79  // old and new images for delta payloads and only the new image for full
80  // payloads.
81  // For delta payloads, the images should be already mounted read-only at
82  // the respective rootfs_mountpt.
83  // |private_key_path| points to a private key used to sign the update.
84  // Pass empty string to not sign the update.
85  // |output_path| is the filename where the delta update should be written.
86  // Returns true on success. Also writes the size of the metadata into
87  // |metadata_size|.
88  static bool GenerateDeltaUpdateFile(const PayloadGenerationConfig& config,
89                                      const std::string& output_path,
90                                      const std::string& private_key_path,
91                                      uint64_t* metadata_size);
92
93  // These functions are public so that the unit tests can access them:
94
95  // Generate the update payload operations for the kernel and rootfs using
96  // SOURCE_* operations, used to generate deltas for the minor version
97  // kSourceMinorPayloadVersion. This function will generate operations in the
98  // rootfs that will read blocks from the source partition in random order and
99  // write the new image on the target partition, also possibly in random order.
100  // The rootfs operations are stored in |graph| and should be executed in the
101  // |final_order| order. The kernel operations are stored in |kernel_ops|. All
102  // the offsets in the operations reference the data written to |data_file_fd|.
103  // The total amount of data written to that file is stored in
104  // |data_file_size|.
105  static bool GenerateDeltaWithSourceOperations(
106      const PayloadGenerationConfig& config,
107      int data_file_fd,
108      off_t* data_file_size,
109      Graph* graph,
110      std::vector<DeltaArchiveManifest_InstallOperation>* kernel_ops,
111      std::vector<Vertex::Index>* final_order);
112
113  // For each regular file within new_root, creates a node in the graph,
114  // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF),
115  // and writes any necessary data to the end of data_fd.
116  static bool DeltaReadFiles(Graph* graph,
117                             std::vector<Block>* blocks,
118                             const std::string& old_root,
119                             const std::string& new_root,
120                             off_t chunk_size,
121                             int data_fd,
122                             off_t* data_file_size,
123                             bool src_ops_allowed);
124
125  // For a given regular file which must exist at new_root + path, and
126  // may exist at old_root + path, creates a new InstallOperation and
127  // adds it to the graph. Also, populates the |blocks| array as
128  // necessary, if |blocks| is non-null.  Also, writes the data
129  // necessary to send the file down to the client into data_fd, which
130  // has length *data_file_size. *data_file_size is updated
131  // appropriately. If |existing_vertex| is no kInvalidIndex, use that
132  // rather than allocating a new vertex. Returns true on success.
133  static bool DeltaReadFile(Graph* graph,
134                            Vertex::Index existing_vertex,
135                            std::vector<Block>* blocks,
136                            const std::string& old_root,
137                            const std::string& new_root,
138                            const std::string& path,
139                            off_t chunk_offset,
140                            off_t chunk_size,
141                            int data_fd,
142                            off_t* data_file_size,
143                            bool src_ops_allowed);
144
145  // Reads old_filename (if it exists) and a new_filename and determines
146  // the smallest way to encode this file for the diff. It stores
147  // necessary data in out_data and fills in out_op.
148  // If there's no change in old and new files, it creates a MOVE
149  // operation. If there is a change, or the old file doesn't exist,
150  // the smallest of REPLACE, REPLACE_BZ, or BSDIFF wins.
151  // new_filename must contain at least one byte.
152  // |new_filename| is read starting at |chunk_offset|.
153  // If |chunk_size| is not -1, only up to |chunk_size| bytes are diffed.
154  // If |src_ops_allowed| is true, it will emit SOURCE_COPY and SOURCE_BSDIFF
155  // operations instead of MOVE and BSDIFF, respectively.
156  // Returns true on success.
157  static bool ReadFileToDiff(const std::string& old_filename,
158                             const std::string& new_filename,
159                             off_t chunk_offset,
160                             off_t chunk_size,
161                             bool bsdiff_allowed,
162                             chromeos::Blob* out_data,
163                             DeltaArchiveManifest_InstallOperation* out_op,
164                             bool gather_extents,
165                             bool src_ops_allowed);
166
167  // Delta compresses a kernel partition |new_kernel_part| with knowledge of the
168  // old kernel partition |old_kernel_part|. If |old_kernel_part| is an empty
169  // string, generates a full update of the partition.
170  static bool DeltaCompressKernelPartition(
171      const std::string& old_kernel_part,
172      const std::string& new_kernel_part,
173      std::vector<DeltaArchiveManifest_InstallOperation>* ops,
174      int blobs_fd,
175      off_t* blobs_length,
176      bool src_ops_allowed);
177
178  // Reads blocks from image_path that are not yet marked as being written in
179  // the blocks array. These blocks that remain are either unchanged files or
180  // non-file-data blocks.  We compare each of them to the old image, and
181  // compress the ones that changed into a single REPLACE_BZ operation. This
182  // updates a newly created node in the graph to write these blocks and writes
183  // the appropriate blob to blobs_fd. Reads and updates blobs_length.
184  static bool ReadUnwrittenBlocks(
185      const std::vector<Block>& blocks,
186      int blobs_fd,
187      off_t* blobs_length,
188      const std::string& old_image_path,
189      const std::string& new_image_path,
190      Vertex* vertex);
191
192  // Stores all Extents in 'extents' into 'out'.
193  static void StoreExtents(const std::vector<Extent>& extents,
194                           google::protobuf::RepeatedPtrField<Extent>* out);
195
196  // Install operations in the manifest may reference data blobs, which
197  // are in data_blobs_path. This function creates a new data blobs file
198  // with the data blobs in the same order as the referencing install
199  // operations in the manifest. E.g. if manifest[0] has a data blob
200  // "X" at offset 1, manifest[1] has a data blob "Y" at offset 0,
201  // and data_blobs_path's file contains "YX", new_data_blobs_path
202  // will set to be a file that contains "XY".
203  static bool ReorderDataBlobs(DeltaArchiveManifest* manifest,
204                               const std::string& data_blobs_path,
205                               const std::string& new_data_blobs_path);
206
207  // Computes a SHA256 hash of the given buf and sets the hash value in the
208  // operation so that update_engine could verify. This hash should be set
209  // for all operations that have a non-zero data blob. One exception is the
210  // dummy operation for signature blob because the contents of the signature
211  // blob will not be available at payload creation time. So, update_engine will
212  // gracefully ignore the dummy signature operation.
213  static bool AddOperationHash(DeltaArchiveManifest_InstallOperation* op,
214                               const chromeos::Blob& buf);
215
216
217  // Returns true if |op| is a no-op operation that doesn't do any useful work
218  // (e.g., a move operation that copies blocks onto themselves).
219  static bool IsNoopOperation(const DeltaArchiveManifest_InstallOperation& op);
220
221  static bool InitializePartitionInfo(bool is_kernel,
222                                      const std::string& partition,
223                                      PartitionInfo* info);
224
225  // Runs the bsdiff tool on two files and returns the resulting delta in
226  // |out|. Returns true on success.
227  static bool BsdiffFiles(const std::string& old_file,
228                          const std::string& new_file,
229                          chromeos::Blob* out);
230
231  // Adds to |manifest| a dummy operation that points to a signature blob
232  // located at the specified offset/length.
233  static void AddSignatureOp(uint64_t signature_blob_offset,
234                             uint64_t signature_blob_length,
235                             DeltaArchiveManifest* manifest);
236
237  // Takes |graph| and returns a vertex order with the vertex indices of
238  // |graph|, in the order they appear. Returns |true| on success.
239  static std::vector<Vertex::Index> OrderIndices(const Graph& graph);
240
241  // Takes a collection (vector or RepeatedPtrField) of Extent and
242  // returns a vector of the blocks referenced, in order.
243  template<typename T>
244  static std::vector<uint64_t> ExpandExtents(const T& extents) {
245    std::vector<uint64_t> ret;
246    for (size_t i = 0, e = static_cast<size_t>(extents.size()); i != e; ++i) {
247      const Extent extent = graph_utils::GetElement(extents, i);
248      if (extent.start_block() == kSparseHole) {
249        ret.resize(ret.size() + extent.num_blocks(), kSparseHole);
250      } else {
251        for (uint64_t block = extent.start_block();
252             block < (extent.start_block() + extent.num_blocks()); block++) {
253          ret.push_back(block);
254        }
255      }
256    }
257    return ret;
258  }
259
260  static void CheckGraph(const Graph& graph);
261
262 private:
263  // This should never be constructed.
264  DISALLOW_IMPLICIT_CONSTRUCTORS(DeltaDiffGenerator);
265};
266
267};  // namespace chromeos_update_engine
268
269#endif  // UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
270