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

Side by Side Diff: filesystem_copier_action.cc

Issue 5516009: AU: Split applied update verification into a separate step. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/update_engine.git@master
Patch Set: review comments Created 10 years 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 | Annotate | Revision Log
« no previous file with comments | « filesystem_copier_action.h ('k') | filesystem_copier_action_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS 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 "update_engine/filesystem_copier_action.h" 5 #include "update_engine/filesystem_copier_action.h"
6 6
7 #include <sys/stat.h> 7 #include <sys/stat.h>
8 #include <sys/types.h> 8 #include <sys/types.h>
9 #include <errno.h> 9 #include <errno.h>
10 #include <fcntl.h> 10 #include <fcntl.h>
(...skipping 14 matching lines...) Expand all
25 #include "update_engine/utils.h" 25 #include "update_engine/utils.h"
26 26
27 using std::map; 27 using std::map;
28 using std::min; 28 using std::min;
29 using std::string; 29 using std::string;
30 using std::vector; 30 using std::vector;
31 31
32 namespace chromeos_update_engine { 32 namespace chromeos_update_engine {
33 33
34 namespace { 34 namespace {
35 const off_t kCopyFileBufferSize = 512 * 1024; 35 const off_t kCopyFileBufferSize = 128 * 1024;
36 } // namespace {} 36 } // namespace {}
37 37
38 FilesystemCopierAction::FilesystemCopierAction( 38 FilesystemCopierAction::FilesystemCopierAction(
39 bool copying_kernel_install_path) 39 bool copying_kernel_install_path,
40 bool verify_hash)
40 : copying_kernel_install_path_(copying_kernel_install_path), 41 : copying_kernel_install_path_(copying_kernel_install_path),
42 verify_hash_(verify_hash),
41 src_stream_(NULL), 43 src_stream_(NULL),
42 dst_stream_(NULL), 44 dst_stream_(NULL),
43 read_done_(false), 45 read_done_(false),
44 failed_(false), 46 failed_(false),
45 cancelled_(false), 47 cancelled_(false),
46 filesystem_size_(kint64max) { 48 filesystem_size_(kint64max) {
47 // A lot of code works on the implicit assumption that processing is done on 49 // A lot of code works on the implicit assumption that processing is done on
48 // exactly 2 ping-pong buffers. 50 // exactly 2 ping-pong buffers.
49 COMPILE_ASSERT(arraysize(buffer_) == 2 && 51 COMPILE_ASSERT(arraysize(buffer_) == 2 &&
50 arraysize(buffer_state_) == 2 && 52 arraysize(buffer_state_) == 2 &&
(...skipping 10 matching lines...) Expand all
61 void FilesystemCopierAction::PerformAction() { 63 void FilesystemCopierAction::PerformAction() {
62 // Will tell the ActionProcessor we've failed if we return. 64 // Will tell the ActionProcessor we've failed if we return.
63 ScopedActionCompleter abort_action_completer(processor_, this); 65 ScopedActionCompleter abort_action_completer(processor_, this);
64 66
65 if (!HasInputObject()) { 67 if (!HasInputObject()) {
66 LOG(ERROR) << "FilesystemCopierAction missing input object."; 68 LOG(ERROR) << "FilesystemCopierAction missing input object.";
67 return; 69 return;
68 } 70 }
69 install_plan_ = GetInputObject(); 71 install_plan_ = GetInputObject();
70 72
71 if (install_plan_.is_full_update || install_plan_.is_resume) { 73 // Note that we do need to run hash verification for new-style full updates
72 // No copy needed. Done! 74 // but currently the |is_full_update| field is set to true only for old-style
75 // full updates and we don't have any expected partition info in that case.
76 if (install_plan_.is_full_update ||
77 (!verify_hash_ && install_plan_.is_resume)) {
78 // No copy or hash verification needed. Done!
73 if (HasOutputPipe()) 79 if (HasOutputPipe())
74 SetOutputObject(install_plan_); 80 SetOutputObject(install_plan_);
75 abort_action_completer.set_code(kActionCodeSuccess); 81 abort_action_completer.set_code(kActionCodeSuccess);
76 return; 82 return;
77 } 83 }
78 84
79 string source = copy_source_; 85 const string destination = copying_kernel_install_path_ ?
86 install_plan_.kernel_install_path :
87 install_plan_.install_path;
88 string source = verify_hash_ ? destination : copy_source_;
80 if (source.empty()) { 89 if (source.empty()) {
81 source = copying_kernel_install_path_ ? 90 source = copying_kernel_install_path_ ?
82 utils::BootKernelDevice(utils::BootDevice()) : 91 utils::BootKernelDevice(utils::BootDevice()) :
83 utils::BootDevice(); 92 utils::BootDevice();
84 } 93 }
85
86 const string destination = copying_kernel_install_path_ ?
87 install_plan_.kernel_install_path :
88 install_plan_.install_path;
89
90 int src_fd = open(source.c_str(), O_RDONLY); 94 int src_fd = open(source.c_str(), O_RDONLY);
91 if (src_fd < 0) { 95 if (src_fd < 0) {
92 PLOG(ERROR) << "Unable to open " << source << " for reading:"; 96 PLOG(ERROR) << "Unable to open " << source << " for reading:";
93 return; 97 return;
94 } 98 }
95 int dst_fd = open(destination.c_str(), 99
96 O_WRONLY | O_TRUNC | O_CREAT, 100 if (!verify_hash_) {
101 int dst_fd = open(destination.c_str(),
102 O_WRONLY | O_TRUNC | O_CREAT,
97 0644); 103 0644);
98 if (dst_fd < 0) { 104 if (dst_fd < 0) {
99 close(src_fd); 105 close(src_fd);
100 PLOG(ERROR) << "Unable to open " << install_plan_.install_path 106 PLOG(ERROR) << "Unable to open " << install_plan_.install_path
101 << " for writing:"; 107 << " for writing:";
102 return; 108 return;
109 }
110
111 dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
103 } 112 }
104 113
105 DetermineFilesystemSize(src_fd); 114 DetermineFilesystemSize(src_fd);
106
107 src_stream_ = g_unix_input_stream_new(src_fd, TRUE); 115 src_stream_ = g_unix_input_stream_new(src_fd, TRUE);
108 dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
109 116
110 for (int i = 0; i < 2; i++) { 117 for (int i = 0; i < 2; i++) {
111 buffer_[i].resize(kCopyFileBufferSize); 118 buffer_[i].resize(kCopyFileBufferSize);
112 canceller_[i] = g_cancellable_new(); 119 canceller_[i] = g_cancellable_new();
113 } 120 }
114 121
115 // Start the first read. 122 // Start the first read.
116 SpawnAsyncActions(); 123 SpawnAsyncActions();
117 124
118 abort_action_completer.set_should_complete(false); 125 abort_action_completer.set_should_complete(false);
119 } 126 }
120 127
121 void FilesystemCopierAction::TerminateProcessing() { 128 void FilesystemCopierAction::TerminateProcessing() {
122 for (int i = 0; i < 2; i++) { 129 for (int i = 0; i < 2; i++) {
123 if (canceller_[i]) { 130 if (canceller_[i]) {
124 g_cancellable_cancel(canceller_[i]); 131 g_cancellable_cancel(canceller_[i]);
125 } 132 }
126 } 133 }
127 } 134 }
128 135
129 void FilesystemCopierAction::Cleanup(bool success) { 136 void FilesystemCopierAction::Cleanup(ActionExitCode code) {
130 for (int i = 0; i < 2; i++) { 137 for (int i = 0; i < 2; i++) {
131 g_object_unref(canceller_[i]); 138 g_object_unref(canceller_[i]);
132 canceller_[i] = NULL; 139 canceller_[i] = NULL;
133 } 140 }
134 g_object_unref(src_stream_); 141 g_object_unref(src_stream_);
135 src_stream_ = NULL; 142 src_stream_ = NULL;
136 g_object_unref(dst_stream_); 143 if (dst_stream_) {
137 dst_stream_ = NULL; 144 g_object_unref(dst_stream_);
145 dst_stream_ = NULL;
146 }
138 if (cancelled_) 147 if (cancelled_)
139 return; 148 return;
140 if (success && HasOutputPipe()) 149 if (code == kActionCodeSuccess && HasOutputPipe())
141 SetOutputObject(install_plan_); 150 SetOutputObject(install_plan_);
142 processor_->ActionComplete( 151 processor_->ActionComplete(this, code);
143 this,
144 success ? kActionCodeSuccess : kActionCodeError);
145 } 152 }
146 153
147 void FilesystemCopierAction::AsyncReadReadyCallback(GObject *source_object, 154 void FilesystemCopierAction::AsyncReadReadyCallback(GObject *source_object,
148 GAsyncResult *res) { 155 GAsyncResult *res) {
149 int index = buffer_state_[0] == kBufferStateReading ? 0 : 1; 156 int index = buffer_state_[0] == kBufferStateReading ? 0 : 1;
150 CHECK(buffer_state_[index] == kBufferStateReading); 157 CHECK(buffer_state_[index] == kBufferStateReading);
151 158
152 GError* error = NULL; 159 GError* error = NULL;
153 CHECK(canceller_[index]); 160 CHECK(canceller_[index]);
154 cancelled_ = g_cancellable_is_cancelled(canceller_[index]) == TRUE; 161 cancelled_ = g_cancellable_is_cancelled(canceller_[index]) == TRUE;
155 162
156 ssize_t bytes_read = g_input_stream_read_finish(src_stream_, res, &error); 163 ssize_t bytes_read = g_input_stream_read_finish(src_stream_, res, &error);
157 if (bytes_read < 0) { 164 if (bytes_read < 0) {
158 LOG(ERROR) << "Read failed: " << utils::GetGErrorMessage(error); 165 LOG(ERROR) << "Read failed: " << utils::GetGErrorMessage(error);
159 failed_ = true; 166 failed_ = true;
160 buffer_state_[index] = kBufferStateEmpty; 167 buffer_state_[index] = kBufferStateEmpty;
161 } else if (bytes_read == 0) { 168 } else if (bytes_read == 0) {
162 read_done_ = true; 169 read_done_ = true;
163 buffer_state_[index] = kBufferStateEmpty; 170 buffer_state_[index] = kBufferStateEmpty;
164 } else { 171 } else {
165 buffer_valid_size_[index] = bytes_read; 172 buffer_valid_size_[index] = bytes_read;
166 buffer_state_[index] = kBufferStateFull; 173 buffer_state_[index] = kBufferStateFull;
167 }
168
169 if (bytes_read > 0) {
170 filesystem_size_ -= bytes_read; 174 filesystem_size_ -= bytes_read;
171 } 175 }
172
173 SpawnAsyncActions(); 176 SpawnAsyncActions();
174 177
175 if (bytes_read > 0) { 178 if (bytes_read > 0) {
179 // If read_done_ is set, SpawnAsyncActions may finalize the hash so the hash
180 // update below would happen too late.
181 CHECK(!read_done_);
176 if (!hasher_.Update(buffer_[index].data(), bytes_read)) { 182 if (!hasher_.Update(buffer_[index].data(), bytes_read)) {
177 LOG(ERROR) << "Unable to update the hash."; 183 LOG(ERROR) << "Unable to update the hash.";
178 failed_ = true; 184 failed_ = true;
179 } 185 }
186 if (verify_hash_) {
187 buffer_state_[index] = kBufferStateEmpty;
188 }
180 } 189 }
181 } 190 }
182 191
183 void FilesystemCopierAction::StaticAsyncReadReadyCallback( 192 void FilesystemCopierAction::StaticAsyncReadReadyCallback(
184 GObject *source_object, 193 GObject *source_object,
185 GAsyncResult *res, 194 GAsyncResult *res,
186 gpointer user_data) { 195 gpointer user_data) {
187 reinterpret_cast<FilesystemCopierAction*>(user_data)-> 196 reinterpret_cast<FilesystemCopierAction*>(user_data)->
188 AsyncReadReadyCallback(source_object, res); 197 AsyncReadReadyCallback(source_object, res);
189 } 198 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 for (int i = 0; i < 2; i++) { 237 for (int i = 0; i < 2; i++) {
229 if (buffer_state_[i] == kBufferStateReading) { 238 if (buffer_state_[i] == kBufferStateReading) {
230 reading = true; 239 reading = true;
231 } 240 }
232 if (buffer_state_[i] == kBufferStateWriting) { 241 if (buffer_state_[i] == kBufferStateWriting) {
233 writing = true; 242 writing = true;
234 } 243 }
235 } 244 }
236 if (failed_ || cancelled_) { 245 if (failed_ || cancelled_) {
237 if (!reading && !writing) { 246 if (!reading && !writing) {
238 Cleanup(false); 247 Cleanup(kActionCodeError);
239 } 248 }
240 return; 249 return;
241 } 250 }
242 for (int i = 0; i < 2; i++) { 251 for (int i = 0; i < 2; i++) {
243 if (!reading && !read_done_ && buffer_state_[i] == kBufferStateEmpty) { 252 if (!reading && !read_done_ && buffer_state_[i] == kBufferStateEmpty) {
253 int64_t bytes_to_read = std::min(static_cast<int64_t>(buffer_[0].size()),
254 filesystem_size_);
244 g_input_stream_read_async( 255 g_input_stream_read_async(
245 src_stream_, 256 src_stream_,
246 buffer_[i].data(), 257 buffer_[i].data(),
247 GetBytesToRead(), 258 bytes_to_read,
248 G_PRIORITY_DEFAULT, 259 G_PRIORITY_DEFAULT,
249 canceller_[i], 260 canceller_[i],
250 &FilesystemCopierAction::StaticAsyncReadReadyCallback, 261 &FilesystemCopierAction::StaticAsyncReadReadyCallback,
251 this); 262 this);
252 reading = true; 263 reading = true;
253 buffer_state_[i] = kBufferStateReading; 264 buffer_state_[i] = kBufferStateReading;
254 } else if (!writing && buffer_state_[i] == kBufferStateFull) { 265 } else if (!writing && !verify_hash_ &&
266 buffer_state_[i] == kBufferStateFull) {
255 g_output_stream_write_async( 267 g_output_stream_write_async(
256 dst_stream_, 268 dst_stream_,
257 buffer_[i].data(), 269 buffer_[i].data(),
258 buffer_valid_size_[i], 270 buffer_valid_size_[i],
259 G_PRIORITY_DEFAULT, 271 G_PRIORITY_DEFAULT,
260 canceller_[i], 272 canceller_[i],
261 &FilesystemCopierAction::StaticAsyncWriteReadyCallback, 273 &FilesystemCopierAction::StaticAsyncWriteReadyCallback,
262 this); 274 this);
263 writing = true; 275 writing = true;
264 buffer_state_[i] = kBufferStateWriting; 276 buffer_state_[i] = kBufferStateWriting;
265 } 277 }
266 } 278 }
267 if (!reading && !writing) { 279 if (!reading && !writing) {
268 // We're done! 280 // We're done!
281 ActionExitCode code = kActionCodeSuccess;
269 if (hasher_.Finalize()) { 282 if (hasher_.Finalize()) {
270 LOG(INFO) << "hash: " << hasher_.hash(); 283 LOG(INFO) << "Hash: " << hasher_.hash();
271 if (copying_kernel_install_path_) { 284 if (verify_hash_) {
272 install_plan_.current_kernel_hash = hasher_.raw_hash(); 285 if (copying_kernel_install_path_) {
286 if (install_plan_.kernel_hash != hasher_.raw_hash()) {
287 code = kActionCodeNewKernelVerificationError;
288 LOG(ERROR) << "New kernel verification failed.";
289 }
290 } else {
291 if (install_plan_.rootfs_hash != hasher_.raw_hash()) {
292 code = kActionCodeNewRootfsVerificationError;
293 LOG(ERROR) << "New rootfs verification failed.";
294 }
295 }
273 } else { 296 } else {
274 install_plan_.current_rootfs_hash = hasher_.raw_hash(); 297 if (copying_kernel_install_path_) {
298 install_plan_.kernel_hash = hasher_.raw_hash();
299 } else {
300 install_plan_.rootfs_hash = hasher_.raw_hash();
301 }
275 } 302 }
276 Cleanup(true);
277 } else { 303 } else {
278 LOG(ERROR) << "Unable to finalize the hash."; 304 LOG(ERROR) << "Unable to finalize the hash.";
279 Cleanup(false); 305 code = kActionCodeError;
280 } 306 }
307 Cleanup(code);
281 } 308 }
282 } 309 }
283 310
284 void FilesystemCopierAction::DetermineFilesystemSize(int fd) { 311 void FilesystemCopierAction::DetermineFilesystemSize(int fd) {
312 if (verify_hash_) {
313 filesystem_size_ = copying_kernel_install_path_ ?
314 install_plan_.kernel_size : install_plan_.rootfs_size;
315 LOG(INFO) << "Filesystem size: " << filesystem_size_;
316 return;
317 }
285 filesystem_size_ = kint64max; 318 filesystem_size_ = kint64max;
286 int block_count = 0, block_size = 0; 319 int block_count = 0, block_size = 0;
287 if (!copying_kernel_install_path_ && 320 if (!copying_kernel_install_path_ &&
288 utils::GetFilesystemSizeFromFD(fd, &block_count, &block_size)) { 321 utils::GetFilesystemSizeFromFD(fd, &block_count, &block_size)) {
289 filesystem_size_ = static_cast<int64_t>(block_count) * block_size; 322 filesystem_size_ = static_cast<int64_t>(block_count) * block_size;
290 LOG(INFO) << "Filesystem size: " << filesystem_size_ << " bytes (" 323 LOG(INFO) << "Filesystem size: " << filesystem_size_ << " bytes ("
291 << block_count << "x" << block_size << ")."; 324 << block_count << "x" << block_size << ").";
292 } 325 }
293 } 326 }
294 327
295 int64_t FilesystemCopierAction::GetBytesToRead() {
296 return std::min(static_cast<int64_t>(buffer_[0].size()), filesystem_size_);
297 }
298
299 } // namespace chromeos_update_engine 328 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « filesystem_copier_action.h ('k') | filesystem_copier_action_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698