OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS 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 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <inttypes.h> | 9 #include <inttypes.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
(...skipping 29 matching lines...) Expand all Loading... |
40 using std::map; | 40 using std::map; |
41 using std::max; | 41 using std::max; |
42 using std::min; | 42 using std::min; |
43 using std::set; | 43 using std::set; |
44 using std::string; | 44 using std::string; |
45 using std::vector; | 45 using std::vector; |
46 | 46 |
47 namespace chromeos_update_engine { | 47 namespace chromeos_update_engine { |
48 | 48 |
49 typedef DeltaDiffGenerator::Block Block; | 49 typedef DeltaDiffGenerator::Block Block; |
| 50 typedef map<const DeltaArchiveManifest_InstallOperation*, |
| 51 const string*> OperationNameMap; |
50 | 52 |
51 namespace { | 53 namespace { |
52 const size_t kBlockSize = 4096; // bytes | 54 const size_t kBlockSize = 4096; // bytes |
53 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // bytes | 55 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // bytes |
54 const uint64_t kVersionNumber = 1; | 56 const uint64_t kVersionNumber = 1; |
55 const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes | 57 const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes |
56 | 58 |
57 static const char* kInstallOperationTypes[] = { | 59 static const char* kInstallOperationTypes[] = { |
58 "REPLACE", | 60 "REPLACE", |
59 "REPLACE_BZ", | 61 "REPLACE_BZ", |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 | 371 |
370 // Writes the uint64_t passed in in host-endian to the file as big-endian. | 372 // Writes the uint64_t passed in in host-endian to the file as big-endian. |
371 // Returns true on success. | 373 // Returns true on success. |
372 bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) { | 374 bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) { |
373 uint64_t value_be = htobe64(value); | 375 uint64_t value_be = htobe64(value); |
374 TEST_AND_RETURN_FALSE(writer->Write(&value_be, sizeof(value_be)) == | 376 TEST_AND_RETURN_FALSE(writer->Write(&value_be, sizeof(value_be)) == |
375 sizeof(value_be)); | 377 sizeof(value_be)); |
376 return true; | 378 return true; |
377 } | 379 } |
378 | 380 |
379 // Adds each operation from the graph to the manifest in the order | 381 // Adds each operation from |graph| to |out_manifest| in the order specified by |
380 // specified by 'order'. | 382 // |order| while building |out_op_name_map| with operation to name |
| 383 // mappings. Adds all |kernel_ops| to |out_manifest|. Filters out no-op |
| 384 // operations. |
381 void InstallOperationsToManifest( | 385 void InstallOperationsToManifest( |
382 const Graph& graph, | 386 const Graph& graph, |
383 const vector<Vertex::Index>& order, | 387 const vector<Vertex::Index>& order, |
384 const vector<DeltaArchiveManifest_InstallOperation>& kernel_ops, | 388 const vector<DeltaArchiveManifest_InstallOperation>& kernel_ops, |
385 DeltaArchiveManifest* out_manifest) { | 389 DeltaArchiveManifest* out_manifest, |
| 390 OperationNameMap* out_op_name_map) { |
386 for (vector<Vertex::Index>::const_iterator it = order.begin(); | 391 for (vector<Vertex::Index>::const_iterator it = order.begin(); |
387 it != order.end(); ++it) { | 392 it != order.end(); ++it) { |
| 393 const Vertex& vertex = graph[*it]; |
| 394 const DeltaArchiveManifest_InstallOperation& add_op = vertex.op; |
| 395 if (DeltaDiffGenerator::IsNoopOperation(add_op)) { |
| 396 continue; |
| 397 } |
388 DeltaArchiveManifest_InstallOperation* op = | 398 DeltaArchiveManifest_InstallOperation* op = |
389 out_manifest->add_install_operations(); | 399 out_manifest->add_install_operations(); |
390 *op = graph[*it].op; | 400 *op = add_op; |
| 401 (*out_op_name_map)[op] = &vertex.file_name; |
391 } | 402 } |
392 for (vector<DeltaArchiveManifest_InstallOperation>::const_iterator it = | 403 for (vector<DeltaArchiveManifest_InstallOperation>::const_iterator it = |
393 kernel_ops.begin(); it != kernel_ops.end(); ++it) { | 404 kernel_ops.begin(); it != kernel_ops.end(); ++it) { |
| 405 const DeltaArchiveManifest_InstallOperation& add_op = *it; |
| 406 if (DeltaDiffGenerator::IsNoopOperation(add_op)) { |
| 407 continue; |
| 408 } |
394 DeltaArchiveManifest_InstallOperation* op = | 409 DeltaArchiveManifest_InstallOperation* op = |
395 out_manifest->add_kernel_install_operations(); | 410 out_manifest->add_kernel_install_operations(); |
396 *op = *it; | 411 *op = add_op; |
397 } | 412 } |
398 } | 413 } |
399 | 414 |
400 void CheckGraph(const Graph& graph) { | 415 void CheckGraph(const Graph& graph) { |
401 for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) { | 416 for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) { |
402 CHECK(it->op.has_type()); | 417 CHECK(it->op.has_type()); |
403 } | 418 } |
404 } | 419 } |
405 | 420 |
406 // Delta compresses a kernel partition |new_kernel_part| with knowledge of the | 421 // Delta compresses a kernel partition |new_kernel_part| with knowledge of the |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 type(in_type), | 461 type(in_type), |
447 size(in_size) {} | 462 size(in_size) {} |
448 bool operator <(const DeltaObject& object) const { | 463 bool operator <(const DeltaObject& object) const { |
449 return (size != object.size) ? (size < object.size) : (name < object.name); | 464 return (size != object.size) ? (size < object.size) : (name < object.name); |
450 } | 465 } |
451 string name; | 466 string name; |
452 int type; | 467 int type; |
453 off_t size; | 468 off_t size; |
454 }; | 469 }; |
455 | 470 |
456 void ReportPayloadUsage(const Graph& graph, | 471 void ReportPayloadUsage(const DeltaArchiveManifest& manifest, |
457 const DeltaArchiveManifest& manifest, | 472 const int64_t manifest_metadata_size, |
458 const int64_t manifest_metadata_size) { | 473 const OperationNameMap& op_name_map) { |
459 vector<DeltaObject> objects; | 474 vector<DeltaObject> objects; |
460 off_t total_size = 0; | 475 off_t total_size = 0; |
461 | 476 |
462 // Graph nodes with information about file names. | 477 // Rootfs install operations. |
463 for (Vertex::Index node = 0; node < graph.size(); node++) { | 478 for (int i = 0; i < manifest.install_operations_size(); ++i) { |
464 const Vertex& vertex = graph[node]; | 479 const DeltaArchiveManifest_InstallOperation& op = |
465 if (!vertex.valid) { | 480 manifest.install_operations(i); |
466 continue; | 481 objects.push_back(DeltaObject(*op_name_map.find(&op)->second, |
467 } | 482 op.type(), |
468 objects.push_back(DeltaObject(vertex.file_name, | 483 op.data_length())); |
469 vertex.op.type(), | 484 total_size += op.data_length(); |
470 vertex.op.data_length())); | |
471 total_size += vertex.op.data_length(); | |
472 } | 485 } |
473 | 486 |
474 // Kernel install operations. | 487 // Kernel install operations. |
475 for (int i = 0; i < manifest.kernel_install_operations_size(); ++i) { | 488 for (int i = 0; i < manifest.kernel_install_operations_size(); ++i) { |
476 const DeltaArchiveManifest_InstallOperation& op = | 489 const DeltaArchiveManifest_InstallOperation& op = |
477 manifest.kernel_install_operations(i); | 490 manifest.kernel_install_operations(i); |
478 objects.push_back(DeltaObject(StringPrintf("<kernel-operation-%d>", i), | 491 objects.push_back(DeltaObject(StringPrintf("<kernel-operation-%d>", i), |
479 op.type(), | 492 op.type(), |
480 op.data_length())); | 493 op.data_length())); |
481 total_size += op.data_length(); | 494 total_size += op.data_length(); |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 return true; | 918 return true; |
906 } | 919 } |
907 // check for wrap-around, which would be a bug: | 920 // check for wrap-around, which would be a bug: |
908 CHECK(start <= (start + num)); | 921 CHECK(start <= (start + num)); |
909 } | 922 } |
910 return false; | 923 return false; |
911 } | 924 } |
912 | 925 |
913 } // namespace {} | 926 } // namespace {} |
914 | 927 |
| 928 // Returns true if |op| is a no-op operation that doesn't do any useful work |
| 929 // (e.g., a move operation that copies blocks onto themselves). |
| 930 bool DeltaDiffGenerator::IsNoopOperation( |
| 931 const DeltaArchiveManifest_InstallOperation& op) { |
| 932 return (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE && |
| 933 ExpandExtents(op.src_extents()) == ExpandExtents(op.dst_extents())); |
| 934 } |
| 935 |
915 bool DeltaDiffGenerator::AssignTempBlocks( | 936 bool DeltaDiffGenerator::AssignTempBlocks( |
916 Graph* graph, | 937 Graph* graph, |
917 const string& new_root, | 938 const string& new_root, |
918 int data_fd, | 939 int data_fd, |
919 off_t* data_file_size, | 940 off_t* data_file_size, |
920 vector<Vertex::Index>* op_indexes, | 941 vector<Vertex::Index>* op_indexes, |
921 vector<vector<Vertex::Index>::size_type>* reverse_op_indexes, | 942 vector<vector<Vertex::Index>::size_type>* reverse_op_indexes, |
922 vector<CutEdgeVertexes>& cuts) { | 943 vector<CutEdgeVertexes>& cuts) { |
923 CHECK(!cuts.empty()); | 944 CHECK(!cuts.empty()); |
924 for (vector<CutEdgeVertexes>::size_type i = cuts.size() - 1, e = 0; | 945 for (vector<CutEdgeVertexes>::size_type i = cuts.size() - 1, e = 0; |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1363 fd, | 1384 fd, |
1364 &data_file_size, | 1385 &data_file_size, |
1365 kFullUpdateChunkSize, | 1386 kFullUpdateChunkSize, |
1366 &kernel_ops, | 1387 &kernel_ops, |
1367 &final_order)); | 1388 &final_order)); |
1368 } | 1389 } |
1369 } | 1390 } |
1370 | 1391 |
1371 // Convert to protobuf Manifest object | 1392 // Convert to protobuf Manifest object |
1372 DeltaArchiveManifest manifest; | 1393 DeltaArchiveManifest manifest; |
| 1394 OperationNameMap op_name_map; |
1373 CheckGraph(graph); | 1395 CheckGraph(graph); |
1374 InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest); | 1396 InstallOperationsToManifest(graph, |
1375 | 1397 final_order, |
| 1398 kernel_ops, |
| 1399 &manifest, |
| 1400 &op_name_map); |
1376 CheckGraph(graph); | 1401 CheckGraph(graph); |
1377 manifest.set_block_size(kBlockSize); | 1402 manifest.set_block_size(kBlockSize); |
1378 | 1403 |
1379 // Reorder the data blobs with the newly ordered manifest | 1404 // Reorder the data blobs with the newly ordered manifest |
1380 string ordered_blobs_path; | 1405 string ordered_blobs_path; |
1381 TEST_AND_RETURN_FALSE(utils::MakeTempFile( | 1406 TEST_AND_RETURN_FALSE(utils::MakeTempFile( |
1382 "/tmp/CrAU_temp_data.ordered.XXXXXX", | 1407 "/tmp/CrAU_temp_data.ordered.XXXXXX", |
1383 &ordered_blobs_path, | 1408 &ordered_blobs_path, |
1384 false)); | 1409 false)); |
1385 TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest, | 1410 TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest, |
1386 temp_file_path, | 1411 temp_file_path, |
1387 ordered_blobs_path)); | 1412 ordered_blobs_path)); |
1388 | 1413 |
1389 // Check that install op blobs are in order and that all blocks are written. | 1414 // Check that install op blobs are in order. |
1390 uint64_t next_blob_offset = 0; | 1415 uint64_t next_blob_offset = 0; |
1391 { | 1416 { |
1392 vector<uint32_t> written_count(blocks.size(), 0); | |
1393 for (int i = 0; i < (manifest.install_operations_size() + | 1417 for (int i = 0; i < (manifest.install_operations_size() + |
1394 manifest.kernel_install_operations_size()); i++) { | 1418 manifest.kernel_install_operations_size()); i++) { |
1395 DeltaArchiveManifest_InstallOperation* op = | 1419 DeltaArchiveManifest_InstallOperation* op = |
1396 i < manifest.install_operations_size() ? | 1420 i < manifest.install_operations_size() ? |
1397 manifest.mutable_install_operations(i) : | 1421 manifest.mutable_install_operations(i) : |
1398 manifest.mutable_kernel_install_operations( | 1422 manifest.mutable_kernel_install_operations( |
1399 i - manifest.install_operations_size()); | 1423 i - manifest.install_operations_size()); |
1400 for (int j = 0; j < op->dst_extents_size(); j++) { | |
1401 const Extent& extent = op->dst_extents(j); | |
1402 for (uint64_t block = extent.start_block(); | |
1403 block < (extent.start_block() + extent.num_blocks()); block++) { | |
1404 if (block < blocks.size()) | |
1405 written_count[block]++; | |
1406 } | |
1407 } | |
1408 if (op->has_data_offset()) { | 1424 if (op->has_data_offset()) { |
1409 if (op->data_offset() != next_blob_offset) { | 1425 if (op->data_offset() != next_blob_offset) { |
1410 LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != " | 1426 LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != " |
1411 << next_blob_offset; | 1427 << next_blob_offset; |
1412 } | 1428 } |
1413 next_blob_offset += op->data_length(); | 1429 next_blob_offset += op->data_length(); |
1414 } | 1430 } |
1415 } | 1431 } |
1416 // check all blocks written to | |
1417 for (vector<uint32_t>::size_type i = 0; i < written_count.size(); i++) { | |
1418 if (written_count[i] == 0) { | |
1419 LOG(FATAL) << "block " << i << " not written!"; | |
1420 } | |
1421 } | |
1422 } | 1432 } |
1423 | 1433 |
1424 // Signatures appear at the end of the blobs. Note the offset in the | 1434 // Signatures appear at the end of the blobs. Note the offset in the |
1425 // manifest | 1435 // manifest |
1426 if (!private_key_path.empty()) { | 1436 if (!private_key_path.empty()) { |
1427 LOG(INFO) << "Making room for signature in file"; | 1437 LOG(INFO) << "Making room for signature in file"; |
1428 manifest.set_signatures_offset(next_blob_offset); | 1438 manifest.set_signatures_offset(next_blob_offset); |
1429 LOG(INFO) << "set? " << manifest.has_signatures_offset(); | 1439 LOG(INFO) << "set? " << manifest.has_signatures_offset(); |
1430 // Add a dummy op at the end to appease older clients | 1440 // Add a dummy op at the end to appease older clients |
1431 DeltaArchiveManifest_InstallOperation* dummy_op = | 1441 DeltaArchiveManifest_InstallOperation* dummy_op = |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1507 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path, | 1517 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path, |
1508 private_key_path, | 1518 private_key_path, |
1509 &signature_blob)); | 1519 &signature_blob)); |
1510 TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0], | 1520 TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0], |
1511 signature_blob.size()) == | 1521 signature_blob.size()) == |
1512 static_cast<ssize_t>(signature_blob.size())); | 1522 static_cast<ssize_t>(signature_blob.size())); |
1513 } | 1523 } |
1514 | 1524 |
1515 int64_t manifest_metadata_size = | 1525 int64_t manifest_metadata_size = |
1516 strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size(); | 1526 strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size(); |
1517 ReportPayloadUsage(graph, manifest, manifest_metadata_size); | 1527 ReportPayloadUsage(manifest, manifest_metadata_size, op_name_map); |
1518 | 1528 |
1519 LOG(INFO) << "All done. Successfully created delta file."; | 1529 LOG(INFO) << "All done. Successfully created delta file."; |
1520 return true; | 1530 return true; |
1521 } | 1531 } |
1522 | 1532 |
1523 const char* const kBsdiffPath = "/usr/bin/bsdiff"; | 1533 const char* const kBsdiffPath = "/usr/bin/bsdiff"; |
1524 const char* const kBspatchPath = "/usr/bin/bspatch"; | 1534 const char* const kBspatchPath = "/usr/bin/bspatch"; |
1525 const char* const kDeltaMagic = "CrAU"; | 1535 const char* const kDeltaMagic = "CrAU"; |
1526 | 1536 |
1527 }; // namespace chromeos_update_engine | 1537 }; // namespace chromeos_update_engine |
OLD | NEW |