OLD | NEW |
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 18 matching lines...) Expand all Loading... |
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 = 512 * 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 Loading... |
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 Loading... |
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 |
OLD | NEW |