Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / utility / image_writer / image_writer.cc
blobde2caebe2a97a038f5a62c60ed63a323f9e8764b
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 "chrome/utility/image_writer/error_messages.h"
8 #include "chrome/utility/image_writer/image_writer_handler.h"
9 #include "content/public/utility/utility_thread.h"
11 namespace image_writer {
13 // Since block devices like large sequential access and IPC is expensive we're
14 // doing work in 1MB chunks.
15 const int kBurningBlockSize = 1 << 20;
17 ImageWriter::ImageWriter(ImageWriterHandler* handler)
18 : bytes_processed_(0),
19 handler_(handler) {}
21 ImageWriter::~ImageWriter() {
22 CleanUp();
25 void ImageWriter::Write(const base::FilePath& image_path,
26 const base::FilePath& device_path) {
27 if (IsRunning()) {
28 handler_->SendFailed(error::kOperationAlreadyInProgress);
29 return;
32 image_path_ = image_path;
33 device_path_ = device_path;
34 bytes_processed_ = 0;
36 image_file_.Initialize(image_path_,
37 base::File::FLAG_OPEN | base::File::FLAG_READ);
39 if (!image_file_.IsValid()) {
40 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
41 Error(error::kOpenImage);
42 return;
45 #if defined(OS_WIN)
46 // Windows requires that device files be opened with FILE_FLAG_NO_BUFFERING
47 // and FILE_FLAG_WRITE_THROUGH. These two flags are not part of base::File.
48 device_file_ =
49 base::File(CreateFile(device_path.value().c_str(),
50 GENERIC_WRITE,
51 FILE_SHARE_WRITE,
52 NULL,
53 OPEN_EXISTING,
54 FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
55 NULL));
57 if (!device_file_.IsValid()) {
58 Error(error::kOpenDevice);
59 return;
61 #else
62 device_file_.Initialize(device_path_,
63 base::File::FLAG_OPEN | base::File::FLAG_WRITE);
65 if (!device_file_.IsValid()) {
66 DLOG(ERROR) << "Unable to open file for write(" <<
67 device_file_.error_details() << "): " <<
68 device_path_.value();
69 Error(error::kOpenDevice);
70 return;
72 #endif
74 PostProgress(0);
76 PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr()));
79 void ImageWriter::Verify(const base::FilePath& image_path,
80 const base::FilePath& device_path) {
81 if (IsRunning()) {
82 handler_->SendFailed(error::kOperationAlreadyInProgress);
83 return;
86 image_path_ = image_path;
87 device_path_ = device_path;
88 bytes_processed_ = 0;
90 image_file_.Initialize(image_path_,
91 base::File::FLAG_OPEN | base::File::FLAG_READ);
93 if (!image_file_.IsValid()) {
94 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value();
95 Error(error::kOpenImage);
96 return;
99 device_file_.Initialize(device_path_,
100 base::File::FLAG_OPEN | base::File::FLAG_READ);
102 if (!device_file_.IsValid()) {
103 DLOG(ERROR) << "Unable to open file for read: " << device_path_.value();
104 Error(error::kOpenDevice);
105 return;
108 PostProgress(0);
110 PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr()));
113 void ImageWriter::Cancel() {
114 CleanUp();
115 handler_->SendCancelled();
118 bool ImageWriter::IsRunning() const {
119 return image_file_.IsValid() || device_file_.IsValid();
122 void ImageWriter::PostTask(const base::Closure& task) {
123 base::MessageLoop::current()->PostTask(FROM_HERE, task);
126 void ImageWriter::PostProgress(int64 progress) {
127 handler_->SendProgress(progress);
130 void ImageWriter::Error(const std::string& message) {
131 CleanUp();
132 handler_->SendFailed(message);
135 void ImageWriter::WriteChunk() {
136 if (!IsRunning()) {
137 return;
140 scoped_ptr<char[]> buffer(new char[kBurningBlockSize]);
141 memset(buffer.get(), 0, kBurningBlockSize);
143 int bytes_read = image_file_.Read(bytes_processed_, buffer.get(),
144 kBurningBlockSize);
146 if (bytes_read > 0) {
147 // Always attempt to write a whole block, as Windows requires 512-byte
148 // aligned writes to devices.
149 int bytes_written = device_file_.Write(bytes_processed_, buffer.get(),
150 kBurningBlockSize);
152 if (bytes_written < bytes_read) {
153 Error(error::kWriteImage);
154 return;
157 bytes_processed_ += bytes_read;
158 PostProgress(bytes_processed_);
160 PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr()));
161 } else if (bytes_read == 0) {
162 // End of file.
163 device_file_.Flush();
164 CleanUp();
165 handler_->SendSucceeded();
166 } else {
167 // Unable to read entire file.
168 Error(error::kReadImage);
172 void ImageWriter::VerifyChunk() {
173 if (!IsRunning()) {
174 return;
177 scoped_ptr<char[]> image_buffer(new char[kBurningBlockSize]);
178 scoped_ptr<char[]> device_buffer(new char[kBurningBlockSize]);
180 int bytes_read = image_file_.Read(bytes_processed_, image_buffer.get(),
181 kBurningBlockSize);
183 if (bytes_read > 0) {
184 if (device_file_.Read(bytes_processed_,
185 device_buffer.get(),
186 kBurningBlockSize) < bytes_read) {
187 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of "
188 << "device at offset " << bytes_processed_;
189 Error(error::kReadDevice);
190 return;
193 if (memcmp(image_buffer.get(), device_buffer.get(), bytes_read) != 0) {
194 LOG(ERROR) << "Write verification failed when comparing " << bytes_read
195 << " bytes at " << bytes_processed_;
196 Error(error::kVerificationFailed);
197 return;
200 bytes_processed_ += bytes_read;
201 PostProgress(bytes_processed_);
203 PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr()));
204 } else if (bytes_read == 0) {
205 // End of file.
206 CleanUp();
207 handler_->SendSucceeded();
208 } else {
209 // Unable to read entire file.
210 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of image "
211 << "at offset " << bytes_processed_;
212 Error(error::kReadImage);
216 void ImageWriter::CleanUp() {
217 image_file_.Close();
218 device_file_.Close();
221 } // namespace image_writer