| 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 |