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