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_performer.h" | 5 #include "update_engine/delta_performer.h" |
6 | 6 |
7 #include <endian.h> | 7 #include <endian.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 } | 191 } |
192 // Remove protobuf and header info from buffer_, so buffer_ contains | 192 // Remove protobuf and header info from buffer_, so buffer_ contains |
193 // just data blobs | 193 // just data blobs |
194 manifest_metadata_size_ = strlen(kDeltaMagic) + kDeltaVersionLength + | 194 manifest_metadata_size_ = strlen(kDeltaMagic) + kDeltaVersionLength + |
195 kDeltaProtobufLengthLength + protobuf_length; | 195 kDeltaProtobufLengthLength + protobuf_length; |
196 DiscardBufferHeadBytes(manifest_metadata_size_); | 196 DiscardBufferHeadBytes(manifest_metadata_size_); |
197 LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize, | 197 LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize, |
198 manifest_metadata_size_)) | 198 manifest_metadata_size_)) |
199 << "Unable to save the manifest metadata size."; | 199 << "Unable to save the manifest metadata size."; |
200 manifest_valid_ = true; | 200 manifest_valid_ = true; |
201 block_size_ = manifest_.block_size(); | 201 if (!PrimeUpdateState()) { |
| 202 LOG(ERROR) << "Unable to prime the update state."; |
| 203 return -EINVAL; |
| 204 } |
202 } | 205 } |
203 ssize_t total_operations = manifest_.install_operations_size() + | 206 ssize_t total_operations = manifest_.install_operations_size() + |
204 manifest_.kernel_install_operations_size(); | 207 manifest_.kernel_install_operations_size(); |
205 while (next_operation_num_ < total_operations) { | 208 while (next_operation_num_ < total_operations) { |
206 const DeltaArchiveManifest_InstallOperation &op = | 209 const DeltaArchiveManifest_InstallOperation &op = |
207 next_operation_num_ < manifest_.install_operations_size() ? | 210 next_operation_num_ < manifest_.install_operations_size() ? |
208 manifest_.install_operations(next_operation_num_) : | 211 manifest_.install_operations(next_operation_num_) : |
209 manifest_.kernel_install_operations( | 212 manifest_.kernel_install_operations( |
210 next_operation_num_ - manifest_.install_operations_size()); | 213 next_operation_num_ - manifest_.install_operations_size()); |
211 if (!CanPerformInstallOperation(op)) | 214 if (!CanPerformInstallOperation(op)) |
212 break; | 215 break; |
213 ScopedTerminatorExitUnblocker exit_unblocker = | 216 ScopedTerminatorExitUnblocker exit_unblocker = |
214 ScopedTerminatorExitUnblocker(); // Avoids a compiler unused var bug. | 217 ScopedTerminatorExitUnblocker(); // Avoids a compiler unused var bug. |
215 // Log every thousandth operation, and also the first and last ones | 218 // Log every thousandth operation, and also the first and last ones |
216 if ((next_operation_num_ % 1000 == 0) || | 219 if ((next_operation_num_ % 1000 == 0) || |
217 (next_operation_num_ + 1 == total_operations)) { | 220 (next_operation_num_ + 1 == total_operations)) { |
218 LOG(INFO) << "Performing operation " << (next_operation_num_ + 1) << "/" | 221 LOG(INFO) << "Performing operation " << (next_operation_num_ + 1) << "/" |
219 << total_operations; | 222 << total_operations; |
220 } | 223 } |
221 bool is_kernel_partition = | 224 bool is_kernel_partition = |
222 (next_operation_num_ >= manifest_.install_operations_size()); | 225 (next_operation_num_ >= manifest_.install_operations_size()); |
223 // If about to start a non-idempotent operation, clear the update state so | 226 // If about to start a non-idempotent operation, clear the update state so |
224 // that if the operation gets interrupted, we don't try to resume the | 227 // that if the operation gets interrupted, we don't try to resume the |
225 // update. | 228 // update. |
226 if (!IsIdempotentOperation(op)) { | 229 if (!IsIdempotentOperation(op)) { |
227 Terminator::set_exit_blocked(true); | 230 Terminator::set_exit_blocked(true); |
228 ResetUpdateProgress(prefs_); | 231 ResetUpdateProgress(prefs_, true); |
229 } | 232 } |
230 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE || | 233 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE || |
231 op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) { | 234 op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) { |
232 if (!PerformReplaceOperation(op, is_kernel_partition)) { | 235 if (!PerformReplaceOperation(op, is_kernel_partition)) { |
233 LOG(ERROR) << "Failed to perform replace operation " | 236 LOG(ERROR) << "Failed to perform replace operation " |
234 << next_operation_num_; | 237 << next_operation_num_; |
235 return -EINVAL; | 238 return -EINVAL; |
236 } | 239 } |
237 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) { | 240 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) { |
238 if (!PerformMoveOperation(op, is_kernel_partition)) { | 241 if (!PerformMoveOperation(op, is_kernel_partition)) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 bool DeltaPerformer::PerformReplaceOperation( | 277 bool DeltaPerformer::PerformReplaceOperation( |
275 const DeltaArchiveManifest_InstallOperation& operation, | 278 const DeltaArchiveManifest_InstallOperation& operation, |
276 bool is_kernel_partition) { | 279 bool is_kernel_partition) { |
277 CHECK(operation.type() == \ | 280 CHECK(operation.type() == \ |
278 DeltaArchiveManifest_InstallOperation_Type_REPLACE || \ | 281 DeltaArchiveManifest_InstallOperation_Type_REPLACE || \ |
279 operation.type() == \ | 282 operation.type() == \ |
280 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); | 283 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); |
281 | 284 |
282 // Since we delete data off the beginning of the buffer as we use it, | 285 // Since we delete data off the beginning of the buffer as we use it, |
283 // the data we need should be exactly at the beginning of the buffer. | 286 // the data we need should be exactly at the beginning of the buffer. |
284 CHECK_EQ(buffer_offset_, operation.data_offset()); | 287 TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset()); |
285 CHECK_GE(buffer_.size(), operation.data_length()); | 288 TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length()); |
286 | 289 |
287 // Extract the signature message if it's in this operation. | 290 // Extract the signature message if it's in this operation. |
288 ExtractSignatureMessage(operation); | 291 ExtractSignatureMessage(operation); |
289 | 292 |
290 DirectExtentWriter direct_writer; | 293 DirectExtentWriter direct_writer; |
291 ZeroPadExtentWriter zero_pad_writer(&direct_writer); | 294 ZeroPadExtentWriter zero_pad_writer(&direct_writer); |
292 scoped_ptr<BzipExtentWriter> bzip_writer; | 295 scoped_ptr<BzipExtentWriter> bzip_writer; |
293 | 296 |
294 // Since bzip decompression is optional, we have a variable writer that will | 297 // Since bzip decompression is optional, we have a variable writer that will |
295 // point to one of the ExtentWriter objects above. | 298 // point to one of the ExtentWriter objects above. |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 ret.resize(ret.size() - 1); // Strip trailing comma off | 401 ret.resize(ret.size() - 1); // Strip trailing comma off |
399 *positions_string = ret; | 402 *positions_string = ret; |
400 return true; | 403 return true; |
401 } | 404 } |
402 | 405 |
403 bool DeltaPerformer::PerformBsdiffOperation( | 406 bool DeltaPerformer::PerformBsdiffOperation( |
404 const DeltaArchiveManifest_InstallOperation& operation, | 407 const DeltaArchiveManifest_InstallOperation& operation, |
405 bool is_kernel_partition) { | 408 bool is_kernel_partition) { |
406 // Since we delete data off the beginning of the buffer as we use it, | 409 // Since we delete data off the beginning of the buffer as we use it, |
407 // the data we need should be exactly at the beginning of the buffer. | 410 // the data we need should be exactly at the beginning of the buffer. |
408 CHECK_EQ(buffer_offset_, operation.data_offset()); | 411 TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset()); |
409 CHECK_GE(buffer_.size(), operation.data_length()); | 412 TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length()); |
410 | 413 |
411 string input_positions; | 414 string input_positions; |
412 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.src_extents(), | 415 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.src_extents(), |
413 block_size_, | 416 block_size_, |
414 operation.src_length(), | 417 operation.src_length(), |
415 &input_positions)); | 418 &input_positions)); |
416 string output_positions; | 419 string output_positions; |
417 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.dst_extents(), | 420 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.dst_extents(), |
418 block_size_, | 421 block_size_, |
419 operation.dst_length(), | 422 operation.dst_length(), |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 !sha256_context.empty()); | 567 !sha256_context.empty()); |
565 | 568 |
566 int64_t manifest_metadata_size = 0; | 569 int64_t manifest_metadata_size = 0; |
567 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsManifestMetadataSize, | 570 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsManifestMetadataSize, |
568 &manifest_metadata_size) && | 571 &manifest_metadata_size) && |
569 manifest_metadata_size > 0); | 572 manifest_metadata_size > 0); |
570 | 573 |
571 return true; | 574 return true; |
572 } | 575 } |
573 | 576 |
574 bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs) { | 577 bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs, bool quick) { |
575 TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation, | 578 TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation, |
576 kUpdateStateOperationInvalid)); | 579 kUpdateStateOperationInvalid)); |
| 580 if (!quick) { |
| 581 prefs->SetString(kPrefsUpdateCheckResponseHash, ""); |
| 582 prefs->SetInt64(kPrefsUpdateStateNextDataOffset, -1); |
| 583 prefs->SetString(kPrefsUpdateStateSHA256Context, ""); |
| 584 prefs->SetString(kPrefsUpdateStateSignedSHA256Context, ""); |
| 585 prefs->SetInt64(kPrefsManifestMetadataSize, -1); |
| 586 } |
577 return true; | 587 return true; |
578 } | 588 } |
579 | 589 |
580 bool DeltaPerformer::CheckpointUpdateProgress() { | 590 bool DeltaPerformer::CheckpointUpdateProgress() { |
581 Terminator::set_exit_blocked(true); | 591 Terminator::set_exit_blocked(true); |
582 if (last_updated_buffer_offset_ != buffer_offset_) { | 592 if (last_updated_buffer_offset_ != buffer_offset_) { |
583 // Resets the progress in case we die in the middle of the state update. | 593 // Resets the progress in case we die in the middle of the state update. |
584 ResetUpdateProgress(prefs_); | 594 ResetUpdateProgress(prefs_, true); |
585 TEST_AND_RETURN_FALSE( | 595 TEST_AND_RETURN_FALSE( |
586 prefs_->SetString(kPrefsUpdateStateSHA256Context, | 596 prefs_->SetString(kPrefsUpdateStateSHA256Context, |
587 hash_calculator_.GetContext())); | 597 hash_calculator_.GetContext())); |
588 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataOffset, | 598 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataOffset, |
589 buffer_offset_)); | 599 buffer_offset_)); |
590 last_updated_buffer_offset_ = buffer_offset_; | 600 last_updated_buffer_offset_ = buffer_offset_; |
591 } | 601 } |
592 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation, | 602 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation, |
593 next_operation_num_)); | 603 next_operation_num_)); |
594 return true; | 604 return true; |
595 } | 605 } |
596 | 606 |
| 607 bool DeltaPerformer::PrimeUpdateState() { |
| 608 CHECK(manifest_valid_); |
| 609 block_size_ = manifest_.block_size(); |
| 610 |
| 611 int64_t next_operation = kUpdateStateOperationInvalid; |
| 612 if (!prefs_->GetInt64(kPrefsUpdateStateNextOperation, &next_operation) || |
| 613 next_operation == kUpdateStateOperationInvalid || |
| 614 next_operation <= 0) { |
| 615 // Initiating a new update, no more state needs to be initialized. |
| 616 return true; |
| 617 } |
| 618 next_operation_num_ = next_operation; |
| 619 |
| 620 // Resuming an update -- load the rest of the update state. |
| 621 int64_t next_data_offset = -1; |
| 622 TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, |
| 623 &next_data_offset) && |
| 624 next_data_offset >= 0); |
| 625 buffer_offset_ = next_data_offset; |
| 626 |
| 627 // The signed hash context may be empty if the interrupted update didn't reach |
| 628 // the signature blob. |
| 629 prefs_->GetString(kPrefsUpdateStateSignedSHA256Context, |
| 630 &signed_hash_context_); |
| 631 |
| 632 string hash_context; |
| 633 TEST_AND_RETURN_FALSE(prefs_->GetString(kPrefsUpdateStateSHA256Context, |
| 634 &hash_context) && |
| 635 hash_calculator_.SetContext(hash_context)); |
| 636 |
| 637 int64_t manifest_metadata_size = 0; |
| 638 TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsManifestMetadataSize, |
| 639 &manifest_metadata_size) && |
| 640 manifest_metadata_size > 0); |
| 641 manifest_metadata_size_ = manifest_metadata_size; |
| 642 |
| 643 return true; |
| 644 } |
| 645 |
597 } // namespace chromeos_update_engine | 646 } // namespace chromeos_update_engine |
OLD | NEW |