| Index: filesystem_copier_action.cc
|
| diff --git a/filesystem_copier_action.cc b/filesystem_copier_action.cc
|
| index f3f71bdbee4b107ddfc7ccba92e1e68cb168da91..7da54a83cf9a6f792b2e0edbdb34d053b4902e85 100755
|
| --- a/filesystem_copier_action.cc
|
| +++ b/filesystem_copier_action.cc
|
| @@ -32,12 +32,14 @@ using std::vector;
|
| namespace chromeos_update_engine {
|
|
|
| namespace {
|
| -const off_t kCopyFileBufferSize = 512 * 1024;
|
| +const off_t kCopyFileBufferSize = 128 * 1024;
|
| } // namespace {}
|
|
|
| FilesystemCopierAction::FilesystemCopierAction(
|
| - bool copying_kernel_install_path)
|
| + bool copying_kernel_install_path,
|
| + bool verify_hash)
|
| : copying_kernel_install_path_(copying_kernel_install_path),
|
| + verify_hash_(verify_hash),
|
| src_stream_(NULL),
|
| dst_stream_(NULL),
|
| read_done_(false),
|
| @@ -68,44 +70,49 @@ void FilesystemCopierAction::PerformAction() {
|
| }
|
| install_plan_ = GetInputObject();
|
|
|
| - if (install_plan_.is_full_update || install_plan_.is_resume) {
|
| - // No copy needed. Done!
|
| + // Note that we do need to run hash verification for new-style full updates
|
| + // but currently the |is_full_update| field is set to true only for old-style
|
| + // full updates and we don't have any expected partition info in that case.
|
| + if (install_plan_.is_full_update ||
|
| + (!verify_hash_ && install_plan_.is_resume)) {
|
| + // No copy or hash verification needed. Done!
|
| if (HasOutputPipe())
|
| SetOutputObject(install_plan_);
|
| abort_action_completer.set_code(kActionCodeSuccess);
|
| return;
|
| }
|
|
|
| - string source = copy_source_;
|
| + const string destination = copying_kernel_install_path_ ?
|
| + install_plan_.kernel_install_path :
|
| + install_plan_.install_path;
|
| + string source = verify_hash_ ? destination : copy_source_;
|
| if (source.empty()) {
|
| source = copying_kernel_install_path_ ?
|
| utils::BootKernelDevice(utils::BootDevice()) :
|
| utils::BootDevice();
|
| }
|
| -
|
| - const string destination = copying_kernel_install_path_ ?
|
| - install_plan_.kernel_install_path :
|
| - install_plan_.install_path;
|
| -
|
| int src_fd = open(source.c_str(), O_RDONLY);
|
| if (src_fd < 0) {
|
| PLOG(ERROR) << "Unable to open " << source << " for reading:";
|
| return;
|
| }
|
| - int dst_fd = open(destination.c_str(),
|
| - O_WRONLY | O_TRUNC | O_CREAT,
|
| +
|
| + if (!verify_hash_) {
|
| + int dst_fd = open(destination.c_str(),
|
| + O_WRONLY | O_TRUNC | O_CREAT,
|
| 0644);
|
| - if (dst_fd < 0) {
|
| - close(src_fd);
|
| - PLOG(ERROR) << "Unable to open " << install_plan_.install_path
|
| - << " for writing:";
|
| - return;
|
| + if (dst_fd < 0) {
|
| + close(src_fd);
|
| + PLOG(ERROR) << "Unable to open " << install_plan_.install_path
|
| + << " for writing:";
|
| + return;
|
| + }
|
| +
|
| + dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
|
| }
|
|
|
| DetermineFilesystemSize(src_fd);
|
| -
|
| src_stream_ = g_unix_input_stream_new(src_fd, TRUE);
|
| - dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
|
|
|
| for (int i = 0; i < 2; i++) {
|
| buffer_[i].resize(kCopyFileBufferSize);
|
| @@ -126,22 +133,22 @@ void FilesystemCopierAction::TerminateProcessing() {
|
| }
|
| }
|
|
|
| -void FilesystemCopierAction::Cleanup(bool success) {
|
| +void FilesystemCopierAction::Cleanup(ActionExitCode code) {
|
| for (int i = 0; i < 2; i++) {
|
| g_object_unref(canceller_[i]);
|
| canceller_[i] = NULL;
|
| }
|
| g_object_unref(src_stream_);
|
| src_stream_ = NULL;
|
| - g_object_unref(dst_stream_);
|
| - dst_stream_ = NULL;
|
| + if (dst_stream_) {
|
| + g_object_unref(dst_stream_);
|
| + dst_stream_ = NULL;
|
| + }
|
| if (cancelled_)
|
| return;
|
| - if (success && HasOutputPipe())
|
| + if (code == kActionCodeSuccess && HasOutputPipe())
|
| SetOutputObject(install_plan_);
|
| - processor_->ActionComplete(
|
| - this,
|
| - success ? kActionCodeSuccess : kActionCodeError);
|
| + processor_->ActionComplete(this, code);
|
| }
|
|
|
| void FilesystemCopierAction::AsyncReadReadyCallback(GObject *source_object,
|
| @@ -164,19 +171,21 @@ void FilesystemCopierAction::AsyncReadReadyCallback(GObject *source_object,
|
| } else {
|
| buffer_valid_size_[index] = bytes_read;
|
| buffer_state_[index] = kBufferStateFull;
|
| - }
|
| -
|
| - if (bytes_read > 0) {
|
| filesystem_size_ -= bytes_read;
|
| }
|
| -
|
| SpawnAsyncActions();
|
|
|
| if (bytes_read > 0) {
|
| + // If read_done_ is set, SpawnAsyncActions may finalize the hash so the hash
|
| + // update below would happen too late.
|
| + CHECK(!read_done_);
|
| if (!hasher_.Update(buffer_[index].data(), bytes_read)) {
|
| LOG(ERROR) << "Unable to update the hash.";
|
| failed_ = true;
|
| }
|
| + if (verify_hash_) {
|
| + buffer_state_[index] = kBufferStateEmpty;
|
| + }
|
| }
|
| }
|
|
|
| @@ -235,23 +244,26 @@ void FilesystemCopierAction::SpawnAsyncActions() {
|
| }
|
| if (failed_ || cancelled_) {
|
| if (!reading && !writing) {
|
| - Cleanup(false);
|
| + Cleanup(kActionCodeError);
|
| }
|
| return;
|
| }
|
| for (int i = 0; i < 2; i++) {
|
| if (!reading && !read_done_ && buffer_state_[i] == kBufferStateEmpty) {
|
| + int64_t bytes_to_read = std::min(static_cast<int64_t>(buffer_[0].size()),
|
| + filesystem_size_);
|
| g_input_stream_read_async(
|
| src_stream_,
|
| buffer_[i].data(),
|
| - GetBytesToRead(),
|
| + bytes_to_read,
|
| G_PRIORITY_DEFAULT,
|
| canceller_[i],
|
| &FilesystemCopierAction::StaticAsyncReadReadyCallback,
|
| this);
|
| reading = true;
|
| buffer_state_[i] = kBufferStateReading;
|
| - } else if (!writing && buffer_state_[i] == kBufferStateFull) {
|
| + } else if (!writing && !verify_hash_ &&
|
| + buffer_state_[i] == kBufferStateFull) {
|
| g_output_stream_write_async(
|
| dst_stream_,
|
| buffer_[i].data(),
|
| @@ -266,22 +278,43 @@ void FilesystemCopierAction::SpawnAsyncActions() {
|
| }
|
| if (!reading && !writing) {
|
| // We're done!
|
| + ActionExitCode code = kActionCodeSuccess;
|
| if (hasher_.Finalize()) {
|
| - LOG(INFO) << "hash: " << hasher_.hash();
|
| - if (copying_kernel_install_path_) {
|
| - install_plan_.current_kernel_hash = hasher_.raw_hash();
|
| + LOG(INFO) << "Hash: " << hasher_.hash();
|
| + if (verify_hash_) {
|
| + if (copying_kernel_install_path_) {
|
| + if (install_plan_.kernel_hash != hasher_.raw_hash()) {
|
| + code = kActionCodeNewKernelVerificationError;
|
| + LOG(ERROR) << "New kernel verification failed.";
|
| + }
|
| + } else {
|
| + if (install_plan_.rootfs_hash != hasher_.raw_hash()) {
|
| + code = kActionCodeNewRootfsVerificationError;
|
| + LOG(ERROR) << "New rootfs verification failed.";
|
| + }
|
| + }
|
| } else {
|
| - install_plan_.current_rootfs_hash = hasher_.raw_hash();
|
| + if (copying_kernel_install_path_) {
|
| + install_plan_.kernel_hash = hasher_.raw_hash();
|
| + } else {
|
| + install_plan_.rootfs_hash = hasher_.raw_hash();
|
| + }
|
| }
|
| - Cleanup(true);
|
| } else {
|
| LOG(ERROR) << "Unable to finalize the hash.";
|
| - Cleanup(false);
|
| + code = kActionCodeError;
|
| }
|
| + Cleanup(code);
|
| }
|
| }
|
|
|
| void FilesystemCopierAction::DetermineFilesystemSize(int fd) {
|
| + if (verify_hash_) {
|
| + filesystem_size_ = copying_kernel_install_path_ ?
|
| + install_plan_.kernel_size : install_plan_.rootfs_size;
|
| + LOG(INFO) << "Filesystem size: " << filesystem_size_;
|
| + return;
|
| + }
|
| filesystem_size_ = kint64max;
|
| int block_count = 0, block_size = 0;
|
| if (!copying_kernel_install_path_ &&
|
| @@ -292,8 +325,4 @@ void FilesystemCopierAction::DetermineFilesystemSize(int fd) {
|
| }
|
| }
|
|
|
| -int64_t FilesystemCopierAction::GetBytesToRead() {
|
| - return std::min(static_cast<int64_t>(buffer_[0].size()), filesystem_size_);
|
| -}
|
| -
|
| } // namespace chromeos_update_engine
|
|
|