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

Side by Side Diff: delta_diff_generator.cc

Issue 5684002: Add support for bsdiff of file system metadata blocks (Closed) Base URL: http://git.chromium.org/git/update_engine.git@master
Patch Set: Addressed code review feedbacks Created 10 years 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 | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « delta_diff_generator.h ('k') | delta_diff_generator_unittest.cc » ('j') | test_utils.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698