Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: delta_diff_generator.cc

Issue 3132033: AU: Sign delta payloads (Closed) Base URL: ssh://git@chromiumos-git/update_engine.git
Patch Set: fixes for review Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « delta_diff_generator.h ('k') | delta_performer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "update_engine/delta_diff_generator.h" 5 #include "update_engine/delta_diff_generator.h"
6 #include <sys/stat.h> 6 #include <sys/stat.h>
7 #include <sys/types.h> 7 #include <sys/types.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <fcntl.h> 9 #include <fcntl.h>
10 #include <algorithm> 10 #include <algorithm>
11 #include <set> 11 #include <set>
12 #include <string> 12 #include <string>
13 #include <utility> 13 #include <utility>
14 #include <vector> 14 #include <vector>
15 #include <bzlib.h> 15 #include <bzlib.h>
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "update_engine/bzip.h" 17 #include "update_engine/bzip.h"
18 #include "update_engine/cycle_breaker.h" 18 #include "update_engine/cycle_breaker.h"
19 #include "update_engine/extent_mapper.h" 19 #include "update_engine/extent_mapper.h"
20 #include "update_engine/file_writer.h" 20 #include "update_engine/file_writer.h"
21 #include "update_engine/filesystem_iterator.h" 21 #include "update_engine/filesystem_iterator.h"
22 #include "update_engine/graph_types.h" 22 #include "update_engine/graph_types.h"
23 #include "update_engine/graph_utils.h" 23 #include "update_engine/graph_utils.h"
24 #include "update_engine/payload_signer.h"
24 #include "update_engine/subprocess.h" 25 #include "update_engine/subprocess.h"
25 #include "update_engine/topological_sort.h" 26 #include "update_engine/topological_sort.h"
26 #include "update_engine/update_metadata.pb.h" 27 #include "update_engine/update_metadata.pb.h"
27 #include "update_engine/utils.h" 28 #include "update_engine/utils.h"
28 29
29 using std::make_pair; 30 using std::make_pair;
30 using std::max; 31 using std::max;
31 using std::min; 32 using std::min;
32 using std::set; 33 using std::set;
33 using std::string; 34 using std::string;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 // error messages. 86 // error messages.
86 bool AddInstallOpToBlocksVector( 87 bool AddInstallOpToBlocksVector(
87 const DeltaArchiveManifest_InstallOperation& operation, 88 const DeltaArchiveManifest_InstallOperation& operation,
88 vector<Block>* blocks, 89 vector<Block>* blocks,
89 const Graph& graph, 90 const Graph& graph,
90 Vertex::Index vertex) { 91 Vertex::Index vertex) {
91 LOG(INFO) << "AddInstallOpToBlocksVector(" << vertex << "), " 92 LOG(INFO) << "AddInstallOpToBlocksVector(" << vertex << "), "
92 << graph[vertex].file_name; 93 << graph[vertex].file_name;
93 // See if this is already present. 94 // See if this is already present.
94 TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0); 95 TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0);
95 96
96 enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT }; 97 enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT };
97 for (int field = READER; field < BLOCK_FIELD_COUNT; field++) { 98 for (int field = READER; field < BLOCK_FIELD_COUNT; field++) {
98 const int extents_size = 99 const int extents_size =
99 (field == READER) ? operation.src_extents_size() : 100 (field == READER) ? operation.src_extents_size() :
100 operation.dst_extents_size(); 101 operation.dst_extents_size();
101 const char* past_participle = (field == READER) ? "read" : "written"; 102 const char* past_participle = (field == READER) ? "read" : "written";
102 const google::protobuf::RepeatedPtrField<Extent>& extents = 103 const google::protobuf::RepeatedPtrField<Extent>& extents =
103 (field == READER) ? operation.src_extents() : operation.dst_extents(); 104 (field == READER) ? operation.src_extents() : operation.dst_extents();
104 Vertex::Index Block::*access_type = 105 Vertex::Index Block::*access_type =
105 (field == READER) ? &Block::reader : &Block::writer; 106 (field == READER) ? &Block::reader : &Block::writer;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 &operation)); 152 &operation));
152 153
153 // Write the data 154 // Write the data
154 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) { 155 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) {
155 operation.set_data_offset(*data_file_size); 156 operation.set_data_offset(*data_file_size);
156 operation.set_data_length(data.size()); 157 operation.set_data_length(data.size());
157 } 158 }
158 159
159 TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size())); 160 TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size()));
160 *data_file_size += data.size(); 161 *data_file_size += data.size();
161 162
162 // Now, insert into graph and blocks vector 163 // Now, insert into graph and blocks vector
163 graph->resize(graph->size() + 1); 164 graph->resize(graph->size() + 1);
164 graph->back().op = operation; 165 graph->back().op = operation;
165 CHECK(graph->back().op.has_type()); 166 CHECK(graph->back().op.has_type());
166 graph->back().file_name = path; 167 graph->back().file_name = path;
167 168
168 TEST_AND_RETURN_FALSE(AddInstallOpToBlocksVector(graph->back().op, 169 TEST_AND_RETURN_FALSE(AddInstallOpToBlocksVector(graph->back().op,
169 blocks, 170 blocks,
170 *graph, 171 *graph,
171 graph->size() - 1)); 172 graph->size() - 1));
172 return true; 173 return true;
173 } 174 }
174 175
175 // For each regular file within new_root, creates a node in the graph, 176 // For each regular file within new_root, creates a node in the graph,
176 // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF), 177 // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF),
177 // and writes any necessary data to the end of data_fd. 178 // and writes any necessary data to the end of data_fd.
(...skipping 11 matching lines...) Expand all
189 continue; 190 continue;
190 191
191 // Make sure we visit each inode only once. 192 // Make sure we visit each inode only once.
192 if (utils::SetContainsKey(visited_inodes, fs_iter.GetStat().st_ino)) 193 if (utils::SetContainsKey(visited_inodes, fs_iter.GetStat().st_ino))
193 continue; 194 continue;
194 visited_inodes.insert(fs_iter.GetStat().st_ino); 195 visited_inodes.insert(fs_iter.GetStat().st_ino);
195 if (fs_iter.GetStat().st_size == 0) 196 if (fs_iter.GetStat().st_size == 0)
196 continue; 197 continue;
197 198
198 LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath(); 199 LOG(INFO) << "Encoding file " << fs_iter.GetPartialPath();
199 200
200 TEST_AND_RETURN_FALSE(DeltaReadFile(graph, 201 TEST_AND_RETURN_FALSE(DeltaReadFile(graph,
201 blocks, 202 blocks,
202 old_root, 203 old_root,
203 new_root, 204 new_root,
204 fs_iter.GetPartialPath(), 205 fs_iter.GetPartialPath(),
205 data_fd, 206 data_fd,
206 data_file_size)); 207 data_file_size));
207 } 208 }
208 return true; 209 return true;
209 } 210 }
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 ScopedFdCloser image_fd_closer(&image_fd); 292 ScopedFdCloser image_fd_closer(&image_fd);
292 293
293 string temp_file_path; 294 string temp_file_path;
294 TEST_AND_RETURN_FALSE(utils::MakeTempFile("/tmp/CrAU_temp_data.XXXXXX", 295 TEST_AND_RETURN_FALSE(utils::MakeTempFile("/tmp/CrAU_temp_data.XXXXXX",
295 &temp_file_path, 296 &temp_file_path,
296 NULL)); 297 NULL));
297 298
298 FILE* file = fopen(temp_file_path.c_str(), "w"); 299 FILE* file = fopen(temp_file_path.c_str(), "w");
299 TEST_AND_RETURN_FALSE(file); 300 TEST_AND_RETURN_FALSE(file);
300 int err = BZ_OK; 301 int err = BZ_OK;
301 302
302 BZFILE* bz_file = BZ2_bzWriteOpen(&err, 303 BZFILE* bz_file = BZ2_bzWriteOpen(&err,
303 file, 304 file,
304 9, // max compression 305 9, // max compression
305 0, // verbosity 306 0, // verbosity
306 0); // default work factor 307 0); // default work factor
307 TEST_AND_RETURN_FALSE(err == BZ_OK); 308 TEST_AND_RETURN_FALSE(err == BZ_OK);
308 309
309 vector<Extent> extents; 310 vector<Extent> extents;
310 vector<Block>::size_type block_count = 0; 311 vector<Block>::size_type block_count = 0;
311 312
312 LOG(INFO) << "Appending left over blocks to extents"; 313 LOG(INFO) << "Appending left over blocks to extents";
313 for (vector<Block>::size_type i = 0; i < blocks.size(); i++) { 314 for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
314 if (blocks[i].writer != Vertex::kInvalidIndex) 315 if (blocks[i].writer != Vertex::kInvalidIndex)
315 continue; 316 continue;
316 graph_utils::AppendBlockToExtents(&extents, i); 317 graph_utils::AppendBlockToExtents(&extents, i);
317 block_count++; 318 block_count++;
318 } 319 }
319 320
320 // Code will handle 'buf' at any size that's a multiple of kBlockSize, 321 // Code will handle 'buf' at any size that's a multiple of kBlockSize,
321 // so we arbitrarily set it to 1024 * kBlockSize. 322 // so we arbitrarily set it to 1024 * kBlockSize.
(...skipping 27 matching lines...) Expand all
349 blocks_read += copy_block_cnt; 350 blocks_read += copy_block_cnt;
350 blocks_copied_count += copy_block_cnt; 351 blocks_copied_count += copy_block_cnt;
351 LOG(INFO) << "progress: " << ((float)blocks_copied_count)/block_count; 352 LOG(INFO) << "progress: " << ((float)blocks_copied_count)/block_count;
352 } 353 }
353 } 354 }
354 BZ2_bzWriteClose(&err, bz_file, 0, NULL, NULL); 355 BZ2_bzWriteClose(&err, bz_file, 0, NULL, NULL);
355 TEST_AND_RETURN_FALSE(err == BZ_OK); 356 TEST_AND_RETURN_FALSE(err == BZ_OK);
356 bz_file = NULL; 357 bz_file = NULL;
357 TEST_AND_RETURN_FALSE_ERRNO(0 == fclose(file)); 358 TEST_AND_RETURN_FALSE_ERRNO(0 == fclose(file));
358 file = NULL; 359 file = NULL;
359 360
360 vector<char> compressed_data; 361 vector<char> compressed_data;
361 LOG(INFO) << "Reading compressed data off disk"; 362 LOG(INFO) << "Reading compressed data off disk";
362 TEST_AND_RETURN_FALSE(utils::ReadFile(temp_file_path, &compressed_data)); 363 TEST_AND_RETURN_FALSE(utils::ReadFile(temp_file_path, &compressed_data));
363 TEST_AND_RETURN_FALSE(unlink(temp_file_path.c_str()) == 0); 364 TEST_AND_RETURN_FALSE(unlink(temp_file_path.c_str()) == 0);
364 365
365 // Add node to graph to write these blocks 366 // Add node to graph to write these blocks
366 out_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); 367 out_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
367 out_op->set_data_offset(*blobs_length); 368 out_op->set_data_offset(*blobs_length);
368 out_op->set_data_length(compressed_data.size()); 369 out_op->set_data_length(compressed_data.size());
369 *blobs_length += compressed_data.size(); 370 *blobs_length += compressed_data.size();
370 out_op->set_dst_length(kBlockSize * block_count); 371 out_op->set_dst_length(kBlockSize * block_count);
371 DeltaDiffGenerator::StoreExtents(extents, out_op->mutable_dst_extents()); 372 DeltaDiffGenerator::StoreExtents(extents, out_op->mutable_dst_extents());
372 373
373 TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, 374 TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd,
374 &compressed_data[0], 375 &compressed_data[0],
375 compressed_data.size())); 376 compressed_data.size()));
376 LOG(INFO) << "done with extra blocks"; 377 LOG(INFO) << "done with extra blocks";
377 return true; 378 return true;
378 } 379 }
379 380
380 // Writes the uint64_t passed in in host-endian to the file as big-endian. 381 // Writes the uint64_t passed in in host-endian to the file as big-endian.
381 // Returns true on success. 382 // Returns true on success.
382 bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) { 383 bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) {
(...skipping 24 matching lines...) Expand all
407 } 408 }
408 } 409 }
409 410
410 void CheckGraph(const Graph& graph) { 411 void CheckGraph(const Graph& graph) {
411 for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) { 412 for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) {
412 CHECK(it->op.has_type()); 413 CHECK(it->op.has_type());
413 } 414 }
414 } 415 }
415 416
416 // Delta compresses a kernel partition new_kernel_part with knowledge of 417 // Delta compresses a kernel partition new_kernel_part with knowledge of
417 // the old kernel partition old_kernel_part. 418 // the old kernel partition old_kernel_part.
418 bool DeltaCompressKernelPartition( 419 bool DeltaCompressKernelPartition(
419 const string& old_kernel_part, 420 const string& old_kernel_part,
420 const string& new_kernel_part, 421 const string& new_kernel_part,
421 vector<DeltaArchiveManifest_InstallOperation>* ops, 422 vector<DeltaArchiveManifest_InstallOperation>* ops,
422 int blobs_fd, 423 int blobs_fd,
423 off_t* blobs_length) { 424 off_t* blobs_length) {
424 // For now, just bsdiff the kernel partition as a whole. 425 // For now, just bsdiff the kernel partition as a whole.
425 // TODO(adlr): Use knowledge of how the kernel partition is laid out 426 // TODO(adlr): Use knowledge of how the kernel partition is laid out
426 // to more efficiently compress it. 427 // to more efficiently compress it.
427 428
428 LOG(INFO) << "Delta compressing kernel partition..."; 429 LOG(INFO) << "Delta compressing kernel partition...";
429 430
430 // Add a new install operation 431 // Add a new install operation
431 ops->resize(1); 432 ops->resize(1);
432 DeltaArchiveManifest_InstallOperation* op = &(*ops)[0]; 433 DeltaArchiveManifest_InstallOperation* op = &(*ops)[0];
433 op->set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF); 434 op->set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
434 op->set_data_offset(*blobs_length); 435 op->set_data_offset(*blobs_length);
435 436
436 // Do the actual compression 437 // Do the actual compression
437 vector<char> data; 438 vector<char> data;
438 TEST_AND_RETURN_FALSE(BsdiffFiles(old_kernel_part, new_kernel_part, &data)); 439 TEST_AND_RETURN_FALSE(BsdiffFiles(old_kernel_part, new_kernel_part, &data));
439 TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, &data[0], data.size())); 440 TEST_AND_RETURN_FALSE(utils::WriteAll(blobs_fd, &data[0], data.size()));
440 *blobs_length += data.size(); 441 *blobs_length += data.size();
441 442
442 off_t old_part_size = utils::FileSize(old_kernel_part); 443 off_t old_part_size = utils::FileSize(old_kernel_part);
443 TEST_AND_RETURN_FALSE(old_part_size >= 0); 444 TEST_AND_RETURN_FALSE(old_part_size >= 0);
444 off_t new_part_size = utils::FileSize(new_kernel_part); 445 off_t new_part_size = utils::FileSize(new_kernel_part);
445 TEST_AND_RETURN_FALSE(new_part_size >= 0); 446 TEST_AND_RETURN_FALSE(new_part_size >= 0);
446 447
447 op->set_data_length(data.size()); 448 op->set_data_length(data.size());
448 449
449 op->set_src_length(old_part_size); 450 op->set_src_length(old_part_size);
450 op->set_dst_length(new_part_size); 451 op->set_dst_length(new_part_size);
451 452
452 // Theres a single src/dest extent for each 453 // Theres a single src/dest extent for each
453 Extent* src_extent = op->add_src_extents(); 454 Extent* src_extent = op->add_src_extents();
454 src_extent->set_start_block(0); 455 src_extent->set_start_block(0);
455 src_extent->set_num_blocks((old_part_size + kBlockSize - 1) / kBlockSize); 456 src_extent->set_num_blocks((old_part_size + kBlockSize - 1) / kBlockSize);
456 457
457 Extent* dst_extent = op->add_dst_extents(); 458 Extent* dst_extent = op->add_dst_extents();
458 dst_extent->set_start_block(0); 459 dst_extent->set_start_block(0);
459 dst_extent->set_num_blocks((new_part_size + kBlockSize - 1) / kBlockSize); 460 dst_extent->set_num_blocks((new_part_size + kBlockSize - 1) / kBlockSize);
460 461
461 LOG(INFO) << "Done delta compressing kernel partition."; 462 LOG(INFO) << "Done delta compressing kernel partition.";
462 return true; 463 return true;
463 } 464 }
464 465
465 } // namespace {} 466 } // namespace {}
466 467
467 bool DeltaDiffGenerator::ReadFileToDiff( 468 bool DeltaDiffGenerator::ReadFileToDiff(
468 const string& old_filename, 469 const string& old_filename,
469 const string& new_filename, 470 const string& new_filename,
470 vector<char>* out_data, 471 vector<char>* out_data,
471 DeltaArchiveManifest_InstallOperation* out_op) { 472 DeltaArchiveManifest_InstallOperation* out_op) {
472 // Read new data in 473 // Read new data in
473 vector<char> new_data; 474 vector<char> new_data;
474 TEST_AND_RETURN_FALSE(utils::ReadFile(new_filename, &new_data)); 475 TEST_AND_RETURN_FALSE(utils::ReadFile(new_filename, &new_data));
475 476
476 TEST_AND_RETURN_FALSE(!new_data.empty()); 477 TEST_AND_RETURN_FALSE(!new_data.empty());
477 478
478 vector<char> new_data_bz; 479 vector<char> new_data_bz;
479 TEST_AND_RETURN_FALSE(BzipCompress(new_data, &new_data_bz)); 480 TEST_AND_RETURN_FALSE(BzipCompress(new_data, &new_data_bz));
480 CHECK(!new_data_bz.empty()); 481 CHECK(!new_data_bz.empty());
481 482
482 vector<char> data; // Data blob that will be written to delta file. 483 vector<char> data; // Data blob that will be written to delta file.
483 484
484 DeltaArchiveManifest_InstallOperation operation; 485 DeltaArchiveManifest_InstallOperation operation;
485 size_t current_best_size = 0; 486 size_t current_best_size = 0;
486 if (new_data.size() <= new_data_bz.size()) { 487 if (new_data.size() <= new_data_bz.size()) {
487 operation.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE); 488 operation.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
(...skipping 21 matching lines...) Expand all
509 data.clear(); 510 data.clear();
510 } else { 511 } else {
511 // Try bsdiff of old to new data 512 // Try bsdiff of old to new data
512 vector<char> bsdiff_delta; 513 vector<char> bsdiff_delta;
513 TEST_AND_RETURN_FALSE( 514 TEST_AND_RETURN_FALSE(
514 BsdiffFiles(old_filename, new_filename, &bsdiff_delta)); 515 BsdiffFiles(old_filename, new_filename, &bsdiff_delta));
515 CHECK_GT(bsdiff_delta.size(), 0); 516 CHECK_GT(bsdiff_delta.size(), 0);
516 if (bsdiff_delta.size() < current_best_size) { 517 if (bsdiff_delta.size() < current_best_size) {
517 operation.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF); 518 operation.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF);
518 current_best_size = bsdiff_delta.size(); 519 current_best_size = bsdiff_delta.size();
519 520
520 data = bsdiff_delta; 521 data = bsdiff_delta;
521 } 522 }
522 } 523 }
523 } 524 }
524 525
525 // Set parameters of the operations 526 // Set parameters of the operations
526 CHECK_EQ(data.size(), current_best_size); 527 CHECK_EQ(data.size(), current_best_size);
527 528
528 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE || 529 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE ||
529 operation.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) { 530 operation.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
530 TEST_AND_RETURN_FALSE( 531 TEST_AND_RETURN_FALSE(
531 GatherExtents(old_filename, operation.mutable_src_extents())); 532 GatherExtents(old_filename, operation.mutable_src_extents()));
532 operation.set_src_length(old_stbuf.st_size); 533 operation.set_src_length(old_stbuf.st_size);
533 } 534 }
534 535
535 TEST_AND_RETURN_FALSE( 536 TEST_AND_RETURN_FALSE(
536 GatherExtents(new_filename, operation.mutable_dst_extents())); 537 GatherExtents(new_filename, operation.mutable_dst_extents()));
537 operation.set_dst_length(new_data.size()); 538 operation.set_dst_length(new_data.size());
538 539
539 out_data->swap(data); 540 out_data->swap(data);
540 *out_op = operation; 541 *out_op = operation;
541 542
542 return true; 543 return true;
543 } 544 }
544 545
545 void DeltaDiffGenerator::SubstituteBlocks( 546 void DeltaDiffGenerator::SubstituteBlocks(
546 DeltaArchiveManifest_InstallOperation* op, 547 DeltaArchiveManifest_InstallOperation* op,
547 const vector<Extent>& remove_extents, 548 const vector<Extent>& remove_extents,
548 const vector<Extent>& replace_extents) { 549 const vector<Extent>& replace_extents) {
549 // First, expand out the blocks that op reads from 550 // First, expand out the blocks that op reads from
550 vector<uint64_t> read_blocks; 551 vector<uint64_t> read_blocks;
551 for (int i = 0; i < op->src_extents_size(); i++) { 552 for (int i = 0; i < op->src_extents_size(); i++) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 // First, find enough scratch space for the edges we'll be cutting. 607 // First, find enough scratch space for the edges we'll be cutting.
607 vector<Block>::size_type blocks_required = 0; 608 vector<Block>::size_type blocks_required = 0;
608 for (set<Edge>::const_iterator it = edges.begin(); it != edges.end(); ++it) { 609 for (set<Edge>::const_iterator it = edges.begin(); it != edges.end(); ++it) {
609 blocks_required += graph_utils::EdgeWeight(*graph, *it); 610 blocks_required += graph_utils::EdgeWeight(*graph, *it);
610 } 611 }
611 vector<Extent> scratch_extents; 612 vector<Extent> scratch_extents;
612 LOG(INFO) << "requesting " << blocks_required << " blocks of scratch"; 613 LOG(INFO) << "requesting " << blocks_required << " blocks of scratch";
613 TEST_AND_RETURN_FALSE( 614 TEST_AND_RETURN_FALSE(
614 FindScratchSpace(blocks, blocks_required, &scratch_extents)); 615 FindScratchSpace(blocks, blocks_required, &scratch_extents));
615 LinearExtentAllocator scratch_allocator(scratch_extents); 616 LinearExtentAllocator scratch_allocator(scratch_extents);
616 617
617 uint64_t scratch_blocks_used = 0; 618 uint64_t scratch_blocks_used = 0;
618 for (set<Edge>::const_iterator it = edges.begin(); 619 for (set<Edge>::const_iterator it = edges.begin();
619 it != edges.end(); ++it) { 620 it != edges.end(); ++it) {
620 vector<Extent> old_extents = 621 vector<Extent> old_extents =
621 (*graph)[it->first].out_edges[it->second].extents; 622 (*graph)[it->first].out_edges[it->second].extents;
622 // Choose some scratch space 623 // Choose some scratch space
623 scratch_blocks_used += graph_utils::EdgeWeight(*graph, *it); 624 scratch_blocks_used += graph_utils::EdgeWeight(*graph, *it);
624 LOG(INFO) << "using " << graph_utils::EdgeWeight(*graph, *it) 625 LOG(INFO) << "using " << graph_utils::EdgeWeight(*graph, *it)
625 << " scratch blocks (" 626 << " scratch blocks ("
626 << scratch_blocks_used << ")"; 627 << scratch_blocks_used << ")";
627 vector<Extent> scratch = 628 vector<Extent> scratch =
628 scratch_allocator.Allocate(graph_utils::EdgeWeight(*graph, *it)); 629 scratch_allocator.Allocate(graph_utils::EdgeWeight(*graph, *it));
629 // create vertex to copy original->scratch 630 // create vertex to copy original->scratch
630 graph->resize(graph->size() + 1); 631 graph->resize(graph->size() + 1);
631 632
632 // make node depend on the copy operation 633 // make node depend on the copy operation
633 (*graph)[it->first].out_edges.insert(make_pair(graph->size() - 1, 634 (*graph)[it->first].out_edges.insert(make_pair(graph->size() - 1,
634 EdgeProperties())); 635 EdgeProperties()));
635 636
636 // Set src/dst extents and other proto variables for copy operation 637 // Set src/dst extents and other proto variables for copy operation
637 graph->back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); 638 graph->back().op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE);
638 DeltaDiffGenerator::StoreExtents( 639 DeltaDiffGenerator::StoreExtents(
639 (*graph)[it->first].out_edges[it->second].extents, 640 (*graph)[it->first].out_edges[it->second].extents,
640 graph->back().op.mutable_src_extents()); 641 graph->back().op.mutable_src_extents());
641 DeltaDiffGenerator::StoreExtents(scratch, 642 DeltaDiffGenerator::StoreExtents(scratch,
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 out_file_size += buf.size(); 737 out_file_size += buf.size();
737 } 738 }
738 return true; 739 return true;
739 } 740 }
740 741
741 bool DeltaDiffGenerator::GenerateDeltaUpdateFile( 742 bool DeltaDiffGenerator::GenerateDeltaUpdateFile(
742 const string& old_root, 743 const string& old_root,
743 const string& old_image, 744 const string& old_image,
744 const string& new_root, 745 const string& new_root,
745 const string& new_image, 746 const string& new_image,
746 const std::string& old_kernel_part, 747 const string& old_kernel_part,
747 const std::string& new_kernel_part, 748 const string& new_kernel_part,
748 const string& output_path) { 749 const string& output_path,
750 const string& private_key_path) {
749 struct stat old_image_stbuf; 751 struct stat old_image_stbuf;
750 TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0); 752 TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0);
751 struct stat new_image_stbuf; 753 struct stat new_image_stbuf;
752 TEST_AND_RETURN_FALSE_ERRNO(stat(new_image.c_str(), &new_image_stbuf) == 0); 754 TEST_AND_RETURN_FALSE_ERRNO(stat(new_image.c_str(), &new_image_stbuf) == 0);
753 LOG_IF(WARNING, new_image_stbuf.st_size != old_image_stbuf.st_size) 755 LOG_IF(WARNING, new_image_stbuf.st_size != old_image_stbuf.st_size)
754 << "Old and new images are different sizes."; 756 << "Old and new images are different sizes.";
755 LOG_IF(FATAL, new_image_stbuf.st_size % kBlockSize) 757 LOG_IF(FATAL, new_image_stbuf.st_size % kBlockSize)
756 << "New image not a multiple of block size " << kBlockSize; 758 << "New image not a multiple of block size " << kBlockSize;
757 LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize) 759 LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize)
758 << "Old image not a multiple of block size " << kBlockSize; 760 << "Old image not a multiple of block size " << kBlockSize;
759 761
760 // Sanity check kernel partition args 762 // Sanity check kernel partition args
761 TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0); 763 TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0);
762 TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0); 764 TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0);
763 765
764 vector<Block> blocks(max(old_image_stbuf.st_size / kBlockSize, 766 vector<Block> blocks(max(old_image_stbuf.st_size / kBlockSize,
765 new_image_stbuf.st_size / kBlockSize)); 767 new_image_stbuf.st_size / kBlockSize));
766 LOG(INFO) << "invalid: " << Vertex::kInvalidIndex; 768 LOG(INFO) << "invalid: " << Vertex::kInvalidIndex;
767 LOG(INFO) << "len: " << blocks.size(); 769 LOG(INFO) << "len: " << blocks.size();
768 for (vector<Block>::size_type i = 0; i < blocks.size(); i++) { 770 for (vector<Block>::size_type i = 0; i < blocks.size(); i++) {
769 CHECK(blocks[i].reader == Vertex::kInvalidIndex); 771 CHECK(blocks[i].reader == Vertex::kInvalidIndex);
770 CHECK(blocks[i].writer == Vertex::kInvalidIndex); 772 CHECK(blocks[i].writer == Vertex::kInvalidIndex);
771 } 773 }
772 Graph graph; 774 Graph graph;
773 CheckGraph(graph); 775 CheckGraph(graph);
774 776
775 const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX"); 777 const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX");
776 string temp_file_path; 778 string temp_file_path;
777 off_t data_file_size = 0; 779 off_t data_file_size = 0;
778 780
779 LOG(INFO) << "Reading files..."; 781 LOG(INFO) << "Reading files...";
780 782
781 vector<DeltaArchiveManifest_InstallOperation> kernel_ops; 783 vector<DeltaArchiveManifest_InstallOperation> kernel_ops;
782 784
783 DeltaArchiveManifest_InstallOperation final_op; 785 DeltaArchiveManifest_InstallOperation final_op;
784 { 786 {
785 int fd; 787 int fd;
786 TEST_AND_RETURN_FALSE( 788 TEST_AND_RETURN_FALSE(
787 utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd)); 789 utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd));
788 TEST_AND_RETURN_FALSE(fd >= 0); 790 TEST_AND_RETURN_FALSE(fd >= 0);
789 ScopedFdCloser fd_closer(&fd); 791 ScopedFdCloser fd_closer(&fd);
790 792
791 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, 793 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph,
792 &blocks, 794 &blocks,
793 old_root, 795 old_root,
794 new_root, 796 new_root,
795 fd, 797 fd,
796 &data_file_size)); 798 &data_file_size));
797 CheckGraph(graph); 799 CheckGraph(graph);
798 800
799 TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks, 801 TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks,
800 fd, 802 fd,
801 &data_file_size, 803 &data_file_size,
802 new_image, 804 new_image,
803 &final_op)); 805 &final_op));
804 806
805 // Read kernel partition 807 // Read kernel partition
806 TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part, 808 TEST_AND_RETURN_FALSE(DeltaCompressKernelPartition(old_kernel_part,
807 new_kernel_part, 809 new_kernel_part,
808 &kernel_ops, 810 &kernel_ops,
809 fd, 811 fd,
810 &data_file_size)); 812 &data_file_size));
811 } 813 }
812 CheckGraph(graph); 814 CheckGraph(graph);
813 815
814 LOG(INFO) << "Creating edges..."; 816 LOG(INFO) << "Creating edges...";
815 CreateEdges(&graph, blocks); 817 CreateEdges(&graph, blocks);
816 CheckGraph(graph); 818 CheckGraph(graph);
817 819
818 CycleBreaker cycle_breaker; 820 CycleBreaker cycle_breaker;
819 LOG(INFO) << "Finding cycles..."; 821 LOG(INFO) << "Finding cycles...";
820 set<Edge> cut_edges; 822 set<Edge> cut_edges;
821 cycle_breaker.BreakCycles(graph, &cut_edges); 823 cycle_breaker.BreakCycles(graph, &cut_edges);
822 CheckGraph(graph); 824 CheckGraph(graph);
823 825
824 // Calculate number of scratch blocks needed 826 // Calculate number of scratch blocks needed
825 827
826 LOG(INFO) << "Cutting cycles..."; 828 LOG(INFO) << "Cutting cycles...";
827 TEST_AND_RETURN_FALSE(CutEdges(&graph, blocks, cut_edges)); 829 TEST_AND_RETURN_FALSE(CutEdges(&graph, blocks, cut_edges));
828 CheckGraph(graph); 830 CheckGraph(graph);
829 831
830 vector<Vertex::Index> final_order; 832 vector<Vertex::Index> final_order;
831 LOG(INFO) << "Ordering..."; 833 LOG(INFO) << "Ordering...";
832 TopologicalSort(graph, &final_order); 834 TopologicalSort(graph, &final_order);
833 CheckGraph(graph); 835 CheckGraph(graph);
834 836
835 // Convert to protobuf Manifest object 837 // Convert to protobuf Manifest object
836 DeltaArchiveManifest manifest; 838 DeltaArchiveManifest manifest;
837 CheckGraph(graph); 839 CheckGraph(graph);
838 InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest); 840 InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest);
839 { 841 {
840 // Write final operation 842 // Write final operation
841 DeltaArchiveManifest_InstallOperation* op = 843 DeltaArchiveManifest_InstallOperation* op =
842 manifest.add_install_operations(); 844 manifest.add_install_operations();
843 *op = final_op; 845 *op = final_op;
844 CHECK(op->has_type()); 846 CHECK(op->has_type());
845 LOG(INFO) << "final op length: " << op->data_length(); 847 LOG(INFO) << "final op length: " << op->data_length();
846 } 848 }
847 849
848 CheckGraph(graph); 850 CheckGraph(graph);
849 manifest.set_block_size(kBlockSize); 851 manifest.set_block_size(kBlockSize);
850 852
851 // Reorder the data blobs with the newly ordered manifest 853 // Reorder the data blobs with the newly ordered manifest
852 string ordered_blobs_path; 854 string ordered_blobs_path;
853 TEST_AND_RETURN_FALSE(utils::MakeTempFile( 855 TEST_AND_RETURN_FALSE(utils::MakeTempFile(
854 "/tmp/CrAU_temp_data.ordered.XXXXXX", 856 "/tmp/CrAU_temp_data.ordered.XXXXXX",
855 &ordered_blobs_path, 857 &ordered_blobs_path,
856 false)); 858 false));
857 TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest, 859 TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest,
858 temp_file_path, 860 temp_file_path,
859 ordered_blobs_path)); 861 ordered_blobs_path));
860 862
861 // Check that install op blobs are in order and that all blocks are written. 863 // Check that install op blobs are in order and that all blocks are written.
864 uint64_t next_blob_offset = 0;
862 { 865 {
863 vector<uint32_t> written_count(blocks.size(), 0); 866 vector<uint32_t> written_count(blocks.size(), 0);
864 uint64_t next_blob_offset = 0;
865 for (int i = 0; i < (manifest.install_operations_size() + 867 for (int i = 0; i < (manifest.install_operations_size() +
866 manifest.kernel_install_operations_size()); i++) { 868 manifest.kernel_install_operations_size()); i++) {
867 const DeltaArchiveManifest_InstallOperation& op = 869 DeltaArchiveManifest_InstallOperation* op =
868 i < manifest.install_operations_size() ? 870 i < manifest.install_operations_size() ?
869 manifest.install_operations(i) : 871 manifest.mutable_install_operations(i) :
870 manifest.kernel_install_operations( 872 manifest.mutable_kernel_install_operations(
871 i - manifest.install_operations_size()); 873 i - manifest.install_operations_size());
872 for (int j = 0; j < op.dst_extents_size(); j++) { 874 for (int j = 0; j < op->dst_extents_size(); j++) {
873 const Extent& extent = op.dst_extents(j); 875 const Extent& extent = op->dst_extents(j);
874 for (uint64_t block = extent.start_block(); 876 for (uint64_t block = extent.start_block();
875 block < (extent.start_block() + extent.num_blocks()); block++) { 877 block < (extent.start_block() + extent.num_blocks()); block++) {
876 written_count[block]++; 878 written_count[block]++;
877 } 879 }
878 } 880 }
879 if (op.has_data_offset()) { 881 if (op->has_data_offset()) {
880 if (op.data_offset() != next_blob_offset) { 882 if (op->data_offset() != next_blob_offset) {
881 LOG(FATAL) << "bad blob offset! " << op.data_offset() << " != " 883 LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != "
882 << next_blob_offset; 884 << next_blob_offset;
883 } 885 }
884 next_blob_offset += op.data_length(); 886 next_blob_offset += op->data_length();
885 } 887 }
886 } 888 }
887 // check all blocks written to 889 // check all blocks written to
888 for (vector<uint32_t>::size_type i = 0; i < written_count.size(); i++) { 890 for (vector<uint32_t>::size_type i = 0; i < written_count.size(); i++) {
889 if (written_count[i] == 0) { 891 if (written_count[i] == 0) {
890 LOG(FATAL) << "block " << i << " not written!"; 892 LOG(FATAL) << "block " << i << " not written!";
891 } 893 }
892 } 894 }
893 } 895 }
894 896
897 // Signatures appear at the end of the blobs. Note the offset in the
898 // manifest
899 if (!private_key_path.empty()) {
900 LOG(INFO) << "Making room for signature in file";
901 manifest.set_signatures_offset(next_blob_offset);
902 LOG(INFO) << "set? " << manifest.has_signatures_offset();
903 // Add a dummy op at the end to appease older clients
904 DeltaArchiveManifest_InstallOperation* dummy_op =
905 manifest.add_kernel_install_operations();
906 dummy_op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE);
907 dummy_op->set_data_offset(next_blob_offset);
908 manifest.set_signatures_offset(next_blob_offset);
909 uint64_t signature_blob_length = 0;
910 TEST_AND_RETURN_FALSE(
911 PayloadSigner::SignatureBlobLength(private_key_path,
912 &signature_blob_length));
913 dummy_op->set_data_length(signature_blob_length);
914 manifest.set_signatures_size(signature_blob_length);
915 Extent* dummy_extent = dummy_op->add_dst_extents();
916 // Tell the dummy op to write this data to a big sparse hole
917 dummy_extent->set_start_block(kSparseHole);
918 dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
919 kBlockSize);
920 }
921
895 // Serialize protobuf 922 // Serialize protobuf
896 string serialized_manifest; 923 string serialized_manifest;
897 924
898 CheckGraph(graph); 925 CheckGraph(graph);
899 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest)); 926 TEST_AND_RETURN_FALSE(manifest.AppendToString(&serialized_manifest));
900 CheckGraph(graph); 927 CheckGraph(graph);
901 928
902 LOG(INFO) << "Writing final delta file header..."; 929 LOG(INFO) << "Writing final delta file header...";
903 DirectFileWriter writer; 930 DirectFileWriter writer;
904 TEST_AND_RETURN_FALSE_ERRNO(writer.Open(output_path.c_str(), 931 TEST_AND_RETURN_FALSE_ERRNO(writer.Open(output_path.c_str(),
905 O_WRONLY | O_CREAT | O_TRUNC, 932 O_WRONLY | O_CREAT | O_TRUNC,
906 0644) == 0); 933 0644) == 0);
907 ScopedFileWriterCloser writer_closer(&writer); 934 ScopedFileWriterCloser writer_closer(&writer);
908 935
909 // Write header 936 // Write header
910 TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)) == 937 TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)) ==
911 static_cast<ssize_t>(strlen(kDeltaMagic))); 938 static_cast<ssize_t>(strlen(kDeltaMagic)));
912 939
913 // Write version number 940 // Write version number
914 TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, kVersionNumber)); 941 TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, kVersionNumber));
915 942
916 // Write protobuf length 943 // Write protobuf length
917 TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, 944 TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer,
918 serialized_manifest.size())); 945 serialized_manifest.size()));
919 946
920 // Write protobuf 947 // Write protobuf
921 LOG(INFO) << "Writing final delta file protobuf... " 948 LOG(INFO) << "Writing final delta file protobuf... "
922 << serialized_manifest.size(); 949 << serialized_manifest.size();
923 TEST_AND_RETURN_FALSE(writer.Write(serialized_manifest.data(), 950 TEST_AND_RETURN_FALSE(writer.Write(serialized_manifest.data(),
924 serialized_manifest.size()) == 951 serialized_manifest.size()) ==
925 static_cast<ssize_t>(serialized_manifest.size())); 952 static_cast<ssize_t>(serialized_manifest.size()));
926 953
927 // Append the data blobs 954 // Append the data blobs
928 LOG(INFO) << "Writing final delta file data blobs..."; 955 LOG(INFO) << "Writing final delta file data blobs...";
929 int blobs_fd = open(ordered_blobs_path.c_str(), O_RDONLY, 0); 956 int blobs_fd = open(ordered_blobs_path.c_str(), O_RDONLY, 0);
930 ScopedFdCloser blobs_fd_closer(&blobs_fd); 957 ScopedFdCloser blobs_fd_closer(&blobs_fd);
931 TEST_AND_RETURN_FALSE(blobs_fd >= 0); 958 TEST_AND_RETURN_FALSE(blobs_fd >= 0);
932 for (;;) { 959 for (;;) {
933 char buf[kBlockSize]; 960 char buf[kBlockSize];
934 ssize_t rc = read(blobs_fd, buf, sizeof(buf)); 961 ssize_t rc = read(blobs_fd, buf, sizeof(buf));
935 if (0 == rc) { 962 if (0 == rc) {
936 // EOF 963 // EOF
937 break; 964 break;
938 } 965 }
939 TEST_AND_RETURN_FALSE_ERRNO(rc > 0); 966 TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
940 TEST_AND_RETURN_FALSE(writer.Write(buf, rc) == rc); 967 TEST_AND_RETURN_FALSE(writer.Write(buf, rc) == rc);
941 } 968 }
942 969
970 // Write signature blob.
971 if (!private_key_path.empty()) {
972 LOG(INFO) << "Signing the update...";
973 vector<char> signature_blob;
974 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path,
975 private_key_path,
976 &signature_blob));
977 TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0],
978 signature_blob.size()) ==
979 static_cast<ssize_t>(signature_blob.size()));
980 }
981
943 LOG(INFO) << "All done. Successfully created delta file."; 982 LOG(INFO) << "All done. Successfully created delta file.";
944 return true; 983 return true;
945 } 984 }
946 985
947 const char* const kBsdiffPath = "/usr/bin/bsdiff"; 986 const char* const kBsdiffPath = "/usr/bin/bsdiff";
948 const char* const kBspatchPath = "/usr/bin/bspatch"; 987 const char* const kBspatchPath = "/usr/bin/bspatch";
949 const char* const kDeltaMagic = "CrAU"; 988 const char* const kDeltaMagic = "CrAU";
950 989
951 }; // namespace chromeos_update_engine 990 }; // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « delta_diff_generator.h ('k') | delta_performer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698