blob: 2436797210fa895738ee43d28d8f9fd7d4180c25 [file] [log] [blame]
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07001// 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
3// found in the LICENSE file.
4
5#include "update_engine/delta_performer.h"
Darin Petkovd7061ab2010-10-06 14:37:09 -07006
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07007#include <endian.h>
8#include <errno.h>
Darin Petkovd7061ab2010-10-06 14:37:09 -07009
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070010#include <algorithm>
11#include <cstring>
12#include <string>
13#include <vector>
14
Darin Petkovd7061ab2010-10-06 14:37:09 -070015#include <base/scoped_ptr.h>
16#include <base/string_util.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070017#include <google/protobuf/repeated_field.h>
18
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070019#include "update_engine/bzip_extent_writer.h"
20#include "update_engine/delta_diff_generator.h"
21#include "update_engine/extent_writer.h"
22#include "update_engine/graph_types.h"
Darin Petkovd7061ab2010-10-06 14:37:09 -070023#include "update_engine/payload_signer.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070024#include "update_engine/subprocess.h"
25
26using std::min;
27using std::string;
28using std::vector;
29using google::protobuf::RepeatedPtrField;
30
31namespace chromeos_update_engine {
32
33namespace {
34
35const int kDeltaVersionLength = 8;
36const int kDeltaProtobufLengthLength = 8;
Darin Petkovd7061ab2010-10-06 14:37:09 -070037const char kUpdatePayloadPublicKeyPath[] =
38 "/usr/share/update_engine/update-payload-key.pub.pem";
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070039
40// Converts extents to a human-readable string, for use by DumpUpdateProto().
41string ExtentsToString(const RepeatedPtrField<Extent>& extents) {
42 string ret;
43 for (int i = 0; i < extents.size(); i++) {
44 const Extent& extent = extents.Get(i);
45 if (extent.start_block() == kSparseHole) {
46 ret += StringPrintf("{kSparseHole, %" PRIu64 "}, ", extent.num_blocks());
47 } else {
48 ret += StringPrintf("{%" PRIu64 ", %" PRIu64 "}, ",
49 extent.start_block(), extent.num_blocks());
50 }
51 }
52 if (!ret.empty()) {
53 DCHECK_GT(ret.size(), static_cast<size_t>(1));
54 ret.resize(ret.size() - 2);
55 }
56 return ret;
57}
58
59// LOGs a DeltaArchiveManifest object. Useful for debugging.
60void DumpUpdateProto(const DeltaArchiveManifest& manifest) {
61 LOG(INFO) << "Update Proto:";
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070062 LOG(INFO) << " block_size: " << manifest.block_size();
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -070063 for (int i = 0; i < (manifest.install_operations_size() +
64 manifest.kernel_install_operations_size()); i++) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070065 const DeltaArchiveManifest_InstallOperation& op =
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -070066 i < manifest.install_operations_size() ?
67 manifest.install_operations(i) :
68 manifest.kernel_install_operations(
69 i - manifest.install_operations_size());
70 if (i == 0)
71 LOG(INFO) << " Rootfs ops:";
72 else if (i == manifest.install_operations_size())
73 LOG(INFO) << " Kernel ops:";
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070074 LOG(INFO) << " operation(" << i << ")";
75 LOG(INFO) << " type: "
76 << DeltaArchiveManifest_InstallOperation_Type_Name(op.type());
77 if (op.has_data_offset())
78 LOG(INFO) << " data_offset: " << op.data_offset();
79 if (op.has_data_length())
80 LOG(INFO) << " data_length: " << op.data_length();
81 LOG(INFO) << " src_extents: " << ExtentsToString(op.src_extents());
82 if (op.has_src_length())
83 LOG(INFO) << " src_length: " << op.src_length();
84 LOG(INFO) << " dst_extents: " << ExtentsToString(op.dst_extents());
85 if (op.has_dst_length())
86 LOG(INFO) << " dst_length: " << op.dst_length();
87 }
88}
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -070089
90// Opens path for read/write, put the fd into *fd. On success returns true
91// and sets *err to 0. On failure, returns false and sets *err to errno.
92bool OpenFile(const char* path, int* fd, int* err) {
93 if (*fd != -1) {
94 LOG(ERROR) << "Can't open(" << path << "), *fd != -1 (it's " << *fd << ")";
95 *err = EINVAL;
96 return false;
97 }
98 *fd = open(path, O_RDWR, 000);
99 if (*fd < 0) {
100 *err = errno;
101 PLOG(ERROR) << "Unable to open file " << path;
102 return false;
103 }
104 *err = 0;
105 return true;
106}
107
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700108} // namespace {}
109
110int DeltaPerformer::Open(const char* path, int flags, mode_t mode) {
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700111 int err;
112 if (OpenFile(path, &fd_, &err))
113 path_ = path;
114 return -err;
115}
116
117bool DeltaPerformer::OpenKernel(const char* kernel_path) {
118 int err;
119 bool success = OpenFile(kernel_path, &kernel_fd_, &err);
120 if (success)
121 kernel_path_ = kernel_path;
122 return success;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700123}
124
125int DeltaPerformer::Close() {
126 if (!buffer_.empty()) {
127 LOG(ERROR) << "Called Close() while buffer not empty!";
128 return -1;
129 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700130 int err = 0;
131 if (close(kernel_fd_) == -1) {
132 err = errno;
133 PLOG(ERROR) << "Unable to close kernel fd:";
134 }
135 if (close(fd_) == -1) {
136 err = errno;
137 PLOG(ERROR) << "Unable to close rootfs fd:";
138 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700139 LOG_IF(ERROR, !hash_calculator_.Finalize()) << "Unable to finalize the hash.";
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700140 fd_ = -2; // Set so that isn't not valid AND calls to Open() will fail.
141 path_ = "";
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700142 return -err;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700143}
144
145// Wrapper around write. Returns bytes written on success or
146// -errno on error.
147// This function performs as many actions as it can, given the amount of
148// data received thus far.
Andrew de los Reyes0cca4212010-04-29 14:00:58 -0700149ssize_t DeltaPerformer::Write(const void* bytes, size_t count) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700150 const char* c_bytes = reinterpret_cast<const char*>(bytes);
151 buffer_.insert(buffer_.end(), c_bytes, c_bytes + count);
152
153 if (!manifest_valid_) {
154 // See if we have enough bytes for the manifest yet
155 if (buffer_.size() < strlen(kDeltaMagic) +
156 kDeltaVersionLength + kDeltaProtobufLengthLength) {
157 // Don't have enough bytes to even know the protobuf length
158 return count;
159 }
160 uint64_t protobuf_length;
161 COMPILE_ASSERT(sizeof(protobuf_length) == kDeltaProtobufLengthLength,
162 protobuf_length_size_mismatch);
163 memcpy(&protobuf_length,
164 &buffer_[strlen(kDeltaMagic) + kDeltaVersionLength],
165 kDeltaProtobufLengthLength);
166 protobuf_length = be64toh(protobuf_length); // switch big endian to host
167 if (buffer_.size() < strlen(kDeltaMagic) + kDeltaVersionLength +
168 kDeltaProtobufLengthLength + protobuf_length) {
169 return count;
170 }
171 // We have the full proto buffer in buffer_. Parse it.
172 const int offset = strlen(kDeltaMagic) + kDeltaVersionLength +
173 kDeltaProtobufLengthLength;
174 if (!manifest_.ParseFromArray(&buffer_[offset], protobuf_length)) {
175 LOG(ERROR) << "Unable to parse manifest in update file.";
176 return -EINVAL;
177 }
178 // Remove protobuf and header info from buffer_, so buffer_ contains
179 // just data blobs
Darin Petkovd7061ab2010-10-06 14:37:09 -0700180 DiscardBufferHeadBytes(strlen(kDeltaMagic) +
181 kDeltaVersionLength +
182 kDeltaProtobufLengthLength + protobuf_length,
183 true); // do_hash
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700184 manifest_valid_ = true;
185 block_size_ = manifest_.block_size();
186 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700187 ssize_t total_operations = manifest_.install_operations_size() +
188 manifest_.kernel_install_operations_size();
189 while (next_operation_num_ < total_operations) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700190 const DeltaArchiveManifest_InstallOperation &op =
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700191 next_operation_num_ < manifest_.install_operations_size() ?
192 manifest_.install_operations(next_operation_num_) :
193 manifest_.kernel_install_operations(
194 next_operation_num_ - manifest_.install_operations_size());
195 if (!CanPerformInstallOperation(op))
196 break;
Andrew de los Reyesbef0c7d2010-08-20 10:20:10 -0700197 // Log every thousandth operation, and also the first and last ones
198 if ((next_operation_num_ % 1000 == 0) ||
199 (next_operation_num_ + 1 == total_operations)) {
200 LOG(INFO) << "Performing operation " << (next_operation_num_ + 1) << "/"
201 << total_operations;
202 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700203 bool is_kernel_partition =
204 (next_operation_num_ >= manifest_.install_operations_size());
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700205 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
206 op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700207 if (!PerformReplaceOperation(op, is_kernel_partition)) {
208 LOG(ERROR) << "Failed to perform replace operation "
209 << next_operation_num_;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700210 return -EINVAL;
211 }
212 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700213 if (!PerformMoveOperation(op, is_kernel_partition)) {
214 LOG(ERROR) << "Failed to perform move operation "
215 << next_operation_num_;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700216 return -EINVAL;
217 }
218 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700219 if (!PerformBsdiffOperation(op, is_kernel_partition)) {
220 LOG(ERROR) << "Failed to perform bsdiff operation "
221 << next_operation_num_;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700222 return -EINVAL;
223 }
224 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700225 next_operation_num_++;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700226 }
227 return count;
228}
229
230bool DeltaPerformer::CanPerformInstallOperation(
231 const chromeos_update_engine::DeltaArchiveManifest_InstallOperation&
232 operation) {
233 // Move operations don't require any data blob, so they can always
234 // be performed
235 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE)
236 return true;
237
238 // See if we have the entire data blob in the buffer
239 if (operation.data_offset() < buffer_offset_) {
240 LOG(ERROR) << "we threw away data it seems?";
241 return false;
242 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700243
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700244 return (operation.data_offset() + operation.data_length()) <=
245 (buffer_offset_ + buffer_.size());
246}
247
248bool DeltaPerformer::PerformReplaceOperation(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700249 const DeltaArchiveManifest_InstallOperation& operation,
250 bool is_kernel_partition) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700251 CHECK(operation.type() == \
252 DeltaArchiveManifest_InstallOperation_Type_REPLACE || \
253 operation.type() == \
254 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
255
256 // Since we delete data off the beginning of the buffer as we use it,
257 // the data we need should be exactly at the beginning of the buffer.
258 CHECK_EQ(buffer_offset_, operation.data_offset());
259 CHECK_GE(buffer_.size(), operation.data_length());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700260
261 // Don't include the signature data blob in the hash.
262 bool do_hash = !ExtractSignatureMessage(operation);
263
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700264 DirectExtentWriter direct_writer;
265 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
266 scoped_ptr<BzipExtentWriter> bzip_writer;
Darin Petkovd7061ab2010-10-06 14:37:09 -0700267
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700268 // Since bzip decompression is optional, we have a variable writer that will
269 // point to one of the ExtentWriter objects above.
270 ExtentWriter* writer = NULL;
271 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
272 writer = &zero_pad_writer;
273 } else if (operation.type() ==
274 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
275 bzip_writer.reset(new BzipExtentWriter(&zero_pad_writer));
276 writer = bzip_writer.get();
277 } else {
278 NOTREACHED();
279 }
280
281 // Create a vector of extents to pass to the ExtentWriter.
282 vector<Extent> extents;
283 for (int i = 0; i < operation.dst_extents_size(); i++) {
284 extents.push_back(operation.dst_extents(i));
285 }
286
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700287 int fd = is_kernel_partition ? kernel_fd_ : fd_;
288
289 TEST_AND_RETURN_FALSE(writer->Init(fd, extents, block_size_));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700290 TEST_AND_RETURN_FALSE(writer->Write(&buffer_[0], operation.data_length()));
291 TEST_AND_RETURN_FALSE(writer->End());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700292
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700293 // Update buffer
294 buffer_offset_ += operation.data_length();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700295 DiscardBufferHeadBytes(operation.data_length(), do_hash);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700296 return true;
297}
298
299bool DeltaPerformer::PerformMoveOperation(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700300 const DeltaArchiveManifest_InstallOperation& operation,
301 bool is_kernel_partition) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700302 // Calculate buffer size. Note, this function doesn't do a sliding
303 // window to copy in case the source and destination blocks overlap.
304 // If we wanted to do a sliding window, we could program the server
305 // to generate deltas that effectively did a sliding window.
306
307 uint64_t blocks_to_read = 0;
308 for (int i = 0; i < operation.src_extents_size(); i++)
309 blocks_to_read += operation.src_extents(i).num_blocks();
310
311 uint64_t blocks_to_write = 0;
312 for (int i = 0; i < operation.dst_extents_size(); i++)
313 blocks_to_write += operation.dst_extents(i).num_blocks();
314
315 DCHECK_EQ(blocks_to_write, blocks_to_read);
316 vector<char> buf(blocks_to_write * block_size_);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700317
318 int fd = is_kernel_partition ? kernel_fd_ : fd_;
319
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700320 // Read in bytes.
321 ssize_t bytes_read = 0;
322 for (int i = 0; i < operation.src_extents_size(); i++) {
323 ssize_t bytes_read_this_iteration = 0;
324 const Extent& extent = operation.src_extents(i);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700325 TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700326 &buf[bytes_read],
327 extent.num_blocks() * block_size_,
328 extent.start_block() * block_size_,
329 &bytes_read_this_iteration));
330 TEST_AND_RETURN_FALSE(
331 bytes_read_this_iteration ==
332 static_cast<ssize_t>(extent.num_blocks() * block_size_));
333 bytes_read += bytes_read_this_iteration;
334 }
335
336 // Write bytes out.
337 ssize_t bytes_written = 0;
338 for (int i = 0; i < operation.dst_extents_size(); i++) {
339 const Extent& extent = operation.dst_extents(i);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700340 TEST_AND_RETURN_FALSE(utils::PWriteAll(fd,
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700341 &buf[bytes_written],
342 extent.num_blocks() * block_size_,
343 extent.start_block() * block_size_));
344 bytes_written += extent.num_blocks() * block_size_;
345 }
346 DCHECK_EQ(bytes_written, bytes_read);
347 DCHECK_EQ(bytes_written, static_cast<ssize_t>(buf.size()));
348 return true;
349}
350
351bool DeltaPerformer::ExtentsToBsdiffPositionsString(
352 const RepeatedPtrField<Extent>& extents,
353 uint64_t block_size,
354 uint64_t full_length,
355 string* positions_string) {
356 string ret;
357 uint64_t length = 0;
358 for (int i = 0; i < extents.size(); i++) {
359 Extent extent = extents.Get(i);
360 int64_t start = extent.start_block();
361 uint64_t this_length = min(full_length - length,
362 extent.num_blocks() * block_size);
363 if (start == static_cast<int64_t>(kSparseHole))
364 start = -1;
365 else
366 start *= block_size;
367 ret += StringPrintf("%" PRIi64 ":%" PRIu64 ",", start, this_length);
368 length += this_length;
369 }
370 TEST_AND_RETURN_FALSE(length == full_length);
371 if (!ret.empty())
372 ret.resize(ret.size() - 1); // Strip trailing comma off
373 *positions_string = ret;
374 return true;
375}
376
377bool DeltaPerformer::PerformBsdiffOperation(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700378 const DeltaArchiveManifest_InstallOperation& operation,
379 bool is_kernel_partition) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700380 // Since we delete data off the beginning of the buffer as we use it,
381 // the data we need should be exactly at the beginning of the buffer.
382 CHECK_EQ(buffer_offset_, operation.data_offset());
383 CHECK_GE(buffer_.size(), operation.data_length());
384
385 string input_positions;
386 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.src_extents(),
387 block_size_,
388 operation.src_length(),
389 &input_positions));
390 string output_positions;
391 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.dst_extents(),
392 block_size_,
393 operation.dst_length(),
394 &output_positions));
395
396 string temp_filename;
397 TEST_AND_RETURN_FALSE(utils::MakeTempFile("/tmp/au_patch.XXXXXX",
398 &temp_filename,
399 NULL));
400 ScopedPathUnlinker path_unlinker(temp_filename);
401 {
402 int fd = open(temp_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
403 ScopedFdCloser fd_closer(&fd);
404 TEST_AND_RETURN_FALSE(
405 utils::WriteAll(fd, &buffer_[0], operation.data_length()));
406 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700407
408 int fd = is_kernel_partition ? kernel_fd_ : fd_;
409 const string& path = is_kernel_partition ? kernel_path_ : path_;
410
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700411 vector<string> cmd;
412 cmd.push_back(kBspatchPath);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700413 cmd.push_back(path);
414 cmd.push_back(path);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700415 cmd.push_back(temp_filename);
416 cmd.push_back(input_positions);
417 cmd.push_back(output_positions);
418 int return_code = 0;
419 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code));
420 TEST_AND_RETURN_FALSE(return_code == 0);
421
422 if (operation.dst_length() % block_size_) {
423 // Zero out rest of final block.
424 // TODO(adlr): build this into bspatch; it's more efficient that way.
425 const Extent& last_extent =
426 operation.dst_extents(operation.dst_extents_size() - 1);
427 const uint64_t end_byte =
428 (last_extent.start_block() + last_extent.num_blocks()) * block_size_;
429 const uint64_t begin_byte =
430 end_byte - (block_size_ - operation.dst_length() % block_size_);
431 vector<char> zeros(end_byte - begin_byte);
432 TEST_AND_RETURN_FALSE(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700433 utils::PWriteAll(fd, &zeros[0], end_byte - begin_byte, begin_byte));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700434 }
435
436 // Update buffer.
437 buffer_offset_ += operation.data_length();
Darin Petkovd7061ab2010-10-06 14:37:09 -0700438 DiscardBufferHeadBytes(operation.data_length(),
439 true); // do_hash
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700440 return true;
441}
442
Darin Petkovd7061ab2010-10-06 14:37:09 -0700443bool DeltaPerformer::ExtractSignatureMessage(
444 const DeltaArchiveManifest_InstallOperation& operation) {
445 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
446 !manifest_.has_signatures_offset() ||
447 manifest_.signatures_offset() != operation.data_offset()) {
448 return false;
449 }
450 TEST_AND_RETURN_FALSE(manifest_.has_signatures_size() &&
451 manifest_.signatures_size() == operation.data_length());
452 TEST_AND_RETURN_FALSE(signatures_message_data_.empty());
453 TEST_AND_RETURN_FALSE(buffer_offset_ == manifest_.signatures_offset());
454 TEST_AND_RETURN_FALSE(buffer_.size() >= manifest_.signatures_size());
455 signatures_message_data_.insert(
456 signatures_message_data_.begin(),
457 buffer_.begin(),
458 buffer_.begin() + manifest_.signatures_size());
459 LOG(INFO) << "Extracted signature data of size "
460 << manifest_.signatures_size() << " at "
461 << manifest_.signatures_offset();
462 return true;
463}
464
465bool DeltaPerformer::VerifyPayload(const string& public_key_path) {
466 string key_path = public_key_path;
467 if (key_path.empty()) {
468 key_path = kUpdatePayloadPublicKeyPath;
469 }
470 LOG(INFO) << "Verifying delta payload. Public key path: " << key_path;
471 if (!utils::FileExists(key_path.c_str())) {
472 LOG(WARNING) << "Not verifying delta payload due to missing public key.";
473 return true;
474 }
475 TEST_AND_RETURN_FALSE(!signatures_message_data_.empty());
476 vector<char> signed_hash_data;
477 TEST_AND_RETURN_FALSE(PayloadSigner::VerifySignature(signatures_message_data_,
478 key_path,
479 &signed_hash_data));
480 const vector<char>& hash_data = hash_calculator_.raw_hash();
481 TEST_AND_RETURN_FALSE(!hash_data.empty());
482 return hash_data == signed_hash_data;
483}
484
485void DeltaPerformer::DiscardBufferHeadBytes(size_t count, bool do_hash) {
486 if (do_hash) {
487 hash_calculator_.Update(&buffer_[0], count);
488 }
489 buffer_.erase(buffer_.begin(), buffer_.begin() + count);
490}
491
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700492} // namespace chromeos_update_engine