OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 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 kProgressComplete = 100; |
| 15 const int kBurningBlockSize = 8 * 1024; // 8 KiB |
| 16 |
| 17 ImageWriter::ImageWriter(base::WeakPtr<ImageWriterHandler> handler) |
| 18 : image_file_(base::kInvalidPlatformFileValue), |
| 19 device_file_(base::kInvalidPlatformFileValue), |
| 20 total_bytes_(0), |
| 21 cancelled_(false), |
| 22 handler_(handler) { |
| 23 } |
| 24 |
| 25 void ImageWriter::Write(const base::FilePath& image_path, |
| 26 const base::FilePath& device_path) { |
| 27 DVLOG(0) << "Starting write from " << image_path.value() |
| 28 << " to " << device_path.value(); |
| 29 |
| 30 if ((image_file_ != base::kInvalidPlatformFileValue |
| 31 || device_file_ != base::kInvalidPlatformFileValue) |
| 32 && handler_) { |
| 33 handler_->SendFailed(error::kOperationAlreadyInProgress); |
| 34 return; |
| 35 } |
| 36 |
| 37 image_path_ = image_path; |
| 38 device_path_ = device_path; |
| 39 |
| 40 base::PlatformFileError error; |
| 41 |
| 42 image_file_ = base::CreatePlatformFile( |
| 43 image_path_, |
| 44 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
| 45 NULL, |
| 46 &error); |
| 47 |
| 48 if (error != base::PLATFORM_FILE_OK) { |
| 49 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value(); |
| 50 Error(error::kOpenImage); |
| 51 return; |
| 52 } |
| 53 |
| 54 device_file_ = base::CreatePlatformFile( |
| 55 device_path_, |
| 56 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, |
| 57 NULL, |
| 58 &error); |
| 59 |
| 60 if (error != base::PLATFORM_FILE_OK) { |
| 61 DLOG(ERROR) << "Unable to open file for write: " << device_path_.value(); |
| 62 Error(error::kOpenDevice); |
| 63 return; |
| 64 } |
| 65 |
| 66 PostTask(base::Bind(&ImageWriter::WriteChunk, this)); |
| 67 } |
| 68 |
| 69 void ImageWriter::Verify(const base::FilePath& image_path, |
| 70 const base::FilePath& device_path) { |
| 71 DVLOG(0) << "Starting verification of " << image_path.value() |
| 72 << " and " << device_path.value(); |
| 73 |
| 74 if ((image_file_ != base::kInvalidPlatformFileValue |
| 75 || device_file_ != base::kInvalidPlatformFileValue) |
| 76 && handler_) { |
| 77 handler_->SendFailed(error::kOperationAlreadyInProgress); |
| 78 return; |
| 79 } |
| 80 |
| 81 image_path_ = image_path; |
| 82 device_path_ = device_path; |
| 83 |
| 84 base::PlatformFileError error; |
| 85 |
| 86 image_file_ = base::CreatePlatformFile( |
| 87 image_path_, |
| 88 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, |
| 89 NULL, |
| 90 &error); |
| 91 |
| 92 if (error != base::PLATFORM_FILE_OK) { |
| 93 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value(); |
| 94 Error(error::kOpenImage); |
| 95 return; |
| 96 } |
| 97 |
| 98 device_file_ = base::CreatePlatformFile( |
| 99 device_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: " << device_path_.value(); |
| 106 Error(error::kOpenDevice); |
| 107 return; |
| 108 } |
| 109 |
| 110 PostTask(base::Bind(&ImageWriter::VerifyChunk, this)); |
| 111 } |
| 112 |
| 113 void ImageWriter::Cancel() { |
| 114 CleanUp(); |
| 115 cancelled_ = true; |
| 116 } |
| 117 |
| 118 ImageWriter::~ImageWriter() { |
| 119 } |
| 120 |
| 121 void ImageWriter::PostTask(const base::Closure& task) { |
| 122 base::MessageLoop::current()->PostTask(FROM_HERE, task); |
| 123 } |
| 124 |
| 125 void ImageWriter::PostProgress(int progress) { |
| 126 if (handler_) |
| 127 handler_->SendProgress(progress); |
| 128 } |
| 129 |
| 130 void ImageWriter::Error(const std::string& message) { |
| 131 CleanUp(); |
| 132 |
| 133 if (handler_) |
| 134 handler_->SendFailed(message); |
| 135 } |
| 136 |
| 137 void ImageWriter::WriteChunk() { |
| 138 |
| 139 if (cancelled_) { |
| 140 return; |
| 141 } |
| 142 |
| 143 char buffer[kBurningBlockSize]; |
| 144 base::PlatformFileInfo info; |
| 145 int image_size; |
| 146 |
| 147 if (base::GetPlatformFileInfo(image_file_, &info)) { |
| 148 image_size = info.size; |
| 149 } else { |
| 150 Error(error::kReadImage); |
| 151 } |
| 152 |
| 153 int bytes_read = base::ReadPlatformFileAtCurrentPos(image_file_, |
| 154 buffer, |
| 155 kBurningBlockSize); |
| 156 |
| 157 if (bytes_read > 0) { |
| 158 int bytes_written = base::WritePlatformFileAtCurrentPos(device_file_, |
| 159 buffer, |
| 160 bytes_read); |
| 161 if (bytes_written != bytes_read) { |
| 162 Error(error::kWriteImage); |
| 163 return; |
| 164 } |
| 165 |
| 166 int percent_prev = kProgressComplete * total_bytes_ / image_size; |
| 167 int percent_curr = kProgressComplete * |
| 168 (total_bytes_ + bytes_written) / image_size; |
| 169 |
| 170 if (percent_curr > percent_prev) { |
| 171 PostProgress(percent_curr); |
| 172 } |
| 173 |
| 174 total_bytes_ += bytes_written; |
| 175 |
| 176 PostTask(base::Bind(&ImageWriter::WriteChunk, this)); |
| 177 } else if (bytes_read == 0 && total_bytes_ == image_size) { |
| 178 // End of file. |
| 179 DLOG(INFO) << "Image write operation complete. Total bytes transferred: " |
| 180 << total_bytes_; |
| 181 PostTask(base::Bind(&ImageWriter::WriteComplete, this)); |
| 182 } else { |
| 183 // Unable to read entire file. |
| 184 DLOG(ERROR) << "Image write operation failed. Total bytes tranferred: " |
| 185 << total_bytes_; |
| 186 Error(error::kReadImage); |
| 187 } |
| 188 } |
| 189 |
| 190 void ImageWriter::WriteComplete() { |
| 191 |
| 192 DVLOG(2) << "Completed write of " << image_path_.value(); |
| 193 PostProgress(kProgressComplete); |
| 194 |
| 195 if (CleanUp() && handler_) { |
| 196 handler_->SendSucceeded(); |
| 197 } |
| 198 } |
| 199 |
| 200 void ImageWriter::VerifyChunk() { |
| 201 |
| 202 if (cancelled_) { |
| 203 return; |
| 204 } |
| 205 |
| 206 char image_buffer[kBurningBlockSize]; |
| 207 char device_buffer[kBurningBlockSize]; |
| 208 base::PlatformFileInfo info; |
| 209 int image_size; |
| 210 |
| 211 if (base::GetPlatformFileInfo(image_file_, &info)) { |
| 212 image_size = info.size; |
| 213 } else { |
| 214 Error(error::kReadImage); |
| 215 } |
| 216 |
| 217 int bytes_read = base::ReadPlatformFileAtCurrentPos(image_file_, |
| 218 image_buffer, |
| 219 kBurningBlockSize); |
| 220 |
| 221 if (bytes_read > 0) { |
| 222 if (base::ReadPlatformFileAtCurrentPos(device_file_, |
| 223 device_buffer, |
| 224 kBurningBlockSize) |
| 225 != bytes_read) { |
| 226 DLOG(ERROR) << "Image verification failed at offset " << total_bytes_ |
| 227 << " with " << bytes_read << " bytes read."; |
| 228 Error(error::kVerificationFailed); |
| 229 return; |
| 230 } |
| 231 |
| 232 for (int i = 0; i < bytes_read; i++) { |
| 233 if (image_buffer[i] != device_buffer[i]) { |
| 234 DLOG(ERROR) << "Image verification failed at offset " << total_bytes_ + i |
| 235 << " with " << bytes_read << " bytes read."; |
| 236 Error(error::kVerificationFailed); |
| 237 return; |
| 238 } |
| 239 } |
| 240 |
| 241 int percent_prev = kProgressComplete * total_bytes_ / image_size; |
| 242 int percent_curr = kProgressComplete * |
| 243 (total_bytes_ + bytes_read) / image_size; |
| 244 |
| 245 if (percent_curr > percent_prev) { |
| 246 PostProgress(percent_curr); |
| 247 } |
| 248 |
| 249 total_bytes_ += bytes_read; |
| 250 |
| 251 PostTask(base::Bind(&ImageWriter::VerifyChunk, this)); |
| 252 } else if (bytes_read == 0 && total_bytes_ == image_size) { |
| 253 // End of file. |
| 254 DLOG(INFO) << "Image verification operation complete. " |
| 255 << "Total bytes checked: " << total_bytes_; |
| 256 PostTask(base::Bind(&ImageWriter::VerifyComplete, this)); |
| 257 } else { |
| 258 // Unable to read entire file. |
| 259 DLOG(ERROR) << "Image verification failed at offset: " << total_bytes_; |
| 260 Error(error::kVerificationFailed); |
| 261 } |
| 262 } |
| 263 |
| 264 void ImageWriter::VerifyComplete() { |
| 265 |
| 266 DVLOG(2) << "Completed verification of " << image_path_.value(); |
| 267 PostProgress(kProgressComplete); |
| 268 |
| 269 if (CleanUp() && handler_) { |
| 270 handler_->SendSucceeded(); |
| 271 } |
| 272 } |
| 273 |
| 274 bool ImageWriter::CleanUp() { |
| 275 bool success = true; |
| 276 |
| 277 total_bytes_ = 0; |
| 278 cancelled_ = false; |
| 279 |
| 280 if (image_file_ != base::kInvalidPlatformFileValue |
| 281 && !base::ClosePlatformFile(image_file_)) { |
| 282 image_file_ = base::kInvalidPlatformFileValue; |
| 283 Error(error::kCloseImage); |
| 284 success = false; |
| 285 } |
| 286 |
| 287 if (device_file_ != base::kInvalidPlatformFileValue |
| 288 && !base::ClosePlatformFile(device_file_)) { |
| 289 device_file_ = base::kInvalidPlatformFileValue; |
| 290 Error(error::kCloseDevice); |
| 291 success = false; |
| 292 } |
| 293 |
| 294 return success; |
| 295 } |
| 296 |
| 297 } // namespace image_writer |
| 298 } // namespace chrome |
OLD | NEW |