| Index: chrome/utility/image_writer/image_writer.cc
|
| diff --git a/chrome/utility/image_writer/image_writer.cc b/chrome/utility/image_writer/image_writer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ac6aa9f3e84546d27b7b576c3351c50e46827cd7
|
| --- /dev/null
|
| +++ b/chrome/utility/image_writer/image_writer.cc
|
| @@ -0,0 +1,298 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this image code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/platform_file.h"
|
| +#include "chrome/utility/image_writer/error_messages.h"
|
| +#include "chrome/utility/image_writer/image_writer.h"
|
| +#include "chrome/utility/image_writer/image_writer_handler.h"
|
| +#include "content/public/utility/utility_thread.h"
|
| +
|
| +namespace chrome {
|
| +namespace image_writer {
|
| +
|
| +const int kProgressComplete = 100;
|
| +const int kBurningBlockSize = 8 * 1024; // 8 KiB
|
| +
|
| +ImageWriter::ImageWriter(base::WeakPtr<ImageWriterHandler> handler)
|
| + : image_file_(base::kInvalidPlatformFileValue),
|
| + device_file_(base::kInvalidPlatformFileValue),
|
| + total_bytes_(0),
|
| + cancelled_(false),
|
| + handler_(handler) {
|
| +}
|
| +
|
| +void ImageWriter::Write(const base::FilePath& image_path,
|
| + const base::FilePath& device_path) {
|
| + DVLOG(0) << "Starting write from " << image_path.value()
|
| + << " to " << device_path.value();
|
| +
|
| + if ((image_file_ != base::kInvalidPlatformFileValue
|
| + || device_file_ != base::kInvalidPlatformFileValue)
|
| + && handler_) {
|
| + handler_->SendFailed(error::kOperationAlreadyInProgress);
|
| + return;
|
| + }
|
| +
|
| + image_path_ = image_path;
|
| + device_path_ = device_path;
|
| +
|
| + base::PlatformFileError error;
|
| +
|
| + image_file_ = base::CreatePlatformFile(
|
| + image_path_,
|
| + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
|
| + NULL,
|
| + &error);
|
| +
|
| + if (error != base::PLATFORM_FILE_OK) {
|
| + DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
|
| + Error(error::kOpenImage);
|
| + return;
|
| + }
|
| +
|
| + device_file_ = base::CreatePlatformFile(
|
| + device_path_,
|
| + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
|
| + NULL,
|
| + &error);
|
| +
|
| + if (error != base::PLATFORM_FILE_OK) {
|
| + DLOG(ERROR) << "Unable to open file for write: " << device_path_.value();
|
| + Error(error::kOpenDevice);
|
| + return;
|
| + }
|
| +
|
| + PostTask(base::Bind(&ImageWriter::WriteChunk, this));
|
| +}
|
| +
|
| +void ImageWriter::Verify(const base::FilePath& image_path,
|
| + const base::FilePath& device_path) {
|
| + DVLOG(0) << "Starting verification of " << image_path.value()
|
| + << " and " << device_path.value();
|
| +
|
| + if ((image_file_ != base::kInvalidPlatformFileValue
|
| + || device_file_ != base::kInvalidPlatformFileValue)
|
| + && handler_) {
|
| + handler_->SendFailed(error::kOperationAlreadyInProgress);
|
| + return;
|
| + }
|
| +
|
| + image_path_ = image_path;
|
| + device_path_ = device_path;
|
| +
|
| + base::PlatformFileError error;
|
| +
|
| + image_file_ = base::CreatePlatformFile(
|
| + image_path_,
|
| + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
|
| + NULL,
|
| + &error);
|
| +
|
| + if (error != base::PLATFORM_FILE_OK) {
|
| + DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
|
| + Error(error::kOpenImage);
|
| + return;
|
| + }
|
| +
|
| + device_file_ = base::CreatePlatformFile(
|
| + device_path_,
|
| + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
|
| + NULL,
|
| + &error);
|
| +
|
| + if (error != base::PLATFORM_FILE_OK) {
|
| + DLOG(ERROR) << "Unable to open file for read: " << device_path_.value();
|
| + Error(error::kOpenDevice);
|
| + return;
|
| + }
|
| +
|
| + PostTask(base::Bind(&ImageWriter::VerifyChunk, this));
|
| +}
|
| +
|
| +void ImageWriter::Cancel() {
|
| + CleanUp();
|
| + cancelled_ = true;
|
| +}
|
| +
|
| +ImageWriter::~ImageWriter() {
|
| +}
|
| +
|
| +void ImageWriter::PostTask(const base::Closure& task) {
|
| + base::MessageLoop::current()->PostTask(FROM_HERE, task);
|
| +}
|
| +
|
| +void ImageWriter::PostProgress(int progress) {
|
| + if (handler_)
|
| + handler_->SendProgress(progress);
|
| +}
|
| +
|
| +void ImageWriter::Error(const std::string& message) {
|
| + CleanUp();
|
| +
|
| + if (handler_)
|
| + handler_->SendFailed(message);
|
| +}
|
| +
|
| +void ImageWriter::WriteChunk() {
|
| +
|
| + if (cancelled_) {
|
| + return;
|
| + }
|
| +
|
| + char buffer[kBurningBlockSize];
|
| + base::PlatformFileInfo info;
|
| + int image_size;
|
| +
|
| + if (base::GetPlatformFileInfo(image_file_, &info)) {
|
| + image_size = info.size;
|
| + } else {
|
| + Error(error::kReadImage);
|
| + }
|
| +
|
| + int bytes_read = base::ReadPlatformFileAtCurrentPos(image_file_,
|
| + buffer,
|
| + kBurningBlockSize);
|
| +
|
| + if (bytes_read > 0) {
|
| + int bytes_written = base::WritePlatformFileAtCurrentPos(device_file_,
|
| + buffer,
|
| + bytes_read);
|
| + if (bytes_written != bytes_read) {
|
| + Error(error::kWriteImage);
|
| + return;
|
| + }
|
| +
|
| + int percent_prev = kProgressComplete * total_bytes_ / image_size;
|
| + int percent_curr = kProgressComplete *
|
| + (total_bytes_ + bytes_written) / image_size;
|
| +
|
| + if (percent_curr > percent_prev) {
|
| + PostProgress(percent_curr);
|
| + }
|
| +
|
| + total_bytes_ += bytes_written;
|
| +
|
| + PostTask(base::Bind(&ImageWriter::WriteChunk, this));
|
| + } else if (bytes_read == 0 && total_bytes_ == image_size) {
|
| + // End of file.
|
| + DLOG(INFO) << "Image write operation complete. Total bytes transferred: "
|
| + << total_bytes_;
|
| + PostTask(base::Bind(&ImageWriter::WriteComplete, this));
|
| + } else {
|
| + // Unable to read entire file.
|
| + DLOG(ERROR) << "Image write operation failed. Total bytes tranferred: "
|
| + << total_bytes_;
|
| + Error(error::kReadImage);
|
| + }
|
| +}
|
| +
|
| +void ImageWriter::WriteComplete() {
|
| +
|
| + DVLOG(2) << "Completed write of " << image_path_.value();
|
| + PostProgress(kProgressComplete);
|
| +
|
| + if (CleanUp() && handler_) {
|
| + handler_->SendSucceeded();
|
| + }
|
| +}
|
| +
|
| +void ImageWriter::VerifyChunk() {
|
| +
|
| + if (cancelled_) {
|
| + return;
|
| + }
|
| +
|
| + char image_buffer[kBurningBlockSize];
|
| + char device_buffer[kBurningBlockSize];
|
| + base::PlatformFileInfo info;
|
| + int image_size;
|
| +
|
| + if (base::GetPlatformFileInfo(image_file_, &info)) {
|
| + image_size = info.size;
|
| + } else {
|
| + Error(error::kReadImage);
|
| + }
|
| +
|
| + int bytes_read = base::ReadPlatformFileAtCurrentPos(image_file_,
|
| + image_buffer,
|
| + kBurningBlockSize);
|
| +
|
| + if (bytes_read > 0) {
|
| + if (base::ReadPlatformFileAtCurrentPos(device_file_,
|
| + device_buffer,
|
| + kBurningBlockSize)
|
| + != bytes_read) {
|
| + DLOG(ERROR) << "Image verification failed at offset " << total_bytes_
|
| + << " with " << bytes_read << " bytes read.";
|
| + Error(error::kVerificationFailed);
|
| + return;
|
| + }
|
| +
|
| + for (int i = 0; i < bytes_read; i++) {
|
| + if (image_buffer[i] != device_buffer[i]) {
|
| + DLOG(ERROR) << "Image verification failed at offset " << total_bytes_ + i
|
| + << " with " << bytes_read << " bytes read.";
|
| + Error(error::kVerificationFailed);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + int percent_prev = kProgressComplete * total_bytes_ / image_size;
|
| + int percent_curr = kProgressComplete *
|
| + (total_bytes_ + bytes_read) / image_size;
|
| +
|
| + if (percent_curr > percent_prev) {
|
| + PostProgress(percent_curr);
|
| + }
|
| +
|
| + total_bytes_ += bytes_read;
|
| +
|
| + PostTask(base::Bind(&ImageWriter::VerifyChunk, this));
|
| + } else if (bytes_read == 0 && total_bytes_ == image_size) {
|
| + // End of file.
|
| + DLOG(INFO) << "Image verification operation complete. "
|
| + << "Total bytes checked: " << total_bytes_;
|
| + PostTask(base::Bind(&ImageWriter::VerifyComplete, this));
|
| + } else {
|
| + // Unable to read entire file.
|
| + DLOG(ERROR) << "Image verification failed at offset: " << total_bytes_;
|
| + Error(error::kVerificationFailed);
|
| + }
|
| +}
|
| +
|
| +void ImageWriter::VerifyComplete() {
|
| +
|
| + DVLOG(2) << "Completed verification of " << image_path_.value();
|
| + PostProgress(kProgressComplete);
|
| +
|
| + if (CleanUp() && handler_) {
|
| + handler_->SendSucceeded();
|
| + }
|
| +}
|
| +
|
| +bool ImageWriter::CleanUp() {
|
| + bool success = true;
|
| +
|
| + total_bytes_ = 0;
|
| + cancelled_ = false;
|
| +
|
| + if (image_file_ != base::kInvalidPlatformFileValue
|
| + && !base::ClosePlatformFile(image_file_)) {
|
| + image_file_ = base::kInvalidPlatformFileValue;
|
| + Error(error::kCloseImage);
|
| + success = false;
|
| + }
|
| +
|
| + if (device_file_ != base::kInvalidPlatformFileValue
|
| + && !base::ClosePlatformFile(device_file_)) {
|
| + device_file_ = base::kInvalidPlatformFileValue;
|
| + Error(error::kCloseDevice);
|
| + success = false;
|
| + }
|
| +
|
| + return success;
|
| +}
|
| +
|
| +} // namespace image_writer
|
| +} // namespace chrome
|
|
|