| 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 |