| Index: delta_diff_generator.cc
|
| diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
|
| index 48730a83229e0436860805f093314ad4e7330534..10f68464a15a5e6e100fc0381b156bd61871d93d 100644
|
| --- a/delta_diff_generator.cc
|
| +++ b/delta_diff_generator.cc
|
| @@ -21,6 +21,7 @@
|
| #include "update_engine/filesystem_iterator.h"
|
| #include "update_engine/graph_types.h"
|
| #include "update_engine/graph_utils.h"
|
| +#include "update_engine/payload_signer.h"
|
| #include "update_engine/subprocess.h"
|
| #include "update_engine/topological_sort.h"
|
| #include "update_engine/update_metadata.pb.h"
|
| @@ -92,7 +93,7 @@ bool AddInstallOpToBlocksVector(
|
| << graph[vertex].file_name;
|
| // See if this is already present.
|
| TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0);
|
| -
|
| +
|
| enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT };
|
| for (int field = READER; field < BLOCK_FIELD_COUNT; field++) {
|
| const int extents_size =
|
| @@ -158,13 +159,13 @@ bool DeltaReadFile(Graph* graph,
|
|
|
| TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size()));
|
| *data_file_size += data.size();
|
| -
|
| +
|
| // Now, insert into graph and blocks vector
|
| graph->resize(graph->size() + 1);
|
| graph->back().op = operation;
|
| CHECK(graph->back().op.has_type());
|
| graph->back().file_name = path;
|
| -
|
| +
|
| TEST_AND_RETURN_FALSE(AddInstallOpToBlocksVector(graph->back().op,
|
| blocks,
|
| *graph,
|
| @@ -196,7 +197,7 @@ bool DeltaReadFiles(Graph* graph,
|
| continue;
|
|
|
| LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath();
|
| -
|
| +
|
| TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
|
| blocks,
|
| old_root,
|
| @@ -298,17 +299,17 @@ bool ReadUnwrittenBlocks(const vector<Block>& blocks,
|
| FILE* file = fopen(temp_file_path.c_str(), "w");
|
| TEST_AND_RETURN_FALSE(file);
|
| int err = BZ_OK;
|
| -
|
| +
|
| BZFILE* bz_file = BZ2_bzWriteOpen(&err,
|
| file,
|
| 9, // max compression
|
| 0, // verbosity
|
| 0); // default work factor
|
| TEST_AND_RETURN_FALSE(err == BZ_OK);
|
| -
|
| +
|
| vector<Extent> extents;
|
| vector<Block>::size_type block_count = 0;
|
| -
|
| +
|
| LOG(INFO) << "Appending left over blocks to extents";
|
| for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
|
| if (blocks[i].writer != Vertex::kInvalidIndex)
|
| @@ -356,12 +357,12 @@ bool ReadUnwrittenBlocks(const vector<Block>& blocks,
|
| bz_file = NULL;
|
| TEST_AND_RETURN_FALSE_ERRNO(0 == fclose(file));
|
| file = NULL;
|
| -
|
| +
|
| vector<char> compressed_data;
|
| LOG(INFO) << "Reading compressed data off disk";
|
| TEST_AND_RETURN_FALSE(utils::ReadFile(temp_file_path, &compressed_data));
|
| TEST_AND_RETURN_FALSE(unlink(temp_file_path.c_str()) == 0);
|
| -
|
| +
|
| // Add node to graph to write these blocks
|
| out_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
|
| out_op->set_data_offset(*blobs_length);
|
| @@ -369,7 +370,7 @@ bool ReadUnwrittenBlocks(const vector<Block>& blocks,
|
| *blobs_length += compressed_data.size();
|
| out_op->set_dst_length(kBlockSize * block_count);
|
| DeltaDiffGenerator::StoreExtents(extents, out_op->mutable_dst_extents());
|
| -
|
| +
|
| TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd,
|
| &compressed_data[0],
|
| compressed_data.size()));
|
| @@ -414,7 +415,7 @@ void CheckGraph(const Graph& graph) {
|
| }
|
|
|
| // Delta compresses a kernel partition new_kernel_part with knowledge of
|
| -// the old kernel partition old_kernel_part.
|
| +// the old kernel partition old_kernel_part.
|
| bool DeltaCompressKernelPartition(
|
| const string& old_kernel_part,
|
| const string& new_kernel_part,
|
| @@ -438,12 +439,12 @@ bool DeltaCompressKernelPartition(
|
| TEST_AND_RETURN_FALSE(BsdiffFiles(old_kernel_part, new_kernel_part, &data));
|
| TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, &data[0], data.size()));
|
| *blobs_length += data.size();
|
| -
|
| +
|
| off_t old_part_size = utils::FileSize(old_kernel_part);
|
| TEST_AND_RETURN_FALSE(old_part_size >= 0);
|
| off_t new_part_size = utils::FileSize(new_kernel_part);
|
| TEST_AND_RETURN_FALSE(new_part_size >= 0);
|
| -
|
| +
|
| op->set_data_length(data.size());
|
|
|
| op->set_src_length(old_part_size);
|
| @@ -457,7 +458,7 @@ bool DeltaCompressKernelPartition(
|
| Extent* dst_extent = op->add_dst_extents();
|
| dst_extent->set_start_block(0);
|
| dst_extent->set_num_blocks((new_part_size + kBlockSize - 1) / kBlockSize);
|
| -
|
| +
|
| LOG(INFO) << "Done delta compressing kernel partition.";
|
| return true;
|
| }
|
| @@ -472,9 +473,9 @@ bool DeltaDiffGenerator::ReadFileToDiff(
|
| // Read new data in
|
| vector<char> new_data;
|
| TEST_AND_RETURN_FALSE(utils::ReadFile(new_filename, &new_data));
|
| -
|
| +
|
| TEST_AND_RETURN_FALSE(!new_data.empty());
|
| -
|
| +
|
| vector<char> new_data_bz;
|
| TEST_AND_RETURN_FALSE(BzipCompress(new_data, &new_data_bz));
|
| CHECK(!new_data_bz.empty());
|
| @@ -516,15 +517,15 @@ bool DeltaDiffGenerator::ReadFileToDiff(
|
| if (bsdiff_delta.size() < current_best_size) {
|
| operation.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
|
| current_best_size = bsdiff_delta.size();
|
| -
|
| +
|
| data = bsdiff_delta;
|
| }
|
| }
|
| }
|
| -
|
| +
|
| // Set parameters of the operations
|
| CHECK_EQ(data.size(), current_best_size);
|
| -
|
| +
|
| if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE ||
|
| operation.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
|
| TEST_AND_RETURN_FALSE(
|
| @@ -535,10 +536,10 @@ bool DeltaDiffGenerator::ReadFileToDiff(
|
| TEST_AND_RETURN_FALSE(
|
| GatherExtents(new_filename, operation.mutable_dst_extents()));
|
| operation.set_dst_length(new_data.size());
|
| -
|
| +
|
| out_data->swap(data);
|
| *out_op = operation;
|
| -
|
| +
|
| return true;
|
| }
|
|
|
| @@ -613,7 +614,7 @@ bool DeltaDiffGenerator::CutEdges(Graph* graph,
|
| TEST_AND_RETURN_FALSE(
|
| FindScratchSpace(blocks, blocks_required, &scratch_extents));
|
| LinearExtentAllocator scratch_allocator(scratch_extents);
|
| -
|
| +
|
| uint64_t scratch_blocks_used = 0;
|
| for (set<Edge>::const_iterator it = edges.begin();
|
| it != edges.end(); ++it) {
|
| @@ -628,7 +629,7 @@ bool DeltaDiffGenerator::CutEdges(Graph* graph,
|
| scratch_allocator.Allocate(graph_utils::EdgeWeight(*graph, *it));
|
| // create vertex to copy original->scratch
|
| graph->resize(graph->size() + 1);
|
| -
|
| +
|
| // make node depend on the copy operation
|
| (*graph)[it->first].out_edges.insert(make_pair(graph->size() - 1,
|
| EdgeProperties()));
|
| @@ -743,9 +744,10 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| const string& old_image,
|
| const string& new_root,
|
| const string& new_image,
|
| - const std::string& old_kernel_part,
|
| - const std::string& new_kernel_part,
|
| - const string& output_path) {
|
| + const string& old_kernel_part,
|
| + const string& new_kernel_part,
|
| + const string& output_path,
|
| + const string& private_key_path) {
|
| struct stat old_image_stbuf;
|
| TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0);
|
| struct stat new_image_stbuf;
|
| @@ -771,7 +773,7 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| }
|
| Graph graph;
|
| CheckGraph(graph);
|
| -
|
| +
|
| const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX");
|
| string temp_file_path;
|
| off_t data_file_size = 0;
|
| @@ -787,7 +789,7 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd));
|
| TEST_AND_RETURN_FALSE(fd >= 0);
|
| ScopedFdCloser fd_closer(&fd);
|
| -
|
| +
|
| TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph,
|
| &blocks,
|
| old_root,
|
| @@ -795,12 +797,12 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| fd,
|
| &data_file_size));
|
| CheckGraph(graph);
|
| -
|
| +
|
| TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks,
|
| fd,
|
| &data_file_size,
|
| new_image,
|
| - &final_op));
|
| + &final_op));
|
|
|
| // Read kernel partition
|
| TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part,
|
| @@ -810,11 +812,11 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| &data_file_size));
|
| }
|
| CheckGraph(graph);
|
| -
|
| +
|
| LOG(INFO) << "Creating edges...";
|
| CreateEdges(&graph, blocks);
|
| CheckGraph(graph);
|
| -
|
| +
|
| CycleBreaker cycle_breaker;
|
| LOG(INFO) << "Finding cycles...";
|
| set<Edge> cut_edges;
|
| @@ -831,7 +833,7 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| LOG(INFO) << "Ordering...";
|
| TopologicalSort(graph, &final_order);
|
| CheckGraph(graph);
|
| -
|
| +
|
| // Convert to protobuf Manifest object
|
| DeltaArchiveManifest manifest;
|
| CheckGraph(graph);
|
| @@ -844,7 +846,7 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| CHECK(op->has_type());
|
| LOG(INFO) << "final op length: " << op->data_length();
|
| }
|
| -
|
| +
|
| CheckGraph(graph);
|
| manifest.set_block_size(kBlockSize);
|
|
|
| @@ -859,29 +861,29 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| ordered_blobs_path));
|
|
|
| // Check that install op blobs are in order and that all blocks are written.
|
| + uint64_t next_blob_offset = 0;
|
| {
|
| vector<uint32_t> written_count(blocks.size(), 0);
|
| - uint64_t next_blob_offset = 0;
|
| for (int i = 0; i < (manifest.install_operations_size() +
|
| manifest.kernel_install_operations_size()); i++) {
|
| - const DeltaArchiveManifest_InstallOperation& op =
|
| + DeltaArchiveManifest_InstallOperation* op =
|
| i < manifest.install_operations_size() ?
|
| - manifest.install_operations(i) :
|
| - manifest.kernel_install_operations(
|
| + manifest.mutable_install_operations(i) :
|
| + manifest.mutable_kernel_install_operations(
|
| i - manifest.install_operations_size());
|
| - for (int j = 0; j < op.dst_extents_size(); j++) {
|
| - const Extent& extent = op.dst_extents(j);
|
| + for (int j = 0; j < op->dst_extents_size(); j++) {
|
| + const Extent& extent = op->dst_extents(j);
|
| for (uint64_t block = extent.start_block();
|
| block < (extent.start_block() + extent.num_blocks()); block++) {
|
| written_count[block]++;
|
| }
|
| }
|
| - if (op.has_data_offset()) {
|
| - if (op.data_offset() != next_blob_offset) {
|
| - LOG(FATAL) << "bad blob offset! " << op.data_offset() << " != "
|
| + if (op->has_data_offset()) {
|
| + if (op->data_offset() != next_blob_offset) {
|
| + LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != "
|
| << next_blob_offset;
|
| }
|
| - next_blob_offset += op.data_length();
|
| + next_blob_offset += op->data_length();
|
| }
|
| }
|
| // check all blocks written to
|
| @@ -892,9 +894,34 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| }
|
| }
|
|
|
| + // Signatures appear at the end of the blobs. Note the offset in the
|
| + // manifest
|
| + if (!private_key_path.empty()) {
|
| + LOG(INFO) << "Making room for signature in file";
|
| + manifest.set_signatures_offset(next_blob_offset);
|
| + LOG(INFO) << "set? " << manifest.has_signatures_offset();
|
| + // Add a dummy op at the end to appease older clients
|
| + DeltaArchiveManifest_InstallOperation* dummy_op =
|
| + manifest.add_kernel_install_operations();
|
| + dummy_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
|
| + dummy_op->set_data_offset(next_blob_offset);
|
| + manifest.set_signatures_offset(next_blob_offset);
|
| + uint64_t signature_blob_length = 0;
|
| + TEST_AND_RETURN_FALSE(
|
| + PayloadSigner::SignatureBlobLength(private_key_path,
|
| + &signature_blob_length));
|
| + dummy_op->set_data_length(signature_blob_length);
|
| + manifest.set_signatures_size(signature_blob_length);
|
| + Extent* dummy_extent = dummy_op->add_dst_extents();
|
| + // Tell the dummy op to write this data to a big sparse hole
|
| + dummy_extent->set_start_block(kSparseHole);
|
| + dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
|
| + kBlockSize);
|
| + }
|
| +
|
| // Serialize protobuf
|
| string serialized_manifest;
|
| -
|
| +
|
| CheckGraph(graph);
|
| TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
|
| CheckGraph(graph);
|
| @@ -905,25 +932,25 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| O_WRONLY | O_CREAT | O_TRUNC,
|
| 0644) == 0);
|
| ScopedFileWriterCloser writer_closer(&writer);
|
| -
|
| +
|
| // Write header
|
| TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)) ==
|
| static_cast<ssize_t>(strlen(kDeltaMagic)));
|
| -
|
| +
|
| // Write version number
|
| TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, kVersionNumber));
|
| -
|
| +
|
| // Write protobuf length
|
| TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer,
|
| serialized_manifest.size()));
|
| -
|
| +
|
| // Write protobuf
|
| LOG(INFO) << "Writing final delta file protobuf... "
|
| << serialized_manifest.size();
|
| TEST_AND_RETURN_FALSE(writer.Write(serialized_manifest.data(),
|
| serialized_manifest.size()) ==
|
| static_cast<ssize_t>(serialized_manifest.size()));
|
| -
|
| +
|
| // Append the data blobs
|
| LOG(INFO) << "Writing final delta file data blobs...";
|
| int blobs_fd = open(ordered_blobs_path.c_str(), O_RDONLY, 0);
|
| @@ -939,7 +966,19 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
|
| TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
|
| TEST_AND_RETURN_FALSE(writer.Write(buf, rc) == rc);
|
| }
|
| -
|
| +
|
| + // Write signature blob.
|
| + if (!private_key_path.empty()) {
|
| + LOG(INFO) << "Signing the update...";
|
| + vector<char> signature_blob;
|
| + TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path,
|
| + private_key_path,
|
| + &signature_blob));
|
| + TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0],
|
| + signature_blob.size()) ==
|
| + static_cast<ssize_t>(signature_blob.size()));
|
| + }
|
| +
|
| LOG(INFO) << "All done. Successfully created delta file.";
|
| return true;
|
| }
|
|
|