| 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..23f7d9ec8c1cf4603bc48e99b76f166a3f302112
|
| --- /dev/null
|
| +++ b/chrome/utility/image_writer/image_writer.cc
|
| @@ -0,0 +1,277 @@
|
| +// Copyright 2013 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 kBurningBlockSize = 0x100000;
|
| +
|
| +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) {
|
| + if ((image_file_ != base::kInvalidPlatformFileValue ||
|
| + device_file_ != base::kInvalidPlatformFileValue) &&
|
| + handler_) {
|
| + handler_->SendFailed(error::kOperationAlreadyInProgress);
|
| + return;
|
| + }
|
| +
|
| + image_path_ = image_path;
|
| + device_path_ = device_path;
|
| + total_bytes_ = 0;
|
| +
|
| + 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;
|
| + }
|
| +
|
| +#if defined(OS_WIN)
|
| + device_file_ = CreateFile(device_path.value().c_str(),
|
| + GENERIC_WRITE,
|
| + FILE_SHARE_WRITE,
|
| + NULL,
|
| + OPEN_EXISTING,
|
| + FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
|
| + INVALID_HANDLE_VALUE);
|
| +
|
| + if (device_file_ == base::kInvalidPlatformFileValue) {
|
| + Error(error::kOpenDevice);
|
| + return;
|
| + }
|
| +#else
|
| + 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(" << error
|
| + << "): " << device_path_.value();
|
| + Error(error::kOpenDevice);
|
| + return;
|
| + }
|
| +#endif
|
| +
|
| + PostProgress(0);
|
| +
|
| + PostTask(base::Bind(&ImageWriter::WriteChunk, this));
|
| +}
|
| +
|
| +void ImageWriter::Verify(const base::FilePath& image_path,
|
| + const base::FilePath& device_path) {
|
| + if ((image_file_ != base::kInvalidPlatformFileValue ||
|
| + device_file_ != base::kInvalidPlatformFileValue) &&
|
| + handler_) {
|
| + handler_->SendFailed(error::kOperationAlreadyInProgress);
|
| + return;
|
| + }
|
| +
|
| + image_path_ = image_path;
|
| + device_path_ = device_path;
|
| + total_bytes_ = 0;
|
| +
|
| + 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;
|
| + }
|
| +
|
| + PostProgress(0);
|
| +
|
| + PostTask(base::Bind(&ImageWriter::VerifyChunk, this));
|
| +}
|
| +
|
| +void ImageWriter::Cancel() {
|
| + CleanUp();
|
| + if (handler_) {
|
| + handler_->SendCancelled();
|
| + }
|
| + cancelled_ = true;
|
| +}
|
| +
|
| +ImageWriter::~ImageWriter() {}
|
| +
|
| +void ImageWriter::PostTask(const base::Closure& task) {
|
| + base::MessageLoop::current()->PostTask(FROM_HERE, task);
|
| +}
|
| +
|
| +void ImageWriter::PostProgress(int64 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;
|
| + }
|
| +
|
| + scoped_ptr<char[]> buffer(new char[kBurningBlockSize]);
|
| + base::PlatformFileInfo info;
|
| +
|
| + int bytes_read = base::ReadPlatformFile(
|
| + image_file_, total_bytes_, buffer.get(), kBurningBlockSize);
|
| +
|
| + if (bytes_read > 0) {
|
| + int bytes_written = base::WritePlatformFile(
|
| + device_file_, total_bytes_, buffer.get(), kBurningBlockSize);
|
| +
|
| + if (bytes_written < bytes_read) {
|
| + Error(error::kWriteImage);
|
| + return;
|
| + }
|
| +
|
| + total_bytes_ += bytes_read;
|
| + PostProgress(total_bytes_);
|
| +
|
| + PostTask(base::Bind(&ImageWriter::WriteChunk, this));
|
| + } else if (bytes_read == 0) {
|
| + // End of file.
|
| + PostTask(base::Bind(&ImageWriter::WriteComplete, this));
|
| + } else {
|
| + // Unable to read entire file.
|
| + Error(error::kReadImage);
|
| + }
|
| +}
|
| +
|
| +void ImageWriter::WriteComplete() {
|
| + base::FlushPlatformFile(device_file_);
|
| + if (CleanUp() && handler_) {
|
| + handler_->SendSucceeded();
|
| + }
|
| +}
|
| +
|
| +void ImageWriter::VerifyChunk() {
|
| + if (cancelled_) {
|
| + return;
|
| + }
|
| +
|
| + scoped_ptr<char[]> image_buffer(new char[kBurningBlockSize]);
|
| + scoped_ptr<char[]> device_buffer(new char[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::ReadPlatformFile(
|
| + image_file_, total_bytes_, image_buffer.get(), kBurningBlockSize);
|
| +
|
| + if (bytes_read > 0) {
|
| + if (base::ReadPlatformFile(device_file_,
|
| + total_bytes_,
|
| + device_buffer.get(),
|
| + kBurningBlockSize) < 0) {
|
| + LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of "
|
| + << "device at offset " << total_bytes_;
|
| + Error(error::kReadDevice);
|
| + return;
|
| + }
|
| +
|
| + if (memcmp(image_buffer.get(), device_buffer.get(), bytes_read) != 0) {
|
| + LOG(ERROR) << "Write verification failed when comparing " << bytes_read
|
| + << " bytes at " << total_bytes_;
|
| + Error(error::kVerificationFailed);
|
| + return;
|
| + }
|
| +
|
| + total_bytes_ += bytes_read;
|
| + PostProgress(total_bytes_);
|
| +
|
| + PostTask(base::Bind(&ImageWriter::VerifyChunk, this));
|
| + } else if (bytes_read == 0 && total_bytes_ == image_size) {
|
| + // End of file.
|
| + PostTask(base::Bind(&ImageWriter::VerifyComplete, this));
|
| + } else {
|
| + // Unable to read entire file.
|
| + LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of image "
|
| + << "at offset " << total_bytes_;
|
| + Error(error::kReadImage);
|
| + }
|
| +}
|
| +
|
| +void ImageWriter::VerifyComplete() {
|
| + 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_)) {
|
| + if (handler_)
|
| + handler_->SendFailed(error::kCloseImage);
|
| + success = false;
|
| + }
|
| + image_file_ = base::kInvalidPlatformFileValue;
|
| +
|
| + if (device_file_ != base::kInvalidPlatformFileValue &&
|
| + !base::ClosePlatformFile(device_file_)) {
|
| + if (handler_)
|
| + handler_->SendFailed(error::kCloseDevice);
|
| + success = false;
|
| + }
|
| + device_file_ = base::kInvalidPlatformFileValue;
|
| +
|
| + return success;
|
| +}
|
| +
|
| +} // namespace image_writer
|
| +} // namespace chrome
|
|
|