OLD | NEW |
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 #include "third_party/zlib/google/zip.h" | |
13 | 12 |
14 namespace extensions { | 13 namespace extensions { |
15 namespace image_writer { | 14 namespace image_writer { |
16 | 15 |
17 using content::BrowserThread; | 16 using content::BrowserThread; |
18 | 17 |
19 const int kBurningBlockSize = 8 * 1024; // 8 KiB | |
20 | |
21 void Operation::WriteStart() { | 18 void Operation::WriteStart() { |
22 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 19 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
23 if (IsCancelled()) { | 20 if (IsCancelled()) { |
24 return; | 21 return; |
25 } | 22 } |
26 | 23 |
27 if (image_path_.empty()) { | 24 if (image_path_.empty()) { |
28 Error(error::kImageNotFound); | 25 Error(error::kImageNotFound); |
29 return; | 26 return; |
30 } | 27 } |
31 | 28 |
32 DVLOG(1) << "Starting write of " << image_path_.value() | 29 DVLOG(1) << "Starting write of " << image_path_.value() |
33 << " to " << storage_unit_id_; | 30 << " to " << storage_unit_id_; |
34 | 31 |
35 SetStage(image_writer_api::STAGE_WRITE); | 32 SetStage(image_writer_api::STAGE_WRITE); |
36 | 33 |
37 // TODO (haven): Unmount partitions before writing. http://crbug.com/284834 | |
38 | |
39 scoped_ptr<image_writer_utils::ImageReader> reader( | |
40 new image_writer_utils::ImageReader()); | |
41 scoped_ptr<image_writer_utils::ImageWriter> writer( | |
42 new image_writer_utils::ImageWriter()); | |
43 base::FilePath storage_path(storage_unit_id_); | 34 base::FilePath storage_path(storage_unit_id_); |
44 | 35 scoped_refptr<base::MessageLoopProxy> task_runner = |
45 if (reader->Open(image_path_)) { | 36 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE); |
46 if (!writer->Open(storage_path)) { | 37 scoped_refptr<ImageWriter> image_writer(new ImageWriter(this, |
47 reader->Close(); | 38 image_path_, |
48 Error(error::kOpenDevice); | 39 storage_path)); |
49 return; | 40 image_writer->Start(task_runner); |
50 } | |
51 } else { | |
52 Error(error::kOpenImage); | |
53 return; | |
54 } | |
55 | |
56 BrowserThread::PostTask( | |
57 BrowserThread::FILE, | |
58 FROM_HERE, | |
59 base::Bind(&Operation::WriteChunk, | |
60 this, | |
61 base::Passed(&reader), | |
62 base::Passed(&writer), | |
63 0)); | |
64 } | |
65 | |
66 void Operation::WriteChunk( | |
67 scoped_ptr<image_writer_utils::ImageReader> reader, | |
68 scoped_ptr<image_writer_utils::ImageWriter> writer, | |
69 int64 bytes_written) { | |
70 if (IsCancelled()) { | |
71 WriteCleanUp(reader.Pass(), writer.Pass()); | |
72 return; | |
73 } | |
74 | |
75 char buffer[kBurningBlockSize]; | |
76 int64 image_size = reader->GetSize(); | |
77 int len = reader->Read(buffer, kBurningBlockSize); | |
78 | |
79 if (len > 0) { | |
80 if (writer->Write(buffer, len) == len) { | |
81 int percent_prev = kProgressComplete * bytes_written / image_size; | |
82 int percent_curr = kProgressComplete * (bytes_written + len) / image_size; | |
83 | |
84 if (percent_curr > percent_prev) { | |
85 SetProgress(percent_curr); | |
86 } | |
87 | |
88 BrowserThread::PostTask( | |
89 BrowserThread::FILE, | |
90 FROM_HERE, | |
91 base::Bind(&Operation::WriteChunk, | |
92 this, | |
93 base::Passed(&reader), | |
94 base::Passed(&writer), | |
95 bytes_written + len)); | |
96 } else { | |
97 WriteCleanUp(reader.Pass(), writer.Pass()); | |
98 Error(error::kWriteImage); | |
99 } | |
100 } else if (len == 0) { | |
101 if (bytes_written == image_size) { | |
102 if (WriteCleanUp(reader.Pass(), writer.Pass())) { | |
103 BrowserThread::PostTask( | |
104 BrowserThread::FILE, | |
105 FROM_HERE, | |
106 base::Bind(&Operation::WriteComplete, | |
107 this)); | |
108 } | |
109 } else { | |
110 WriteCleanUp(reader.Pass(), writer.Pass()); | |
111 Error(error::kPrematureEndOfFile); | |
112 } | |
113 } else { // len < 0 | |
114 WriteCleanUp(reader.Pass(), writer.Pass()); | |
115 Error(error::kReadImage); | |
116 } | |
117 } | |
118 | |
119 bool Operation::WriteCleanUp( | |
120 scoped_ptr<image_writer_utils::ImageReader> reader, | |
121 scoped_ptr<image_writer_utils::ImageWriter> writer) { | |
122 | |
123 bool success = true; | |
124 if (!reader->Close()) { | |
125 Error(error::kCloseImage); | |
126 success = false; | |
127 } | |
128 | |
129 if (!writer->Close()) { | |
130 Error(error::kCloseDevice); | |
131 success = false; | |
132 } | |
133 return success; | |
134 } | |
135 | |
136 void Operation::WriteComplete() { | |
137 | |
138 DVLOG(2) << "Completed write of " << image_path_.value(); | |
139 SetProgress(kProgressComplete); | |
140 | |
141 BrowserThread::PostTask( | |
142 BrowserThread::FILE, | |
143 FROM_HERE, | |
144 base::Bind(&Operation::VerifyWriteStart, | |
145 this)); | |
146 } | |
147 | |
148 void Operation::VerifyWriteStart() { | |
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
150 if (IsCancelled()) { | |
151 return; | |
152 } | |
153 | |
154 DVLOG(1) << "Starting verification stage."; | |
155 | |
156 SetStage(image_writer_api::STAGE_VERIFYWRITE); | |
157 | |
158 scoped_ptr<base::FilePath> image_path(new base::FilePath(image_path_)); | |
159 | |
160 GetMD5SumOfFile( | |
161 image_path.Pass(), | |
162 -1, | |
163 0, // progress_offset | |
164 50, // progress_scale | |
165 base::Bind(&Operation::VerifyWriteStage2, | |
166 this)); | |
167 } | |
168 | |
169 void Operation::VerifyWriteStage2( | |
170 scoped_ptr<std::string> image_hash) { | |
171 DVLOG(1) << "Building MD5 sum of device: " << storage_unit_id_; | |
172 | |
173 int64 image_size; | |
174 scoped_ptr<base::FilePath> device_path(new base::FilePath(storage_unit_id_)); | |
175 | |
176 if (!file_util::GetFileSize(image_path_, &image_size)){ | |
177 Error(error::kImageSize); | |
178 return; | |
179 } | |
180 | |
181 GetMD5SumOfFile( | |
182 device_path.Pass(), | |
183 image_size, | |
184 50, // progress_offset | |
185 50, // progress_scale | |
186 base::Bind(&Operation::VerifyWriteCompare, | |
187 this, | |
188 base::Passed(&image_hash))); | |
189 } | |
190 | |
191 void Operation::VerifyWriteCompare( | |
192 scoped_ptr<std::string> image_hash, | |
193 scoped_ptr<std::string> device_hash) { | |
194 DVLOG(1) << "Comparing hashes: " << *image_hash << " vs " << *device_hash; | |
195 | |
196 if (*image_hash != *device_hash) { | |
197 Error(error::kWriteHash); | |
198 return; | |
199 } | |
200 | |
201 DVLOG(2) << "Completed write verification of " << image_path_.value(); | |
202 | |
203 SetProgress(kProgressComplete); | |
204 | |
205 Finish(); | |
206 } | 41 } |
207 | 42 |
208 } // namespace image_writer | 43 } // namespace image_writer |
209 } // namespace extensions | 44 } // namespace extensions |
OLD | NEW |