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 |