| Amin Hassani | f94b643 | 2018-01-26 17:39:47 -0800 | [diff] [blame] | 1 | # | 
|  | 2 | # Copyright (C) 2013 The Android Open Source Project | 
|  | 3 | # | 
|  | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | # you may not use this file except in compliance with the License. | 
|  | 6 | # You may obtain a copy of the License at | 
|  | 7 | # | 
|  | 8 | #      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | # | 
|  | 10 | # Unless required by applicable law or agreed to in writing, software | 
|  | 11 | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | # See the License for the specific language governing permissions and | 
|  | 14 | # limitations under the License. | 
|  | 15 | # | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 16 |  | 
|  | 17 | """Tools for reading, verifying and applying Chrome OS update payloads.""" | 
|  | 18 |  | 
| Andrew Lassalle | 165843c | 2019-11-05 13:30:34 -0800 | [diff] [blame] | 19 | from __future__ import absolute_import | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 20 | from __future__ import print_function | 
|  | 21 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 22 | import hashlib | 
| Kelvin Zhang | 9e7a6db | 2020-08-13 14:55:58 -0400 | [diff] [blame] | 23 | import io | 
| Kelvin Zhang | 7977564 | 2021-02-19 16:05:08 -0500 | [diff] [blame] | 24 | import mmap | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 25 | import struct | 
| Kelvin Zhang | 9e7a6db | 2020-08-13 14:55:58 -0400 | [diff] [blame] | 26 | import zipfile | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 27 |  | 
| Sen Jiang | c2527f4 | 2017-09-27 16:35:03 -0700 | [diff] [blame] | 28 | from update_payload import applier | 
| Sen Jiang | c2527f4 | 2017-09-27 16:35:03 -0700 | [diff] [blame] | 29 | from update_payload import checker | 
|  | 30 | from update_payload import common | 
| Sen Jiang | c2527f4 | 2017-09-27 16:35:03 -0700 | [diff] [blame] | 31 | from update_payload import update_metadata_pb2 | 
| Amin Hassani | b05a65a | 2017-12-18 15:15:32 -0800 | [diff] [blame] | 32 | from update_payload.error import PayloadError | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 33 |  | 
|  | 34 |  | 
|  | 35 | # | 
|  | 36 | # Helper functions. | 
|  | 37 | # | 
|  | 38 | def _ReadInt(file_obj, size, is_unsigned, hasher=None): | 
| Gilad Arnold | 5502b56 | 2013-03-08 13:22:31 -0800 | [diff] [blame] | 39 | """Reads a binary-encoded integer from a file. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 40 |  | 
|  | 41 | It will do the correct conversion based on the reported size and whether or | 
|  | 42 | not a signed number is expected. Assumes a network (big-endian) byte | 
|  | 43 | ordering. | 
|  | 44 |  | 
|  | 45 | Args: | 
|  | 46 | file_obj: a file object | 
|  | 47 | size: the integer size in bytes (2, 4 or 8) | 
|  | 48 | is_unsigned: whether it is signed or not | 
|  | 49 | hasher: an optional hasher to pass the value through | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 50 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 51 | Returns: | 
|  | 52 | An "unpacked" (Python) integer value. | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 53 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 54 | Raises: | 
|  | 55 | PayloadError if an read error occurred. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 56 | """ | 
| Gilad Arnold | 5502b56 | 2013-03-08 13:22:31 -0800 | [diff] [blame] | 57 | return struct.unpack(common.IntPackingFmtStr(size, is_unsigned), | 
|  | 58 | common.Read(file_obj, size, hasher=hasher))[0] | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 59 |  | 
|  | 60 |  | 
|  | 61 | # | 
|  | 62 | # Update payload. | 
|  | 63 | # | 
|  | 64 | class Payload(object): | 
|  | 65 | """Chrome OS update payload processor.""" | 
|  | 66 |  | 
|  | 67 | class _PayloadHeader(object): | 
|  | 68 | """Update payload header struct.""" | 
|  | 69 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 70 | # Header constants; sizes are in bytes. | 
| Andrew Lassalle | 165843c | 2019-11-05 13:30:34 -0800 | [diff] [blame] | 71 | _MAGIC = b'CrAU' | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 72 | _VERSION_SIZE = 8 | 
|  | 73 | _MANIFEST_LEN_SIZE = 8 | 
|  | 74 | _METADATA_SIGNATURE_LEN_SIZE = 4 | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 75 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 76 | def __init__(self): | 
|  | 77 | self.version = None | 
|  | 78 | self.manifest_len = None | 
|  | 79 | self.metadata_signature_len = None | 
|  | 80 | self.size = None | 
|  | 81 |  | 
|  | 82 | def ReadFromPayload(self, payload_file, hasher=None): | 
|  | 83 | """Reads the payload header from a file. | 
|  | 84 |  | 
|  | 85 | Reads the payload header from the |payload_file| and updates the |hasher| | 
|  | 86 | if one is passed. The parsed header is stored in the _PayloadHeader | 
|  | 87 | instance attributes. | 
|  | 88 |  | 
|  | 89 | Args: | 
|  | 90 | payload_file: a file object | 
|  | 91 | hasher: an optional hasher to pass the value through | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 92 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 93 | Returns: | 
|  | 94 | None. | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 95 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 96 | Raises: | 
|  | 97 | PayloadError if a read error occurred or the header is invalid. | 
|  | 98 | """ | 
|  | 99 | # Verify magic | 
|  | 100 | magic = common.Read(payload_file, len(self._MAGIC), hasher=hasher) | 
|  | 101 | if magic != self._MAGIC: | 
|  | 102 | raise PayloadError('invalid payload magic: %s' % magic) | 
|  | 103 |  | 
|  | 104 | self.version = _ReadInt(payload_file, self._VERSION_SIZE, True, | 
|  | 105 | hasher=hasher) | 
|  | 106 | self.manifest_len = _ReadInt(payload_file, self._MANIFEST_LEN_SIZE, True, | 
|  | 107 | hasher=hasher) | 
|  | 108 | self.size = (len(self._MAGIC) + self._VERSION_SIZE + | 
|  | 109 | self._MANIFEST_LEN_SIZE) | 
|  | 110 | self.metadata_signature_len = 0 | 
|  | 111 |  | 
|  | 112 | if self.version == common.BRILLO_MAJOR_PAYLOAD_VERSION: | 
|  | 113 | self.size += self._METADATA_SIGNATURE_LEN_SIZE | 
|  | 114 | self.metadata_signature_len = _ReadInt( | 
|  | 115 | payload_file, self._METADATA_SIGNATURE_LEN_SIZE, True, | 
|  | 116 | hasher=hasher) | 
|  | 117 |  | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 118 | def __init__(self, payload_file, payload_file_offset=0): | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 119 | """Initialize the payload object. | 
|  | 120 |  | 
|  | 121 | Args: | 
|  | 122 | payload_file: update payload file object open for reading | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 123 | payload_file_offset: the offset of the actual payload | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 124 | """ | 
| Kelvin Zhang | 9e7a6db | 2020-08-13 14:55:58 -0400 | [diff] [blame] | 125 | if zipfile.is_zipfile(payload_file): | 
|  | 126 | with zipfile.ZipFile(payload_file) as zfp: | 
| Kelvin Zhang | 7977564 | 2021-02-19 16:05:08 -0500 | [diff] [blame] | 127 | self.payload_file = zfp.open("payload.bin", "r") | 
| Kelvin Zhang | 576efc5 | 2020-12-01 12:06:40 -0500 | [diff] [blame] | 128 | elif isinstance(payload_file, str): | 
| Kelvin Zhang | 7977564 | 2021-02-19 16:05:08 -0500 | [diff] [blame] | 129 | payload_fp = open(payload_file, "rb") | 
| Kelvin Zhang | faddb7e | 2021-06-23 15:53:48 -0400 | [diff] [blame] | 130 | payload_bytes = mmap.mmap( | 
|  | 131 | payload_fp.fileno(), 0, access=mmap.ACCESS_READ) | 
| Kelvin Zhang | 7977564 | 2021-02-19 16:05:08 -0500 | [diff] [blame] | 132 | self.payload_file = io.BytesIO(payload_bytes) | 
| Kelvin Zhang | 576efc5 | 2020-12-01 12:06:40 -0500 | [diff] [blame] | 133 | else: | 
|  | 134 | self.payload_file = payload_file | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 135 | self.payload_file_offset = payload_file_offset | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 136 | self.manifest_hasher = None | 
|  | 137 | self.is_init = False | 
|  | 138 | self.header = None | 
|  | 139 | self.manifest = None | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 140 | self.data_offset = None | 
|  | 141 | self.metadata_signature = None | 
| Kelvin Zhang | faddb7e | 2021-06-23 15:53:48 -0400 | [diff] [blame] | 142 | self.payload_signature = None | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 143 | self.metadata_size = None | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 144 |  | 
| Kelvin Zhang | 8c85655 | 2021-09-07 21:15:49 -0700 | [diff] [blame] | 145 | @property | 
|  | 146 | def is_incremental(self): | 
|  | 147 | return any([part.HasField("old_partition_info") for part in self.manifest.partitions]) | 
|  | 148 |  | 
|  | 149 | @property | 
|  | 150 | def is_partial(self): | 
|  | 151 | return self.manifest.partial_update | 
|  | 152 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 153 | def _ReadHeader(self): | 
|  | 154 | """Reads and returns the payload header. | 
|  | 155 |  | 
|  | 156 | Returns: | 
|  | 157 | A payload header object. | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 158 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 159 | Raises: | 
|  | 160 | PayloadError if a read error occurred. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 161 | """ | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 162 | header = self._PayloadHeader() | 
|  | 163 | header.ReadFromPayload(self.payload_file, self.manifest_hasher) | 
|  | 164 | return header | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 165 |  | 
|  | 166 | def _ReadManifest(self): | 
|  | 167 | """Reads and returns the payload manifest. | 
|  | 168 |  | 
|  | 169 | Returns: | 
|  | 170 | A string containing the payload manifest in binary form. | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 171 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 172 | Raises: | 
|  | 173 | PayloadError if a read error occurred. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 174 | """ | 
|  | 175 | if not self.header: | 
|  | 176 | raise PayloadError('payload header not present') | 
|  | 177 |  | 
|  | 178 | return common.Read(self.payload_file, self.header.manifest_len, | 
|  | 179 | hasher=self.manifest_hasher) | 
|  | 180 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 181 | def _ReadMetadataSignature(self): | 
|  | 182 | """Reads and returns the metadata signatures. | 
|  | 183 |  | 
|  | 184 | Returns: | 
|  | 185 | A string containing the metadata signatures protobuf in binary form or | 
|  | 186 | an empty string if no metadata signature found in the payload. | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 187 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 188 | Raises: | 
|  | 189 | PayloadError if a read error occurred. | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 190 | """ | 
|  | 191 | if not self.header: | 
|  | 192 | raise PayloadError('payload header not present') | 
|  | 193 |  | 
|  | 194 | return common.Read( | 
|  | 195 | self.payload_file, self.header.metadata_signature_len, | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 196 | offset=self.payload_file_offset + self.header.size + | 
|  | 197 | self.header.manifest_len) | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 198 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 199 | def ReadDataBlob(self, offset, length): | 
|  | 200 | """Reads and returns a single data blob from the update payload. | 
|  | 201 |  | 
|  | 202 | Args: | 
|  | 203 | offset: offset to the beginning of the blob from the end of the manifest | 
|  | 204 | length: the blob's length | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 205 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 206 | Returns: | 
|  | 207 | A string containing the raw blob data. | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 208 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 209 | Raises: | 
|  | 210 | PayloadError if a read error occurred. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 211 | """ | 
|  | 212 | return common.Read(self.payload_file, length, | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 213 | offset=self.payload_file_offset + self.data_offset + | 
|  | 214 | offset) | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 215 |  | 
|  | 216 | def Init(self): | 
|  | 217 | """Initializes the payload object. | 
|  | 218 |  | 
|  | 219 | This is a prerequisite for any other public API call. | 
|  | 220 |  | 
|  | 221 | Raises: | 
|  | 222 | PayloadError if object already initialized or fails to initialize | 
|  | 223 | correctly. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 224 | """ | 
|  | 225 | if self.is_init: | 
|  | 226 | raise PayloadError('payload object already initialized') | 
|  | 227 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 228 | self.manifest_hasher = hashlib.sha256() | 
|  | 229 |  | 
|  | 230 | # Read the file header. | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 231 | self.payload_file.seek(self.payload_file_offset) | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 232 | self.header = self._ReadHeader() | 
|  | 233 |  | 
|  | 234 | # Read the manifest. | 
|  | 235 | manifest_raw = self._ReadManifest() | 
|  | 236 | self.manifest = update_metadata_pb2.DeltaArchiveManifest() | 
|  | 237 | self.manifest.ParseFromString(manifest_raw) | 
|  | 238 |  | 
| Alex Deymo | ef49735 | 2015-10-15 09:14:58 -0700 | [diff] [blame] | 239 | # Read the metadata signature (if any). | 
|  | 240 | metadata_signature_raw = self._ReadMetadataSignature() | 
|  | 241 | if metadata_signature_raw: | 
|  | 242 | self.metadata_signature = update_metadata_pb2.Signatures() | 
|  | 243 | self.metadata_signature.ParseFromString(metadata_signature_raw) | 
|  | 244 |  | 
|  | 245 | self.metadata_size = self.header.size + self.header.manifest_len | 
|  | 246 | self.data_offset = self.metadata_size + self.header.metadata_signature_len | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 247 |  | 
| Kelvin Zhang | faddb7e | 2021-06-23 15:53:48 -0400 | [diff] [blame] | 248 | if self.manifest.signatures_offset and self.manifest.signatures_size: | 
|  | 249 | payload_signature_blob = self.ReadDataBlob( | 
|  | 250 | self.manifest.signatures_offset, self.manifest.signatures_size) | 
|  | 251 | payload_signature = update_metadata_pb2.Signatures() | 
|  | 252 | payload_signature.ParseFromString(payload_signature_blob) | 
|  | 253 | self.payload_signature = payload_signature | 
|  | 254 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 255 | self.is_init = True | 
|  | 256 |  | 
|  | 257 | def _AssertInit(self): | 
|  | 258 | """Raises an exception if the object was not initialized.""" | 
|  | 259 | if not self.is_init: | 
|  | 260 | raise PayloadError('payload object not initialized') | 
|  | 261 |  | 
|  | 262 | def ResetFile(self): | 
|  | 263 | """Resets the offset of the payload file to right past the manifest.""" | 
| Sen Jiang | 3b15b59 | 2017-09-26 18:21:04 -0700 | [diff] [blame] | 264 | self.payload_file.seek(self.payload_file_offset + self.data_offset) | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 265 |  | 
|  | 266 | def IsDelta(self): | 
|  | 267 | """Returns True iff the payload appears to be a delta.""" | 
|  | 268 | self._AssertInit() | 
| Amin Hassani | 55c7541 | 2019-10-07 11:20:39 -0700 | [diff] [blame] | 269 | return (any(partition.HasField('old_partition_info') | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 270 | for partition in self.manifest.partitions)) | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 271 |  | 
|  | 272 | def IsFull(self): | 
|  | 273 | """Returns True iff the payload appears to be a full.""" | 
|  | 274 | return not self.IsDelta() | 
|  | 275 |  | 
|  | 276 | def Check(self, pubkey_file_name=None, metadata_sig_file=None, | 
| Amin Hassani | a86b108 | 2018-03-08 15:48:59 -0800 | [diff] [blame] | 277 | metadata_size=0, report_out_file=None, assert_type=None, | 
| Tudor Brindus | 2d22c1a | 2018-06-15 13:07:13 -0700 | [diff] [blame] | 278 | block_size=0, part_sizes=None, allow_unhashed=False, | 
|  | 279 | disabled_tests=()): | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 280 | """Checks the payload integrity. | 
|  | 281 |  | 
|  | 282 | Args: | 
|  | 283 | pubkey_file_name: public key used for signature verification | 
|  | 284 | metadata_sig_file: metadata signature, if verification is desired | 
| Amin Hassani | a86b108 | 2018-03-08 15:48:59 -0800 | [diff] [blame] | 285 | metadata_size: metadata size, if verification is desired | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 286 | report_out_file: file object to dump the report to | 
|  | 287 | assert_type: assert that payload is either 'full' or 'delta' | 
|  | 288 | block_size: expected filesystem / payload block size | 
| Tudor Brindus | 2d22c1a | 2018-06-15 13:07:13 -0700 | [diff] [blame] | 289 | part_sizes: map of partition label to (physical) size in bytes | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 290 | allow_unhashed: allow unhashed operation blobs | 
| Gilad Arnold | eaed0d1 | 2013-04-30 15:38:22 -0700 | [diff] [blame] | 291 | disabled_tests: list of tests to disable | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 292 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 293 | Raises: | 
|  | 294 | PayloadError if payload verification failed. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 295 | """ | 
|  | 296 | self._AssertInit() | 
|  | 297 |  | 
|  | 298 | # Create a short-lived payload checker object and run it. | 
| Gilad Arnold | eaed0d1 | 2013-04-30 15:38:22 -0700 | [diff] [blame] | 299 | helper = checker.PayloadChecker( | 
|  | 300 | self, assert_type=assert_type, block_size=block_size, | 
|  | 301 | allow_unhashed=allow_unhashed, disabled_tests=disabled_tests) | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 302 | helper.Run(pubkey_file_name=pubkey_file_name, | 
|  | 303 | metadata_sig_file=metadata_sig_file, | 
| Amin Hassani | a86b108 | 2018-03-08 15:48:59 -0800 | [diff] [blame] | 304 | metadata_size=metadata_size, | 
| Tudor Brindus | 2d22c1a | 2018-06-15 13:07:13 -0700 | [diff] [blame] | 305 | part_sizes=part_sizes, | 
| Gilad Arnold | eaed0d1 | 2013-04-30 15:38:22 -0700 | [diff] [blame] | 306 | report_out_file=report_out_file) | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 307 |  | 
| Tudor Brindus | 2d22c1a | 2018-06-15 13:07:13 -0700 | [diff] [blame] | 308 | def Apply(self, new_parts, old_parts=None, bsdiff_in_place=True, | 
|  | 309 | bspatch_path=None, puffpatch_path=None, | 
|  | 310 | truncate_to_expected_size=True): | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 311 | """Applies the update payload. | 
|  | 312 |  | 
|  | 313 | Args: | 
| Tudor Brindus | 2d22c1a | 2018-06-15 13:07:13 -0700 | [diff] [blame] | 314 | new_parts: map of partition name to dest partition file | 
|  | 315 | old_parts: map of partition name to partition file (optional) | 
| Gilad Arnold | 272a499 | 2013-05-08 13:12:53 -0700 | [diff] [blame] | 316 | bsdiff_in_place: whether to perform BSDIFF operations in-place (optional) | 
| Gilad Arnold | 21a0250 | 2013-08-22 16:59:48 -0700 | [diff] [blame] | 317 | bspatch_path: path to the bspatch binary (optional) | 
| Amin Hassani | 6be7168 | 2017-12-01 10:46:45 -0800 | [diff] [blame] | 318 | puffpatch_path: path to the puffpatch binary (optional) | 
| Gilad Arnold | e5fdf18 | 2013-05-23 16:13:38 -0700 | [diff] [blame] | 319 | truncate_to_expected_size: whether to truncate the resulting partitions | 
|  | 320 | to their expected sizes, as specified in the | 
|  | 321 | payload (optional) | 
| Sen Jiang | 349fd29 | 2015-11-16 17:28:09 -0800 | [diff] [blame] | 322 |  | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 323 | Raises: | 
|  | 324 | PayloadError if payload application failed. | 
| Gilad Arnold | 553b0ec | 2013-01-26 01:00:39 -0800 | [diff] [blame] | 325 | """ | 
|  | 326 | self._AssertInit() | 
|  | 327 |  | 
|  | 328 | # Create a short-lived payload applier object and run it. | 
| Gilad Arnold | e5fdf18 | 2013-05-23 16:13:38 -0700 | [diff] [blame] | 329 | helper = applier.PayloadApplier( | 
| Gilad Arnold | 21a0250 | 2013-08-22 16:59:48 -0700 | [diff] [blame] | 330 | self, bsdiff_in_place=bsdiff_in_place, bspatch_path=bspatch_path, | 
| Amin Hassani | 6be7168 | 2017-12-01 10:46:45 -0800 | [diff] [blame] | 331 | puffpatch_path=puffpatch_path, | 
| Gilad Arnold | e5fdf18 | 2013-05-23 16:13:38 -0700 | [diff] [blame] | 332 | truncate_to_expected_size=truncate_to_expected_size) | 
| Tudor Brindus | 2d22c1a | 2018-06-15 13:07:13 -0700 | [diff] [blame] | 333 | helper.Run(new_parts, old_parts=old_parts) |