delta_diff_generator.h revision f1cbe1783dd025bd7243a8df12f20548196cc023
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 minor version used by the in-place delta generator algorithm.
35extern const uint32_t kInPlaceMinorPayloadVersion;
36
37// The minor version used by the A to B delta generator algorithm.
38extern const uint32_t kSourceMinorPayloadVersion;
39
40class DeltaDiffGenerator {
41 public:
42  // Represents a disk block on the install partition.
43  struct Block {
44    // During install, each block on the install partition will be written
45    // and some may be read (in all likelihood, many will be read).
46    // The reading and writing will be performed by InstallOperations,
47    // each of which has a corresponding vertex in a graph.
48    // A Block object tells which vertex will read or write this block
49    // at install time.
50    // Generally, there will be a vector of Block objects whose length
51    // is the number of blocks on the install partition.
52    Block() : reader(Vertex::kInvalidIndex), writer(Vertex::kInvalidIndex) {}
53    Vertex::Index reader;
54    Vertex::Index writer;
55  };
56
57  // This is the only function that external users of the class should call.
58  // The |config| describes the payload generation request, describing both
59  // old and new images for delta payloads and only the new image for full
60  // payloads.
61  // For delta payloads, the images should be already mounted read-only at
62  // the respective rootfs_mountpt.
63  // |private_key_path| points to a private key used to sign the update.
64  // Pass empty string to not sign the update.
65  // |output_path| is the filename where the delta update should be written.
66  // This method computes scratch space based on |rootfs_partition_size|.
67  // Returns true on success. Also writes the size of the metadata into
68  // |metadata_size|.
69  static bool GenerateDeltaUpdateFile(const PayloadGenerationConfig& config,
70                                      const std::string& output_path,
71                                      const std::string& private_key_path,
72                                      size_t rootfs_partition_size,
73                                      uint64_t* metadata_size);
74
75  // These functions are public so that the unit tests can access them:
76
77  // For a given regular file which must exist at new_root + path, and
78  // may exist at old_root + path, creates a new InstallOperation and
79  // adds it to the graph. Also, populates the |blocks| array as
80  // necessary, if |blocks| is non-null.  Also, writes the data
81  // necessary to send the file down to the client into data_fd, which
82  // has length *data_file_size. *data_file_size is updated
83  // appropriately. If |existing_vertex| is no kInvalidIndex, use that
84  // rather than allocating a new vertex. Returns true on success.
85  static bool DeltaReadFile(Graph* graph,
86                            Vertex::Index existing_vertex,
87                            std::vector<Block>* blocks,
88                            const std::string& old_root,
89                            const std::string& new_root,
90                            const std::string& path,
91                            off_t chunk_offset,
92                            off_t chunk_size,
93                            int data_fd,
94                            off_t* data_file_size,
95                            bool src_ops_allowed);
96
97  // Reads old_filename (if it exists) and a new_filename and determines
98  // the smallest way to encode this file for the diff. It stores
99  // necessary data in out_data and fills in out_op.
100  // If there's no change in old and new files, it creates a MOVE
101  // operation. If there is a change, or the old file doesn't exist,
102  // the smallest of REPLACE, REPLACE_BZ, or BSDIFF wins.
103  // new_filename must contain at least one byte.
104  // |new_filename| is read starting at |chunk_offset|.
105  // If |chunk_size| is not -1, only up to |chunk_size| bytes are diffed.
106  // If |src_ops_allowed| is true, it will emit SOURCE_COPY and SOURCE_BSDIFF
107  // operations instead of MOVE and BSDIFF, respectively.
108  // Returns true on success.
109  static bool ReadFileToDiff(const std::string& old_filename,
110                             const std::string& new_filename,
111                             off_t chunk_offset,
112                             off_t chunk_size,
113                             bool bsdiff_allowed,
114                             chromeos::Blob* out_data,
115                             DeltaArchiveManifest_InstallOperation* out_op,
116                             bool gather_extents,
117                             bool src_ops_allowed);
118
119  // Stores all Extents in 'extents' into 'out'.
120  static void StoreExtents(const std::vector<Extent>& extents,
121                           google::protobuf::RepeatedPtrField<Extent>* out);
122
123  // Install operations in the manifest may reference data blobs, which
124  // are in data_blobs_path. This function creates a new data blobs file
125  // with the data blobs in the same order as the referencing install
126  // operations in the manifest. E.g. if manifest[0] has a data blob
127  // "X" at offset 1, manifest[1] has a data blob "Y" at offset 0,
128  // and data_blobs_path's file contains "YX", new_data_blobs_path
129  // will set to be a file that contains "XY".
130  static bool ReorderDataBlobs(DeltaArchiveManifest* manifest,
131                               const std::string& data_blobs_path,
132                               const std::string& new_data_blobs_path);
133
134  // Computes a SHA256 hash of the given buf and sets the hash value in the
135  // operation so that update_engine could verify. This hash should be set
136  // for all operations that have a non-zero data blob. One exception is the
137  // dummy operation for signature blob because the contents of the signature
138  // blob will not be available at payload creation time. So, update_engine will
139  // gracefully ignore the dummy signature operation.
140  static bool AddOperationHash(DeltaArchiveManifest_InstallOperation* op,
141                               const chromeos::Blob& buf);
142
143
144  // Returns true if |op| is a no-op operation that doesn't do any useful work
145  // (e.g., a move operation that copies blocks onto themselves).
146  static bool IsNoopOperation(const DeltaArchiveManifest_InstallOperation& op);
147
148  static bool InitializePartitionInfo(bool is_kernel,
149                                      const std::string& partition,
150                                      PartitionInfo* info);
151
152  // Runs the bsdiff tool on two files and returns the resulting delta in
153  // |out|. Returns true on success.
154  static bool BsdiffFiles(const std::string& old_file,
155                          const std::string& new_file,
156                          chromeos::Blob* out);
157
158  // Adds to |manifest| a dummy operation that points to a signature blob
159  // located at the specified offset/length.
160  static void AddSignatureOp(uint64_t signature_blob_offset,
161                             uint64_t signature_blob_length,
162                             DeltaArchiveManifest* manifest);
163
164  // Takes |graph| and returns a vertex order with the vertex indices of
165  // |graph|, in the order they appear. Returns |true| on success.
166  static std::vector<Vertex::Index> OrderIndices(const Graph& graph);
167
168  // Takes a collection (vector or RepeatedPtrField) of Extent and
169  // returns a vector of the blocks referenced, in order.
170  template<typename T>
171  static std::vector<uint64_t> ExpandExtents(const T& extents) {
172    std::vector<uint64_t> ret;
173    for (size_t i = 0, e = static_cast<size_t>(extents.size()); i != e; ++i) {
174      const Extent extent = graph_utils::GetElement(extents, i);
175      if (extent.start_block() == kSparseHole) {
176        ret.resize(ret.size() + extent.num_blocks(), kSparseHole);
177      } else {
178        for (uint64_t block = extent.start_block();
179             block < (extent.start_block() + extent.num_blocks()); block++) {
180          ret.push_back(block);
181        }
182      }
183    }
184    return ret;
185  }
186
187  static void CheckGraph(const Graph& graph);
188
189 private:
190  // This should never be constructed.
191  DISALLOW_IMPLICIT_CONSTRUCTORS(DeltaDiffGenerator);
192};
193
194};  // namespace chromeos_update_engine
195
196#endif  // UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_GENERATOR_H_
197