Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: chrome/browser/extensions/api/image_writer_private/operation.cc

Issue 170123002: Revert of Significantly cleans up the ImageWriter Operation class and subclasses. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/file_util.h" 5 #include "base/file_util.h"
6 #include "base/files/file_enumerator.h" 6 #include "base/files/file_enumerator.h"
7 #include "base/threading/worker_pool.h" 7 #include "base/threading/worker_pool.h"
8 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h" 8 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
9 #include "chrome/browser/extensions/api/image_writer_private/operation.h" 9 #include "chrome/browser/extensions/api/image_writer_private/operation.h"
10 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h " 10 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h "
11 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
12 12
13 namespace extensions { 13 namespace extensions {
14 namespace image_writer { 14 namespace image_writer {
15 15
16 using content::BrowserThread; 16 using content::BrowserThread;
17 17
18 namespace {
19
18 const int kMD5BufferSize = 1024; 20 const int kMD5BufferSize = 1024;
19 #if defined(OS_CHROMEOS) 21
20 // Chrome OS only has a 1 GB temporary partition. This is too small to hold our 22 void RemoveTempDirectory(const base::FilePath path) {
21 // unzipped image. Fortunately we mount part of the temporary partition under 23 base::DeleteFile(path, true);
22 // /var/tmp. 24 }
23 const char kChromeOSTempRoot[] = "/var/tmp"; 25
24 #endif 26 } // namespace
25 27
26 Operation::Operation(base::WeakPtr<OperationManager> manager, 28 Operation::Operation(base::WeakPtr<OperationManager> manager,
27 const ExtensionId& extension_id, 29 const ExtensionId& extension_id,
28 const std::string& device_path) 30 const std::string& storage_unit_id)
29 : manager_(manager), 31 : manager_(manager),
30 extension_id_(extension_id), 32 extension_id_(extension_id),
31 #if defined(OS_WIN) 33 storage_unit_id_(storage_unit_id),
32 device_path_(base::FilePath::FromUTF8Unsafe(device_path)), 34 verify_write_(true),
33 #else
34 device_path_(device_path),
35 #endif
36 #if defined(OS_LINUX) && !defined(CHROMEOS)
37 image_file_(base::kInvalidPlatformFileValue),
38 device_file_(base::kInvalidPlatformFileValue),
39 #endif
40 stage_(image_writer_api::STAGE_UNKNOWN), 35 stage_(image_writer_api::STAGE_UNKNOWN),
41 progress_(0) { 36 progress_(0) {
42 } 37 }
43 38
44 Operation::~Operation() {} 39 Operation::~Operation() {
40 }
45 41
46 void Operation::Cancel() { 42 void Operation::Cancel() {
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
48 44
45 DVLOG(1) << "Cancelling image writing operation for ext: " << extension_id_;
46
49 stage_ = image_writer_api::STAGE_NONE; 47 stage_ = image_writer_api::STAGE_NONE;
50 48
51 CleanUp(); 49 CleanUp();
52 } 50 }
53 51
54 void Operation::Abort() { 52 void Operation::Abort() {
55 Error(error::kAborted); 53 Error(error::kAborted);
56 } 54 }
57 55
58 int Operation::GetProgress() { 56 int Operation::GetProgress() {
59 return progress_; 57 return progress_;
60 } 58 }
61 59
62 image_writer_api::Stage Operation::GetStage() { 60 image_writer_api::Stage Operation::GetStage() {
63 return stage_; 61 return stage_;
64 } 62 }
65 63
66 void Operation::Start() {
67 #if defined(OS_CHROMEOS)
68 if (!temp_dir_.CreateUniqueTempDirUnderPath(
69 base::FilePath(kChromeOSTempRoot))) {
70 #else
71 if (!temp_dir_.CreateUniqueTempDir()) {
72 #endif
73 Error(error::kTempDirError);
74 return;
75 }
76
77 AddCleanUpFunction(
78 base::Bind(base::IgnoreResult(&base::ScopedTempDir::Delete),
79 base::Unretained(&temp_dir_)));
80
81 StartImpl();
82 }
83
84 void Operation::Unzip(const base::Closure& continuation) {
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
86 if (IsCancelled()) {
87 return;
88 }
89
90 if (image_path_.Extension() != FILE_PATH_LITERAL(".zip")) {
91 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation);
92 return;
93 }
94
95 SetStage(image_writer_api::STAGE_UNZIP);
96
97 if (!(zip_reader_.Open(image_path_) && zip_reader_.AdvanceToNextEntry() &&
98 zip_reader_.OpenCurrentEntryInZip())) {
99 Error(error::kUnzipGenericError);
100 return;
101 }
102
103 if (zip_reader_.HasMore()) {
104 Error(error::kUnzipInvalidArchive);
105 return;
106 }
107
108 // Create a new target to unzip to. The original file is opened by the
109 // zip_reader_.
110 zip::ZipReader::EntryInfo* entry_info = zip_reader_.current_entry_info();
111 if (entry_info) {
112 image_path_ = temp_dir_.path().Append(entry_info->file_path().BaseName());
113 } else {
114 Error(error::kTempDirError);
115 return;
116 }
117
118 zip_reader_.ExtractCurrentEntryToFilePathAsync(
119 image_path_,
120 base::Bind(&Operation::OnUnzipSuccess, this, continuation),
121 base::Bind(&Operation::OnUnzipFailure, this),
122 base::Bind(&Operation::OnUnzipProgress,
123 this,
124 zip_reader_.current_entry_info()->original_size()));
125 }
126
127 void Operation::Finish() {
128 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
129 BrowserThread::PostTask(
130 BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Finish, this));
131 return;
132 }
133
134 CleanUp();
135
136 BrowserThread::PostTask(
137 BrowserThread::UI,
138 FROM_HERE,
139 base::Bind(&OperationManager::OnComplete, manager_, extension_id_));
140 }
141
142 void Operation::Error(const std::string& error_message) { 64 void Operation::Error(const std::string& error_message) {
143 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 65 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
144 BrowserThread::PostTask(BrowserThread::FILE, 66 BrowserThread::PostTask(BrowserThread::FILE,
145 FROM_HERE, 67 FROM_HERE,
146 base::Bind(&Operation::Error, this, error_message)); 68 base::Bind(&Operation::Error, this, error_message));
147 return; 69 return;
148 } 70 }
149 71
150 BrowserThread::PostTask( 72 BrowserThread::PostTask(
151 BrowserThread::UI, 73 BrowserThread::UI,
(...skipping 12 matching lines...) Expand all
164 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 86 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
165 BrowserThread::PostTask( 87 BrowserThread::PostTask(
166 BrowserThread::FILE, 88 BrowserThread::FILE,
167 FROM_HERE, 89 FROM_HERE,
168 base::Bind(&Operation::SetProgress, 90 base::Bind(&Operation::SetProgress,
169 this, 91 this,
170 progress)); 92 progress));
171 return; 93 return;
172 } 94 }
173 95
174 if (progress <= progress_) {
175 return;
176 }
177
178 if (IsCancelled()) { 96 if (IsCancelled()) {
179 return; 97 return;
180 } 98 }
181 99
182 progress_ = progress; 100 progress_ = progress;
183 101
184 BrowserThread::PostTask( 102 BrowserThread::PostTask(
185 BrowserThread::UI, 103 BrowserThread::UI,
186 FROM_HERE, 104 FROM_HERE,
187 base::Bind(&OperationManager::OnProgress, 105 base::Bind(&OperationManager::OnProgress,
(...skipping 24 matching lines...) Expand all
212 BrowserThread::PostTask( 130 BrowserThread::PostTask(
213 BrowserThread::UI, 131 BrowserThread::UI,
214 FROM_HERE, 132 FROM_HERE,
215 base::Bind(&OperationManager::OnProgress, 133 base::Bind(&OperationManager::OnProgress,
216 manager_, 134 manager_,
217 extension_id_, 135 extension_id_,
218 stage_, 136 stage_,
219 progress_)); 137 progress_));
220 } 138 }
221 139
140 void Operation::Finish() {
141 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
142 BrowserThread::PostTask(BrowserThread::FILE,
143 FROM_HERE,
144 base::Bind(&Operation::Finish, this));
145 return;
146 }
147 DVLOG(1) << "Write operation complete.";
148
149 CleanUp();
150
151 BrowserThread::PostTask(
152 BrowserThread::UI,
153 FROM_HERE,
154 base::Bind(&OperationManager::OnComplete,
155 manager_,
156 extension_id_));
157 }
158
222 bool Operation::IsCancelled() { 159 bool Operation::IsCancelled() {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
224 161
225 return stage_ == image_writer_api::STAGE_NONE; 162 return stage_ == image_writer_api::STAGE_NONE;
226 } 163 }
227 164
228 void Operation::AddCleanUpFunction(const base::Closure& callback) { 165 void Operation::AddCleanUpFunction(base::Closure callback) {
229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
167
230 cleanup_functions_.push_back(callback); 168 cleanup_functions_.push_back(callback);
231 } 169 }
232 170
171 void Operation::CleanUp() {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
173 for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin();
174 it != cleanup_functions_.end();
175 ++it) {
176 it->Run();
177 }
178 cleanup_functions_.clear();
179 }
180
181 void Operation::UnzipStart(scoped_ptr<base::FilePath> zip_path) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
183 if (IsCancelled()) {
184 return;
185 }
186
187 DVLOG(1) << "Starting unzip stage for " << zip_path->value();
188
189 SetStage(image_writer_api::STAGE_UNZIP);
190
191 base::FilePath tmp_dir;
192 if (!base::CreateTemporaryDirInDir(zip_path->DirName(),
193 FILE_PATH_LITERAL("image_writer"),
194 &tmp_dir)) {
195 Error(error::kTempDirError);
196 return;
197 }
198
199 AddCleanUpFunction(base::Bind(&RemoveTempDirectory, tmp_dir));
200
201 if (!base::CreateTemporaryFileInDir(tmp_dir, &image_path_)) {
202 DLOG(ERROR) << "Failed create temporary unzip target in "
203 << tmp_dir.value();
204 Error(error::kTempDirError);
205 return;
206 }
207
208 if (!(zip_reader_.Open(*zip_path) &&
209 zip_reader_.AdvanceToNextEntry() &&
210 zip_reader_.OpenCurrentEntryInZip())) {
211 DLOG(ERROR) << "Failed to open zip file.";
212 Error(error::kUnzipGenericError);
213 return;
214 }
215
216 if (zip_reader_.HasMore()) {
217 DLOG(ERROR) << "Image zip has more than one file.";
218 Error(error::kUnzipInvalidArchive);
219 return;
220 }
221
222 zip_reader_.ExtractCurrentEntryToFilePathAsync(
223 image_path_,
224 base::Bind(&Operation::OnUnzipSuccess, this),
225 base::Bind(&Operation::OnUnzipFailure, this),
226 base::Bind(&Operation::OnUnzipProgress,
227 this,
228 zip_reader_.current_entry_info()->original_size()));
229 }
230
233 void Operation::GetMD5SumOfFile( 231 void Operation::GetMD5SumOfFile(
234 const base::FilePath& file_path, 232 scoped_ptr<base::FilePath> file_path,
235 int64 file_size, 233 int64 file_size,
236 int progress_offset, 234 int progress_offset,
237 int progress_scale, 235 int progress_scale,
238 const base::Callback<void(const std::string&)>& callback) { 236 const base::Callback<void(scoped_ptr<std::string>)>& callback) {
239 if (IsCancelled()) { 237 if (IsCancelled()) {
240 return; 238 return;
241 } 239 }
242 240
243 base::MD5Init(&md5_context_); 241 base::MD5Init(&md5_context_);
242 scoped_ptr<image_writer_utils::ImageReader> reader(
243 new image_writer_utils::ImageReader());
244 244
245 base::PlatformFile file = base::CreatePlatformFile( 245 if (!reader->Open(*file_path)) {
246 file_path,
247 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
248 NULL,
249 NULL);
250 if (file == base::kInvalidPlatformFileValue) {
251 Error(error::kImageOpenError); 246 Error(error::kImageOpenError);
252 return; 247 return;
253 } 248 }
254
255 if (file_size <= 0) { 249 if (file_size <= 0) {
256 if (!base::GetFileSize(file_path, &file_size)) { 250 file_size = reader->GetSize();
257 Error(error::kImageOpenError);
258 return;
259 }
260 } 251 }
261 252
262 BrowserThread::PostTask(BrowserThread::FILE, 253 BrowserThread::PostTask(BrowserThread::FILE,
263 FROM_HERE, 254 FROM_HERE,
264 base::Bind(&Operation::MD5Chunk, 255 base::Bind(&Operation::MD5Chunk,
265 this, 256 this,
266 file, 257 base::Passed(&reader),
267 0, 258 0,
268 file_size, 259 file_size,
269 progress_offset, 260 progress_offset,
270 progress_scale, 261 progress_scale,
271 callback)); 262 callback));
272 } 263 }
273 264
274 void Operation::MD5Chunk( 265 void Operation::MD5Chunk(
275 const base::PlatformFile& file, 266 scoped_ptr<image_writer_utils::ImageReader> reader,
276 int64 bytes_processed, 267 int64 bytes_processed,
277 int64 bytes_total, 268 int64 bytes_total,
278 int progress_offset, 269 int progress_offset,
279 int progress_scale, 270 int progress_scale,
280 const base::Callback<void(const std::string&)>& callback) { 271 const base::Callback<void(scoped_ptr<std::string>)>& callback) {
281 if (IsCancelled()) { 272 if (IsCancelled()) {
282 base::ClosePlatformFile(file); 273 reader->Close();
283 return; 274 return;
284 } 275 }
285 276
286 CHECK_LE(bytes_processed, bytes_total); 277 char buffer[kMD5BufferSize];
278 int len;
287 279
288 scoped_ptr<char[]> buffer(new char[kMD5BufferSize]); 280 if (bytes_total - bytes_processed <= kMD5BufferSize) {
289 int read_size = std::min(bytes_total - bytes_processed, 281 len = reader->Read(buffer, bytes_total - bytes_processed);
290 static_cast<int64>(kMD5BufferSize)); 282 } else {
283 len = reader->Read(buffer, kMD5BufferSize);
284 }
291 285
292 if (read_size == 0) { 286 if (len > 0) {
293 // Nothing to read, we are done. 287 base::MD5Update(&md5_context_, base::StringPiece(buffer, len));
294 base::MD5Digest digest; 288 int percent_prev = (bytes_processed * progress_scale + progress_offset) /
295 base::MD5Final(&digest, &md5_context_); 289 (bytes_total);
296 callback.Run(base::MD5DigestToBase16(digest)); 290 int percent_curr = ((bytes_processed + len) * progress_scale +
297 } else { 291 progress_offset) /
298 int len = 292 (bytes_total);
299 base::ReadPlatformFile(file, bytes_processed, buffer.get(), read_size); 293 if (percent_curr > percent_prev) {
294 SetProgress(progress_);
295 }
300 296
301 if (len == read_size) { 297 BrowserThread::PostTask(BrowserThread::FILE,
302 // Process data. 298 FROM_HERE,
303 base::MD5Update(&md5_context_, base::StringPiece(buffer.get(), len)); 299 base::Bind(&Operation::MD5Chunk,
304 int percent_curr = 300 this,
305 ((bytes_processed + len) * progress_scale) / bytes_total + 301 base::Passed(&reader),
306 progress_offset; 302 bytes_processed + len,
307 SetProgress(percent_curr); 303 bytes_total,
308 304 progress_offset,
309 BrowserThread::PostTask(BrowserThread::FILE, 305 progress_scale,
310 FROM_HERE, 306 callback));
311 base::Bind(&Operation::MD5Chunk, 307 } else if (len == 0) {
312 this, 308 if (bytes_processed + len < bytes_total) {
313 file, 309 reader->Close();
314 bytes_processed + len, 310 Error(error::kHashReadError);
315 bytes_total,
316 progress_offset,
317 progress_scale,
318 callback));
319 // Skip closing the file.
320 return;
321 } else { 311 } else {
322 // We didn't read the bytes we expected. 312 base::MD5Digest digest;
323 Error(error::kHashReadError); 313 base::MD5Final(&digest, &md5_context_);
314 scoped_ptr<std::string> hash(
315 new std::string(base::MD5DigestToBase16(digest)));
316 callback.Run(hash.Pass());
324 } 317 }
318 } else { // len < 0
319 reader->Close();
320 Error(error::kHashReadError);
325 } 321 }
326 base::ClosePlatformFile(file);
327 } 322 }
328 323
329 void Operation::OnUnzipSuccess(const base::Closure& continuation) { 324 void Operation::OnUnzipSuccess() {
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
331 SetProgress(kProgressComplete); 326 SetProgress(kProgressComplete);
332 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, continuation); 327 WriteStart();
333 } 328 }
334 329
335 void Operation::OnUnzipFailure() { 330 void Operation::OnUnzipFailure() {
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
337 Error(error::kUnzipGenericError); 332 Error(error::kUnzipGenericError);
338 } 333 }
339 334
340 void Operation::OnUnzipProgress(int64 total_bytes, int64 progress_bytes) { 335 void Operation::OnUnzipProgress(int64 total_bytes, int64 progress_bytes) {
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
342 337
343 int progress_percent = 100 * progress_bytes / total_bytes; 338 int progress_percent = 100 * progress_bytes / total_bytes;
344 SetProgress(progress_percent); 339 SetProgress(progress_percent);
345 } 340 }
346 341
347 void Operation::CleanUp() {
348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
349 for (std::vector<base::Closure>::iterator it = cleanup_functions_.begin();
350 it != cleanup_functions_.end();
351 ++it) {
352 it->Run();
353 }
354 cleanup_functions_.clear();
355 }
356
357 } // namespace image_writer 342 } // namespace image_writer
358 } // namespace extensions 343 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698