delta_diff_generator.cc revision 072359ca138504065e1e0c1189eb38c09576d324
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#include "update_engine/payload_generator/delta_diff_generator.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <inttypes.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12
13#include <algorithm>
14#include <map>
15#include <set>
16#include <string>
17#include <utility>
18#include <vector>
19
20#include <base/file_util.h>
21#include <base/files/file_path.h>
22#include <base/logging.h>
23#include <base/memory/scoped_ptr.h>
24#include <base/strings/string_number_conversions.h>
25#include <base/strings/string_util.h>
26#include <base/strings/stringprintf.h>
27#include <bzlib.h>
28
29#include "update_engine/bzip.h"
30#include "update_engine/delta_performer.h"
31#include "update_engine/extent_ranges.h"
32#include "update_engine/file_writer.h"
33#include "update_engine/omaha_hash_calculator.h"
34#include "update_engine/payload_constants.h"
35#include "update_engine/payload_generator/cycle_breaker.h"
36#include "update_engine/payload_generator/extent_mapper.h"
37#include "update_engine/payload_generator/filesystem_iterator.h"
38#include "update_engine/payload_generator/full_update_generator.h"
39#include "update_engine/payload_generator/graph_types.h"
40#include "update_engine/payload_generator/graph_utils.h"
41#include "update_engine/payload_generator/metadata.h"
42#include "update_engine/payload_generator/payload_signer.h"
43#include "update_engine/payload_generator/topological_sort.h"
44#include "update_engine/payload_verifier.h"
45#include "update_engine/subprocess.h"
46#include "update_engine/update_metadata.pb.h"
47#include "update_engine/utils.h"
48
49using std::make_pair;
50using std::map;
51using std::max;
52using std::min;
53using std::pair;
54using std::set;
55using std::string;
56using std::vector;
57
58namespace {
59
60const uint64_t kVersionNumber = 1;
61const uint64_t kFullUpdateChunkSize = 1024 * 1024;  // bytes
62
63const size_t kBlockSize = 4096;  // bytes
64const char kEmptyPath[] = "";
65
66static const char* kInstallOperationTypes[] = {
67  "REPLACE",
68  "REPLACE_BZ",
69  "MOVE",
70  "BSDIFF"
71};
72
73}  // namespace
74
75namespace chromeos_update_engine {
76
77typedef DeltaDiffGenerator::Block Block;
78typedef map<const DeltaArchiveManifest_InstallOperation*,
79            string> OperationNameMap;
80
81// bytes
82const size_t kRootFSPartitionSize = static_cast<size_t>(2) * 1024 * 1024 * 1024;
83
84// Needed for testing purposes, in case we can't use actual filesystem objects.
85// TODO(garnold) (chromium:331965) Replace this hack with a properly injected
86// parameter in form of a mockable abstract class.
87bool (*get_extents_with_chunk_func)(const std::string&, off_t, off_t,
88                                    std::vector<Extent>*) =
89    extent_mapper::ExtentsForFileChunkFibmap;
90
91namespace {
92
93// Stores all the extents of |path| into |extents|. Returns true on success.
94bool GatherExtents(const string& path,
95                   off_t chunk_offset,
96                   off_t chunk_size,
97                   vector<Extent>* extents) {
98  extents->clear();
99  TEST_AND_RETURN_FALSE(
100      get_extents_with_chunk_func(
101          path, chunk_offset, chunk_size, extents));
102  return true;
103}
104
105// For a given regular file which must exist at new_root + path, and
106// may exist at old_root + path, creates a new InstallOperation and
107// adds it to the graph. Also, populates the |blocks| array as
108// necessary, if |blocks| is non-NULL.  Also, writes the data
109// necessary to send the file down to the client into data_fd, which
110// has length *data_file_size. *data_file_size is updated
111// appropriately. If |existing_vertex| is no kInvalidIndex, use that
112// rather than allocating a new vertex. Returns true on success.
113bool DeltaReadFile(Graph* graph,
114                   Vertex::Index existing_vertex,
115                   vector<Block>* blocks,
116                   const string& old_root,
117                   const string& new_root,
118                   const string& path,  // within new_root
119                   off_t chunk_offset,
120                   off_t chunk_size,
121                   int data_fd,
122                   off_t* data_file_size) {
123  vector<char> data;
124  DeltaArchiveManifest_InstallOperation operation;
125
126  string old_path = (old_root == kEmptyPath) ? kEmptyPath :
127      old_root + path;
128
129  // If bsdiff breaks again, blacklist the problem file by using:
130  //   bsdiff_allowed = (path != "/foo/bar")
131  //
132  // TODO(dgarrett): chromium-os:15274 connect this test to the command line.
133  bool bsdiff_allowed = true;
134
135  if (!bsdiff_allowed)
136    LOG(INFO) << "bsdiff blacklisting: " << path;
137
138  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::ReadFileToDiff(old_path,
139                                                           new_root + path,
140                                                           chunk_offset,
141                                                           chunk_size,
142                                                           bsdiff_allowed,
143                                                           &data,
144                                                           &operation,
145                                                           true));
146
147  // Check if the operation writes nothing.
148  if (operation.dst_extents_size() == 0) {
149    if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
150      LOG(INFO) << "Empty MOVE operation (" << new_root + path << "), skipping";
151      return true;
152    } else {
153      LOG(ERROR) << "Empty non-MOVE operation";
154      return false;
155    }
156  }
157
158  // Write the data
159  if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) {
160    operation.set_data_offset(*data_file_size);
161    operation.set_data_length(data.size());
162  }
163
164  TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size()));
165  *data_file_size += data.size();
166
167  // Now, insert into graph and blocks vector
168  Vertex::Index vertex = existing_vertex;
169  if (vertex == Vertex::kInvalidIndex) {
170    graph->resize(graph->size() + 1);
171    vertex = graph->size() - 1;
172  }
173  (*graph)[vertex].op = operation;
174  CHECK((*graph)[vertex].op.has_type());
175  (*graph)[vertex].file_name = path;
176  (*graph)[vertex].chunk_offset = chunk_offset;
177  (*graph)[vertex].chunk_size = chunk_size;
178
179  if (blocks)
180    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::AddInstallOpToBlocksVector(
181        (*graph)[vertex].op,
182        *graph,
183        vertex,
184        blocks));
185  return true;
186}
187
188// For each regular file within new_root, creates a node in the graph,
189// determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF),
190// and writes any necessary data to the end of data_fd.
191bool DeltaReadFiles(Graph* graph,
192                    vector<Block>* blocks,
193                    const string& old_root,
194                    const string& new_root,
195                    off_t chunk_size,
196                    int data_fd,
197                    off_t* data_file_size) {
198  set<ino_t> visited_inodes;
199  set<ino_t> visited_src_inodes;
200  for (FilesystemIterator fs_iter(new_root,
201                                  utils::SetWithValue<string>("/lost+found"));
202       !fs_iter.IsEnd(); fs_iter.Increment()) {
203    // We never diff symlinks (here, we check that dst file is not a symlink).
204    if (!S_ISREG(fs_iter.GetStat().st_mode))
205      continue;
206
207    // Make sure we visit each inode only once.
208    if (utils::SetContainsKey(visited_inodes, fs_iter.GetStat().st_ino))
209      continue;
210    visited_inodes.insert(fs_iter.GetStat().st_ino);
211    off_t dst_size = fs_iter.GetStat().st_size;
212    if (dst_size == 0)
213      continue;
214
215    LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath();
216
217    // We can't visit each dst image inode more than once, as that would
218    // duplicate work. Here, we avoid visiting each source image inode
219    // more than once. Technically, we could have multiple operations
220    // that read the same blocks from the source image for diffing, but
221    // we choose not to avoid complexity. Eventually we will move away
222    // from using a graph/cycle detection/etc to generate diffs, and at that
223    // time, it will be easy (non-complex) to have many operations read
224    // from the same source blocks. At that time, this code can die. -adlr
225    bool should_diff_from_source = false;
226    string src_path = old_root + fs_iter.GetPartialPath();
227    struct stat src_stbuf;
228    // We never diff symlinks (here, we check that src file is not a symlink).
229    if (0 == lstat(src_path.c_str(), &src_stbuf) &&
230        S_ISREG(src_stbuf.st_mode)) {
231      should_diff_from_source = !utils::SetContainsKey(visited_src_inodes,
232                                                       src_stbuf.st_ino);
233      visited_src_inodes.insert(src_stbuf.st_ino);
234    }
235
236    off_t size = chunk_size == -1 ? dst_size : chunk_size;
237    off_t step = size;
238    for (off_t offset = 0; offset < dst_size; offset += step) {
239      if (offset + size >= dst_size) {
240        size = -1;  // Read through the end of the file.
241      }
242      TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
243                                          Vertex::kInvalidIndex,
244                                          blocks,
245                                          (should_diff_from_source ?
246                                           old_root :
247                                           kEmptyPath),
248                                          new_root,
249                                          fs_iter.GetPartialPath(),
250                                          offset,
251                                          size,
252                                          data_fd,
253                                          data_file_size));
254    }
255  }
256  return true;
257}
258
259// This class allocates non-existent temp blocks, starting from
260// kTempBlockStart. Other code is responsible for converting these
261// temp blocks into real blocks, as the client can't read or write to
262// these blocks.
263class DummyExtentAllocator {
264 public:
265  explicit DummyExtentAllocator()
266      : next_block_(kTempBlockStart) {}
267  vector<Extent> Allocate(const uint64_t block_count) {
268    vector<Extent> ret(1);
269    ret[0].set_start_block(next_block_);
270    ret[0].set_num_blocks(block_count);
271    next_block_ += block_count;
272    return ret;
273  }
274 private:
275  uint64_t next_block_;
276};
277
278// Reads blocks from image_path that are not yet marked as being written
279// in the blocks array. These blocks that remain are non-file-data blocks.
280// In the future we might consider intelligent diffing between this data
281// and data in the previous image, but for now we just bzip2 compress it
282// and include it in the update.
283// Creates a new node in the graph to write these blocks and writes the
284// appropriate blob to blobs_fd. Reads and updates blobs_length;
285bool ReadUnwrittenBlocks(const vector<Block>& blocks,
286                         int blobs_fd,
287                         off_t* blobs_length,
288                         const string& image_path,
289                         Vertex* vertex) {
290  vertex->file_name = "<rootfs-non-file-data>";
291
292  DeltaArchiveManifest_InstallOperation* out_op = &vertex->op;
293  int image_fd = open(image_path.c_str(), O_RDONLY, 000);
294  TEST_AND_RETURN_FALSE_ERRNO(image_fd >= 0);
295  ScopedFdCloser image_fd_closer(&image_fd);
296
297  string temp_file_path;
298  TEST_AND_RETURN_FALSE(utils::MakeTempFile("CrAU_temp_data.XXXXXX",
299                                            &temp_file_path,
300                                            NULL));
301
302  FILE* file = fopen(temp_file_path.c_str(), "w");
303  TEST_AND_RETURN_FALSE(file);
304  int err = BZ_OK;
305
306  BZFILE* bz_file = BZ2_bzWriteOpen(&err,
307                                    file,
308                                    9,  // max compression
309                                    0,  // verbosity
310                                    0);  // default work factor
311  TEST_AND_RETURN_FALSE(err == BZ_OK);
312
313  vector<Extent> extents;
314  vector<Block>::size_type block_count = 0;
315
316  LOG(INFO) << "Appending left over blocks to extents";
317  for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
318    if (blocks[i].writer != Vertex::kInvalidIndex)
319      continue;
320    if (blocks[i].reader != Vertex::kInvalidIndex) {
321      graph_utils::AddReadBeforeDep(vertex, blocks[i].reader, i);
322    }
323    graph_utils::AppendBlockToExtents(&extents, i);
324    block_count++;
325  }
326
327  // Code will handle 'buf' at any size that's a multiple of kBlockSize,
328  // so we arbitrarily set it to 1024 * kBlockSize.
329  vector<char> buf(1024 * kBlockSize);
330
331  LOG(INFO) << "Reading left over blocks";
332  vector<Block>::size_type blocks_copied_count = 0;
333
334  // For each extent in extents, write the data into BZ2_bzWrite which
335  // sends it to an output file.
336  // We use the temporary buffer 'buf' to hold the data, which may be
337  // smaller than the extent, so in that case we have to loop to get
338  // the extent's data (that's the inner while loop).
339  for (vector<Extent>::const_iterator it = extents.begin();
340       it != extents.end(); ++it) {
341    vector<Block>::size_type blocks_read = 0;
342    float printed_progress = -1;
343    while (blocks_read < it->num_blocks()) {
344      const int copy_block_cnt =
345          min(buf.size() / kBlockSize,
346              static_cast<vector<char>::size_type>(
347                  it->num_blocks() - blocks_read));
348      ssize_t rc = pread(image_fd,
349                         &buf[0],
350                         copy_block_cnt * kBlockSize,
351                         (it->start_block() + blocks_read) * kBlockSize);
352      TEST_AND_RETURN_FALSE_ERRNO(rc >= 0);
353      TEST_AND_RETURN_FALSE(static_cast<size_t>(rc) ==
354                            copy_block_cnt * kBlockSize);
355      BZ2_bzWrite(&err, bz_file, &buf[0], copy_block_cnt * kBlockSize);
356      TEST_AND_RETURN_FALSE(err == BZ_OK);
357      blocks_read += copy_block_cnt;
358      blocks_copied_count += copy_block_cnt;
359      float current_progress =
360          static_cast<float>(blocks_copied_count) / block_count;
361      if (printed_progress + 0.1 < current_progress ||
362          blocks_copied_count == block_count) {
363        LOG(INFO) << "progress: " << current_progress;
364        printed_progress = current_progress;
365      }
366    }
367  }
368  BZ2_bzWriteClose(&err, bz_file, 0, NULL, NULL);
369  TEST_AND_RETURN_FALSE(err == BZ_OK);
370  bz_file = NULL;
371  TEST_AND_RETURN_FALSE_ERRNO(0 == fclose(file));
372  file = NULL;
373
374  vector<char> compressed_data;
375  LOG(INFO) << "Reading compressed data off disk";
376  TEST_AND_RETURN_FALSE(utils::ReadFile(temp_file_path, &compressed_data));
377  TEST_AND_RETURN_FALSE(unlink(temp_file_path.c_str()) == 0);
378
379  // Add node to graph to write these blocks
380  out_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
381  out_op->set_data_offset(*blobs_length);
382  out_op->set_data_length(compressed_data.size());
383  LOG(INFO) << "Rootfs non-data blocks compressed take up "
384            << compressed_data.size();
385  *blobs_length += compressed_data.size();
386  out_op->set_dst_length(kBlockSize * block_count);
387  DeltaDiffGenerator::StoreExtents(extents, out_op->mutable_dst_extents());
388
389  TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd,
390                                        &compressed_data[0],
391                                        compressed_data.size()));
392  LOG(INFO) << "done with extra blocks";
393  return true;
394}
395
396// Writes the uint64_t passed in in host-endian to the file as big-endian.
397// Returns true on success.
398bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) {
399  uint64_t value_be = htobe64(value);
400  TEST_AND_RETURN_FALSE(writer->Write(&value_be, sizeof(value_be)));
401  return true;
402}
403
404// Adds each operation from |graph| to |out_manifest| in the order specified by
405// |order| while building |out_op_name_map| with operation to name
406// mappings. Adds all |kernel_ops| to |out_manifest|. Filters out no-op
407// operations.
408void InstallOperationsToManifest(
409    const Graph& graph,
410    const vector<Vertex::Index>& order,
411    const vector<DeltaArchiveManifest_InstallOperation>& kernel_ops,
412    DeltaArchiveManifest* out_manifest,
413    OperationNameMap* out_op_name_map) {
414  for (vector<Vertex::Index>::const_iterator it = order.begin();
415       it != order.end(); ++it) {
416    const Vertex& vertex = graph[*it];
417    const DeltaArchiveManifest_InstallOperation& add_op = vertex.op;
418    if (DeltaDiffGenerator::IsNoopOperation(add_op)) {
419      continue;
420    }
421    DeltaArchiveManifest_InstallOperation* op =
422        out_manifest->add_install_operations();
423    *op = add_op;
424    string name = vertex.file_name;
425    if (vertex.chunk_offset || vertex.chunk_size != -1) {
426      string offset = base::Int64ToString(vertex.chunk_offset);
427      if (vertex.chunk_size != -1) {
428        name += " [" + offset + ", " +
429            base::Int64ToString(vertex.chunk_offset + vertex.chunk_size - 1) +
430            "]";
431      } else {
432        name += " [" + offset + ", end]";
433      }
434    }
435    (*out_op_name_map)[op] = name;
436  }
437  for (vector<DeltaArchiveManifest_InstallOperation>::const_iterator it =
438           kernel_ops.begin(); it != kernel_ops.end(); ++it) {
439    const DeltaArchiveManifest_InstallOperation& add_op = *it;
440    if (DeltaDiffGenerator::IsNoopOperation(add_op)) {
441      continue;
442    }
443    DeltaArchiveManifest_InstallOperation* op =
444        out_manifest->add_kernel_install_operations();
445    *op = add_op;
446  }
447}
448
449void CheckGraph(const Graph& graph) {
450  for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) {
451    CHECK(it->op.has_type());
452  }
453}
454
455// Delta compresses a kernel partition |new_kernel_part| with knowledge of the
456// old kernel partition |old_kernel_part|. If |old_kernel_part| is an empty
457// string, generates a full update of the partition.
458bool DeltaCompressKernelPartition(
459    const string& old_kernel_part,
460    const string& new_kernel_part,
461    vector<DeltaArchiveManifest_InstallOperation>* ops,
462    int blobs_fd,
463    off_t* blobs_length) {
464  LOG(INFO) << "Delta compressing kernel partition...";
465  LOG_IF(INFO, old_kernel_part.empty()) << "Generating full kernel update...";
466
467  DeltaArchiveManifest_InstallOperation op;
468  vector<char> data;
469  TEST_AND_RETURN_FALSE(
470      DeltaDiffGenerator::ReadFileToDiff(old_kernel_part,
471                                         new_kernel_part,
472                                         0,  // chunk_offset
473                                         -1,  // chunk_size
474                                         true,  // bsdiff_allowed
475                                         &data,
476                                         &op,
477                                         false));
478
479  // Check if the operation writes nothing.
480  if (op.dst_extents_size() == 0) {
481    if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
482      LOG(INFO) << "Empty MOVE operation, nothing to do.";
483      return true;
484    } else {
485      LOG(ERROR) << "Empty non-MOVE operation";
486      return false;
487    }
488  }
489
490  // Write the data.
491  if (op.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) {
492    op.set_data_offset(*blobs_length);
493    op.set_data_length(data.size());
494  }
495
496  // Add the new install operation.
497  ops->clear();
498  ops->push_back(op);
499
500  TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, &data[0], data.size()));
501  *blobs_length += data.size();
502
503  LOG(INFO) << "Done delta compressing kernel partition: "
504            << kInstallOperationTypes[op.type()];
505  return true;
506}
507
508struct DeltaObject {
509  DeltaObject(const string& in_name, const int in_type, const off_t in_size)
510      : name(in_name),
511        type(in_type),
512        size(in_size) {}
513  bool operator <(const DeltaObject& object) const {
514    return (size != object.size) ? (size < object.size) : (name < object.name);
515  }
516  string name;
517  int type;
518  off_t size;
519};
520
521void ReportPayloadUsage(const DeltaArchiveManifest& manifest,
522                        const int64_t manifest_metadata_size,
523                        const OperationNameMap& op_name_map) {
524  vector<DeltaObject> objects;
525  off_t total_size = 0;
526
527  // Rootfs install operations.
528  for (int i = 0; i < manifest.install_operations_size(); ++i) {
529    const DeltaArchiveManifest_InstallOperation& op =
530        manifest.install_operations(i);
531    objects.push_back(DeltaObject(op_name_map.find(&op)->second,
532                                  op.type(),
533                                  op.data_length()));
534    total_size += op.data_length();
535  }
536
537  // Kernel install operations.
538  for (int i = 0; i < manifest.kernel_install_operations_size(); ++i) {
539    const DeltaArchiveManifest_InstallOperation& op =
540        manifest.kernel_install_operations(i);
541    objects.push_back(DeltaObject(base::StringPrintf("<kernel-operation-%d>",
542                                                     i),
543                                  op.type(),
544                                  op.data_length()));
545    total_size += op.data_length();
546  }
547
548  objects.push_back(DeltaObject("<manifest-metadata>",
549                                -1,
550                                manifest_metadata_size));
551  total_size += manifest_metadata_size;
552
553  std::sort(objects.begin(), objects.end());
554
555  static const char kFormatString[] = "%6.2f%% %10jd %-10s %s\n";
556  for (vector<DeltaObject>::const_iterator it = objects.begin();
557       it != objects.end(); ++it) {
558    const DeltaObject& object = *it;
559    fprintf(stderr, kFormatString,
560            object.size * 100.0 / total_size,
561            static_cast<intmax_t>(object.size),
562            object.type >= 0 ? kInstallOperationTypes[object.type] : "-",
563            object.name.c_str());
564  }
565  fprintf(stderr, kFormatString,
566          100.0, static_cast<intmax_t>(total_size), "", "<total>");
567}
568
569// Process a range of blocks from |range_start| to |range_end| in the extent at
570// position |*idx_p| of |extents|. If |do_remove| is true, this range will be
571// removed, which may cause the extent to be trimmed, split or removed entirely.
572// The value of |*idx_p| is updated to point to the next extent to be processed.
573// Returns true iff the next extent to process is a new or updated one.
574bool ProcessExtentBlockRange(vector<Extent>* extents, size_t* idx_p,
575                             const bool do_remove, uint64_t range_start,
576                             uint64_t range_end) {
577  size_t idx = *idx_p;
578  uint64_t start_block = (*extents)[idx].start_block();
579  uint64_t num_blocks = (*extents)[idx].num_blocks();
580  uint64_t range_size = range_end - range_start;
581
582  if (do_remove) {
583    if (range_size == num_blocks) {
584      // Remove the entire extent.
585      extents->erase(extents->begin() + idx);
586    } else if (range_end == num_blocks) {
587      // Trim the end of the extent.
588      (*extents)[idx].set_num_blocks(num_blocks - range_size);
589      idx++;
590    } else if (range_start == 0) {
591      // Trim the head of the extent.
592      (*extents)[idx].set_start_block(start_block + range_size);
593      (*extents)[idx].set_num_blocks(num_blocks - range_size);
594    } else {
595      // Trim the middle, splitting the remainder into two parts.
596      (*extents)[idx].set_num_blocks(range_start);
597      Extent e;
598      e.set_start_block(start_block + range_end);
599      e.set_num_blocks(num_blocks - range_end);
600      idx++;
601      extents->insert(extents->begin() + idx, e);
602    }
603  } else if (range_end == num_blocks) {
604    // Done with this extent.
605    idx++;
606  } else {
607    return false;
608  }
609
610  *idx_p = idx;
611  return true;
612}
613
614// Remove identical corresponding block ranges in |src_extents| and
615// |dst_extents|. Used for preventing moving of blocks onto themselves during
616// MOVE operations. The value of |total_bytes| indicates the actual length of
617// content; this may be slightly less than the total size of blocks, in which
618// case the last block is only partly occupied with data. Returns the total
619// number of bytes removed.
620size_t RemoveIdenticalBlockRanges(vector<Extent>* src_extents,
621                                  vector<Extent>* dst_extents,
622                                  const size_t total_bytes) {
623  size_t src_idx = 0;
624  size_t dst_idx = 0;
625  uint64_t src_offset = 0, dst_offset = 0;
626  bool new_src = true, new_dst = true;
627  size_t removed_bytes = 0, nonfull_block_bytes;
628  bool do_remove = false;
629  while (src_idx < src_extents->size() && dst_idx < dst_extents->size()) {
630    if (new_src) {
631      src_offset = 0;
632      new_src = false;
633    }
634    if (new_dst) {
635      dst_offset = 0;
636      new_dst = false;
637    }
638
639    do_remove = ((*src_extents)[src_idx].start_block() + src_offset ==
640                 (*dst_extents)[dst_idx].start_block() + dst_offset);
641
642    uint64_t src_num_blocks = (*src_extents)[src_idx].num_blocks();
643    uint64_t dst_num_blocks = (*dst_extents)[dst_idx].num_blocks();
644    uint64_t min_num_blocks = min(src_num_blocks - src_offset,
645                                  dst_num_blocks - dst_offset);
646    uint64_t prev_src_offset = src_offset;
647    uint64_t prev_dst_offset = dst_offset;
648    src_offset += min_num_blocks;
649    dst_offset += min_num_blocks;
650
651    new_src = ProcessExtentBlockRange(src_extents, &src_idx, do_remove,
652                                      prev_src_offset, src_offset);
653    new_dst = ProcessExtentBlockRange(dst_extents, &dst_idx, do_remove,
654                                      prev_dst_offset, dst_offset);
655    if (do_remove)
656      removed_bytes += min_num_blocks * kBlockSize;
657  }
658
659  // If we removed the last block and this block is only partly used by file
660  // content, deduct the unused portion from the total removed byte count.
661  if (do_remove && (nonfull_block_bytes = total_bytes % kBlockSize))
662    removed_bytes -= kBlockSize - nonfull_block_bytes;
663
664  return removed_bytes;
665}
666
667}  // namespace
668
669bool DeltaDiffGenerator::ReadFileToDiff(
670    const string& old_filename,
671    const string& new_filename,
672    off_t chunk_offset,
673    off_t chunk_size,
674    bool bsdiff_allowed,
675    vector<char>* out_data,
676    DeltaArchiveManifest_InstallOperation* out_op,
677    bool gather_extents) {
678  // Read new data in
679  vector<char> new_data;
680  TEST_AND_RETURN_FALSE(
681      utils::ReadFileChunk(new_filename, chunk_offset, chunk_size, &new_data));
682
683  TEST_AND_RETURN_FALSE(!new_data.empty());
684  TEST_AND_RETURN_FALSE(chunk_size == -1 ||
685                        static_cast<off_t>(new_data.size()) <= chunk_size);
686
687  vector<char> new_data_bz;
688  TEST_AND_RETURN_FALSE(BzipCompress(new_data, &new_data_bz));
689  CHECK(!new_data_bz.empty());
690
691  vector<char> data;  // Data blob that will be written to delta file.
692
693  DeltaArchiveManifest_InstallOperation operation;
694  size_t current_best_size = 0;
695  if (new_data.size() <= new_data_bz.size()) {
696    operation.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
697    current_best_size = new_data.size();
698    data = new_data;
699  } else {
700    operation.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
701    current_best_size = new_data_bz.size();
702    data = new_data_bz;
703  }
704
705  // Do we have an original file to consider?
706  struct stat old_stbuf;
707  bool original = !old_filename.empty();
708  if (original && 0 != stat(old_filename.c_str(), &old_stbuf)) {
709    // If stat-ing the old file fails, it should be because it doesn't exist.
710    TEST_AND_RETURN_FALSE(errno == ENOTDIR || errno == ENOENT);
711    original = false;
712  }
713
714  vector<char> old_data;
715  if (original) {
716    // Read old data
717    TEST_AND_RETURN_FALSE(
718        utils::ReadFileChunk(
719            old_filename, chunk_offset, chunk_size, &old_data));
720    if (old_data == new_data) {
721      // No change in data.
722      operation.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
723      current_best_size = 0;
724      data.clear();
725    } else if (!old_data.empty() && bsdiff_allowed) {
726      // If the source file is considered bsdiff safe (no bsdiff bugs
727      // triggered), see if BSDIFF encoding is smaller.
728      base::FilePath old_chunk;
729      TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&old_chunk));
730      ScopedPathUnlinker old_unlinker(old_chunk.value());
731      TEST_AND_RETURN_FALSE(
732          utils::WriteFile(old_chunk.value().c_str(),
733                           &old_data[0], old_data.size()));
734      base::FilePath new_chunk;
735      TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&new_chunk));
736      ScopedPathUnlinker new_unlinker(new_chunk.value());
737      TEST_AND_RETURN_FALSE(
738          utils::WriteFile(new_chunk.value().c_str(),
739                           &new_data[0], new_data.size()));
740
741      vector<char> bsdiff_delta;
742      TEST_AND_RETURN_FALSE(
743          BsdiffFiles(old_chunk.value(), new_chunk.value(), &bsdiff_delta));
744      CHECK_GT(bsdiff_delta.size(), static_cast<vector<char>::size_type>(0));
745      if (bsdiff_delta.size() < current_best_size) {
746        operation.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
747        current_best_size = bsdiff_delta.size();
748        data = bsdiff_delta;
749      }
750    }
751  }
752
753  // Set parameters of the operations
754  CHECK_EQ(data.size(), current_best_size);
755
756  vector<Extent> src_extents, dst_extents;
757  if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE ||
758      operation.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
759    if (gather_extents) {
760      TEST_AND_RETURN_FALSE(
761          GatherExtents(old_filename,
762                        chunk_offset,
763                        chunk_size,
764                        &src_extents));
765    } else {
766      Extent* src_extent = operation.add_src_extents();
767      src_extent->set_start_block(0);
768      src_extent->set_num_blocks(
769          (old_stbuf.st_size + kBlockSize - 1) / kBlockSize);
770    }
771    operation.set_src_length(old_data.size());
772  }
773
774  if (gather_extents) {
775    TEST_AND_RETURN_FALSE(
776        GatherExtents(new_filename,
777                      chunk_offset,
778                      chunk_size,
779                      &dst_extents));
780  } else {
781    Extent* dst_extent = operation.add_dst_extents();
782    dst_extent->set_start_block(0);
783    dst_extent->set_num_blocks((new_data.size() + kBlockSize - 1) / kBlockSize);
784  }
785  operation.set_dst_length(new_data.size());
786
787  if (gather_extents) {
788    // Remove identical src/dst block ranges in MOVE operations.
789    if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
790      size_t removed_bytes = RemoveIdenticalBlockRanges(
791          &src_extents, &dst_extents, new_data.size());
792
793      // Adjust the file length field accordingly.
794      if (removed_bytes) {
795        operation.set_src_length(old_data.size() - removed_bytes);
796        operation.set_dst_length(new_data.size() - removed_bytes);
797      }
798    }
799
800    // Embed extents in the operation.
801    DeltaDiffGenerator::StoreExtents(src_extents,
802                                     operation.mutable_src_extents());
803    DeltaDiffGenerator::StoreExtents(dst_extents,
804                                     operation.mutable_dst_extents());
805  }
806
807  out_data->swap(data);
808  *out_op = operation;
809
810  return true;
811}
812
813bool DeltaDiffGenerator::InitializePartitionInfo(bool is_kernel,
814                                                 const string& partition,
815                                                 PartitionInfo* info) {
816  int64_t size = 0;
817  if (is_kernel) {
818    size = utils::FileSize(partition);
819  } else {
820    int block_count = 0, block_size = 0;
821    TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(partition,
822                                                   &block_count,
823                                                   &block_size));
824    size = static_cast<int64_t>(block_count) * block_size;
825  }
826  TEST_AND_RETURN_FALSE(size > 0);
827  info->set_size(size);
828  OmahaHashCalculator hasher;
829  TEST_AND_RETURN_FALSE(hasher.UpdateFile(partition, size) == size);
830  TEST_AND_RETURN_FALSE(hasher.Finalize());
831  const vector<char>& hash = hasher.raw_hash();
832  info->set_hash(hash.data(), hash.size());
833  LOG(INFO) << partition << ": size=" << size << " hash=" << hasher.hash();
834  return true;
835}
836
837bool InitializePartitionInfos(const string& old_kernel,
838                              const string& new_kernel,
839                              const string& old_rootfs,
840                              const string& new_rootfs,
841                              DeltaArchiveManifest* manifest) {
842  if (!old_kernel.empty()) {
843    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
844        true,
845        old_kernel,
846        manifest->mutable_old_kernel_info()));
847  }
848  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
849      true,
850      new_kernel,
851      manifest->mutable_new_kernel_info()));
852  if (!old_rootfs.empty()) {
853    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
854        false,
855        old_rootfs,
856        manifest->mutable_old_rootfs_info()));
857  }
858  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
859      false,
860      new_rootfs,
861      manifest->mutable_new_rootfs_info()));
862  return true;
863}
864
865namespace {
866
867// Takes a collection (vector or RepeatedPtrField) of Extent and
868// returns a vector of the blocks referenced, in order.
869template<typename T>
870vector<uint64_t> ExpandExtents(const T& extents) {
871  vector<uint64_t> ret;
872  for (size_t i = 0, e = static_cast<size_t>(extents.size()); i != e; ++i) {
873    const Extent extent = graph_utils::GetElement(extents, i);
874    if (extent.start_block() == kSparseHole) {
875      ret.resize(ret.size() + extent.num_blocks(), kSparseHole);
876    } else {
877      for (uint64_t block = extent.start_block();
878           block < (extent.start_block() + extent.num_blocks()); block++) {
879        ret.push_back(block);
880      }
881    }
882  }
883  return ret;
884}
885
886// Takes a vector of blocks and returns an equivalent vector of Extent
887// objects.
888vector<Extent> CompressExtents(const vector<uint64_t>& blocks) {
889  vector<Extent> new_extents;
890  for (vector<uint64_t>::const_iterator it = blocks.begin(), e = blocks.end();
891       it != e; ++it) {
892    graph_utils::AppendBlockToExtents(&new_extents, *it);
893  }
894  return new_extents;
895}
896
897}  // namespace
898
899void DeltaDiffGenerator::SubstituteBlocks(
900    Vertex* vertex,
901    const vector<Extent>& remove_extents,
902    const vector<Extent>& replace_extents) {
903  // First, expand out the blocks that op reads from
904  vector<uint64_t> read_blocks = ExpandExtents(vertex->op.src_extents());
905  {
906    // Expand remove_extents and replace_extents
907    vector<uint64_t> remove_extents_expanded =
908        ExpandExtents(remove_extents);
909    vector<uint64_t> replace_extents_expanded =
910        ExpandExtents(replace_extents);
911    CHECK_EQ(remove_extents_expanded.size(), replace_extents_expanded.size());
912    map<uint64_t, uint64_t> conversion;
913    for (vector<uint64_t>::size_type i = 0;
914         i < replace_extents_expanded.size(); i++) {
915      conversion[remove_extents_expanded[i]] = replace_extents_expanded[i];
916    }
917    utils::ApplyMap(&read_blocks, conversion);
918    for (Vertex::EdgeMap::iterator it = vertex->out_edges.begin(),
919             e = vertex->out_edges.end(); it != e; ++it) {
920      vector<uint64_t> write_before_deps_expanded =
921          ExpandExtents(it->second.write_extents);
922      utils::ApplyMap(&write_before_deps_expanded, conversion);
923      it->second.write_extents = CompressExtents(write_before_deps_expanded);
924    }
925  }
926  // Convert read_blocks back to extents
927  vertex->op.clear_src_extents();
928  vector<Extent> new_extents = CompressExtents(read_blocks);
929  DeltaDiffGenerator::StoreExtents(new_extents,
930                                   vertex->op.mutable_src_extents());
931}
932
933bool DeltaDiffGenerator::CutEdges(Graph* graph,
934                                  const set<Edge>& edges,
935                                  vector<CutEdgeVertexes>* out_cuts) {
936  DummyExtentAllocator scratch_allocator;
937  vector<CutEdgeVertexes> cuts;
938  cuts.reserve(edges.size());
939
940  uint64_t scratch_blocks_used = 0;
941  for (set<Edge>::const_iterator it = edges.begin();
942       it != edges.end(); ++it) {
943    cuts.resize(cuts.size() + 1);
944    vector<Extent> old_extents =
945        (*graph)[it->first].out_edges[it->second].extents;
946    // Choose some scratch space
947    scratch_blocks_used += graph_utils::EdgeWeight(*graph, *it);
948    cuts.back().tmp_extents =
949        scratch_allocator.Allocate(graph_utils::EdgeWeight(*graph, *it));
950    // create vertex to copy original->scratch
951    cuts.back().new_vertex = graph->size();
952    graph->resize(graph->size() + 1);
953    cuts.back().old_src = it->first;
954    cuts.back().old_dst = it->second;
955
956    EdgeProperties& cut_edge_properties =
957        (*graph)[it->first].out_edges.find(it->second)->second;
958
959    // This should never happen, as we should only be cutting edges between
960    // real file nodes, and write-before relationships are created from
961    // a real file node to a temp copy node:
962    CHECK(cut_edge_properties.write_extents.empty())
963        << "Can't cut edge that has write-before relationship.";
964
965    // make node depend on the copy operation
966    (*graph)[it->first].out_edges.insert(make_pair(graph->size() - 1,
967                                                   cut_edge_properties));
968
969    // Set src/dst extents and other proto variables for copy operation
970    graph->back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
971    DeltaDiffGenerator::StoreExtents(
972        cut_edge_properties.extents,
973        graph->back().op.mutable_src_extents());
974    DeltaDiffGenerator::StoreExtents(cuts.back().tmp_extents,
975                                     graph->back().op.mutable_dst_extents());
976    graph->back().op.set_src_length(
977        graph_utils::EdgeWeight(*graph, *it) * kBlockSize);
978    graph->back().op.set_dst_length(graph->back().op.src_length());
979
980    // make the dest node read from the scratch space
981    DeltaDiffGenerator::SubstituteBlocks(
982        &((*graph)[it->second]),
983        (*graph)[it->first].out_edges[it->second].extents,
984        cuts.back().tmp_extents);
985
986    // delete the old edge
987    CHECK_EQ(static_cast<Graph::size_type>(1),
988             (*graph)[it->first].out_edges.erase(it->second));
989
990    // Add an edge from dst to copy operation
991    EdgeProperties write_before_edge_properties;
992    write_before_edge_properties.write_extents = cuts.back().tmp_extents;
993    (*graph)[it->second].out_edges.insert(
994        make_pair(graph->size() - 1, write_before_edge_properties));
995  }
996  out_cuts->swap(cuts);
997  return true;
998}
999
1000// Stores all Extents in 'extents' into 'out'.
1001void DeltaDiffGenerator::StoreExtents(
1002    const vector<Extent>& extents,
1003    google::protobuf::RepeatedPtrField<Extent>* out) {
1004  for (vector<Extent>::const_iterator it = extents.begin();
1005       it != extents.end(); ++it) {
1006    Extent* new_extent = out->Add();
1007    *new_extent = *it;
1008  }
1009}
1010
1011// Creates all the edges for the graph. Writers of a block point to
1012// readers of the same block. This is because for an edge A->B, B
1013// must complete before A executes.
1014void DeltaDiffGenerator::CreateEdges(Graph* graph,
1015                                     const vector<Block>& blocks) {
1016  for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
1017    // Blocks with both a reader and writer get an edge
1018    if (blocks[i].reader == Vertex::kInvalidIndex ||
1019        blocks[i].writer == Vertex::kInvalidIndex)
1020      continue;
1021    // Don't have a node depend on itself
1022    if (blocks[i].reader == blocks[i].writer)
1023      continue;
1024    // See if there's already an edge we can add onto
1025    Vertex::EdgeMap::iterator edge_it =
1026        (*graph)[blocks[i].writer].out_edges.find(blocks[i].reader);
1027    if (edge_it == (*graph)[blocks[i].writer].out_edges.end()) {
1028      // No existing edge. Create one
1029      (*graph)[blocks[i].writer].out_edges.insert(
1030          make_pair(blocks[i].reader, EdgeProperties()));
1031      edge_it = (*graph)[blocks[i].writer].out_edges.find(blocks[i].reader);
1032      CHECK(edge_it != (*graph)[blocks[i].writer].out_edges.end());
1033    }
1034    graph_utils::AppendBlockToExtents(&edge_it->second.extents, i);
1035  }
1036}
1037
1038namespace {
1039
1040class SortCutsByTopoOrderLess {
1041 public:
1042  explicit SortCutsByTopoOrderLess(
1043      const vector<vector<Vertex::Index>::size_type>& table)
1044      : table_(table) {}
1045  bool operator()(const CutEdgeVertexes& a, const CutEdgeVertexes& b) {
1046    return table_[a.old_dst] < table_[b.old_dst];
1047  }
1048 private:
1049  const vector<vector<Vertex::Index>::size_type>& table_;
1050};
1051
1052}  // namespace
1053
1054void DeltaDiffGenerator::GenerateReverseTopoOrderMap(
1055    const vector<Vertex::Index>& op_indexes,
1056    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes) {
1057  vector<vector<Vertex::Index>::size_type> table(op_indexes.size());
1058  for (vector<Vertex::Index>::size_type i = 0, e = op_indexes.size();
1059       i != e; ++i) {
1060    Vertex::Index node = op_indexes[i];
1061    if (table.size() < (node + 1)) {
1062      table.resize(node + 1);
1063    }
1064    table[node] = i;
1065  }
1066  reverse_op_indexes->swap(table);
1067}
1068
1069void DeltaDiffGenerator::SortCutsByTopoOrder(
1070    const vector<Vertex::Index>& op_indexes,
1071    vector<CutEdgeVertexes>* cuts) {
1072  // first, make a reverse lookup table.
1073  vector<vector<Vertex::Index>::size_type> table;
1074  GenerateReverseTopoOrderMap(op_indexes, &table);
1075  SortCutsByTopoOrderLess less(table);
1076  sort(cuts->begin(), cuts->end(), less);
1077}
1078
1079void DeltaDiffGenerator::MoveFullOpsToBack(Graph* graph,
1080                                           vector<Vertex::Index>* op_indexes) {
1081  vector<Vertex::Index> ret;
1082  vector<Vertex::Index> full_ops;
1083  ret.reserve(op_indexes->size());
1084  for (vector<Vertex::Index>::size_type i = 0, e = op_indexes->size(); i != e;
1085       ++i) {
1086    DeltaArchiveManifest_InstallOperation_Type type =
1087        (*graph)[(*op_indexes)[i]].op.type();
1088    if (type == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
1089        type == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
1090      full_ops.push_back((*op_indexes)[i]);
1091    } else {
1092      ret.push_back((*op_indexes)[i]);
1093    }
1094  }
1095  LOG(INFO) << "Stats: " << full_ops.size() << " full ops out of "
1096            << (full_ops.size() + ret.size()) << " total ops.";
1097  ret.insert(ret.end(), full_ops.begin(), full_ops.end());
1098  op_indexes->swap(ret);
1099}
1100
1101namespace {
1102
1103template<typename T>
1104bool TempBlocksExistInExtents(const T& extents) {
1105  for (int i = 0, e = extents.size(); i < e; ++i) {
1106    Extent extent = graph_utils::GetElement(extents, i);
1107    uint64_t start = extent.start_block();
1108    uint64_t num = extent.num_blocks();
1109    if (start == kSparseHole)
1110      continue;
1111    if (start >= kTempBlockStart ||
1112        (start + num) >= kTempBlockStart) {
1113      LOG(ERROR) << "temp block!";
1114      LOG(ERROR) << "start: " << start << ", num: " << num;
1115      LOG(ERROR) << "kTempBlockStart: " << kTempBlockStart;
1116      LOG(ERROR) << "returning true";
1117      return true;
1118    }
1119    // check for wrap-around, which would be a bug:
1120    CHECK(start <= (start + num));
1121  }
1122  return false;
1123}
1124
1125// Converts the cuts, which must all have the same |old_dst| member,
1126// to full. It does this by converting the |old_dst| to REPLACE or
1127// REPLACE_BZ, dropping all incoming edges to |old_dst|, and marking
1128// all temp nodes invalid.
1129bool ConvertCutsToFull(
1130    Graph* graph,
1131    const string& new_root,
1132    int data_fd,
1133    off_t* data_file_size,
1134    vector<Vertex::Index>* op_indexes,
1135    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
1136    const vector<CutEdgeVertexes>& cuts) {
1137  CHECK(!cuts.empty());
1138  set<Vertex::Index> deleted_nodes;
1139  for (vector<CutEdgeVertexes>::const_iterator it = cuts.begin(),
1140           e = cuts.end(); it != e; ++it) {
1141    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::ConvertCutToFullOp(
1142        graph,
1143        *it,
1144        new_root,
1145        data_fd,
1146        data_file_size));
1147    deleted_nodes.insert(it->new_vertex);
1148  }
1149  deleted_nodes.insert(cuts[0].old_dst);
1150
1151  vector<Vertex::Index> new_op_indexes;
1152  new_op_indexes.reserve(op_indexes->size());
1153  for (vector<Vertex::Index>::iterator it = op_indexes->begin(),
1154           e = op_indexes->end(); it != e; ++it) {
1155    if (utils::SetContainsKey(deleted_nodes, *it))
1156      continue;
1157    new_op_indexes.push_back(*it);
1158  }
1159  new_op_indexes.push_back(cuts[0].old_dst);
1160  op_indexes->swap(new_op_indexes);
1161  DeltaDiffGenerator::GenerateReverseTopoOrderMap(*op_indexes,
1162                                                  reverse_op_indexes);
1163  return true;
1164}
1165
1166// Tries to assign temp blocks for a collection of cuts, all of which share
1167// the same old_dst member. If temp blocks can't be found, old_dst will be
1168// converted to a REPLACE or REPLACE_BZ operation. Returns true on success,
1169// which can happen even if blocks are converted to full. Returns false
1170// on exceptional error cases.
1171bool AssignBlockForAdjoiningCuts(
1172    Graph* graph,
1173    const string& new_root,
1174    int data_fd,
1175    off_t* data_file_size,
1176    vector<Vertex::Index>* op_indexes,
1177    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
1178    const vector<CutEdgeVertexes>& cuts) {
1179  CHECK(!cuts.empty());
1180  const Vertex::Index old_dst = cuts[0].old_dst;
1181  // Calculate # of blocks needed
1182  uint64_t blocks_needed = 0;
1183  map<const CutEdgeVertexes*, uint64_t> cuts_blocks_needed;
1184  for (vector<CutEdgeVertexes>::const_iterator it = cuts.begin(),
1185           e = cuts.end(); it != e; ++it) {
1186    uint64_t cut_blocks_needed = 0;
1187    for (vector<Extent>::const_iterator jt = it->tmp_extents.begin(),
1188             je = it->tmp_extents.end(); jt != je; ++jt) {
1189      cut_blocks_needed += jt->num_blocks();
1190    }
1191    blocks_needed += cut_blocks_needed;
1192    cuts_blocks_needed[&*it] = cut_blocks_needed;
1193  }
1194
1195  // Find enough blocks
1196  ExtentRanges scratch_ranges;
1197  // Each block that's supplying temp blocks and the corresponding blocks:
1198  typedef vector<pair<Vertex::Index, ExtentRanges> > SupplierVector;
1199  SupplierVector block_suppliers;
1200  uint64_t scratch_blocks_found = 0;
1201  for (vector<Vertex::Index>::size_type i = (*reverse_op_indexes)[old_dst] + 1,
1202           e = op_indexes->size(); i < e; ++i) {
1203    Vertex::Index test_node = (*op_indexes)[i];
1204    if (!(*graph)[test_node].valid)
1205      continue;
1206    // See if this node has sufficient blocks
1207    ExtentRanges ranges;
1208    ranges.AddRepeatedExtents((*graph)[test_node].op.dst_extents());
1209    ranges.SubtractExtent(ExtentForRange(
1210        kTempBlockStart, kSparseHole - kTempBlockStart));
1211    ranges.SubtractRepeatedExtents((*graph)[test_node].op.src_extents());
1212    // For now, for simplicity, subtract out all blocks in read-before
1213    // dependencies.
1214    for (Vertex::EdgeMap::const_iterator edge_i =
1215             (*graph)[test_node].out_edges.begin(),
1216             edge_e = (*graph)[test_node].out_edges.end();
1217         edge_i != edge_e; ++edge_i) {
1218      ranges.SubtractExtents(edge_i->second.extents);
1219    }
1220    if (ranges.blocks() == 0)
1221      continue;
1222
1223    if (ranges.blocks() + scratch_blocks_found > blocks_needed) {
1224      // trim down ranges
1225      vector<Extent> new_ranges = ranges.GetExtentsForBlockCount(
1226          blocks_needed - scratch_blocks_found);
1227      ranges = ExtentRanges();
1228      ranges.AddExtents(new_ranges);
1229    }
1230    scratch_ranges.AddRanges(ranges);
1231    block_suppliers.push_back(make_pair(test_node, ranges));
1232    scratch_blocks_found += ranges.blocks();
1233    if (scratch_ranges.blocks() >= blocks_needed)
1234      break;
1235  }
1236  if (scratch_ranges.blocks() < blocks_needed) {
1237    LOG(INFO) << "Unable to find sufficient scratch";
1238    TEST_AND_RETURN_FALSE(ConvertCutsToFull(graph,
1239                                            new_root,
1240                                            data_fd,
1241                                            data_file_size,
1242                                            op_indexes,
1243                                            reverse_op_indexes,
1244                                            cuts));
1245    return true;
1246  }
1247  // Use the scratch we found
1248  TEST_AND_RETURN_FALSE(scratch_ranges.blocks() == scratch_blocks_found);
1249
1250  // Make all the suppliers depend on this node
1251  for (SupplierVector::iterator it = block_suppliers.begin(),
1252           e = block_suppliers.end(); it != e; ++it) {
1253    graph_utils::AddReadBeforeDepExtents(
1254        &(*graph)[it->first],
1255        old_dst,
1256        it->second.GetExtentsForBlockCount(it->second.blocks()));
1257  }
1258
1259  // Replace temp blocks in each cut
1260  for (vector<CutEdgeVertexes>::const_iterator it = cuts.begin(),
1261           e = cuts.end(); it != e; ++it) {
1262    vector<Extent> real_extents =
1263        scratch_ranges.GetExtentsForBlockCount(cuts_blocks_needed[&*it]);
1264    scratch_ranges.SubtractExtents(real_extents);
1265
1266    // Fix the old dest node w/ the real blocks
1267    DeltaDiffGenerator::SubstituteBlocks(&(*graph)[old_dst],
1268                                         it->tmp_extents,
1269                                         real_extents);
1270
1271    // Fix the new node w/ the real blocks. Since the new node is just a
1272    // copy operation, we can replace all the dest extents w/ the real
1273    // blocks.
1274    DeltaArchiveManifest_InstallOperation *op =
1275        &(*graph)[it->new_vertex].op;
1276    op->clear_dst_extents();
1277    DeltaDiffGenerator::StoreExtents(real_extents, op->mutable_dst_extents());
1278  }
1279  return true;
1280}
1281
1282}  // namespace
1283
1284// Returns true if |op| is a no-op operation that doesn't do any useful work
1285// (e.g., a move operation that copies blocks onto themselves).
1286bool DeltaDiffGenerator::IsNoopOperation(
1287    const DeltaArchiveManifest_InstallOperation& op) {
1288  return (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE &&
1289          ExpandExtents(op.src_extents()) == ExpandExtents(op.dst_extents()));
1290}
1291
1292bool DeltaDiffGenerator::AssignTempBlocks(
1293    Graph* graph,
1294    const string& new_root,
1295    int data_fd,
1296    off_t* data_file_size,
1297    vector<Vertex::Index>* op_indexes,
1298    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
1299    const vector<CutEdgeVertexes>& cuts) {
1300  CHECK(!cuts.empty());
1301
1302  // group of cuts w/ the same old_dst:
1303  vector<CutEdgeVertexes> cuts_group;
1304
1305  for (vector<CutEdgeVertexes>::size_type i = cuts.size() - 1, e = 0;
1306       true ; --i) {
1307    LOG(INFO) << "Fixing temp blocks in cut " << i
1308              << ": old dst: " << cuts[i].old_dst << " new vertex: "
1309              << cuts[i].new_vertex << " path: "
1310              << (*graph)[cuts[i].old_dst].file_name;
1311
1312    if (cuts_group.empty() || (cuts_group[0].old_dst == cuts[i].old_dst)) {
1313      cuts_group.push_back(cuts[i]);
1314    } else {
1315      CHECK(!cuts_group.empty());
1316      TEST_AND_RETURN_FALSE(AssignBlockForAdjoiningCuts(graph,
1317                                                        new_root,
1318                                                        data_fd,
1319                                                        data_file_size,
1320                                                        op_indexes,
1321                                                        reverse_op_indexes,
1322                                                        cuts_group));
1323      cuts_group.clear();
1324      cuts_group.push_back(cuts[i]);
1325    }
1326
1327    if (i == e) {
1328      // break out of for() loop
1329      break;
1330    }
1331  }
1332  CHECK(!cuts_group.empty());
1333  TEST_AND_RETURN_FALSE(AssignBlockForAdjoiningCuts(graph,
1334                                                    new_root,
1335                                                    data_fd,
1336                                                    data_file_size,
1337                                                    op_indexes,
1338                                                    reverse_op_indexes,
1339                                                    cuts_group));
1340  return true;
1341}
1342
1343bool DeltaDiffGenerator::NoTempBlocksRemain(const Graph& graph) {
1344  size_t idx = 0;
1345  for (Graph::const_iterator it = graph.begin(), e = graph.end(); it != e;
1346       ++it, ++idx) {
1347    if (!it->valid)
1348      continue;
1349    const DeltaArchiveManifest_InstallOperation& op = it->op;
1350    if (TempBlocksExistInExtents(op.dst_extents()) ||
1351        TempBlocksExistInExtents(op.src_extents())) {
1352      LOG(INFO) << "bad extents in node " << idx;
1353      LOG(INFO) << "so yeah";
1354      return false;
1355    }
1356
1357    // Check out-edges:
1358    for (Vertex::EdgeMap::const_iterator jt = it->out_edges.begin(),
1359             je = it->out_edges.end(); jt != je; ++jt) {
1360      if (TempBlocksExistInExtents(jt->second.extents) ||
1361          TempBlocksExistInExtents(jt->second.write_extents)) {
1362        LOG(INFO) << "bad out edge in node " << idx;
1363        LOG(INFO) << "so yeah";
1364        return false;
1365      }
1366    }
1367  }
1368  return true;
1369}
1370
1371bool DeltaDiffGenerator::ReorderDataBlobs(
1372    DeltaArchiveManifest* manifest,
1373    const std::string& data_blobs_path,
1374    const std::string& new_data_blobs_path) {
1375  int in_fd = open(data_blobs_path.c_str(), O_RDONLY, 0);
1376  TEST_AND_RETURN_FALSE_ERRNO(in_fd >= 0);
1377  ScopedFdCloser in_fd_closer(&in_fd);
1378
1379  DirectFileWriter writer;
1380  TEST_AND_RETURN_FALSE(
1381      writer.Open(new_data_blobs_path.c_str(),
1382                  O_WRONLY | O_TRUNC | O_CREAT,
1383                  0644) == 0);
1384  ScopedFileWriterCloser writer_closer(&writer);
1385  uint64_t out_file_size = 0;
1386
1387  for (int i = 0; i < (manifest->install_operations_size() +
1388                       manifest->kernel_install_operations_size()); i++) {
1389    DeltaArchiveManifest_InstallOperation* op = NULL;
1390    if (i < manifest->install_operations_size()) {
1391      op = manifest->mutable_install_operations(i);
1392    } else {
1393      op = manifest->mutable_kernel_install_operations(
1394          i - manifest->install_operations_size());
1395    }
1396    if (!op->has_data_offset())
1397      continue;
1398    CHECK(op->has_data_length());
1399    vector<char> buf(op->data_length());
1400    ssize_t rc = pread(in_fd, &buf[0], buf.size(), op->data_offset());
1401    TEST_AND_RETURN_FALSE(rc == static_cast<ssize_t>(buf.size()));
1402
1403    // Add the hash of the data blobs for this operation
1404    TEST_AND_RETURN_FALSE(AddOperationHash(op, buf));
1405
1406    op->set_data_offset(out_file_size);
1407    TEST_AND_RETURN_FALSE(writer.Write(&buf[0], buf.size()));
1408    out_file_size += buf.size();
1409  }
1410  return true;
1411}
1412
1413bool DeltaDiffGenerator::AddOperationHash(
1414    DeltaArchiveManifest_InstallOperation* op,
1415    const vector<char>& buf) {
1416  OmahaHashCalculator hasher;
1417
1418  TEST_AND_RETURN_FALSE(hasher.Update(&buf[0], buf.size()));
1419  TEST_AND_RETURN_FALSE(hasher.Finalize());
1420
1421  const vector<char>& hash = hasher.raw_hash();
1422  op->set_data_sha256_hash(hash.data(), hash.size());
1423  return true;
1424}
1425
1426bool DeltaDiffGenerator::ConvertCutToFullOp(Graph* graph,
1427                                            const CutEdgeVertexes& cut,
1428                                            const string& new_root,
1429                                            int data_fd,
1430                                            off_t* data_file_size) {
1431  // Drop all incoming edges, keep all outgoing edges
1432
1433  // Keep all outgoing edges
1434  if ((*graph)[cut.old_dst].op.type() !=
1435      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ &&
1436      (*graph)[cut.old_dst].op.type() !=
1437      DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
1438    Vertex::EdgeMap out_edges = (*graph)[cut.old_dst].out_edges;
1439    graph_utils::DropWriteBeforeDeps(&out_edges);
1440
1441    TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
1442                                        cut.old_dst,
1443                                        NULL,
1444                                        kEmptyPath,
1445                                        new_root,
1446                                        (*graph)[cut.old_dst].file_name,
1447                                        (*graph)[cut.old_dst].chunk_offset,
1448                                        (*graph)[cut.old_dst].chunk_size,
1449                                        data_fd,
1450                                        data_file_size));
1451
1452    (*graph)[cut.old_dst].out_edges = out_edges;
1453
1454    // Right now we don't have doubly-linked edges, so we have to scan
1455    // the whole graph.
1456    graph_utils::DropIncomingEdgesTo(graph, cut.old_dst);
1457  }
1458
1459  // Delete temp node
1460  (*graph)[cut.old_src].out_edges.erase(cut.new_vertex);
1461  CHECK((*graph)[cut.old_dst].out_edges.find(cut.new_vertex) ==
1462        (*graph)[cut.old_dst].out_edges.end());
1463  (*graph)[cut.new_vertex].valid = false;
1464  LOG(INFO) << "marked node invalid: " << cut.new_vertex;
1465  return true;
1466}
1467
1468bool DeltaDiffGenerator::ConvertGraphToDag(Graph* graph,
1469                                           const string& new_root,
1470                                           int fd,
1471                                           off_t* data_file_size,
1472                                           vector<Vertex::Index>* final_order,
1473                                           Vertex::Index scratch_vertex) {
1474  CycleBreaker cycle_breaker;
1475  LOG(INFO) << "Finding cycles...";
1476  set<Edge> cut_edges;
1477  cycle_breaker.BreakCycles(*graph, &cut_edges);
1478  LOG(INFO) << "done finding cycles";
1479  CheckGraph(*graph);
1480
1481  // Calculate number of scratch blocks needed
1482
1483  LOG(INFO) << "Cutting cycles...";
1484  vector<CutEdgeVertexes> cuts;
1485  TEST_AND_RETURN_FALSE(CutEdges(graph, cut_edges, &cuts));
1486  LOG(INFO) << "done cutting cycles";
1487  LOG(INFO) << "There are " << cuts.size() << " cuts.";
1488  CheckGraph(*graph);
1489
1490  LOG(INFO) << "Creating initial topological order...";
1491  TopologicalSort(*graph, final_order);
1492  LOG(INFO) << "done with initial topo order";
1493  CheckGraph(*graph);
1494
1495  LOG(INFO) << "Moving full ops to the back";
1496  MoveFullOpsToBack(graph, final_order);
1497  LOG(INFO) << "done moving full ops to back";
1498
1499  vector<vector<Vertex::Index>::size_type> inverse_final_order;
1500  GenerateReverseTopoOrderMap(*final_order, &inverse_final_order);
1501
1502  SortCutsByTopoOrder(*final_order, &cuts);
1503
1504  if (!cuts.empty())
1505    TEST_AND_RETURN_FALSE(AssignTempBlocks(graph,
1506                                           new_root,
1507                                           fd,
1508                                           data_file_size,
1509                                           final_order,
1510                                           &inverse_final_order,
1511                                           cuts));
1512  LOG(INFO) << "Making sure all temp blocks have been allocated";
1513
1514  // Remove the scratch node, if any
1515  if (scratch_vertex != Vertex::kInvalidIndex) {
1516    final_order->erase(final_order->begin() +
1517                       inverse_final_order[scratch_vertex]);
1518    (*graph)[scratch_vertex].valid = false;
1519    GenerateReverseTopoOrderMap(*final_order, &inverse_final_order);
1520  }
1521
1522  graph_utils::DumpGraph(*graph);
1523  CHECK(NoTempBlocksRemain(*graph));
1524  LOG(INFO) << "done making sure all temp blocks are allocated";
1525  return true;
1526}
1527
1528void DeltaDiffGenerator::CreateScratchNode(uint64_t start_block,
1529                                           uint64_t num_blocks,
1530                                           Vertex* vertex) {
1531  vertex->file_name = "<scratch>";
1532  vertex->op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
1533  vertex->op.set_data_offset(0);
1534  vertex->op.set_data_length(0);
1535  Extent* extent = vertex->op.add_dst_extents();
1536  extent->set_start_block(start_block);
1537  extent->set_num_blocks(num_blocks);
1538}
1539
1540bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
1541    const string& old_root,
1542    const string& old_image,
1543    const string& new_root,
1544    const string& new_image,
1545    const string& old_kernel_part,
1546    const string& new_kernel_part,
1547    const string& output_path,
1548    const string& private_key_path,
1549    off_t chunk_size,
1550    size_t rootfs_partition_size,
1551    const ImageInfo* old_image_info,
1552    const ImageInfo* new_image_info,
1553    uint64_t* metadata_size) {
1554  TEST_AND_RETURN_FALSE(chunk_size == -1 || chunk_size % kBlockSize == 0);
1555  int old_image_block_count = 0, old_image_block_size = 0;
1556  int new_image_block_count = 0, new_image_block_size = 0;
1557  TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(new_image,
1558                                                 &new_image_block_count,
1559                                                 &new_image_block_size));
1560  if (!old_image.empty()) {
1561    TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(old_image,
1562                                                   &old_image_block_count,
1563                                                   &old_image_block_size));
1564    TEST_AND_RETURN_FALSE(old_image_block_size == new_image_block_size);
1565    LOG_IF(WARNING, old_image_block_count != new_image_block_count)
1566        << "Old and new images have different block counts.";
1567
1568    // If new_image_info is present, old_image_info must be present.
1569    TEST_AND_RETURN_FALSE(!old_image_info == !new_image_info);
1570  } else {
1571    // old_image_info must not be present for a full update.
1572    TEST_AND_RETURN_FALSE(!old_image_info);
1573  }
1574
1575  // Sanity checks for the partition size.
1576  TEST_AND_RETURN_FALSE(rootfs_partition_size % kBlockSize == 0);
1577  size_t fs_size = static_cast<size_t>(new_image_block_size) *
1578                   new_image_block_count;
1579  LOG(INFO) << "Rootfs partition size: " << rootfs_partition_size;
1580  LOG(INFO) << "Actual filesystem size: " << fs_size;
1581  TEST_AND_RETURN_FALSE(rootfs_partition_size >= fs_size);
1582
1583  // Sanity check kernel partition arg
1584  TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0);
1585
1586  vector<Block> blocks(max(old_image_block_count, new_image_block_count));
1587  LOG(INFO) << "Invalid block index: " << Vertex::kInvalidIndex;
1588  LOG(INFO) << "Block count: " << blocks.size();
1589  for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
1590    CHECK(blocks[i].reader == Vertex::kInvalidIndex);
1591    CHECK(blocks[i].writer == Vertex::kInvalidIndex);
1592  }
1593  Graph graph;
1594  CheckGraph(graph);
1595
1596  const string kTempFileTemplate("CrAU_temp_data.XXXXXX");
1597  string temp_file_path;
1598  scoped_ptr<ScopedPathUnlinker> temp_file_unlinker;
1599  off_t data_file_size = 0;
1600
1601  LOG(INFO) << "Reading files...";
1602
1603  // Create empty protobuf Manifest object
1604  DeltaArchiveManifest manifest;
1605
1606  vector<DeltaArchiveManifest_InstallOperation> kernel_ops;
1607
1608  vector<Vertex::Index> final_order;
1609  Vertex::Index scratch_vertex = Vertex::kInvalidIndex;
1610  {
1611    int fd;
1612    TEST_AND_RETURN_FALSE(
1613        utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd));
1614    temp_file_unlinker.reset(new ScopedPathUnlinker(temp_file_path));
1615    TEST_AND_RETURN_FALSE(fd >= 0);
1616    ScopedFdCloser fd_closer(&fd);
1617    if (!old_image.empty()) {
1618      // Delta update
1619
1620      TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph,
1621                                           &blocks,
1622                                           old_root,
1623                                           new_root,
1624                                           chunk_size,
1625                                           fd,
1626                                           &data_file_size));
1627      LOG(INFO) << "done reading normal files";
1628      CheckGraph(graph);
1629
1630      LOG(INFO) << "Starting metadata processing";
1631      TEST_AND_RETURN_FALSE(Metadata::DeltaReadMetadata(&graph,
1632                                                        &blocks,
1633                                                        old_image,
1634                                                        new_image,
1635                                                        fd,
1636                                                        &data_file_size));
1637      LOG(INFO) << "Done metadata processing";
1638      CheckGraph(graph);
1639
1640      graph.resize(graph.size() + 1);
1641      TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks,
1642                                                fd,
1643                                                &data_file_size,
1644                                                new_image,
1645                                                &graph.back()));
1646
1647      // Final scratch block (if there's space)
1648      if (blocks.size() < (rootfs_partition_size / kBlockSize)) {
1649        scratch_vertex = graph.size();
1650        graph.resize(graph.size() + 1);
1651        CreateScratchNode(blocks.size(),
1652                          (rootfs_partition_size / kBlockSize) - blocks.size(),
1653                          &graph.back());
1654      }
1655
1656      // Read kernel partition
1657      TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part,
1658                                                         new_kernel_part,
1659                                                         &kernel_ops,
1660                                                         fd,
1661                                                         &data_file_size));
1662
1663      LOG(INFO) << "done reading kernel";
1664      CheckGraph(graph);
1665
1666      LOG(INFO) << "Creating edges...";
1667      CreateEdges(&graph, blocks);
1668      LOG(INFO) << "Done creating edges";
1669      CheckGraph(graph);
1670
1671      TEST_AND_RETURN_FALSE(ConvertGraphToDag(&graph,
1672                                              new_root,
1673                                              fd,
1674                                              &data_file_size,
1675                                              &final_order,
1676                                              scratch_vertex));
1677
1678      // Set the minor version for this payload.
1679      LOG(INFO) << "Adding Delta Minor Version.";
1680      manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion);
1681    } else {
1682      // Full update
1683      off_t new_image_size =
1684          static_cast<off_t>(new_image_block_count) * new_image_block_size;
1685      TEST_AND_RETURN_FALSE(FullUpdateGenerator::Run(&graph,
1686                                                     new_kernel_part,
1687                                                     new_image,
1688                                                     new_image_size,
1689                                                     fd,
1690                                                     &data_file_size,
1691                                                     kFullUpdateChunkSize,
1692                                                     kBlockSize,
1693                                                     &kernel_ops,
1694                                                     &final_order));
1695
1696      // Set the minor version for this payload.
1697      LOG(INFO) << "Adding Full Minor Version.";
1698      manifest.set_minor_version(DeltaPerformer::kFullPayloadMinorVersion);
1699    }
1700  }
1701
1702  if (old_image_info)
1703    *(manifest.mutable_old_image_info()) = *old_image_info;
1704
1705  if (new_image_info)
1706    *(manifest.mutable_new_image_info()) = *new_image_info;
1707
1708  OperationNameMap op_name_map;
1709  CheckGraph(graph);
1710  InstallOperationsToManifest(graph,
1711                              final_order,
1712                              kernel_ops,
1713                              &manifest,
1714                              &op_name_map);
1715  CheckGraph(graph);
1716  manifest.set_block_size(kBlockSize);
1717
1718  // Reorder the data blobs with the newly ordered manifest
1719  string ordered_blobs_path;
1720  TEST_AND_RETURN_FALSE(utils::MakeTempFile(
1721      "CrAU_temp_data.ordered.XXXXXX",
1722      &ordered_blobs_path,
1723      NULL));
1724  ScopedPathUnlinker ordered_blobs_unlinker(ordered_blobs_path);
1725  TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest,
1726                                         temp_file_path,
1727                                         ordered_blobs_path));
1728  temp_file_unlinker.reset();
1729
1730  // Check that install op blobs are in order.
1731  uint64_t next_blob_offset = 0;
1732  {
1733    for (int i = 0; i < (manifest.install_operations_size() +
1734                         manifest.kernel_install_operations_size()); i++) {
1735      DeltaArchiveManifest_InstallOperation* op =
1736          i < manifest.install_operations_size() ?
1737          manifest.mutable_install_operations(i) :
1738          manifest.mutable_kernel_install_operations(
1739              i - manifest.install_operations_size());
1740      if (op->has_data_offset()) {
1741        if (op->data_offset() != next_blob_offset) {
1742          LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != "
1743                     << next_blob_offset;
1744        }
1745        next_blob_offset += op->data_length();
1746      }
1747    }
1748  }
1749
1750  // Signatures appear at the end of the blobs. Note the offset in the
1751  // manifest
1752  if (!private_key_path.empty()) {
1753    uint64_t signature_blob_length = 0;
1754    TEST_AND_RETURN_FALSE(
1755        PayloadSigner::SignatureBlobLength(vector<string>(1, private_key_path),
1756                                           &signature_blob_length));
1757    AddSignatureOp(next_blob_offset, signature_blob_length, &manifest);
1758  }
1759
1760  TEST_AND_RETURN_FALSE(InitializePartitionInfos(old_kernel_part,
1761                                                 new_kernel_part,
1762                                                 old_image,
1763                                                 new_image,
1764                                                 &manifest));
1765
1766  // Serialize protobuf
1767  string serialized_manifest;
1768
1769  CheckGraph(graph);
1770  TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
1771  CheckGraph(graph);
1772
1773  LOG(INFO) << "Writing final delta file header...";
1774  DirectFileWriter writer;
1775  TEST_AND_RETURN_FALSE_ERRNO(writer.Open(output_path.c_str(),
1776                                          O_WRONLY | O_CREAT | O_TRUNC,
1777                                          0644) == 0);
1778  ScopedFileWriterCloser writer_closer(&writer);
1779
1780  // Write header
1781  TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)));
1782
1783  // Write version number
1784  TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, kVersionNumber));
1785
1786  // Write protobuf length
1787  TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer,
1788                                               serialized_manifest.size()));
1789
1790  // Write protobuf
1791  LOG(INFO) << "Writing final delta file protobuf... "
1792            << serialized_manifest.size();
1793  TEST_AND_RETURN_FALSE(writer.Write(serialized_manifest.data(),
1794                                     serialized_manifest.size()));
1795
1796  // Append the data blobs
1797  LOG(INFO) << "Writing final delta file data blobs...";
1798  int blobs_fd = open(ordered_blobs_path.c_str(), O_RDONLY, 0);
1799  ScopedFdCloser blobs_fd_closer(&blobs_fd);
1800  TEST_AND_RETURN_FALSE(blobs_fd >= 0);
1801  for (;;) {
1802    char buf[kBlockSize];
1803    ssize_t rc = read(blobs_fd, buf, sizeof(buf));
1804    if (0 == rc) {
1805      // EOF
1806      break;
1807    }
1808    TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
1809    TEST_AND_RETURN_FALSE(writer.Write(buf, rc));
1810  }
1811
1812  // Write signature blob.
1813  if (!private_key_path.empty()) {
1814    LOG(INFO) << "Signing the update...";
1815    vector<char> signature_blob;
1816    TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(
1817        output_path,
1818        vector<string>(1, private_key_path),
1819        &signature_blob));
1820    TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0],
1821                                       signature_blob.size()));
1822  }
1823
1824  *metadata_size =
1825      strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size();
1826  ReportPayloadUsage(manifest, *metadata_size, op_name_map);
1827
1828  LOG(INFO) << "All done. Successfully created delta file with "
1829            << "metadata size = " << *metadata_size;
1830  return true;
1831}
1832
1833// Runs the bsdiff tool on two files and returns the resulting delta in
1834// 'out'. Returns true on success.
1835bool DeltaDiffGenerator::BsdiffFiles(const string& old_file,
1836                                     const string& new_file,
1837                                     vector<char>* out) {
1838  const string kPatchFile = "delta.patchXXXXXX";
1839  string patch_file_path;
1840
1841  TEST_AND_RETURN_FALSE(
1842      utils::MakeTempFile(kPatchFile, &patch_file_path, NULL));
1843
1844  vector<string> cmd;
1845  cmd.push_back(kBsdiffPath);
1846  cmd.push_back(old_file);
1847  cmd.push_back(new_file);
1848  cmd.push_back(patch_file_path);
1849
1850  int rc = 1;
1851  vector<char> patch_file;
1852  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc, NULL));
1853  TEST_AND_RETURN_FALSE(rc == 0);
1854  TEST_AND_RETURN_FALSE(utils::ReadFile(patch_file_path, out));
1855  unlink(patch_file_path.c_str());
1856  return true;
1857}
1858
1859// The |blocks| vector contains a reader and writer for each block on the
1860// filesystem that's being in-place updated. We populate the reader/writer
1861// fields of |blocks| by calling this function.
1862// For each block in |operation| that is read or written, find that block
1863// in |blocks| and set the reader/writer field to the vertex passed.
1864// |graph| is not strictly necessary, but useful for printing out
1865// error messages.
1866bool DeltaDiffGenerator::AddInstallOpToBlocksVector(
1867    const DeltaArchiveManifest_InstallOperation& operation,
1868    const Graph& graph,
1869    Vertex::Index vertex,
1870    vector<Block>* blocks) {
1871  // See if this is already present.
1872  TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0);
1873
1874  enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT };
1875  for (int field = READER; field < BLOCK_FIELD_COUNT; field++) {
1876    const int extents_size =
1877        (field == READER) ? operation.src_extents_size() :
1878        operation.dst_extents_size();
1879    const char* past_participle = (field == READER) ? "read" : "written";
1880    const google::protobuf::RepeatedPtrField<Extent>& extents =
1881        (field == READER) ? operation.src_extents() : operation.dst_extents();
1882    Vertex::Index Block::*access_type =
1883        (field == READER) ? &Block::reader : &Block::writer;
1884
1885    for (int i = 0; i < extents_size; i++) {
1886      const Extent& extent = extents.Get(i);
1887      if (extent.start_block() == kSparseHole) {
1888        // Hole in sparse file. skip
1889        continue;
1890      }
1891      for (uint64_t block = extent.start_block();
1892           block < (extent.start_block() + extent.num_blocks()); block++) {
1893        if ((*blocks)[block].*access_type != Vertex::kInvalidIndex) {
1894          LOG(FATAL) << "Block " << block << " is already "
1895                     << past_participle << " by "
1896                     << (*blocks)[block].*access_type << "("
1897                     << graph[(*blocks)[block].*access_type].file_name
1898                     << ") and also " << vertex << "("
1899                     << graph[vertex].file_name << ")";
1900        }
1901        (*blocks)[block].*access_type = vertex;
1902      }
1903    }
1904  }
1905  return true;
1906}
1907
1908void DeltaDiffGenerator::AddSignatureOp(uint64_t signature_blob_offset,
1909                                        uint64_t signature_blob_length,
1910                                        DeltaArchiveManifest* manifest) {
1911  LOG(INFO) << "Making room for signature in file";
1912  manifest->set_signatures_offset(signature_blob_offset);
1913  LOG(INFO) << "set? " << manifest->has_signatures_offset();
1914  // Add a dummy op at the end to appease older clients
1915  DeltaArchiveManifest_InstallOperation* dummy_op =
1916      manifest->add_kernel_install_operations();
1917  dummy_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
1918  dummy_op->set_data_offset(signature_blob_offset);
1919  manifest->set_signatures_offset(signature_blob_offset);
1920  dummy_op->set_data_length(signature_blob_length);
1921  manifest->set_signatures_size(signature_blob_length);
1922  Extent* dummy_extent = dummy_op->add_dst_extents();
1923  // Tell the dummy op to write this data to a big sparse hole
1924  dummy_extent->set_start_block(kSparseHole);
1925  dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
1926                               kBlockSize);
1927}
1928
1929const char* const kBsdiffPath = "bsdiff";
1930
1931};  // namespace chromeos_update_engine
1932