This source file includes following definitions.
- handler_
- Verify
- Cancel
- IsRunning
- PostTask
- PostProgress
- Error
- WriteChunk
- VerifyChunk
- CleanUp
#include "chrome/utility/image_writer/image_writer.h"
#include "chrome/utility/image_writer/error_messages.h"
#include "chrome/utility/image_writer/image_writer_handler.h"
#include "content/public/utility/utility_thread.h"
namespace image_writer {
const int kBurningBlockSize = 1 << 20;
ImageWriter::ImageWriter(ImageWriterHandler* handler)
: bytes_processed_(0),
handler_(handler) {}
ImageWriter::~ImageWriter() {
CleanUp();
}
void ImageWriter::Write(const base::FilePath& image_path,
const base::FilePath& device_path) {
if (IsRunning()) {
handler_->SendFailed(error::kOperationAlreadyInProgress);
return;
}
image_path_ = image_path;
device_path_ = device_path;
bytes_processed_ = 0;
image_file_.Initialize(image_path_,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!image_file_.IsValid()) {
DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
Error(error::kOpenImage);
return;
}
#if defined(OS_WIN)
device_file_ =
base::File(CreateFile(device_path.value().c_str(),
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
NULL));
if (!device_file_.IsValid()) {
Error(error::kOpenDevice);
return;
}
#else
device_file_.Initialize(device_path_,
base::File::FLAG_OPEN | base::File::FLAG_WRITE);
if (!device_file_.IsValid()) {
DLOG(ERROR) << "Unable to open file for write(" <<
device_file_.error_details() << "): " <<
device_path_.value();
Error(error::kOpenDevice);
return;
}
#endif
PostProgress(0);
PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr()));
}
void ImageWriter::Verify(const base::FilePath& image_path,
const base::FilePath& device_path) {
if (IsRunning()) {
handler_->SendFailed(error::kOperationAlreadyInProgress);
return;
}
image_path_ = image_path;
device_path_ = device_path;
bytes_processed_ = 0;
image_file_.Initialize(image_path_,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!image_file_.IsValid()) {
DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
Error(error::kOpenImage);
return;
}
device_file_.Initialize(device_path_,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!device_file_.IsValid()) {
DLOG(ERROR) << "Unable to open file for read: " << device_path_.value();
Error(error::kOpenDevice);
return;
}
PostProgress(0);
PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr()));
}
void ImageWriter::Cancel() {
CleanUp();
handler_->SendCancelled();
}
bool ImageWriter::IsRunning() const {
return image_file_.IsValid() || device_file_.IsValid();
}
void ImageWriter::PostTask(const base::Closure& task) {
base::MessageLoop::current()->PostTask(FROM_HERE, task);
}
void ImageWriter::PostProgress(int64 progress) {
handler_->SendProgress(progress);
}
void ImageWriter::Error(const std::string& message) {
CleanUp();
handler_->SendFailed(message);
}
void ImageWriter::WriteChunk() {
if (!IsRunning()) {
return;
}
scoped_ptr<char[]> buffer(new char[kBurningBlockSize]);
memset(buffer.get(), 0, kBurningBlockSize);
int bytes_read = image_file_.Read(bytes_processed_, buffer.get(),
kBurningBlockSize);
if (bytes_read > 0) {
int bytes_written = device_file_.Write(bytes_processed_, buffer.get(),
kBurningBlockSize);
if (bytes_written < bytes_read) {
Error(error::kWriteImage);
return;
}
bytes_processed_ += bytes_read;
PostProgress(bytes_processed_);
PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr()));
} else if (bytes_read == 0) {
device_file_.Flush();
CleanUp();
handler_->SendSucceeded();
} else {
Error(error::kReadImage);
}
}
void ImageWriter::VerifyChunk() {
if (!IsRunning()) {
return;
}
scoped_ptr<char[]> image_buffer(new char[kBurningBlockSize]);
scoped_ptr<char[]> device_buffer(new char[kBurningBlockSize]);
int bytes_read = image_file_.Read(bytes_processed_, image_buffer.get(),
kBurningBlockSize);
if (bytes_read > 0) {
if (device_file_.Read(bytes_processed_,
device_buffer.get(),
kBurningBlockSize) < bytes_read) {
LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of "
<< "device at offset " << bytes_processed_;
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 " << bytes_processed_;
Error(error::kVerificationFailed);
return;
}
bytes_processed_ += bytes_read;
PostProgress(bytes_processed_);
PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr()));
} else if (bytes_read == 0) {
CleanUp();
handler_->SendSucceeded();
} else {
LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of image "
<< "at offset " << bytes_processed_;
Error(error::kReadImage);
}
}
void ImageWriter::CleanUp() {
image_file_.Close();
device_file_.Close();
}
}