delta_diff_generator.cc revision d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6
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/topological_sort.h"
43#include "update_engine/payload_signer.h"
44#include "update_engine/subprocess.h"
45#include "update_engine/update_metadata.pb.h"
46#include "update_engine/utils.h"
47
48using std::make_pair;
49using std::map;
50using std::max;
51using std::min;
52using std::pair;
53using std::set;
54using std::string;
55using std::vector;
56
57namespace {
58
59const uint64_t kVersionNumber = 1;
60const uint64_t kFullUpdateChunkSize = 1024 * 1024;  // bytes
61
62const size_t kBlockSize = 4096;  // bytes
63const string kNonexistentPath = "";
64
65static const char* kInstallOperationTypes[] = {
66  "REPLACE",
67  "REPLACE_BZ",
68  "MOVE",
69  "BSDIFF"
70};
71
72}  // namespace
73
74namespace chromeos_update_engine {
75
76typedef DeltaDiffGenerator::Block Block;
77typedef map<const DeltaArchiveManifest_InstallOperation*,
78            string> OperationNameMap;
79
80// bytes
81const size_t kRootFSPartitionSize = static_cast<size_t>(2) * 1024 * 1024 * 1024;
82
83// Needed for testing purposes, in case we can't use actual filesystem objects.
84// TODO(garnold)(chromium:331965) Replace this hack with a properly injected
85// parameter in form of a mockable abstract class.
86bool (*get_extents_with_chunk_func)(const std::string&, off_t, off_t,
87                                    std::vector<Extent>*) =
88    extent_mapper::ExtentsForFileChunkFibmap;
89
90namespace {
91
92// Stores all the extents of |path| into |extents|. Returns true on success.
93bool GatherExtents(const string& path,
94                   off_t chunk_offset,
95                   off_t chunk_size,
96                   vector<Extent>* extents) {
97  extents->clear();
98  TEST_AND_RETURN_FALSE(
99      get_extents_with_chunk_func(
100          path, chunk_offset, chunk_size, extents));
101  return true;
102}
103
104// For a given regular file which must exist at new_root + path, and
105// may exist at old_root + path, creates a new InstallOperation and
106// adds it to the graph. Also, populates the |blocks| array as
107// necessary, if |blocks| is non-NULL.  Also, writes the data
108// necessary to send the file down to the client into data_fd, which
109// has length *data_file_size. *data_file_size is updated
110// appropriately. If |existing_vertex| is no kInvalidIndex, use that
111// rather than allocating a new vertex. Returns true on success.
112bool DeltaReadFile(Graph* graph,
113                   Vertex::Index existing_vertex,
114                   vector<Block>* blocks,
115                   const string& old_root,
116                   const string& new_root,
117                   const string& path,  // within new_root
118                   off_t chunk_offset,
119                   off_t chunk_size,
120                   int data_fd,
121                   off_t* data_file_size) {
122  vector<char> data;
123  DeltaArchiveManifest_InstallOperation operation;
124
125  string old_path = (old_root == kNonexistentPath) ? kNonexistentPath :
126      old_root + path;
127
128  // If bsdiff breaks again, blacklist the problem file by using:
129  //   bsdiff_allowed = (path != "/foo/bar")
130  //
131  // TODO(dgarrett): chromium-os:15274 connect this test to the command line.
132  bool bsdiff_allowed = true;
133
134  if (!bsdiff_allowed)
135    LOG(INFO) << "bsdiff blacklisting: " << path;
136
137  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::ReadFileToDiff(old_path,
138                                                           new_root + path,
139                                                           chunk_offset,
140                                                           chunk_size,
141                                                           bsdiff_allowed,
142                                                           &data,
143                                                           &operation,
144                                                           true));
145
146  // Check if the operation writes nothing.
147  if (operation.dst_extents_size() == 0) {
148    if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
149      LOG(INFO) << "Empty MOVE operation (" << new_root + path << "), skipping";
150      return true;
151    } else {
152      LOG(ERROR) << "Empty non-MOVE operation";
153      return false;
154    }
155  }
156
157  // Write the data
158  if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) {
159    operation.set_data_offset(*data_file_size);
160    operation.set_data_length(data.size());
161  }
162
163  TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size()));
164  *data_file_size += data.size();
165
166  // Now, insert into graph and blocks vector
167  Vertex::Index vertex = existing_vertex;
168  if (vertex == Vertex::kInvalidIndex) {
169    graph->resize(graph->size() + 1);
170    vertex = graph->size() - 1;
171  }
172  (*graph)[vertex].op = operation;
173  CHECK((*graph)[vertex].op.has_type());
174  (*graph)[vertex].file_name = path;
175  (*graph)[vertex].chunk_offset = chunk_offset;
176  (*graph)[vertex].chunk_size = chunk_size;
177
178  if (blocks)
179    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::AddInstallOpToBlocksVector(
180        (*graph)[vertex].op,
181        *graph,
182        vertex,
183        blocks));
184  return true;
185}
186
187// For each regular file within new_root, creates a node in the graph,
188// determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF),
189// and writes any necessary data to the end of data_fd.
190bool DeltaReadFiles(Graph* graph,
191                    vector<Block>* blocks,
192                    const string& old_root,
193                    const string& new_root,
194                    off_t chunk_size,
195                    int data_fd,
196                    off_t* data_file_size) {
197  set<ino_t> visited_inodes;
198  set<ino_t> visited_src_inodes;
199  for (FilesystemIterator fs_iter(new_root,
200                                  utils::SetWithValue<string>("/lost+found"));
201       !fs_iter.IsEnd(); fs_iter.Increment()) {
202    // We never diff symlinks (here, we check that dst file is not a symlink).
203    if (!S_ISREG(fs_iter.GetStat().st_mode))
204      continue;
205
206    // Make sure we visit each inode only once.
207    if (utils::SetContainsKey(visited_inodes, fs_iter.GetStat().st_ino))
208      continue;
209    visited_inodes.insert(fs_iter.GetStat().st_ino);
210    off_t dst_size = fs_iter.GetStat().st_size;
211    if (dst_size == 0)
212      continue;
213
214    LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath();
215
216    // We can't visit each dst image inode more than once, as that would
217    // duplicate work. Here, we avoid visiting each source image inode
218    // more than once. Technically, we could have multiple operations
219    // that read the same blocks from the source image for diffing, but
220    // we choose not to to avoid complexity. Eventually we will move away
221    // from using a graph/cycle detection/etc to generate diffs, and at that
222    // time, it will be easy (non-complex) to have many operations read
223    // from the same source blocks. At that time, this code can die. -adlr
224    bool should_diff_from_source = false;
225    string src_path = old_root + fs_iter.GetPartialPath();
226    struct stat src_stbuf;
227    // We never diff symlinks (here, we check that src file is not a symlink).
228    if (0 == lstat(src_path.c_str(), &src_stbuf) &&
229        S_ISREG(src_stbuf.st_mode)) {
230      should_diff_from_source = !utils::SetContainsKey(visited_src_inodes,
231                                                       src_stbuf.st_ino);
232      visited_src_inodes.insert(src_stbuf.st_ino);
233    }
234
235    off_t size = chunk_size == -1 ? dst_size : chunk_size;
236    off_t step = size;
237    for (off_t offset = 0; offset < dst_size; offset += step) {
238      if (offset + size >= dst_size) {
239        size = -1;  // Read through the end of the file.
240      }
241      TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
242                                          Vertex::kInvalidIndex,
243                                          blocks,
244                                          (should_diff_from_source ?
245                                           old_root :
246                                           kNonexistentPath),
247                                          new_root,
248                                          fs_iter.GetPartialPath(),
249                                          offset,
250                                          size,
251                                          data_fd,
252                                          data_file_size));
253    }
254  }
255  return true;
256}
257
258// This class allocates non-existent temp blocks, starting from
259// kTempBlockStart. Other code is responsible for converting these
260// temp blocks into real blocks, as the client can't read or write to
261// these blocks.
262class DummyExtentAllocator {
263 public:
264  explicit DummyExtentAllocator()
265      : 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                                            NULL));
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, NULL, NULL);
368  TEST_AND_RETURN_FALSE(err == BZ_OK);
369  bz_file = NULL;
370  TEST_AND_RETURN_FALSE_ERRNO(0 == fclose(file));
371  file = NULL;
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  struct stat old_stbuf;
706  bool original = !old_filename.empty();
707  if (original && 0 != stat(old_filename.c_str(), &old_stbuf)) {
708    // If stat-ing the old file fails, it should be because it doesn't exist.
709    TEST_AND_RETURN_FALSE(errno == ENOTDIR || errno == ENOENT);
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(
768          (old_stbuf.st_size + kBlockSize - 1) / kBlockSize);
769    }
770    operation.set_src_length(old_data.size());
771  }
772
773  if (gather_extents) {
774    TEST_AND_RETURN_FALSE(
775        GatherExtents(new_filename,
776                      chunk_offset,
777                      chunk_size,
778                      &dst_extents));
779  } else {
780    Extent* dst_extent = operation.add_dst_extents();
781    dst_extent->set_start_block(0);
782    dst_extent->set_num_blocks((new_data.size() + kBlockSize - 1) / kBlockSize);
783  }
784  operation.set_dst_length(new_data.size());
785
786  if (gather_extents) {
787    // Remove identical src/dst block ranges in MOVE operations.
788    if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
789      size_t removed_bytes = RemoveIdenticalBlockRanges(
790          &src_extents, &dst_extents, new_data.size());
791
792      // Adjust the file length field accordingly.
793      if (removed_bytes) {
794        operation.set_src_length(old_data.size() - removed_bytes);
795        operation.set_dst_length(new_data.size() - removed_bytes);
796      }
797    }
798
799    // Embed extents in the operation.
800    DeltaDiffGenerator::StoreExtents(src_extents,
801                                     operation.mutable_src_extents());
802    DeltaDiffGenerator::StoreExtents(dst_extents,
803                                     operation.mutable_dst_extents());
804  }
805
806  out_data->swap(data);
807  *out_op = operation;
808
809  return true;
810}
811
812bool DeltaDiffGenerator::InitializePartitionInfo(bool is_kernel,
813                                                 const string& partition,
814                                                 PartitionInfo* info) {
815  int64_t size = 0;
816  if (is_kernel) {
817    size = utils::FileSize(partition);
818  } else {
819    int block_count = 0, block_size = 0;
820    TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(partition,
821                                                   &block_count,
822                                                   &block_size));
823    size = static_cast<int64_t>(block_count) * block_size;
824  }
825  TEST_AND_RETURN_FALSE(size > 0);
826  info->set_size(size);
827  OmahaHashCalculator hasher;
828  TEST_AND_RETURN_FALSE(hasher.UpdateFile(partition, size) == size);
829  TEST_AND_RETURN_FALSE(hasher.Finalize());
830  const vector<char>& hash = hasher.raw_hash();
831  info->set_hash(hash.data(), hash.size());
832  LOG(INFO) << partition << ": size=" << size << " hash=" << hasher.hash();
833  return true;
834}
835
836bool InitializePartitionInfos(const string& old_kernel,
837                              const string& new_kernel,
838                              const string& old_rootfs,
839                              const string& new_rootfs,
840                              DeltaArchiveManifest* manifest) {
841  if (!old_kernel.empty()) {
842    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
843        true,
844        old_kernel,
845        manifest->mutable_old_kernel_info()));
846  }
847  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
848      true,
849      new_kernel,
850      manifest->mutable_new_kernel_info()));
851  if (!old_rootfs.empty()) {
852    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
853        false,
854        old_rootfs,
855        manifest->mutable_old_rootfs_info()));
856  }
857  TEST_AND_RETURN_FALSE(DeltaDiffGenerator::InitializePartitionInfo(
858      false,
859      new_rootfs,
860      manifest->mutable_new_rootfs_info()));
861  return true;
862}
863
864namespace {
865
866// Takes a collection (vector or RepeatedPtrField) of Extent and
867// returns a vector of the blocks referenced, in order.
868template<typename T>
869vector<uint64_t> ExpandExtents(const T& extents) {
870  vector<uint64_t> ret;
871  for (size_t i = 0, e = static_cast<size_t>(extents.size()); i != e; ++i) {
872    const Extent extent = graph_utils::GetElement(extents, i);
873    if (extent.start_block() == kSparseHole) {
874      ret.resize(ret.size() + extent.num_blocks(), kSparseHole);
875    } else {
876      for (uint64_t block = extent.start_block();
877           block < (extent.start_block() + extent.num_blocks()); block++) {
878        ret.push_back(block);
879      }
880    }
881  }
882  return ret;
883}
884
885// Takes a vector of blocks and returns an equivalent vector of Extent
886// objects.
887vector<Extent> CompressExtents(const vector<uint64_t>& blocks) {
888  vector<Extent> new_extents;
889  for (vector<uint64_t>::const_iterator it = blocks.begin(), e = blocks.end();
890       it != e; ++it) {
891    graph_utils::AppendBlockToExtents(&new_extents, *it);
892  }
893  return new_extents;
894}
895
896}  // namespace
897
898void DeltaDiffGenerator::SubstituteBlocks(
899    Vertex* vertex,
900    const vector<Extent>& remove_extents,
901    const vector<Extent>& replace_extents) {
902  // First, expand out the blocks that op reads from
903  vector<uint64_t> read_blocks = ExpandExtents(vertex->op.src_extents());
904  {
905    // Expand remove_extents and replace_extents
906    vector<uint64_t> remove_extents_expanded =
907        ExpandExtents(remove_extents);
908    vector<uint64_t> replace_extents_expanded =
909        ExpandExtents(replace_extents);
910    CHECK_EQ(remove_extents_expanded.size(), replace_extents_expanded.size());
911    map<uint64_t, uint64_t> conversion;
912    for (vector<uint64_t>::size_type i = 0;
913         i < replace_extents_expanded.size(); i++) {
914      conversion[remove_extents_expanded[i]] = replace_extents_expanded[i];
915    }
916    utils::ApplyMap(&read_blocks, conversion);
917    for (Vertex::EdgeMap::iterator it = vertex->out_edges.begin(),
918             e = vertex->out_edges.end(); it != e; ++it) {
919      vector<uint64_t> write_before_deps_expanded =
920          ExpandExtents(it->second.write_extents);
921      utils::ApplyMap(&write_before_deps_expanded, conversion);
922      it->second.write_extents = CompressExtents(write_before_deps_expanded);
923    }
924  }
925  // Convert read_blocks back to extents
926  vertex->op.clear_src_extents();
927  vector<Extent> new_extents = CompressExtents(read_blocks);
928  DeltaDiffGenerator::StoreExtents(new_extents,
929                                   vertex->op.mutable_src_extents());
930}
931
932bool DeltaDiffGenerator::CutEdges(Graph* graph,
933                                  const set<Edge>& edges,
934                                  vector<CutEdgeVertexes>* out_cuts) {
935  DummyExtentAllocator scratch_allocator;
936  vector<CutEdgeVertexes> cuts;
937  cuts.reserve(edges.size());
938
939  uint64_t scratch_blocks_used = 0;
940  for (set<Edge>::const_iterator it = edges.begin();
941       it != edges.end(); ++it) {
942    cuts.resize(cuts.size() + 1);
943    vector<Extent> old_extents =
944        (*graph)[it->first].out_edges[it->second].extents;
945    // Choose some scratch space
946    scratch_blocks_used += graph_utils::EdgeWeight(*graph, *it);
947    cuts.back().tmp_extents =
948        scratch_allocator.Allocate(graph_utils::EdgeWeight(*graph, *it));
949    // create vertex to copy original->scratch
950    cuts.back().new_vertex = graph->size();
951    graph->resize(graph->size() + 1);
952    cuts.back().old_src = it->first;
953    cuts.back().old_dst = it->second;
954
955    EdgeProperties& cut_edge_properties =
956        (*graph)[it->first].out_edges.find(it->second)->second;
957
958    // This should never happen, as we should only be cutting edges between
959    // real file nodes, and write-before relationships are created from
960    // a real file node to a temp copy node:
961    CHECK(cut_edge_properties.write_extents.empty())
962        << "Can't cut edge that has write-before relationship.";
963
964    // make node depend on the copy operation
965    (*graph)[it->first].out_edges.insert(make_pair(graph->size() - 1,
966                                                   cut_edge_properties));
967
968    // Set src/dst extents and other proto variables for copy operation
969    graph->back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
970    DeltaDiffGenerator::StoreExtents(
971        cut_edge_properties.extents,
972        graph->back().op.mutable_src_extents());
973    DeltaDiffGenerator::StoreExtents(cuts.back().tmp_extents,
974                                     graph->back().op.mutable_dst_extents());
975    graph->back().op.set_src_length(
976        graph_utils::EdgeWeight(*graph, *it) * kBlockSize);
977    graph->back().op.set_dst_length(graph->back().op.src_length());
978
979    // make the dest node read from the scratch space
980    DeltaDiffGenerator::SubstituteBlocks(
981        &((*graph)[it->second]),
982        (*graph)[it->first].out_edges[it->second].extents,
983        cuts.back().tmp_extents);
984
985    // delete the old edge
986    CHECK_EQ(static_cast<Graph::size_type>(1),
987             (*graph)[it->first].out_edges.erase(it->second));
988
989    // Add an edge from dst to copy operation
990    EdgeProperties write_before_edge_properties;
991    write_before_edge_properties.write_extents = cuts.back().tmp_extents;
992    (*graph)[it->second].out_edges.insert(
993        make_pair(graph->size() - 1, write_before_edge_properties));
994  }
995  out_cuts->swap(cuts);
996  return true;
997}
998
999// Stores all Extents in 'extents' into 'out'.
1000void DeltaDiffGenerator::StoreExtents(
1001    const vector<Extent>& extents,
1002    google::protobuf::RepeatedPtrField<Extent>* out) {
1003  for (vector<Extent>::const_iterator it = extents.begin();
1004       it != extents.end(); ++it) {
1005    Extent* new_extent = out->Add();
1006    *new_extent = *it;
1007  }
1008}
1009
1010// Creates all the edges for the graph. Writers of a block point to
1011// readers of the same block. This is because for an edge A->B, B
1012// must complete before A executes.
1013void DeltaDiffGenerator::CreateEdges(Graph* graph,
1014                                     const vector<Block>& blocks) {
1015  for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
1016    // Blocks with both a reader and writer get an edge
1017    if (blocks[i].reader == Vertex::kInvalidIndex ||
1018        blocks[i].writer == Vertex::kInvalidIndex)
1019      continue;
1020    // Don't have a node depend on itself
1021    if (blocks[i].reader == blocks[i].writer)
1022      continue;
1023    // See if there's already an edge we can add onto
1024    Vertex::EdgeMap::iterator edge_it =
1025        (*graph)[blocks[i].writer].out_edges.find(blocks[i].reader);
1026    if (edge_it == (*graph)[blocks[i].writer].out_edges.end()) {
1027      // No existing edge. Create one
1028      (*graph)[blocks[i].writer].out_edges.insert(
1029          make_pair(blocks[i].reader, EdgeProperties()));
1030      edge_it = (*graph)[blocks[i].writer].out_edges.find(blocks[i].reader);
1031      CHECK(edge_it != (*graph)[blocks[i].writer].out_edges.end());
1032    }
1033    graph_utils::AppendBlockToExtents(&edge_it->second.extents, i);
1034  }
1035}
1036
1037namespace {
1038
1039class SortCutsByTopoOrderLess {
1040 public:
1041  SortCutsByTopoOrderLess(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  vector<vector<Vertex::Index>::size_type>& table_;
1048};
1049
1050}  // namespace
1051
1052void DeltaDiffGenerator::GenerateReverseTopoOrderMap(
1053    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(vector<Vertex::Index>& op_indexes,
1068                                             vector<CutEdgeVertexes>* cuts) {
1069  // first, make a reverse lookup table.
1070  vector<vector<Vertex::Index>::size_type> table;
1071  GenerateReverseTopoOrderMap(op_indexes, &table);
1072  SortCutsByTopoOrderLess less(table);
1073  sort(cuts->begin(), cuts->end(), less);
1074}
1075
1076void DeltaDiffGenerator::MoveFullOpsToBack(Graph* graph,
1077                                           vector<Vertex::Index>* op_indexes) {
1078  vector<Vertex::Index> ret;
1079  vector<Vertex::Index> full_ops;
1080  ret.reserve(op_indexes->size());
1081  for (vector<Vertex::Index>::size_type i = 0, e = op_indexes->size(); i != e;
1082       ++i) {
1083    DeltaArchiveManifest_InstallOperation_Type type =
1084        (*graph)[(*op_indexes)[i]].op.type();
1085    if (type == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
1086        type == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
1087      full_ops.push_back((*op_indexes)[i]);
1088    } else {
1089      ret.push_back((*op_indexes)[i]);
1090    }
1091  }
1092  LOG(INFO) << "Stats: " << full_ops.size() << " full ops out of "
1093            << (full_ops.size() + ret.size()) << " total ops.";
1094  ret.insert(ret.end(), full_ops.begin(), full_ops.end());
1095  op_indexes->swap(ret);
1096}
1097
1098namespace {
1099
1100template<typename T>
1101bool TempBlocksExistInExtents(const T& extents) {
1102  for (int i = 0, e = extents.size(); i < e; ++i) {
1103    Extent extent = graph_utils::GetElement(extents, i);
1104    uint64_t start = extent.start_block();
1105    uint64_t num = extent.num_blocks();
1106    if (start == kSparseHole)
1107      continue;
1108    if (start >= kTempBlockStart ||
1109        (start + num) >= kTempBlockStart) {
1110      LOG(ERROR) << "temp block!";
1111      LOG(ERROR) << "start: " << start << ", num: " << num;
1112      LOG(ERROR) << "kTempBlockStart: " << kTempBlockStart;
1113      LOG(ERROR) << "returning true";
1114      return true;
1115    }
1116    // check for wrap-around, which would be a bug:
1117    CHECK(start <= (start + num));
1118  }
1119  return false;
1120}
1121
1122// Convertes the cuts, which must all have the same |old_dst| member,
1123// to full. It does this by converting the |old_dst| to REPLACE or
1124// REPLACE_BZ, dropping all incoming edges to |old_dst|, and marking
1125// all temp nodes invalid.
1126bool ConvertCutsToFull(
1127    Graph* graph,
1128    const string& new_root,
1129    int data_fd,
1130    off_t* data_file_size,
1131    vector<Vertex::Index>* op_indexes,
1132    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
1133    const vector<CutEdgeVertexes>& cuts) {
1134  CHECK(!cuts.empty());
1135  set<Vertex::Index> deleted_nodes;
1136  for (vector<CutEdgeVertexes>::const_iterator it = cuts.begin(),
1137           e = cuts.end(); it != e; ++it) {
1138    TEST_AND_RETURN_FALSE(DeltaDiffGenerator::ConvertCutToFullOp(
1139        graph,
1140        *it,
1141        new_root,
1142        data_fd,
1143        data_file_size));
1144    deleted_nodes.insert(it->new_vertex);
1145  }
1146  deleted_nodes.insert(cuts[0].old_dst);
1147
1148  vector<Vertex::Index> new_op_indexes;
1149  new_op_indexes.reserve(op_indexes->size());
1150  for (vector<Vertex::Index>::iterator it = op_indexes->begin(),
1151           e = op_indexes->end(); it != e; ++it) {
1152    if (utils::SetContainsKey(deleted_nodes, *it))
1153      continue;
1154    new_op_indexes.push_back(*it);
1155  }
1156  new_op_indexes.push_back(cuts[0].old_dst);
1157  op_indexes->swap(new_op_indexes);
1158  DeltaDiffGenerator::GenerateReverseTopoOrderMap(*op_indexes,
1159                                                  reverse_op_indexes);
1160  return true;
1161}
1162
1163// Tries to assign temp blocks for a collection of cuts, all of which share
1164// the same old_dst member. If temp blocks can't be found, old_dst will be
1165// converted to a REPLACE or REPLACE_BZ operation. Returns true on success,
1166// which can happen even if blocks are converted to full. Returns false
1167// on exceptional error cases.
1168bool AssignBlockForAdjoiningCuts(
1169    Graph* graph,
1170    const string& new_root,
1171    int data_fd,
1172    off_t* data_file_size,
1173    vector<Vertex::Index>* op_indexes,
1174    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
1175    const vector<CutEdgeVertexes>& cuts) {
1176  CHECK(!cuts.empty());
1177  const Vertex::Index old_dst = cuts[0].old_dst;
1178  // Calculate # of blocks needed
1179  uint64_t blocks_needed = 0;
1180  map<const CutEdgeVertexes*, uint64_t> cuts_blocks_needed;
1181  for (vector<CutEdgeVertexes>::const_iterator it = cuts.begin(),
1182           e = cuts.end(); it != e; ++it) {
1183    uint64_t cut_blocks_needed = 0;
1184    for (vector<Extent>::const_iterator jt = it->tmp_extents.begin(),
1185             je = it->tmp_extents.end(); jt != je; ++jt) {
1186      cut_blocks_needed += jt->num_blocks();
1187    }
1188    blocks_needed += cut_blocks_needed;
1189    cuts_blocks_needed[&*it] = cut_blocks_needed;
1190  }
1191
1192  // Find enough blocks
1193  ExtentRanges scratch_ranges;
1194  // Each block that's supplying temp blocks and the corresponding blocks:
1195  typedef vector<pair<Vertex::Index, ExtentRanges> > SupplierVector;
1196  SupplierVector block_suppliers;
1197  uint64_t scratch_blocks_found = 0;
1198  for (vector<Vertex::Index>::size_type i = (*reverse_op_indexes)[old_dst] + 1,
1199           e = op_indexes->size(); i < e; ++i) {
1200    Vertex::Index test_node = (*op_indexes)[i];
1201    if (!(*graph)[test_node].valid)
1202      continue;
1203    // See if this node has sufficient blocks
1204    ExtentRanges ranges;
1205    ranges.AddRepeatedExtents((*graph)[test_node].op.dst_extents());
1206    ranges.SubtractExtent(ExtentForRange(
1207        kTempBlockStart, kSparseHole - kTempBlockStart));
1208    ranges.SubtractRepeatedExtents((*graph)[test_node].op.src_extents());
1209    // For now, for simplicity, subtract out all blocks in read-before
1210    // dependencies.
1211    for (Vertex::EdgeMap::const_iterator edge_i =
1212             (*graph)[test_node].out_edges.begin(),
1213             edge_e = (*graph)[test_node].out_edges.end();
1214         edge_i != edge_e; ++edge_i) {
1215      ranges.SubtractExtents(edge_i->second.extents);
1216    }
1217    if (ranges.blocks() == 0)
1218      continue;
1219
1220    if (ranges.blocks() + scratch_blocks_found > blocks_needed) {
1221      // trim down ranges
1222      vector<Extent> new_ranges = ranges.GetExtentsForBlockCount(
1223          blocks_needed - scratch_blocks_found);
1224      ranges = ExtentRanges();
1225      ranges.AddExtents(new_ranges);
1226    }
1227    scratch_ranges.AddRanges(ranges);
1228    block_suppliers.push_back(make_pair(test_node, ranges));
1229    scratch_blocks_found += ranges.blocks();
1230    if (scratch_ranges.blocks() >= blocks_needed)
1231      break;
1232  }
1233  if (scratch_ranges.blocks() < blocks_needed) {
1234    LOG(INFO) << "Unable to find sufficient scratch";
1235    TEST_AND_RETURN_FALSE(ConvertCutsToFull(graph,
1236                                            new_root,
1237                                            data_fd,
1238                                            data_file_size,
1239                                            op_indexes,
1240                                            reverse_op_indexes,
1241                                            cuts));
1242    return true;
1243  }
1244  // Use the scratch we found
1245  TEST_AND_RETURN_FALSE(scratch_ranges.blocks() == scratch_blocks_found);
1246
1247  // Make all the suppliers depend on this node
1248  for (SupplierVector::iterator it = block_suppliers.begin(),
1249           e = block_suppliers.end(); it != e; ++it) {
1250    graph_utils::AddReadBeforeDepExtents(
1251        &(*graph)[it->first],
1252        old_dst,
1253        it->second.GetExtentsForBlockCount(it->second.blocks()));
1254  }
1255
1256  // Replace temp blocks in each cut
1257  for (vector<CutEdgeVertexes>::const_iterator it = cuts.begin(),
1258           e = cuts.end(); it != e; ++it) {
1259    vector<Extent> real_extents =
1260        scratch_ranges.GetExtentsForBlockCount(cuts_blocks_needed[&*it]);
1261    scratch_ranges.SubtractExtents(real_extents);
1262
1263    // Fix the old dest node w/ the real blocks
1264    DeltaDiffGenerator::SubstituteBlocks(&(*graph)[old_dst],
1265                                         it->tmp_extents,
1266                                         real_extents);
1267
1268    // Fix the new node w/ the real blocks. Since the new node is just a
1269    // copy operation, we can replace all the dest extents w/ the real
1270    // blocks.
1271    DeltaArchiveManifest_InstallOperation *op =
1272        &(*graph)[it->new_vertex].op;
1273    op->clear_dst_extents();
1274    DeltaDiffGenerator::StoreExtents(real_extents, op->mutable_dst_extents());
1275  }
1276  return true;
1277}
1278
1279}  // namespace
1280
1281// Returns true if |op| is a no-op operation that doesn't do any useful work
1282// (e.g., a move operation that copies blocks onto themselves).
1283bool DeltaDiffGenerator::IsNoopOperation(
1284    const DeltaArchiveManifest_InstallOperation& op) {
1285  return (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE &&
1286          ExpandExtents(op.src_extents()) == ExpandExtents(op.dst_extents()));
1287}
1288
1289bool DeltaDiffGenerator::AssignTempBlocks(
1290    Graph* graph,
1291    const string& new_root,
1292    int data_fd,
1293    off_t* data_file_size,
1294    vector<Vertex::Index>* op_indexes,
1295    vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
1296    const vector<CutEdgeVertexes>& cuts) {
1297  CHECK(!cuts.empty());
1298
1299  // group of cuts w/ the same old_dst:
1300  vector<CutEdgeVertexes> cuts_group;
1301
1302  for (vector<CutEdgeVertexes>::size_type i = cuts.size() - 1, e = 0;
1303       true ; --i) {
1304    LOG(INFO) << "Fixing temp blocks in cut " << i
1305              << ": old dst: " << cuts[i].old_dst << " new vertex: "
1306              << cuts[i].new_vertex << " path: "
1307              << (*graph)[cuts[i].old_dst].file_name;
1308
1309    if (cuts_group.empty() || (cuts_group[0].old_dst == cuts[i].old_dst)) {
1310      cuts_group.push_back(cuts[i]);
1311    } else {
1312      CHECK(!cuts_group.empty());
1313      TEST_AND_RETURN_FALSE(AssignBlockForAdjoiningCuts(graph,
1314                                                        new_root,
1315                                                        data_fd,
1316                                                        data_file_size,
1317                                                        op_indexes,
1318                                                        reverse_op_indexes,
1319                                                        cuts_group));
1320      cuts_group.clear();
1321      cuts_group.push_back(cuts[i]);
1322    }
1323
1324    if (i == e) {
1325      // break out of for() loop
1326      break;
1327    }
1328  }
1329  CHECK(!cuts_group.empty());
1330  TEST_AND_RETURN_FALSE(AssignBlockForAdjoiningCuts(graph,
1331                                                    new_root,
1332                                                    data_fd,
1333                                                    data_file_size,
1334                                                    op_indexes,
1335                                                    reverse_op_indexes,
1336                                                    cuts_group));
1337  return true;
1338}
1339
1340bool DeltaDiffGenerator::NoTempBlocksRemain(const Graph& graph) {
1341  size_t idx = 0;
1342  for (Graph::const_iterator it = graph.begin(), e = graph.end(); it != e;
1343       ++it, ++idx) {
1344    if (!it->valid)
1345      continue;
1346    const DeltaArchiveManifest_InstallOperation& op = it->op;
1347    if (TempBlocksExistInExtents(op.dst_extents()) ||
1348        TempBlocksExistInExtents(op.src_extents())) {
1349      LOG(INFO) << "bad extents in node " << idx;
1350      LOG(INFO) << "so yeah";
1351      return false;
1352    }
1353
1354    // Check out-edges:
1355    for (Vertex::EdgeMap::const_iterator jt = it->out_edges.begin(),
1356             je = it->out_edges.end(); jt != je; ++jt) {
1357      if (TempBlocksExistInExtents(jt->second.extents) ||
1358          TempBlocksExistInExtents(jt->second.write_extents)) {
1359        LOG(INFO) << "bad out edge in node " << idx;
1360        LOG(INFO) << "so yeah";
1361        return false;
1362      }
1363    }
1364  }
1365  return true;
1366}
1367
1368bool DeltaDiffGenerator::ReorderDataBlobs(
1369    DeltaArchiveManifest* manifest,
1370    const std::string& data_blobs_path,
1371    const std::string& new_data_blobs_path) {
1372  int in_fd = open(data_blobs_path.c_str(), O_RDONLY, 0);
1373  TEST_AND_RETURN_FALSE_ERRNO(in_fd >= 0);
1374  ScopedFdCloser in_fd_closer(&in_fd);
1375
1376  DirectFileWriter writer;
1377  TEST_AND_RETURN_FALSE(
1378      writer.Open(new_data_blobs_path.c_str(),
1379                  O_WRONLY | O_TRUNC | O_CREAT,
1380                  0644) == 0);
1381  ScopedFileWriterCloser writer_closer(&writer);
1382  uint64_t out_file_size = 0;
1383
1384  for (int i = 0; i < (manifest->install_operations_size() +
1385                       manifest->kernel_install_operations_size()); i++) {
1386    DeltaArchiveManifest_InstallOperation* op = NULL;
1387    if (i < manifest->install_operations_size()) {
1388      op = manifest->mutable_install_operations(i);
1389    } else {
1390      op = manifest->mutable_kernel_install_operations(
1391          i - manifest->install_operations_size());
1392    }
1393    if (!op->has_data_offset())
1394      continue;
1395    CHECK(op->has_data_length());
1396    vector<char> buf(op->data_length());
1397    ssize_t rc = pread(in_fd, &buf[0], buf.size(), op->data_offset());
1398    TEST_AND_RETURN_FALSE(rc == static_cast<ssize_t>(buf.size()));
1399
1400    // Add the hash of the data blobs for this operation
1401    TEST_AND_RETURN_FALSE(AddOperationHash(op, buf));
1402
1403    op->set_data_offset(out_file_size);
1404    TEST_AND_RETURN_FALSE(writer.Write(&buf[0], buf.size()));
1405    out_file_size += buf.size();
1406  }
1407  return true;
1408}
1409
1410bool DeltaDiffGenerator::AddOperationHash(
1411    DeltaArchiveManifest_InstallOperation* op,
1412    const vector<char>& buf) {
1413  OmahaHashCalculator hasher;
1414
1415  TEST_AND_RETURN_FALSE(hasher.Update(&buf[0], buf.size()));
1416  TEST_AND_RETURN_FALSE(hasher.Finalize());
1417
1418  const vector<char>& hash = hasher.raw_hash();
1419  op->set_data_sha256_hash(hash.data(), hash.size());
1420  return true;
1421}
1422
1423bool DeltaDiffGenerator::ConvertCutToFullOp(Graph* graph,
1424                                            const CutEdgeVertexes& cut,
1425                                            const string& new_root,
1426                                            int data_fd,
1427                                            off_t* data_file_size) {
1428  // Drop all incoming edges, keep all outgoing edges
1429
1430  // Keep all outgoing edges
1431  if ((*graph)[cut.old_dst].op.type() !=
1432      DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ &&
1433      (*graph)[cut.old_dst].op.type() !=
1434      DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
1435    Vertex::EdgeMap out_edges = (*graph)[cut.old_dst].out_edges;
1436    graph_utils::DropWriteBeforeDeps(&out_edges);
1437
1438    TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
1439                                        cut.old_dst,
1440                                        NULL,
1441                                        kNonexistentPath,
1442                                        new_root,
1443                                        (*graph)[cut.old_dst].file_name,
1444                                        (*graph)[cut.old_dst].chunk_offset,
1445                                        (*graph)[cut.old_dst].chunk_size,
1446                                        data_fd,
1447                                        data_file_size));
1448
1449    (*graph)[cut.old_dst].out_edges = out_edges;
1450
1451    // Right now we don't have doubly-linked edges, so we have to scan
1452    // the whole graph.
1453    graph_utils::DropIncomingEdgesTo(graph, cut.old_dst);
1454  }
1455
1456  // Delete temp node
1457  (*graph)[cut.old_src].out_edges.erase(cut.new_vertex);
1458  CHECK((*graph)[cut.old_dst].out_edges.find(cut.new_vertex) ==
1459        (*graph)[cut.old_dst].out_edges.end());
1460  (*graph)[cut.new_vertex].valid = false;
1461  LOG(INFO) << "marked node invalid: " << cut.new_vertex;
1462  return true;
1463}
1464
1465bool DeltaDiffGenerator::ConvertGraphToDag(Graph* graph,
1466                                           const string& new_root,
1467                                           int fd,
1468                                           off_t* data_file_size,
1469                                           vector<Vertex::Index>* final_order,
1470                                           Vertex::Index scratch_vertex) {
1471  CycleBreaker cycle_breaker;
1472  LOG(INFO) << "Finding cycles...";
1473  set<Edge> cut_edges;
1474  cycle_breaker.BreakCycles(*graph, &cut_edges);
1475  LOG(INFO) << "done finding cycles";
1476  CheckGraph(*graph);
1477
1478  // Calculate number of scratch blocks needed
1479
1480  LOG(INFO) << "Cutting cycles...";
1481  vector<CutEdgeVertexes> cuts;
1482  TEST_AND_RETURN_FALSE(CutEdges(graph, cut_edges, &cuts));
1483  LOG(INFO) << "done cutting cycles";
1484  LOG(INFO) << "There are " << cuts.size() << " cuts.";
1485  CheckGraph(*graph);
1486
1487  LOG(INFO) << "Creating initial topological order...";
1488  TopologicalSort(*graph, final_order);
1489  LOG(INFO) << "done with initial topo order";
1490  CheckGraph(*graph);
1491
1492  LOG(INFO) << "Moving full ops to the back";
1493  MoveFullOpsToBack(graph, final_order);
1494  LOG(INFO) << "done moving full ops to back";
1495
1496  vector<vector<Vertex::Index>::size_type> inverse_final_order;
1497  GenerateReverseTopoOrderMap(*final_order, &inverse_final_order);
1498
1499  SortCutsByTopoOrder(*final_order, &cuts);
1500
1501  if (!cuts.empty())
1502    TEST_AND_RETURN_FALSE(AssignTempBlocks(graph,
1503                                           new_root,
1504                                           fd,
1505                                           data_file_size,
1506                                           final_order,
1507                                           &inverse_final_order,
1508                                           cuts));
1509  LOG(INFO) << "Making sure all temp blocks have been allocated";
1510
1511  // Remove the scratch node, if any
1512  if (scratch_vertex != Vertex::kInvalidIndex) {
1513    final_order->erase(final_order->begin() +
1514                       inverse_final_order[scratch_vertex]);
1515    (*graph)[scratch_vertex].valid = false;
1516    GenerateReverseTopoOrderMap(*final_order, &inverse_final_order);
1517  }
1518
1519  graph_utils::DumpGraph(*graph);
1520  CHECK(NoTempBlocksRemain(*graph));
1521  LOG(INFO) << "done making sure all temp blocks are allocated";
1522  return true;
1523}
1524
1525void DeltaDiffGenerator::CreateScratchNode(uint64_t start_block,
1526                                           uint64_t num_blocks,
1527                                           Vertex* vertex) {
1528  vertex->file_name = "<scratch>";
1529  vertex->op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
1530  vertex->op.set_data_offset(0);
1531  vertex->op.set_data_length(0);
1532  Extent* extent = vertex->op.add_dst_extents();
1533  extent->set_start_block(start_block);
1534  extent->set_num_blocks(num_blocks);
1535}
1536
1537bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
1538    const string& old_root,
1539    const string& old_image,
1540    const string& new_root,
1541    const string& new_image,
1542    const string& old_kernel_part,
1543    const string& new_kernel_part,
1544    const string& output_path,
1545    const string& private_key_path,
1546    off_t chunk_size,
1547    size_t rootfs_partition_size,
1548    const ImageInfo* old_image_info,
1549    const ImageInfo* new_image_info,
1550    uint64_t* metadata_size) {
1551  TEST_AND_RETURN_FALSE(chunk_size == -1 || chunk_size % kBlockSize == 0);
1552  int old_image_block_count = 0, old_image_block_size = 0;
1553  int new_image_block_count = 0, new_image_block_size = 0;
1554  TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(new_image,
1555                                                 &new_image_block_count,
1556                                                 &new_image_block_size));
1557  if (!old_image.empty()) {
1558    TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(old_image,
1559                                                   &old_image_block_count,
1560                                                   &old_image_block_size));
1561    TEST_AND_RETURN_FALSE(old_image_block_size == new_image_block_size);
1562    LOG_IF(WARNING, old_image_block_count != new_image_block_count)
1563        << "Old and new images have different block counts.";
1564
1565    // If new_image_info is present, old_image_info must be present.
1566    TEST_AND_RETURN_FALSE((bool)old_image_info == (bool)new_image_info);
1567  } else {
1568    // old_image_info must not be present for a full update.
1569    TEST_AND_RETURN_FALSE(!old_image_info);
1570  }
1571
1572  // Sanity checks for the partition size.
1573  TEST_AND_RETURN_FALSE(rootfs_partition_size % kBlockSize == 0);
1574  size_t fs_size = static_cast<size_t>(new_image_block_size) *
1575                   new_image_block_count;
1576  LOG(INFO) << "Rootfs partition size: " << rootfs_partition_size;
1577  LOG(INFO) << "Actual filesystem size: " << fs_size;
1578  TEST_AND_RETURN_FALSE(rootfs_partition_size >= fs_size);
1579
1580  // Sanity check kernel partition arg
1581  TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0);
1582
1583  vector<Block> blocks(max(old_image_block_count, new_image_block_count));
1584  LOG(INFO) << "Invalid block index: " << Vertex::kInvalidIndex;
1585  LOG(INFO) << "Block count: " << blocks.size();
1586  for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
1587    CHECK(blocks[i].reader == Vertex::kInvalidIndex);
1588    CHECK(blocks[i].writer == Vertex::kInvalidIndex);
1589  }
1590  Graph graph;
1591  CheckGraph(graph);
1592
1593  const string kTempFileTemplate("CrAU_temp_data.XXXXXX");
1594  string temp_file_path;
1595  scoped_ptr<ScopedPathUnlinker> temp_file_unlinker;
1596  off_t data_file_size = 0;
1597
1598  LOG(INFO) << "Reading files...";
1599
1600  // Create empty protobuf Manifest object
1601  DeltaArchiveManifest manifest;
1602
1603  vector<DeltaArchiveManifest_InstallOperation> kernel_ops;
1604
1605  vector<Vertex::Index> final_order;
1606  Vertex::Index scratch_vertex = Vertex::kInvalidIndex;
1607  {
1608    int fd;
1609    TEST_AND_RETURN_FALSE(
1610        utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd));
1611    temp_file_unlinker.reset(new ScopedPathUnlinker(temp_file_path));
1612    TEST_AND_RETURN_FALSE(fd >= 0);
1613    ScopedFdCloser fd_closer(&fd);
1614    if (!old_image.empty()) {
1615      // Delta update
1616
1617      TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph,
1618                                           &blocks,
1619                                           old_root,
1620                                           new_root,
1621                                           chunk_size,
1622                                           fd,
1623                                           &data_file_size));
1624      LOG(INFO) << "done reading normal files";
1625      CheckGraph(graph);
1626
1627      LOG(INFO) << "Starting metadata processing";
1628      TEST_AND_RETURN_FALSE(Metadata::DeltaReadMetadata(&graph,
1629                                                        &blocks,
1630                                                        old_image,
1631                                                        new_image,
1632                                                        fd,
1633                                                        &data_file_size));
1634      LOG(INFO) << "Done metadata processing";
1635      CheckGraph(graph);
1636
1637      graph.resize(graph.size() + 1);
1638      TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks,
1639                                                fd,
1640                                                &data_file_size,
1641                                                new_image,
1642                                                &graph.back()));
1643
1644      // Final scratch block (if there's space)
1645      if (blocks.size() < (rootfs_partition_size / kBlockSize)) {
1646        scratch_vertex = graph.size();
1647        graph.resize(graph.size() + 1);
1648        CreateScratchNode(blocks.size(),
1649                          (rootfs_partition_size / kBlockSize) - blocks.size(),
1650                          &graph.back());
1651      }
1652
1653      // Read kernel partition
1654      TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part,
1655                                                         new_kernel_part,
1656                                                         &kernel_ops,
1657                                                         fd,
1658                                                         &data_file_size));
1659
1660      LOG(INFO) << "done reading kernel";
1661      CheckGraph(graph);
1662
1663      LOG(INFO) << "Creating edges...";
1664      CreateEdges(&graph, blocks);
1665      LOG(INFO) << "Done creating edges";
1666      CheckGraph(graph);
1667
1668      TEST_AND_RETURN_FALSE(ConvertGraphToDag(&graph,
1669                                              new_root,
1670                                              fd,
1671                                              &data_file_size,
1672                                              &final_order,
1673                                              scratch_vertex));
1674
1675      // Set the minor version for this payload.
1676      LOG(INFO) << "Adding Delta Minor Version.";
1677      manifest.set_minor_version(DeltaPerformer::kSupportedMinorPayloadVersion);
1678    } else {
1679      // Full update
1680      off_t new_image_size =
1681          static_cast<off_t>(new_image_block_count) * new_image_block_size;
1682      TEST_AND_RETURN_FALSE(FullUpdateGenerator::Run(&graph,
1683                                                     new_kernel_part,
1684                                                     new_image,
1685                                                     new_image_size,
1686                                                     fd,
1687                                                     &data_file_size,
1688                                                     kFullUpdateChunkSize,
1689                                                     kBlockSize,
1690                                                     &kernel_ops,
1691                                                     &final_order));
1692
1693      // Set the minor version for this payload.
1694      LOG(INFO) << "Adding Full Minor Version.";
1695      manifest.set_minor_version(DeltaPerformer::kFullPayloadMinorVersion);
1696    }
1697  }
1698
1699  if (old_image_info)
1700    *(manifest.mutable_old_image_info()) = *old_image_info;
1701
1702  if (new_image_info)
1703    *(manifest.mutable_new_image_info()) = *new_image_info;
1704
1705  OperationNameMap op_name_map;
1706  CheckGraph(graph);
1707  InstallOperationsToManifest(graph,
1708                              final_order,
1709                              kernel_ops,
1710                              &manifest,
1711                              &op_name_map);
1712  CheckGraph(graph);
1713  manifest.set_block_size(kBlockSize);
1714
1715  // Reorder the data blobs with the newly ordered manifest
1716  string ordered_blobs_path;
1717  TEST_AND_RETURN_FALSE(utils::MakeTempFile(
1718      "CrAU_temp_data.ordered.XXXXXX",
1719      &ordered_blobs_path,
1720      NULL));
1721  ScopedPathUnlinker ordered_blobs_unlinker(ordered_blobs_path);
1722  TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest,
1723                                         temp_file_path,
1724                                         ordered_blobs_path));
1725  temp_file_unlinker.reset();
1726
1727  // Check that install op blobs are in order.
1728  uint64_t next_blob_offset = 0;
1729  {
1730    for (int i = 0; i < (manifest.install_operations_size() +
1731                         manifest.kernel_install_operations_size()); i++) {
1732      DeltaArchiveManifest_InstallOperation* op =
1733          i < manifest.install_operations_size() ?
1734          manifest.mutable_install_operations(i) :
1735          manifest.mutable_kernel_install_operations(
1736              i - manifest.install_operations_size());
1737      if (op->has_data_offset()) {
1738        if (op->data_offset() != next_blob_offset) {
1739          LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != "
1740                     << next_blob_offset;
1741        }
1742        next_blob_offset += op->data_length();
1743      }
1744    }
1745  }
1746
1747  // Signatures appear at the end of the blobs. Note the offset in the
1748  // manifest
1749  if (!private_key_path.empty()) {
1750    uint64_t signature_blob_length = 0;
1751    TEST_AND_RETURN_FALSE(
1752        PayloadSigner::SignatureBlobLength(vector<string>(1, private_key_path),
1753                                           &signature_blob_length));
1754    AddSignatureOp(next_blob_offset, signature_blob_length, &manifest);
1755  }
1756
1757  TEST_AND_RETURN_FALSE(InitializePartitionInfos(old_kernel_part,
1758                                                 new_kernel_part,
1759                                                 old_image,
1760                                                 new_image,
1761                                                 &manifest));
1762
1763  // Serialize protobuf
1764  string serialized_manifest;
1765
1766  CheckGraph(graph);
1767  TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
1768  CheckGraph(graph);
1769
1770  LOG(INFO) << "Writing final delta file header...";
1771  DirectFileWriter writer;
1772  TEST_AND_RETURN_FALSE_ERRNO(writer.Open(output_path.c_str(),
1773                                          O_WRONLY | O_CREAT | O_TRUNC,
1774                                          0644) == 0);
1775  ScopedFileWriterCloser writer_closer(&writer);
1776
1777  // Write header
1778  TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)));
1779
1780  // Write version number
1781  TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, kVersionNumber));
1782
1783  // Write protobuf length
1784  TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer,
1785                                               serialized_manifest.size()));
1786
1787  // Write protobuf
1788  LOG(INFO) << "Writing final delta file protobuf... "
1789            << serialized_manifest.size();
1790  TEST_AND_RETURN_FALSE(writer.Write(serialized_manifest.data(),
1791                                     serialized_manifest.size()));
1792
1793  // Append the data blobs
1794  LOG(INFO) << "Writing final delta file data blobs...";
1795  int blobs_fd = open(ordered_blobs_path.c_str(), O_RDONLY, 0);
1796  ScopedFdCloser blobs_fd_closer(&blobs_fd);
1797  TEST_AND_RETURN_FALSE(blobs_fd >= 0);
1798  for (;;) {
1799    char buf[kBlockSize];
1800    ssize_t rc = read(blobs_fd, buf, sizeof(buf));
1801    if (0 == rc) {
1802      // EOF
1803      break;
1804    }
1805    TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
1806    TEST_AND_RETURN_FALSE(writer.Write(buf, rc));
1807  }
1808
1809  // Write signature blob.
1810  if (!private_key_path.empty()) {
1811    LOG(INFO) << "Signing the update...";
1812    vector<char> signature_blob;
1813    TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(
1814        output_path,
1815        vector<string>(1, private_key_path),
1816        &signature_blob));
1817    TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0],
1818                                       signature_blob.size()));
1819  }
1820
1821  *metadata_size =
1822      strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size();
1823  ReportPayloadUsage(manifest, *metadata_size, op_name_map);
1824
1825  LOG(INFO) << "All done. Successfully created delta file with "
1826            << "metadata size = " << *metadata_size;
1827  return true;
1828}
1829
1830// Runs the bsdiff tool on two files and returns the resulting delta in
1831// 'out'. Returns true on success.
1832bool DeltaDiffGenerator::BsdiffFiles(const string& old_file,
1833                                     const string& new_file,
1834                                     vector<char>* out) {
1835  const string kPatchFile = "delta.patchXXXXXX";
1836  string patch_file_path;
1837
1838  TEST_AND_RETURN_FALSE(
1839      utils::MakeTempFile(kPatchFile, &patch_file_path, NULL));
1840
1841  vector<string> cmd;
1842  cmd.push_back(kBsdiffPath);
1843  cmd.push_back(old_file);
1844  cmd.push_back(new_file);
1845  cmd.push_back(patch_file_path);
1846
1847  int rc = 1;
1848  vector<char> patch_file;
1849  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc, NULL));
1850  TEST_AND_RETURN_FALSE(rc == 0);
1851  TEST_AND_RETURN_FALSE(utils::ReadFile(patch_file_path, out));
1852  unlink(patch_file_path.c_str());
1853  return true;
1854}
1855
1856// The |blocks| vector contains a reader and writer for each block on the
1857// filesystem that's being in-place updated. We populate the reader/writer
1858// fields of |blocks| by calling this function.
1859// For each block in |operation| that is read or written, find that block
1860// in |blocks| and set the reader/writer field to the vertex passed.
1861// |graph| is not strictly necessary, but useful for printing out
1862// error messages.
1863bool DeltaDiffGenerator::AddInstallOpToBlocksVector(
1864    const DeltaArchiveManifest_InstallOperation& operation,
1865    const Graph& graph,
1866    Vertex::Index vertex,
1867    vector<Block>* blocks) {
1868  // See if this is already present.
1869  TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0);
1870
1871  enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT };
1872  for (int field = READER; field < BLOCK_FIELD_COUNT; field++) {
1873    const int extents_size =
1874        (field == READER) ? operation.src_extents_size() :
1875        operation.dst_extents_size();
1876    const char* past_participle = (field == READER) ? "read" : "written";
1877    const google::protobuf::RepeatedPtrField<Extent>& extents =
1878        (field == READER) ? operation.src_extents() : operation.dst_extents();
1879    Vertex::Index Block::*access_type =
1880        (field == READER) ? &Block::reader : &Block::writer;
1881
1882    for (int i = 0; i < extents_size; i++) {
1883      const Extent& extent = extents.Get(i);
1884      if (extent.start_block() == kSparseHole) {
1885        // Hole in sparse file. skip
1886        continue;
1887      }
1888      for (uint64_t block = extent.start_block();
1889           block < (extent.start_block() + extent.num_blocks()); block++) {
1890        if ((*blocks)[block].*access_type != Vertex::kInvalidIndex) {
1891          LOG(FATAL) << "Block " << block << " is already "
1892                     << past_participle << " by "
1893                     << (*blocks)[block].*access_type << "("
1894                     << graph[(*blocks)[block].*access_type].file_name
1895                     << ") and also " << vertex << "("
1896                     << graph[vertex].file_name << ")";
1897        }
1898        (*blocks)[block].*access_type = vertex;
1899      }
1900    }
1901  }
1902  return true;
1903}
1904
1905void DeltaDiffGenerator::AddSignatureOp(uint64_t signature_blob_offset,
1906                                        uint64_t signature_blob_length,
1907                                        DeltaArchiveManifest* manifest) {
1908  LOG(INFO) << "Making room for signature in file";
1909  manifest->set_signatures_offset(signature_blob_offset);
1910  LOG(INFO) << "set? " << manifest->has_signatures_offset();
1911  // Add a dummy op at the end to appease older clients
1912  DeltaArchiveManifest_InstallOperation* dummy_op =
1913      manifest->add_kernel_install_operations();
1914  dummy_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
1915  dummy_op->set_data_offset(signature_blob_offset);
1916  manifest->set_signatures_offset(signature_blob_offset);
1917  dummy_op->set_data_length(signature_blob_length);
1918  manifest->set_signatures_size(signature_blob_length);
1919  Extent* dummy_extent = dummy_op->add_dst_extents();
1920  // Tell the dummy op to write this data to a big sparse hole
1921  dummy_extent->set_start_block(kSparseHole);
1922  dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
1923                               kBlockSize);
1924}
1925
1926const char* const kBsdiffPath = "bsdiff";
1927
1928};  // namespace chromeos_update_engine
1929