OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this image code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/platform_file.h" |
| 6 #include "chrome/utility/image_writer/error_messages.h" |
| 7 #include "chrome/utility/image_writer/image_writer.h" |
| 8 #include "chrome/utility/image_writer/image_writer_handler.h" |
| 9 #include "content/public/utility/utility_thread.h" |
| 10 |
| 11 namespace chrome { |
| 12 namespace image_writer { |
| 13 |
| 14 const int kBurningBlockSize = 0x100000; |
| 15 |
| 16 ImageWriter::ImageWriter(base::WeakPtr<ImageWriterHandler> handler) |
| 17 : image_file_(base::kInvalidPlatformFileValue), |
| 18 device_file_(base::kInvalidPlatformFileValue), |
| 19 total_bytes_(0), |
| 20 cancelled_(false), |
| 21 handler_(handler) {} |
| 22 |
| 23 void ImageWriter::Write(const base::FilePath& image_path, |
| 24 const base::FilePath& device_path) { |
| 25 if ((image_file_ != base::kInvalidPlatformFileValue || |
| 26 device_file_ != base::kInvalidPlatformFileValue) && |
| 27 handler_) { |
| 28 handler_->SendFailed(error::kOperationAlreadyInProgress); |
| 29 return; |
| 30 } |
| 31 |
| 32 image_path_ = image_path; |
| 33 device_path_ = device_path; |
| 34 total_bytes_ = 0; |
| 35 |
| 36 base::PlatformFileError error; |
| 37 |
| 38 image_file_ = base::CreatePlatformFile( |
| 39 image_path_, |
| 40 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
| 41 NULL, |
| 42 &error); |
| 43 |
| 44 if (error != base::PLATFORM_FILE_OK) { |
| 45 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value(); |
| 46 Error(error::kOpenImage); |
| 47 return; |
| 48 } |
| 49 |
| 50 #if defined(OS_WIN) |
| 51 device_file_ = CreateFile(device_path.value().c_str(), |
| 52 GENERIC_WRITE, |
| 53 FILE_SHARE_WRITE, |
| 54 NULL, |
| 55 OPEN_EXISTING, |
| 56 FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, |
| 57 INVALID_HANDLE_VALUE); |
| 58 |
| 59 if (device_file_ == base::kInvalidPlatformFileValue) { |
| 60 Error(error::kOpenDevice); |
| 61 return; |
| 62 } |
| 63 #else |
| 64 device_file_ = base::CreatePlatformFile( |
| 65 device_path_, |
| 66 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, |
| 67 NULL, |
| 68 &error); |
| 69 |
| 70 if (error != base::PLATFORM_FILE_OK) { |
| 71 DLOG(ERROR) << "Unable to open file for write(" << error |
| 72 << "): " << device_path_.value(); |
| 73 Error(error::kOpenDevice); |
| 74 return; |
| 75 } |
| 76 #endif |
| 77 |
| 78 PostProgress(0); |
| 79 |
| 80 PostTask(base::Bind(&ImageWriter::WriteChunk, this)); |
| 81 } |
| 82 |
| 83 void ImageWriter::Verify(const base::FilePath& image_path, |
| 84 const base::FilePath& device_path) { |
| 85 if ((image_file_ != base::kInvalidPlatformFileValue || |
| 86 device_file_ != base::kInvalidPlatformFileValue) && |
| 87 handler_) { |
| 88 handler_->SendFailed(error::kOperationAlreadyInProgress); |
| 89 return; |
| 90 } |
| 91 |
| 92 image_path_ = image_path; |
| 93 device_path_ = device_path; |
| 94 total_bytes_ = 0; |
| 95 |
| 96 base::PlatformFileError error; |
| 97 |
| 98 image_file_ = base::CreatePlatformFile( |
| 99 image_path_, |
| 100 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
| 101 NULL, |
| 102 &error); |
| 103 |
| 104 if (error != base::PLATFORM_FILE_OK) { |
| 105 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value(); |
| 106 Error(error::kOpenImage); |
| 107 return; |
| 108 } |
| 109 |
| 110 device_file_ = base::CreatePlatformFile( |
| 111 device_path_, |
| 112 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
| 113 NULL, |
| 114 &error); |
| 115 |
| 116 if (error != base::PLATFORM_FILE_OK) { |
| 117 DLOG(ERROR) << "Unable to open file for read: " << device_path_.value(); |
| 118 Error(error::kOpenDevice); |
| 119 return; |
| 120 } |
| 121 |
| 122 PostProgress(0); |
| 123 |
| 124 PostTask(base::Bind(&ImageWriter::VerifyChunk, this)); |
| 125 } |
| 126 |
| 127 void ImageWriter::Cancel() { |
| 128 CleanUp(); |
| 129 if (handler_) { |
| 130 handler_->SendCancelled(); |
| 131 } |
| 132 cancelled_ = true; |
| 133 } |
| 134 |
| 135 ImageWriter::~ImageWriter() {} |
| 136 |
| 137 void ImageWriter::PostTask(const base::Closure& task) { |
| 138 base::MessageLoop::current()->PostTask(FROM_HERE, task); |
| 139 } |
| 140 |
| 141 void ImageWriter::PostProgress(int64 progress) { |
| 142 if (handler_) |
| 143 handler_->SendProgress(progress); |
| 144 } |
| 145 |
| 146 void ImageWriter::Error(const std::string& message) { |
| 147 CleanUp(); |
| 148 |
| 149 if (handler_) |
| 150 handler_->SendFailed(message); |
| 151 } |
| 152 |
| 153 void ImageWriter::WriteChunk() { |
| 154 if (cancelled_) { |
| 155 return; |
| 156 } |
| 157 |
| 158 scoped_ptr<char[]> buffer(new char[kBurningBlockSize]); |
| 159 base::PlatformFileInfo info; |
| 160 |
| 161 int bytes_read = base::ReadPlatformFile( |
| 162 image_file_, total_bytes_, buffer.get(), kBurningBlockSize); |
| 163 |
| 164 if (bytes_read > 0) { |
| 165 int bytes_written = base::WritePlatformFile( |
| 166 device_file_, total_bytes_, buffer.get(), kBurningBlockSize); |
| 167 |
| 168 if (bytes_written < bytes_read) { |
| 169 Error(error::kWriteImage); |
| 170 return; |
| 171 } |
| 172 |
| 173 total_bytes_ += bytes_read; |
| 174 PostProgress(total_bytes_); |
| 175 |
| 176 PostTask(base::Bind(&ImageWriter::WriteChunk, this)); |
| 177 } else if (bytes_read == 0) { |
| 178 // End of file. |
| 179 PostTask(base::Bind(&ImageWriter::WriteComplete, this)); |
| 180 } else { |
| 181 // Unable to read entire file. |
| 182 Error(error::kReadImage); |
| 183 } |
| 184 } |
| 185 |
| 186 void ImageWriter::WriteComplete() { |
| 187 base::FlushPlatformFile(device_file_); |
| 188 if (CleanUp() && handler_) { |
| 189 handler_->SendSucceeded(); |
| 190 } |
| 191 } |
| 192 |
| 193 void ImageWriter::VerifyChunk() { |
| 194 if (cancelled_) { |
| 195 return; |
| 196 } |
| 197 |
| 198 scoped_ptr<char[]> image_buffer(new char[kBurningBlockSize]); |
| 199 scoped_ptr<char[]> device_buffer(new char[kBurningBlockSize]); |
| 200 base::PlatformFileInfo info; |
| 201 int image_size; |
| 202 |
| 203 if (base::GetPlatformFileInfo(image_file_, &info)) { |
| 204 image_size = info.size; |
| 205 } else { |
| 206 Error(error::kReadImage); |
| 207 } |
| 208 |
| 209 int bytes_read = base::ReadPlatformFile( |
| 210 image_file_, total_bytes_, image_buffer.get(), kBurningBlockSize); |
| 211 |
| 212 if (bytes_read > 0) { |
| 213 if (base::ReadPlatformFile(device_file_, |
| 214 total_bytes_, |
| 215 device_buffer.get(), |
| 216 kBurningBlockSize) < 0) { |
| 217 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of " |
| 218 << "device at offset " << total_bytes_; |
| 219 Error(error::kReadDevice); |
| 220 return; |
| 221 } |
| 222 |
| 223 if (memcmp(image_buffer.get(), device_buffer.get(), bytes_read) != 0) { |
| 224 LOG(ERROR) << "Write verification failed when comparing " << bytes_read |
| 225 << " bytes at " << total_bytes_; |
| 226 Error(error::kVerificationFailed); |
| 227 return; |
| 228 } |
| 229 |
| 230 total_bytes_ += bytes_read; |
| 231 PostProgress(total_bytes_); |
| 232 |
| 233 PostTask(base::Bind(&ImageWriter::VerifyChunk, this)); |
| 234 } else if (bytes_read == 0 && total_bytes_ == image_size) { |
| 235 // End of file. |
| 236 PostTask(base::Bind(&ImageWriter::VerifyComplete, this)); |
| 237 } else { |
| 238 // Unable to read entire file. |
| 239 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of image " |
| 240 << "at offset " << total_bytes_; |
| 241 Error(error::kReadImage); |
| 242 } |
| 243 } |
| 244 |
| 245 void ImageWriter::VerifyComplete() { |
| 246 if (CleanUp() && handler_) { |
| 247 handler_->SendSucceeded(); |
| 248 } |
| 249 } |
| 250 |
| 251 bool ImageWriter::CleanUp() { |
| 252 bool success = true; |
| 253 |
| 254 total_bytes_ = 0; |
| 255 cancelled_ = false; |
| 256 |
| 257 if (image_file_ != base::kInvalidPlatformFileValue && |
| 258 !base::ClosePlatformFile(image_file_)) { |
| 259 if (handler_) |
| 260 handler_->SendFailed(error::kCloseImage); |
| 261 success = false; |
| 262 } |
| 263 image_file_ = base::kInvalidPlatformFileValue; |
| 264 |
| 265 if (device_file_ != base::kInvalidPlatformFileValue && |
| 266 !base::ClosePlatformFile(device_file_)) { |
| 267 if (handler_) |
| 268 handler_->SendFailed(error::kCloseDevice); |
| 269 success = false; |
| 270 } |
| 271 device_file_ = base::kInvalidPlatformFileValue; |
| 272 |
| 273 return success; |
| 274 } |
| 275 |
| 276 } // namespace image_writer |
| 277 } // namespace chrome |
OLD | NEW |