Chromium Code Reviews| 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> |
| 11 #include <sys/types.h> | 11 #include <sys/types.h> |
| 12 | 12 |
| 13 #include <base/logging.h> | |
|
petkov
2010/12/10 00:46:55
move this block of includes after the c++ headers
thieule
2010/12/14 23:11:21
Done.
| |
| 14 #include <base/string_util.h> | |
| 15 #include <bzlib.h> | |
| 16 | |
|
petkov
2010/12/10 00:46:55
no need for blank line
thieule
2010/12/14 23:11:21
Done.
| |
| 17 #include <ext2fs/ext2_io.h> | |
| 18 #include <ext2fs/ext2fs.h> | |
| 19 | |
| 13 #include <algorithm> | 20 #include <algorithm> |
| 14 #include <map> | 21 #include <map> |
| 15 #include <set> | 22 #include <set> |
| 16 #include <string> | 23 #include <string> |
| 17 #include <utility> | 24 #include <utility> |
| 18 #include <vector> | 25 #include <vector> |
| 19 | 26 |
| 20 #include <base/logging.h> | |
| 21 #include <base/string_util.h> | |
| 22 #include <bzlib.h> | |
| 23 | |
| 24 #include "update_engine/bzip.h" | 27 #include "update_engine/bzip.h" |
| 25 #include "update_engine/cycle_breaker.h" | 28 #include "update_engine/cycle_breaker.h" |
| 26 #include "update_engine/extent_mapper.h" | 29 #include "update_engine/extent_mapper.h" |
| 27 #include "update_engine/extent_ranges.h" | 30 #include "update_engine/extent_ranges.h" |
| 28 #include "update_engine/file_writer.h" | 31 #include "update_engine/file_writer.h" |
| 29 #include "update_engine/filesystem_iterator.h" | 32 #include "update_engine/filesystem_iterator.h" |
| 30 #include "update_engine/full_update_generator.h" | 33 #include "update_engine/full_update_generator.h" |
| 31 #include "update_engine/graph_types.h" | 34 #include "update_engine/graph_types.h" |
| 32 #include "update_engine/graph_utils.h" | 35 #include "update_engine/graph_utils.h" |
| 33 #include "update_engine/omaha_hash_calculator.h" | 36 #include "update_engine/omaha_hash_calculator.h" |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 blocks, | 237 blocks, |
| 235 old_root, | 238 old_root, |
| 236 new_root, | 239 new_root, |
| 237 fs_iter.GetPartialPath(), | 240 fs_iter.GetPartialPath(), |
| 238 data_fd, | 241 data_fd, |
| 239 data_file_size)); | 242 data_file_size)); |
| 240 } | 243 } |
| 241 return true; | 244 return true; |
| 242 } | 245 } |
| 243 | 246 |
| 247 // Read data from the specified extents. | |
| 248 bool ReadExtentsData(const ext2_filsys fs, | |
| 249 const vector<Extent>& extents, | |
| 250 vector<char>* data) { | |
| 251 // Resize the data buffer to hold all data in the extents | |
| 252 size_t num_data_blocks = 0; | |
| 253 for (vector<Extent>::const_iterator it = extents.begin(); | |
| 254 it != extents.end(); it++) { | |
| 255 num_data_blocks += it->num_blocks(); | |
| 256 } | |
| 257 | |
| 258 data->resize(num_data_blocks * kBlockSize); | |
| 259 | |
| 260 // Read in the data blocks | |
| 261 const size_t max_read_blocks = 256; | |
| 262 vector<Block>::size_type blocks_copied_count = 0; | |
| 263 for (vector<Extent>::const_iterator it = extents.begin(); | |
| 264 it != extents.end(); it++) { | |
| 265 vector<Block>::size_type blocks_read = 0; | |
| 266 while (blocks_read < it->num_blocks()) { | |
| 267 const int copy_block_cnt = | |
| 268 min(max_read_blocks, | |
| 269 static_cast<vector<char>::size_type>( | |
| 270 it->num_blocks() - blocks_read)); | |
| 271 TEST_AND_RETURN_FALSE_ERRCODE( | |
| 272 io_channel_read_blk(fs->io, | |
| 273 it->start_block() + blocks_read, | |
| 274 copy_block_cnt, | |
| 275 &(*data)[blocks_copied_count * kBlockSize])); | |
| 276 blocks_read += copy_block_cnt; | |
| 277 blocks_copied_count += copy_block_cnt; | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 return true; | |
| 282 } | |
| 283 | |
| 284 // Compute the bsdiff between two metadata blobs. | |
| 285 bool ComputeMetadataBsdiff(const vector<char>& old_metadata, | |
| 286 const vector<char>& new_metadata, | |
| 287 vector<char>* bsdiff_delta) { | |
| 288 const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX"); | |
| 289 | |
| 290 // Write the metadata buffers to temporary files | |
| 291 int old_fd; | |
| 292 string temp_old_file_path; | |
| 293 TEST_AND_RETURN_FALSE( | |
| 294 utils::MakeTempFile(kTempFileTemplate, &temp_old_file_path, &old_fd)); | |
| 295 TEST_AND_RETURN_FALSE(old_fd >= 0); | |
| 296 ScopedPathUnlinker temp_old_file_path_unlinker(temp_old_file_path); | |
| 297 ScopedFdCloser old_fd_closer(&old_fd); | |
| 298 TEST_AND_RETURN_FALSE(utils::WriteAll(old_fd, | |
| 299 &old_metadata[0], | |
| 300 old_metadata.size())); | |
| 301 | |
| 302 int new_fd; | |
| 303 string temp_new_file_path; | |
| 304 TEST_AND_RETURN_FALSE( | |
| 305 utils::MakeTempFile(kTempFileTemplate, &temp_new_file_path, &new_fd)); | |
| 306 TEST_AND_RETURN_FALSE(new_fd >= 0); | |
| 307 ScopedPathUnlinker temp_new_file_path_unlinker(temp_new_file_path); | |
| 308 ScopedFdCloser new_fd_closer(&new_fd); | |
| 309 TEST_AND_RETURN_FALSE(utils::WriteAll(new_fd, | |
| 310 &new_metadata[0], | |
| 311 new_metadata.size())); | |
| 312 | |
| 313 // Perform bsdiff on these files | |
| 314 TEST_AND_RETURN_FALSE( | |
| 315 BsdiffFiles(temp_old_file_path, temp_new_file_path, bsdiff_delta)); | |
| 316 CHECK_GT(bsdiff_delta->size(), 0); | |
| 317 | |
| 318 return true; | |
| 319 } | |
| 320 | |
| 321 // Add the specified metadata extents to the graph and blocks vector. | |
| 322 bool AddMetadataExtents(Graph* graph, | |
| 323 vector<Block>* blocks, | |
| 324 const ext2_filsys fs_old, | |
| 325 const ext2_filsys fs_new, | |
| 326 const string& metadata_name, | |
| 327 const vector<Extent>& extents, | |
| 328 int data_fd, | |
| 329 off_t* data_file_size) { | |
| 330 vector<char> data; // Data blob that will be written to delta file. | |
| 331 | |
| 332 // Read in the metadata blocks from the old and new image. | |
| 333 vector<char> old_data; | |
| 334 TEST_AND_RETURN_FALSE(ReadExtentsData(fs_old, extents, &old_data)); | |
| 335 | |
| 336 vector<char> new_data; | |
| 337 TEST_AND_RETURN_FALSE(ReadExtentsData(fs_new, extents, &new_data)); | |
| 338 | |
| 339 // Determine the best way to compress this. | |
| 340 vector<char> new_data_bz; | |
| 341 TEST_AND_RETURN_FALSE(BzipCompress(new_data, &new_data_bz)); | |
| 342 CHECK(!new_data_bz.empty()); | |
| 343 | |
| 344 DeltaArchiveManifest_InstallOperation op; | |
| 345 size_t current_best_size = 0; | |
| 346 if (new_data.size() <= new_data_bz.size()) { | |
| 347 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE); | |
| 348 current_best_size = new_data.size(); | |
| 349 data = new_data; | |
| 350 } else { | |
| 351 op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); | |
| 352 current_best_size = new_data_bz.size(); | |
| 353 data = new_data_bz; | |
| 354 } | |
| 355 | |
| 356 if (old_data == new_data) { | |
| 357 // No change in data. | |
| 358 op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); | |
| 359 current_best_size = 0; | |
| 360 data.clear(); | |
| 361 } else { | |
| 362 // Try bsdiff of old to new data | |
| 363 vector<char> bsdiff_delta; | |
| 364 TEST_AND_RETURN_FALSE(ComputeMetadataBsdiff(old_data, | |
| 365 new_data, | |
| 366 &bsdiff_delta)); | |
| 367 CHECK_GT(bsdiff_delta.size(), 0); | |
| 368 | |
| 369 if (bsdiff_delta.size() < current_best_size) { | |
| 370 op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF); | |
| 371 current_best_size = bsdiff_delta.size(); | |
| 372 data = bsdiff_delta; | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 CHECK_EQ(data.size(), current_best_size); | |
| 377 | |
| 378 // Set the source and dest extents to be the same since the filesystem | |
| 379 // structures are identical | |
| 380 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE || | |
| 381 op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) { | |
| 382 DeltaDiffGenerator::StoreExtents(extents, op.mutable_src_extents()); | |
| 383 op.set_src_length(old_data.size()); | |
| 384 } | |
| 385 | |
| 386 DeltaDiffGenerator::StoreExtents(extents, op.mutable_dst_extents()); | |
| 387 op.set_dst_length(new_data.size()); | |
| 388 | |
| 389 // Write data to output file | |
| 390 if (op.type() != DeltaArchiveManifest_InstallOperation_Type_MOVE) { | |
| 391 op.set_data_offset(*data_file_size); | |
| 392 op.set_data_length(data.size()); | |
| 393 } | |
| 394 | |
| 395 TEST_AND_RETURN_FALSE(utils::WriteAll(data_fd, &data[0], data.size())); | |
| 396 *data_file_size += data.size(); | |
| 397 | |
| 398 // Now, insert into graph and blocks vector | |
| 399 graph->resize(graph->size() + 1); | |
| 400 Vertex::Index vertex = graph->size() - 1; | |
| 401 (*graph)[vertex].op = op; | |
| 402 CHECK((*graph)[vertex].op.has_type()); | |
| 403 (*graph)[vertex].file_name = metadata_name; | |
| 404 | |
| 405 TEST_AND_RETURN_FALSE(AddInstallOpToBlocksVector((*graph)[vertex].op, | |
| 406 blocks, | |
| 407 *graph, | |
| 408 vertex)); | |
| 409 | |
| 410 return true; | |
| 411 } | |
| 412 | |
| 413 // Reads the file system metadata extents. | |
| 414 bool ReadFilesystemMetadata(Graph* graph, | |
| 415 vector<Block>* blocks, | |
| 416 const ext2_filsys fs_old, | |
| 417 const ext2_filsys fs_new, | |
| 418 int data_fd, | |
| 419 off_t* data_file_size) { | |
| 420 LOG(INFO) << "Processing <rootfs-metadata>"; | |
| 421 | |
| 422 // Read all the extents that belong to the main file system metadata. | |
| 423 // The metadata blocks are at the the start of each block group and goes | |
|
petkov
2010/12/10 00:46:55
typo: the the
thieule
2010/12/14 23:11:21
Done.
| |
| 424 // until the end of the inode table. | |
| 425 for (dgrp_t bg = 0; bg < fs_old->group_desc_count; bg++) { | |
| 426 struct ext2_group_desc* group_desc = &fs_old->group_desc[bg]; | |
| 427 __u32 num_metadata_blocks = (group_desc->bg_inode_table + | |
| 428 fs_old->inode_blocks_per_group) - | |
| 429 (bg * fs_old->super->s_blocks_per_group); | |
| 430 __u32 bg_start_block = bg * fs_old->super->s_blocks_per_group; | |
| 431 | |
| 432 // Due to bsdiff slowness, we're going to break each block group down | |
|
petkov
2010/12/10 00:46:55
would it be better for the payload size to not bre
thieule
2010/12/14 23:11:21
I ran this without breaking up into chunks and bsd
| |
| 433 // into metadata chunks and feed them to bsdiff. | |
| 434 __u32 num_chunks = 4; | |
| 435 __u32 blocks_per_chunk = num_metadata_blocks / num_chunks; | |
| 436 __u32 curr_block = bg_start_block; | |
| 437 for (__u32 chunk = 0; chunk < num_chunks; chunk++) { | |
| 438 | |
|
petkov
2010/12/10 00:46:55
remove blank line
thieule
2010/12/14 23:11:21
Done.
| |
| 439 __u32 end_block = 0; | |
| 440 if (chunk < num_chunks - 1) { | |
| 441 end_block = curr_block + blocks_per_chunk; | |
| 442 } else { | |
| 443 end_block = bg_start_block + num_metadata_blocks; | |
| 444 } | |
| 445 | |
| 446 vector<Extent> extents; | |
| 447 for (__u32 i = curr_block; i < end_block; i++) { | |
|
petkov
2010/12/10 00:46:55
there's an ExtentForRange utility in extent_ranges
thieule
2010/12/14 23:11:21
Done.
| |
| 448 graph_utils::AppendBlockToExtents(&extents, i); | |
| 449 } | |
| 450 | |
| 451 std::stringstream metadata_name; | |
| 452 metadata_name << "<rootfs-bg-" << bg << "-" << chunk << "-metadata>"; | |
|
petkov
2010/12/10 00:46:55
maybe use StringPrintf instead?
thieule
2010/12/14 23:11:21
Done.
| |
| 453 | |
| 454 LOG(INFO) << "Processing " << metadata_name.str(); | |
| 455 | |
| 456 TEST_AND_RETURN_FALSE(AddMetadataExtents(graph, | |
| 457 blocks, | |
| 458 fs_old, | |
| 459 fs_new, | |
| 460 metadata_name.str(), | |
| 461 extents, | |
| 462 data_fd, | |
| 463 data_file_size)); | |
| 464 | |
| 465 curr_block += blocks_per_chunk; | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 return true; | |
| 470 } | |
| 471 | |
| 472 // Processes all blocks belonging to an inode | |
| 473 int ProcessInodeAllBlocks(ext2_filsys fs, | |
| 474 blk_t* blocknr, | |
| 475 e2_blkcnt_t blockcnt, | |
| 476 blk_t ref_blk, | |
| 477 int ref_offset, | |
| 478 void* priv) { | |
| 479 vector<Extent>* extents = static_cast<vector<Extent>*>(priv); | |
| 480 graph_utils::AppendBlockToExtents(extents, *blocknr); | |
| 481 return 0; | |
| 482 } | |
| 483 | |
| 484 // Processes only indirect, double indirect or triple indirect metadata | |
| 485 // blocks belonging to an inode | |
| 486 int ProcessInodeMetadataBlocks(ext2_filsys fs, | |
| 487 blk_t* blocknr, | |
| 488 e2_blkcnt_t blockcnt, | |
| 489 blk_t ref_blk, | |
| 490 int ref_offset, | |
| 491 void* priv) { | |
| 492 vector<Extent>* extents = static_cast<vector<Extent>*>(priv); | |
| 493 if (blockcnt < 0) { | |
| 494 graph_utils::AppendBlockToExtents(extents, *blocknr); | |
| 495 } | |
| 496 return 0; | |
| 497 } | |
| 498 | |
| 499 // Read inode metadata blocks. | |
| 500 bool ReadInodeMetadata(Graph* graph, | |
| 501 vector<Block>* blocks, | |
| 502 const ext2_filsys fs_old, | |
| 503 const ext2_filsys fs_new, | |
| 504 int data_fd, | |
| 505 off_t* data_file_size) { | |
| 506 TEST_AND_RETURN_FALSE_ERRCODE(ext2fs_read_inode_bitmap(fs_old)); | |
| 507 | |
| 508 TEST_AND_RETURN_FALSE_ERRCODE(ext2fs_read_inode_bitmap(fs_new)); | |
| 509 | |
| 510 ext2_inode_scan iscan; | |
| 511 TEST_AND_RETURN_FALSE_ERRCODE(ext2fs_open_inode_scan(fs_old, 0, &iscan)); | |
| 512 | |
| 513 ext2_ino_t ino; | |
| 514 ext2_inode old_inode; | |
| 515 while (true) { | |
| 516 // Get the next inode on both file systems | |
| 517 errcode_t error = ext2fs_get_next_inode(iscan, &ino, &old_inode); | |
| 518 if (error) { | |
| 519 LOG(ERROR) << "Failed to retrieve next inode (" << error << ")"; | |
| 520 break; | |
| 521 } | |
| 522 | |
| 523 if (ino == 0) { | |
| 524 break; | |
| 525 } | |
| 526 | |
| 527 if (ino == EXT2_RESIZE_INO) { | |
| 528 continue; | |
| 529 } | |
| 530 | |
| 531 ext2_inode new_inode; | |
| 532 error = ext2fs_read_inode(fs_new, ino, &new_inode); | |
| 533 if (error) { | |
| 534 LOG(ERROR) << "Failed to retrieve new inode (" << error << ")"; | |
| 535 continue; | |
| 536 } | |
| 537 | |
| 538 // Skip inodes that are not in use | |
| 539 if (!ext2fs_test_inode_bitmap(fs_old->inode_map, ino) || | |
| 540 !ext2fs_test_inode_bitmap(fs_new->inode_map, ino)) { | |
| 541 continue; | |
| 542 } | |
| 543 | |
| 544 // Skip inodes that have no data blocks | |
| 545 if (old_inode.i_blocks == 0 || new_inode.i_blocks == 0) { | |
| 546 continue; | |
| 547 } | |
| 548 | |
| 549 // Skip inodes that are not the same type | |
| 550 bool is_old_dir = (ext2fs_check_directory(fs_old, ino) == 0); | |
| 551 bool is_new_dir = (ext2fs_check_directory(fs_new, ino) == 0); | |
| 552 if (is_old_dir != is_new_dir) { | |
| 553 continue; | |
| 554 } | |
| 555 | |
| 556 // Process the inodes metadata blocks | |
| 557 // For normal files, metadata blocks are indirect, double indirect | |
| 558 // and triple indirect blocks (no data blocks). For directories and | |
| 559 // the journal, all blocks are considered metadata blocks. | |
| 560 LOG(INFO) << "Processing inode " << ino << " metadata"; | |
| 561 | |
| 562 bool all_blocks = ((ino == EXT2_JOURNAL_INO) || is_old_dir || is_new_dir); | |
| 563 | |
| 564 vector<Extent> old_extents; | |
| 565 error = ext2fs_block_iterate2(fs_old, ino, 0, NULL, | |
| 566 all_blocks ? ProcessInodeAllBlocks : | |
| 567 ProcessInodeMetadataBlocks, | |
| 568 &old_extents); | |
| 569 if (error) { | |
| 570 LOG(ERROR) << "Failed to enumerate old inode " << ino | |
| 571 << " blocks (" << error << ")"; | |
| 572 continue; | |
| 573 } | |
| 574 | |
| 575 vector<Extent> new_extents; | |
| 576 error = ext2fs_block_iterate2(fs_new, ino, 0, NULL, | |
| 577 all_blocks ? ProcessInodeAllBlocks : | |
| 578 ProcessInodeMetadataBlocks, | |
| 579 &new_extents); | |
| 580 if (error) { | |
| 581 LOG(ERROR) << "Failed to enumerate new inode " << ino | |
| 582 << " blocks (" << error << ")"; | |
| 583 continue; | |
| 584 } | |
| 585 | |
| 586 // Skip inode if there are no metadata blocks | |
| 587 if (old_extents.size() == 0 || new_extents.size() == 0) { | |
| 588 continue; | |
| 589 } | |
| 590 | |
| 591 // Make sure the two inodes have the same metadata blocks | |
| 592 if (old_extents.size() != new_extents.size()) { | |
| 593 continue; | |
| 594 } | |
| 595 | |
| 596 bool same_metadata_extents = true; | |
| 597 vector<Extent>::iterator it_old; | |
| 598 vector<Extent>::iterator it_new; | |
| 599 for (it_old = old_extents.begin(), | |
| 600 it_new = new_extents.begin(); | |
| 601 it_old != old_extents.end() && it_new != new_extents.end(); | |
| 602 it_old++, it_new++) { | |
| 603 if (it_old->start_block() != it_new->start_block() || | |
| 604 it_old->num_blocks() != it_new->num_blocks()) { | |
| 605 same_metadata_extents = false; | |
| 606 break; | |
| 607 } | |
| 608 } | |
| 609 | |
| 610 if (!same_metadata_extents) { | |
| 611 continue; | |
| 612 } | |
| 613 | |
| 614 // We have identical inode metadata blocks, we can now add them to | |
| 615 // our graph and blocks vector | |
| 616 std::stringstream metadata_name; | |
| 617 metadata_name << "<rootfs-inode-" << ino << "-metadata>"; | |
| 618 TEST_AND_RETURN_FALSE(AddMetadataExtents(graph, | |
| 619 blocks, | |
| 620 fs_old, | |
| 621 fs_new, | |
| 622 metadata_name.str(), | |
| 623 old_extents, | |
| 624 data_fd, | |
| 625 data_file_size)); | |
| 626 } | |
| 627 | |
| 628 ext2fs_close_inode_scan(iscan); | |
| 629 | |
| 630 return true; | |
| 631 } | |
| 632 | |
| 244 // This class allocates non-existent temp blocks, starting from | 633 // This class allocates non-existent temp blocks, starting from |
| 245 // kTempBlockStart. Other code is responsible for converting these | 634 // kTempBlockStart. Other code is responsible for converting these |
| 246 // temp blocks into real blocks, as the client can't read or write to | 635 // temp blocks into real blocks, as the client can't read or write to |
| 247 // these blocks. | 636 // these blocks. |
| 248 class DummyExtentAllocator { | 637 class DummyExtentAllocator { |
| 249 public: | 638 public: |
| 250 explicit DummyExtentAllocator() | 639 explicit DummyExtentAllocator() |
| 251 : next_block_(kTempBlockStart) {} | 640 : next_block_(kTempBlockStart) {} |
| 252 vector<Extent> Allocate(const uint64_t block_count) { | 641 vector<Extent> Allocate(const uint64_t block_count) { |
| 253 vector<Extent> ret(1); | 642 vector<Extent> ret(1); |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 613 dst_extent->set_num_blocks((new_data.size() + kBlockSize - 1) / kBlockSize); | 1002 dst_extent->set_num_blocks((new_data.size() + kBlockSize - 1) / kBlockSize); |
| 614 } | 1003 } |
| 615 operation.set_dst_length(new_data.size()); | 1004 operation.set_dst_length(new_data.size()); |
| 616 | 1005 |
| 617 out_data->swap(data); | 1006 out_data->swap(data); |
| 618 *out_op = operation; | 1007 *out_op = operation; |
| 619 | 1008 |
| 620 return true; | 1009 return true; |
| 621 } | 1010 } |
| 622 | 1011 |
| 1012 bool DeltaDiffGenerator::DeltaReadMetadata(Graph* graph, | |
| 1013 vector<Block>* blocks, | |
| 1014 const string& old_image, | |
| 1015 const string& new_image, | |
| 1016 int data_fd, | |
| 1017 off_t* data_file_size) { | |
| 1018 // Open the two file systems. | |
| 1019 ext2_filsys fs_old; | |
| 1020 TEST_AND_RETURN_FALSE_ERRCODE(ext2fs_open(old_image.c_str(), 0, 0, 0, | |
| 1021 unix_io_manager, &fs_old)); | |
| 1022 ScopedExt2fsCloser fs_old_closer(fs_old); | |
| 1023 | |
| 1024 ext2_filsys fs_new; | |
| 1025 TEST_AND_RETURN_FALSE_ERRCODE(ext2fs_open(new_image.c_str(), 0, 0, 0, | |
| 1026 unix_io_manager, &fs_new)); | |
| 1027 ScopedExt2fsCloser fs_new_closer(fs_new); | |
| 1028 | |
| 1029 // Make sure these two file systems are the same. | |
|
petkov
2010/12/10 00:46:55
clarify that if they aren't the same we'll just se
thieule
2010/12/14 23:11:21
Done.
| |
| 1030 if (fs_old->blocksize != fs_new->blocksize || | |
| 1031 fs_old->fragsize != fs_new->fragsize || | |
| 1032 fs_old->group_desc_count != fs_new->group_desc_count || | |
| 1033 fs_old->inode_blocks_per_group != fs_new->inode_blocks_per_group || | |
| 1034 fs_old->super->s_inodes_count != fs_new->super->s_inodes_count || | |
| 1035 fs_old->super->s_blocks_count != fs_new->super->s_blocks_count) { | |
| 1036 return true; | |
| 1037 } | |
| 1038 | |
| 1039 // Process the main file system metadata (superblock, inode tables, etc) | |
| 1040 TEST_AND_RETURN_FALSE(ReadFilesystemMetadata(graph, | |
| 1041 blocks, | |
| 1042 fs_old, | |
| 1043 fs_new, | |
| 1044 data_fd, | |
| 1045 data_file_size)); | |
| 1046 | |
| 1047 // Process each inode metadata blocks. | |
| 1048 TEST_AND_RETURN_FALSE(ReadInodeMetadata(graph, | |
| 1049 blocks, | |
| 1050 fs_old, | |
| 1051 fs_new, | |
| 1052 data_fd, | |
| 1053 data_file_size)); | |
| 1054 | |
| 1055 return true; | |
| 1056 } | |
| 1057 | |
| 623 bool DeltaDiffGenerator::InitializePartitionInfo(bool is_kernel, | 1058 bool DeltaDiffGenerator::InitializePartitionInfo(bool is_kernel, |
| 624 const string& partition, | 1059 const string& partition, |
| 625 PartitionInfo* info) { | 1060 PartitionInfo* info) { |
| 626 int64_t size = 0; | 1061 int64_t size = 0; |
| 627 if (is_kernel) { | 1062 if (is_kernel) { |
| 628 size = utils::FileSize(partition); | 1063 size = utils::FileSize(partition); |
| 629 } else { | 1064 } else { |
| 630 int block_count = 0, block_size = 0; | 1065 int block_count = 0, block_size = 0; |
| 631 TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(partition, | 1066 TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(partition, |
| 632 &block_count, | 1067 &block_count, |
| (...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1383 | 1818 |
| 1384 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, | 1819 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, |
| 1385 &blocks, | 1820 &blocks, |
| 1386 old_root, | 1821 old_root, |
| 1387 new_root, | 1822 new_root, |
| 1388 fd, | 1823 fd, |
| 1389 &data_file_size)); | 1824 &data_file_size)); |
| 1390 LOG(INFO) << "done reading normal files"; | 1825 LOG(INFO) << "done reading normal files"; |
| 1391 CheckGraph(graph); | 1826 CheckGraph(graph); |
| 1392 | 1827 |
| 1828 LOG(INFO) << "Starting metadata processing"; | |
| 1829 TEST_AND_RETURN_FALSE(DeltaReadMetadata(&graph, | |
| 1830 &blocks, | |
| 1831 old_image, | |
| 1832 new_image, | |
| 1833 fd, | |
| 1834 &data_file_size)); | |
| 1835 LOG(INFO) << "Done metadata processing"; | |
| 1836 CheckGraph(graph); | |
| 1837 | |
| 1393 graph.resize(graph.size() + 1); | 1838 graph.resize(graph.size() + 1); |
| 1394 TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks, | 1839 TEST_AND_RETURN_FALSE(ReadUnwrittenBlocks(blocks, |
| 1395 fd, | 1840 fd, |
| 1396 &data_file_size, | 1841 &data_file_size, |
| 1397 new_image, | 1842 new_image, |
| 1398 &graph.back())); | 1843 &graph.back())); |
| 1399 | 1844 |
| 1400 // Final scratch block (if there's space) | 1845 // Final scratch block (if there's space) |
| 1401 if (blocks.size() < (kRootFSPartitionSize / kBlockSize)) { | 1846 if (blocks.size() < (kRootFSPartitionSize / kBlockSize)) { |
| 1402 scratch_vertex = graph.size(); | 1847 scratch_vertex = graph.size(); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1583 | 2028 |
| 1584 LOG(INFO) << "All done. Successfully created delta file."; | 2029 LOG(INFO) << "All done. Successfully created delta file."; |
| 1585 return true; | 2030 return true; |
| 1586 } | 2031 } |
| 1587 | 2032 |
| 1588 const char* const kBsdiffPath = "bsdiff"; | 2033 const char* const kBsdiffPath = "bsdiff"; |
| 1589 const char* const kBspatchPath = "bspatch"; | 2034 const char* const kBspatchPath = "bspatch"; |
| 1590 const char* const kDeltaMagic = "CrAU"; | 2035 const char* const kDeltaMagic = "CrAU"; |
| 1591 | 2036 |
| 1592 }; // namespace chromeos_update_engine | 2037 }; // namespace chromeos_update_engine |
| OLD | NEW |