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