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 // Since block devices like large sequential access and IPC is expensive we're | |
15 // doing work in 1MB chunks. | |
16 const int kBurningBlockSize = 1 << 20; | |
17 | |
18 ImageWriter::ImageWriter(ImageWriterHandler* handler) | |
19 : image_file_(base::kInvalidPlatformFileValue), | |
20 device_file_(base::kInvalidPlatformFileValue), | |
21 bytes_processed_(0), | |
22 handler_(handler) {} | |
23 | |
24 ImageWriter::~ImageWriter() { CleanUp(); } | |
25 | |
26 void ImageWriter::Write(const base::FilePath& image_path, | |
27 const base::FilePath& device_path) { | |
28 if (IsRunning()) { | |
29 handler_->SendFailed(error::kOperationAlreadyInProgress); | |
30 return; | |
31 } | |
32 | |
33 image_path_ = image_path; | |
34 device_path_ = device_path; | |
35 bytes_processed_ = 0; | |
36 | |
37 base::PlatformFileError error; | |
38 | |
39 image_file_ = base::CreatePlatformFile( | |
40 image_path_, | |
41 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, | |
42 NULL, | |
43 &error); | |
44 | |
45 if (error != base::PLATFORM_FILE_OK) { | |
46 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value(); | |
47 Error(error::kOpenImage); | |
48 return; | |
49 } | |
50 | |
51 #if defined(OS_WIN) | |
52 // Windows requires that device files be opened with FILE_FLAG_NO_BUFFERING | |
53 // and FILE_FLAG_WRITE_THROUGH. These two flags are not part of | |
54 // PlatformFile::CreatePlatformFile. | |
55 device_file_ = CreateFile(device_path.value().c_str(), | |
56 GENERIC_WRITE, | |
57 FILE_SHARE_WRITE, | |
58 NULL, | |
59 OPEN_EXISTING, | |
60 FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, | |
61 INVALID_HANDLE_VALUE); | |
62 | |
63 if (device_file_ == base::kInvalidPlatformFileValue) { | |
64 Error(error::kOpenDevice); | |
65 return; | |
66 } | |
67 #else | |
68 device_file_ = base::CreatePlatformFile( | |
69 device_path_, | |
70 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, | |
71 NULL, | |
72 &error); | |
73 | |
74 if (error != base::PLATFORM_FILE_OK) { | |
75 DLOG(ERROR) << "Unable to open file for write(" << error | |
76 << "): " << device_path_.value(); | |
77 Error(error::kOpenDevice); | |
78 return; | |
79 } | |
80 #endif | |
81 | |
82 PostProgress(0); | |
83 | |
84 PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr())); | |
85 } | |
86 | |
87 void ImageWriter::Verify(const base::FilePath& image_path, | |
88 const base::FilePath& device_path) { | |
89 if (IsRunning()) { | |
90 handler_->SendFailed(error::kOperationAlreadyInProgress); | |
91 return; | |
92 } | |
93 | |
94 image_path_ = image_path; | |
95 device_path_ = device_path; | |
96 bytes_processed_ = 0; | |
97 | |
98 base::PlatformFileError error; | |
99 | |
100 image_file_ = base::CreatePlatformFile( | |
101 image_path_, | |
102 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, | |
103 NULL, | |
104 &error); | |
105 | |
106 if (error != base::PLATFORM_FILE_OK) { | |
107 DLOG(ERROR) << "Unable to open file for read: " << image_path_.value(); | |
108 Error(error::kOpenImage); | |
109 return; | |
110 } | |
111 | |
112 device_file_ = base::CreatePlatformFile( | |
113 device_path_, | |
114 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, | |
115 NULL, | |
116 &error); | |
117 | |
118 if (error != base::PLATFORM_FILE_OK) { | |
119 DLOG(ERROR) << "Unable to open file for read: " << device_path_.value(); | |
120 Error(error::kOpenDevice); | |
121 return; | |
122 } | |
123 | |
124 PostProgress(0); | |
125 | |
126 PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr())); | |
127 } | |
128 | |
129 void ImageWriter::Cancel() { | |
130 CleanUp(); | |
131 handler_->SendCancelled(); | |
132 } | |
133 | |
134 bool ImageWriter::IsRunning() { | |
Lei Zhang
2014/02/15 00:49:16
nit: const method
Drew Haven
2014/02/15 01:23:58
Done.
| |
135 return image_file_ != base::kInvalidPlatformFileValue || | |
136 device_file_ != base::kInvalidPlatformFileValue; | |
137 } | |
138 | |
139 void ImageWriter::PostTask(const base::Closure& task) { | |
140 base::MessageLoop::current()->PostTask(FROM_HERE, task); | |
141 } | |
142 | |
143 void ImageWriter::PostProgress(int64 progress) { | |
144 handler_->SendProgress(progress); | |
145 } | |
146 | |
147 void ImageWriter::Error(const std::string& message) { | |
148 CleanUp(); | |
149 handler_->SendFailed(message); | |
150 } | |
151 | |
152 void ImageWriter::WriteChunk() { | |
153 if (!IsRunning()) { | |
154 return; | |
155 } | |
156 | |
157 scoped_ptr<char[]> buffer(new char[kBurningBlockSize]); | |
158 base::PlatformFileInfo info; | |
159 | |
160 int bytes_read = base::ReadPlatformFile( | |
161 image_file_, bytes_processed_, buffer.get(), kBurningBlockSize); | |
162 | |
163 if (bytes_read > 0) { | |
164 // Always attempt to write a whole block, as Windows requires 512-byte | |
165 // aligned writes to devices. | |
166 int bytes_written = base::WritePlatformFile( | |
167 device_file_, bytes_processed_, buffer.get(), kBurningBlockSize); | |
168 | |
169 if (bytes_written < bytes_read) { | |
170 Error(error::kWriteImage); | |
171 return; | |
172 } | |
173 | |
174 bytes_processed_ += bytes_read; | |
Lei Zhang
2014/02/15 00:49:16
Presumably it's ok to share |bytes_processed_| bet
Drew Haven
2014/02/15 01:23:58
Correct. Since the PlatformFiles are ultimately th
| |
175 PostProgress(bytes_processed_); | |
176 | |
177 PostTask(base::Bind(&ImageWriter::WriteChunk, AsWeakPtr())); | |
178 } else if (bytes_read == 0) { | |
179 // End of file. | |
180 base::FlushPlatformFile(device_file_); | |
181 CleanUp(); | |
182 handler_->SendSucceeded(); | |
183 } else { | |
184 // Unable to read entire file. | |
185 Error(error::kReadImage); | |
186 } | |
187 } | |
188 | |
189 void ImageWriter::VerifyChunk() { | |
190 if (!IsRunning()) { | |
191 return; | |
192 } | |
193 | |
194 scoped_ptr<char[]> image_buffer(new char[kBurningBlockSize]); | |
195 scoped_ptr<char[]> device_buffer(new char[kBurningBlockSize]); | |
196 base::PlatformFileInfo info; | |
197 int image_size; | |
198 | |
199 if (base::GetPlatformFileInfo(image_file_, &info)) { | |
200 image_size = info.size; | |
201 } else { | |
202 Error(error::kReadImage); | |
Lei Zhang
2014/02/15 00:49:16
do you want to return in this case?
Drew Haven
2014/02/15 01:23:58
Actually, I'm going to remove this because I shoul
| |
203 } | |
204 | |
205 int bytes_read = base::ReadPlatformFile( | |
206 image_file_, bytes_processed_, image_buffer.get(), kBurningBlockSize); | |
207 | |
208 if (bytes_read > 0) { | |
209 if (base::ReadPlatformFile(device_file_, | |
210 bytes_processed_, | |
211 device_buffer.get(), | |
212 kBurningBlockSize) < 0) { | |
213 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of " | |
214 << "device at offset " << bytes_processed_; | |
215 Error(error::kReadDevice); | |
216 return; | |
217 } | |
218 | |
219 if (memcmp(image_buffer.get(), device_buffer.get(), bytes_read) != 0) { | |
220 LOG(ERROR) << "Write verification failed when comparing " << bytes_read | |
221 << " bytes at " << bytes_processed_; | |
222 Error(error::kVerificationFailed); | |
223 return; | |
224 } | |
225 | |
226 bytes_processed_ += bytes_read; | |
227 PostProgress(bytes_processed_); | |
228 | |
229 PostTask(base::Bind(&ImageWriter::VerifyChunk, AsWeakPtr())); | |
230 } else if (bytes_read == 0 && bytes_processed_ == image_size) { | |
231 // End of file. | |
232 CleanUp(); | |
233 handler_->SendSucceeded(); | |
234 } else { | |
235 // Unable to read entire file. | |
236 LOG(ERROR) << "Failed to read " << kBurningBlockSize << " bytes of image " | |
237 << "at offset " << bytes_processed_; | |
238 Error(error::kReadImage); | |
239 } | |
240 } | |
241 | |
242 void ImageWriter::CleanUp() { | |
243 if (image_file_ != base::kInvalidPlatformFileValue) { | |
244 base::ClosePlatformFile(image_file_); | |
245 image_file_ = base::kInvalidPlatformFileValue; | |
246 } | |
247 if (device_file_ != base::kInvalidPlatformFileValue) { | |
248 base::ClosePlatformFile(device_file_); | |
249 device_file_ = base::kInvalidPlatformFileValue; | |
250 } | |
251 } | |
252 | |
253 } // namespace image_writer | |
254 } // namespace chrome | |
OLD | NEW |