Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / utility / image_writer / image_writer.cc
blob2a2b8a1c5d62cb348351429ecfb38ec802df4ea6
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/utility/image_writer/image_writer.h"
7 #include "base/memory/aligned_memory.h"
8 #include "chrome/utility/image_writer/error_messages.h"
9 #include "chrome/utility/image_writer/image_writer_handler.h"
10 #include "content/public/utility/utility_thread.h"
12 #if defined(OS_MACOSX)
13 #include "chrome/utility/image_writer/disk_unmounter_mac.h"
14 #endif
16 namespace image_writer {
18 // Since block devices like large sequential access and IPC is expensive we're
19 // doing work in 1MB chunks.
20 const int kBurningBlockSize = 1 << 20; // 1 MB
21 const int kMemoryAlignment = 4096;
23 ImageWriter::ImageWriter(ImageWriterHandler* handler,
24 const base::FilePath& image_path,
25 const base::FilePath& device_path)
26 : image_path_(image_path),
27 device_path_(device_path),
28 bytes_processed_(0),
29 running_(false),
30 handler_(handler) {}
32 ImageWriter::~ImageWriter() {
33 #if defined(OS_WIN)
34 for (std::vector<HANDLE>::const_iterator it = volume_handles_.begin();
35 it != volume_handles_.end();
36 ++it) {
37 CloseHandle(*it);
39 #endif
42 void ImageWriter::Write() {
43 if (!InitializeFiles()) {
44 return;
47 PostProgress(0);
48 PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr()));
51 void ImageWriter::Verify() {
52 if (!InitializeFiles()) {
53 return;
56 PostProgress(0);
57 PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr()));
60 void ImageWriter::Cancel() {
61 running_ = false;
62 handler_->SendCancelled();
65 bool ImageWriter::IsRunning() const { return running_; }
67 const base::FilePath& ImageWriter::GetImagePath() { return image_path_; }
69 const base::FilePath& ImageWriter::GetDevicePath() { return device_path_; }
71 void ImageWriter::PostTask(const base::Closure& task) {
72 base::MessageLoop::current()->PostTask(FROM_HERE, task);
75 void ImageWriter::PostProgress(int64 progress) {
76 handler_->SendProgress(progress);
79 void ImageWriter::Error(const std::string& message) {
80 running_ = false;
81 handler_->SendFailed(message);
84 bool ImageWriter::InitializeFiles() {
85 if (!image_file_.IsValid()) {
86 image_file_.Initialize(image_path_,
87 base::File::FLAG_OPEN | base::File::FLAG_READ |
88 base::File::FLAG_EXCLUSIVE_READ);
90 if (!image_file_.IsValid()) {
91 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
92 Error(error::kOpenImage);
93 return false;
97 if (!device_file_.IsValid()) {
98 if (!OpenDevice()) {
99 Error(error::kOpenDevice);
100 return false;
104 bytes_processed_ = 0;
105 running_ = true;
107 return true;
110 void ImageWriter::WriteChunk() {
111 if (!IsRunning()) {
112 return;
115 // DASD buffers require memory alignment on some systems.
116 scoped_ptr<char, base::AlignedFreeDeleter> buffer(static_cast<char*>(
117 base::AlignedAlloc(kBurningBlockSize, kMemoryAlignment)));
118 memset(buffer.get(), 0, kBurningBlockSize);
120 int bytes_read = image_file_.Read(bytes_processed_, buffer.get(),
121 kBurningBlockSize);
123 if (bytes_read > 0) {
124 // Always attempt to write a whole block, as writing DASD requires sector-
125 // aligned writes to devices.
126 int bytes_to_write = bytes_read + (kMemoryAlignment - 1) -
127 (bytes_read - 1) % kMemoryAlignment;
128 DCHECK_EQ(0, bytes_to_write % kMemoryAlignment);
129 int bytes_written =
130 device_file_.Write(bytes_processed_, buffer.get(), bytes_to_write);
132 if (bytes_written < bytes_read) {
133 Error(error::kWriteImage);
134 return;
137 bytes_processed_ += bytes_read;
138 PostProgress(bytes_processed_);
140 PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr()));
141 } else if (bytes_read == 0) {
142 // End of file.
143 device_file_.Flush();
144 running_ = false;
145 handler_->SendSucceeded();
146 } else {
147 // Unable to read entire file.
148 Error(error::kReadImage);
152 void ImageWriter::VerifyChunk() {
153 if (!IsRunning()) {
154 return;
157 scoped_ptr<char[]> image_buffer(new char[kBurningBlockSize]);
158 // DASD buffers require memory alignment on some systems.
159 scoped_ptr<char, base::AlignedFreeDeleter> device_buffer(static_cast<char*>(
160 base::AlignedAlloc(kBurningBlockSize, kMemoryAlignment)));
162 int bytes_read = image_file_.Read(bytes_processed_, image_buffer.get(),
163 kBurningBlockSize);
165 if (bytes_read > 0) {
166 if (device_file_.Read(bytes_processed_,
167 device_buffer.get(),
168 kBurningBlockSize) < bytes_read) {
169 LOG(ERROR) << "Failed to read " << bytes_read << " bytes of "
170 << "device at offset " << bytes_processed_;
171 Error(error::kReadDevice);
172 return;
175 if (memcmp(image_buffer.get(), device_buffer.get(), bytes_read) != 0) {
176 LOG(ERROR) << "Write verification failed when comparing " << bytes_read
177 << " bytes at " << bytes_processed_;
178 Error(error::kVerificationFailed);
179 return;
182 bytes_processed_ += bytes_read;
183 PostProgress(bytes_processed_);
185 PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr()));
186 } else if (bytes_read == 0) {
187 // End of file.
188 handler_->SendSucceeded();
189 running_ = false;
190 } else {
191 // Unable to read entire file.
192 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of image "
193 << "at offset " << bytes_processed_;
194 Error(error::kReadImage);
198 } // namespace image_writer