| 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 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 #include "update_engine/bzip.h" | 24 #include "update_engine/bzip.h" |
| 25 #include "update_engine/cycle_breaker.h" | 25 #include "update_engine/cycle_breaker.h" |
| 26 #include "update_engine/extent_mapper.h" | 26 #include "update_engine/extent_mapper.h" |
| 27 #include "update_engine/extent_ranges.h" | 27 #include "update_engine/extent_ranges.h" |
| 28 #include "update_engine/file_writer.h" | 28 #include "update_engine/file_writer.h" |
| 29 #include "update_engine/filesystem_iterator.h" | 29 #include "update_engine/filesystem_iterator.h" |
| 30 #include "update_engine/full_update_generator.h" | 30 #include "update_engine/full_update_generator.h" |
| 31 #include "update_engine/graph_types.h" | 31 #include "update_engine/graph_types.h" |
| 32 #include "update_engine/graph_utils.h" | 32 #include "update_engine/graph_utils.h" |
| 33 #include "update_engine/metadata.h" |
| 33 #include "update_engine/omaha_hash_calculator.h" | 34 #include "update_engine/omaha_hash_calculator.h" |
| 34 #include "update_engine/payload_signer.h" | 35 #include "update_engine/payload_signer.h" |
| 35 #include "update_engine/subprocess.h" | 36 #include "update_engine/subprocess.h" |
| 36 #include "update_engine/topological_sort.h" | 37 #include "update_engine/topological_sort.h" |
| 37 #include "update_engine/update_metadata.pb.h" | 38 #include "update_engine/update_metadata.pb.h" |
| 38 #include "update_engine/utils.h" | 39 #include "update_engine/utils.h" |
| 39 | 40 |
| 40 using std::make_pair; | 41 using std::make_pair; |
| 41 using std::map; | 42 using std::map; |
| 42 using std::max; | 43 using std::max; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 70 | 71 |
| 71 // Stores all Extents for a file into 'out'. Returns true on success. | 72 // Stores all Extents for a file into 'out'. Returns true on success. |
| 72 bool GatherExtents(const string& path, | 73 bool GatherExtents(const string& path, |
| 73 google::protobuf::RepeatedPtrField<Extent>* out) { | 74 google::protobuf::RepeatedPtrField<Extent>* out) { |
| 74 vector<Extent> extents; | 75 vector<Extent> extents; |
| 75 TEST_AND_RETURN_FALSE(extent_mapper::ExtentsForFileFibmap(path, &extents)); | 76 TEST_AND_RETURN_FALSE(extent_mapper::ExtentsForFileFibmap(path, &extents)); |
| 76 DeltaDiffGenerator::StoreExtents(extents, out); | 77 DeltaDiffGenerator::StoreExtents(extents, out); |
| 77 return true; | 78 return true; |
| 78 } | 79 } |
| 79 | 80 |
| 80 // Runs the bsdiff tool on two files and returns the resulting delta in | |
| 81 // 'out'. Returns true on success. | |
| 82 bool BsdiffFiles(const string& old_file, | |
| 83 const string& new_file, | |
| 84 vector<char>* out) { | |
| 85 const string kPatchFile = "/tmp/delta.patchXXXXXX"; | |
| 86 string patch_file_path; | |
| 87 | |
| 88 TEST_AND_RETURN_FALSE( | |
| 89 utils::MakeTempFile(kPatchFile, &patch_file_path, NULL)); | |
| 90 | |
| 91 vector<string> cmd; | |
| 92 cmd.push_back(kBsdiffPath); | |
| 93 cmd.push_back(old_file); | |
| 94 cmd.push_back(new_file); | |
| 95 cmd.push_back(patch_file_path); | |
| 96 | |
| 97 int rc = 1; | |
| 98 vector<char> patch_file; | |
| 99 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc)); | |
| 100 TEST_AND_RETURN_FALSE(rc == 0); | |
| 101 TEST_AND_RETURN_FALSE(utils::ReadFile(patch_file_path, out)); | |
| 102 unlink(patch_file_path.c_str()); | |
| 103 return true; | |
| 104 } | |
| 105 | |
| 106 // The blocks vector contains a reader and writer for each block on the | |
| 107 // filesystem that's being in-place updated. We populate the reader/writer | |
| 108 // fields of blocks by calling this function. | |
| 109 // For each block in 'operation' that is read or written, find that block | |
| 110 // in 'blocks' and set the reader/writer field to the vertex passed. | |
| 111 // 'graph' is not strictly necessary, but useful for printing out | |
| 112 // error messages. | |
| 113 bool AddInstallOpToBlocksVector( | |
| 114 const DeltaArchiveManifest_InstallOperation& operation, | |
| 115 vector<Block>* blocks, | |
| 116 const Graph& graph, | |
| 117 Vertex::Index vertex) { | |
| 118 // See if this is already present. | |
| 119 TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0); | |
| 120 | |
| 121 enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT }; | |
| 122 for (int field = READER; field < BLOCK_FIELD_COUNT; field++) { | |
| 123 const int extents_size = | |
| 124 (field == READER) ? operation.src_extents_size() : | |
| 125 operation.dst_extents_size(); | |
| 126 const char* past_participle = (field == READER) ? "read" : "written"; | |
| 127 const google::protobuf::RepeatedPtrField<Extent>& extents = | |
| 128 (field == READER) ? operation.src_extents() : operation.dst_extents(); | |
| 129 Vertex::Index Block::*access_type = | |
| 130 (field == READER) ? &Block::reader : &Block::writer; | |
| 131 | |
| 132 for (int i = 0; i < extents_size; i++) { | |
| 133 const Extent& extent = extents.Get(i); | |
| 134 if (extent.start_block() == kSparseHole) { | |
| 135 // Hole in sparse file. skip | |
| 136 continue; | |
| 137 } | |
| 138 for (uint64_t block = extent.start_block(); | |
| 139 block < (extent.start_block() + extent.num_blocks()); block++) { | |
| 140 if ((*blocks)[block].*access_type != Vertex::kInvalidIndex) { | |
| 141 LOG(FATAL) << "Block " << block << " is already " | |
| 142 << past_participle << " by " | |
| 143 << (*blocks)[block].*access_type << "(" | |
| 144 << graph[(*blocks)[block].*access_type].file_name | |
| 145 << ") and also " << vertex << "(" | |
| 146 << graph[vertex].file_name << ")"; | |
| 147 } | |
| 148 (*blocks)[block].*access_type = vertex; | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 return true; | |
| 153 } | |
| 154 | |
| 155 // For a given regular file which must exist at new_root + path, and | 81 // For a given regular file which must exist at new_root + path, and |
| 156 // may exist at old_root + path, creates a new InstallOperation and | 82 // may exist at old_root + path, creates a new InstallOperation and |
| 157 // adds it to the graph. Also, populates the |blocks| array as | 83 // adds it to the graph. Also, populates the |blocks| array as |
| 158 // necessary, if |blocks| is non-NULL. Also, writes the data | 84 // necessary, if |blocks| is non-NULL. Also, writes the data |
| 159 // necessary to send the file down to the client into data_fd, which | 85 // necessary to send the file down to the client into data_fd, which |
| 160 // has length *data_file_size. *data_file_size is updated | 86 // has length *data_file_size. *data_file_size is updated |
| 161 // appropriately. If |existing_vertex| is no kInvalidIndex, use that | 87 // appropriately. If |existing_vertex| is no kInvalidIndex, use that |
| 162 // rather than allocating a new vertex. Returns true on success. | 88 // rather than allocating a new vertex. Returns true on success. |
| 163 bool DeltaReadFile(Graph* graph, | 89 bool DeltaReadFile(Graph* graph, |
| 164 Vertex::Index existing_vertex, | 90 Vertex::Index existing_vertex, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 190 Vertex::Index vertex = existing_vertex; | 116 Vertex::Index vertex = existing_vertex; |
| 191 if (vertex == Vertex::kInvalidIndex) { | 117 if (vertex == Vertex::kInvalidIndex) { |
| 192 graph->resize(graph->size() + 1); | 118 graph->resize(graph->size() + 1); |
| 193 vertex = graph->size() - 1; | 119 vertex = graph->size() - 1; |
| 194 } | 120 } |
| 195 (*graph)[vertex].op = operation; | 121 (*graph)[vertex].op = operation; |
| 196 CHECK((*graph)[vertex].op.has_type()); | 122 CHECK((*graph)[vertex].op.has_type()); |
| 197 (*graph)[vertex].file_name = path; | 123 (*graph)[vertex].file_name = path; |
| 198 | 124 |
| 199 if (blocks) | 125 if (blocks) |
| 200 TEST_AND_RETURN_FALSE(AddInstallOpToBlocksVector((*graph)[vertex].op, | 126 TEST_AND_RETURN_FALSE(DeltaDiffGenerator::AddInstallOpToBlocksVector( |
| 201 blocks, | 127 (*graph)[vertex].op, |
| 202 *graph, | 128 *graph, |
| 203 vertex)); | 129 vertex, |
| 130 blocks)); |
| 204 return true; | 131 return true; |
| 205 } | 132 } |
| 206 | 133 |
| 207 // For each regular file within new_root, creates a node in the graph, | 134 // For each regular file within new_root, creates a node in the graph, |
| 208 // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF), | 135 // determines the best way to compress it (REPLACE, REPLACE_BZ, COPY, BSDIFF), |
| 209 // and writes any necessary data to the end of data_fd. | 136 // and writes any necessary data to the end of data_fd. |
| 210 bool DeltaReadFiles(Graph* graph, | 137 bool DeltaReadFiles(Graph* graph, |
| 211 vector<Block>* blocks, | 138 vector<Block>* blocks, |
| 212 const string& old_root, | 139 const string& old_root, |
| 213 const string& new_root, | 140 const string& new_root, |
| (...skipping 1169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1383 | 1310 |
| 1384 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, | 1311 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, |
| 1385 &blocks, | 1312 &blocks, |
| 1386 old_root, | 1313 old_root, |
| 1387 new_root, | 1314 new_root, |
| 1388 fd, | 1315 fd, |
| 1389 &data_file_size)); | 1316 &data_file_size)); |
| 1390 LOG(INFO) << "done reading normal files"; | 1317 LOG(INFO) << "done reading normal files"; |
| 1391 CheckGraph(graph); | 1318 CheckGraph(graph); |
| 1392 | 1319 |
| 1320 LOG(INFO) << "Starting metadata processing"; |
| 1321 TEST_AND_RETURN_FALSE(Metadata::DeltaReadMetadata(&graph, |
| 1322 &blocks, |
| 1323 old_image, |
| 1324 new_image, |
| 1325 fd, |
| 1326 &data_file_size)); |
| 1327 LOG(INFO) << "Done metadata processing"; |
| 1328 CheckGraph(graph); |
| 1329 |
| 1393 graph.resize(graph.size() + 1); | 1330 graph.resize(graph.size() + 1); |
| 1394 TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks, | 1331 TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks, |
| 1395 fd, | 1332 fd, |
| 1396 &data_file_size, | 1333 &data_file_size, |
| 1397 new_image, | 1334 new_image, |
| 1398 &graph.back())); | 1335 &graph.back())); |
| 1399 | 1336 |
| 1400 // Final scratch block (if there's space) | 1337 // Final scratch block (if there's space) |
| 1401 if (blocks.size() < (kRootFSPartitionSize / kBlockSize)) { | 1338 if (blocks.size() < (kRootFSPartitionSize / kBlockSize)) { |
| 1402 scratch_vertex = graph.size(); | 1339 scratch_vertex = graph.size(); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1578 } | 1515 } |
| 1579 | 1516 |
| 1580 int64_t manifest_metadata_size = | 1517 int64_t manifest_metadata_size = |
| 1581 strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size(); | 1518 strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size(); |
| 1582 ReportPayloadUsage(manifest, manifest_metadata_size, op_name_map); | 1519 ReportPayloadUsage(manifest, manifest_metadata_size, op_name_map); |
| 1583 | 1520 |
| 1584 LOG(INFO) << "All done. Successfully created delta file."; | 1521 LOG(INFO) << "All done. Successfully created delta file."; |
| 1585 return true; | 1522 return true; |
| 1586 } | 1523 } |
| 1587 | 1524 |
| 1525 // Runs the bsdiff tool on two files and returns the resulting delta in |
| 1526 // 'out'. Returns true on success. |
| 1527 bool DeltaDiffGenerator::BsdiffFiles(const string& old_file, |
| 1528 const string& new_file, |
| 1529 vector<char>* out) { |
| 1530 const string kPatchFile = "/tmp/delta.patchXXXXXX"; |
| 1531 string patch_file_path; |
| 1532 |
| 1533 TEST_AND_RETURN_FALSE( |
| 1534 utils::MakeTempFile(kPatchFile, &patch_file_path, NULL)); |
| 1535 |
| 1536 vector<string> cmd; |
| 1537 cmd.push_back(kBsdiffPath); |
| 1538 cmd.push_back(old_file); |
| 1539 cmd.push_back(new_file); |
| 1540 cmd.push_back(patch_file_path); |
| 1541 |
| 1542 int rc = 1; |
| 1543 vector<char> patch_file; |
| 1544 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc)); |
| 1545 TEST_AND_RETURN_FALSE(rc == 0); |
| 1546 TEST_AND_RETURN_FALSE(utils::ReadFile(patch_file_path, out)); |
| 1547 unlink(patch_file_path.c_str()); |
| 1548 return true; |
| 1549 } |
| 1550 |
| 1551 // The |blocks| vector contains a reader and writer for each block on the |
| 1552 // filesystem that's being in-place updated. We populate the reader/writer |
| 1553 // fields of |blocks| by calling this function. |
| 1554 // For each block in |operation| that is read or written, find that block |
| 1555 // in |blocks| and set the reader/writer field to the vertex passed. |
| 1556 // |graph| is not strictly necessary, but useful for printing out |
| 1557 // error messages. |
| 1558 bool DeltaDiffGenerator::AddInstallOpToBlocksVector( |
| 1559 const DeltaArchiveManifest_InstallOperation& operation, |
| 1560 const Graph& graph, |
| 1561 Vertex::Index vertex, |
| 1562 vector<Block>* blocks) { |
| 1563 // See if this is already present. |
| 1564 TEST_AND_RETURN_FALSE(operation.dst_extents_size() > 0); |
| 1565 |
| 1566 enum BlockField { READER = 0, WRITER, BLOCK_FIELD_COUNT }; |
| 1567 for (int field = READER; field < BLOCK_FIELD_COUNT; field++) { |
| 1568 const int extents_size = |
| 1569 (field == READER) ? operation.src_extents_size() : |
| 1570 operation.dst_extents_size(); |
| 1571 const char* past_participle = (field == READER) ? "read" : "written"; |
| 1572 const google::protobuf::RepeatedPtrField<Extent>& extents = |
| 1573 (field == READER) ? operation.src_extents() : operation.dst_extents(); |
| 1574 Vertex::Index Block::*access_type = |
| 1575 (field == READER) ? &Block::reader : &Block::writer; |
| 1576 |
| 1577 for (int i = 0; i < extents_size; i++) { |
| 1578 const Extent& extent = extents.Get(i); |
| 1579 if (extent.start_block() == kSparseHole) { |
| 1580 // Hole in sparse file. skip |
| 1581 continue; |
| 1582 } |
| 1583 for (uint64_t block = extent.start_block(); |
| 1584 block < (extent.start_block() + extent.num_blocks()); block++) { |
| 1585 if ((*blocks)[block].*access_type != Vertex::kInvalidIndex) { |
| 1586 LOG(FATAL) << "Block " << block << " is already " |
| 1587 << past_participle << " by " |
| 1588 << (*blocks)[block].*access_type << "(" |
| 1589 << graph[(*blocks)[block].*access_type].file_name |
| 1590 << ") and also " << vertex << "(" |
| 1591 << graph[vertex].file_name << ")"; |
| 1592 } |
| 1593 (*blocks)[block].*access_type = vertex; |
| 1594 } |
| 1595 } |
| 1596 } |
| 1597 return true; |
| 1598 } |
| 1599 |
| 1588 const char* const kBsdiffPath = "bsdiff"; | 1600 const char* const kBsdiffPath = "bsdiff"; |
| 1589 const char* const kBspatchPath = "bspatch"; | 1601 const char* const kBspatchPath = "bspatch"; |
| 1590 const char* const kDeltaMagic = "CrAU"; | 1602 const char* const kDeltaMagic = "CrAU"; |
| 1591 | 1603 |
| 1592 }; // namespace chromeos_update_engine | 1604 }; // namespace chromeos_update_engine |
| OLD | NEW |