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 |