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# 16 17"""Utilities for update payload processing.""" 18 19from __future__ import absolute_import 20from __future__ import print_function 21 22import base64 23 24from update_payload import update_metadata_pb2 25from update_payload.error import PayloadError 26 27 28# 29# Constants. 30# 31SIG_ASN1_HEADER = ( 32 b'\x30\x31\x30\x0d\x06\x09\x60\x86' 33 b'\x48\x01\x65\x03\x04\x02\x01\x05' 34 b'\x00\x04\x20' 35) 36 37BRILLO_MAJOR_PAYLOAD_VERSION = 2 38 39SOURCE_MINOR_PAYLOAD_VERSION = 2 40OPSRCHASH_MINOR_PAYLOAD_VERSION = 3 41BROTLI_BSDIFF_MINOR_PAYLOAD_VERSION = 4 42PUFFDIFF_MINOR_PAYLOAD_VERSION = 5 43 44KERNEL = 'kernel' 45ROOTFS = 'root' 46# Tuple of (name in system, name in protobuf). 47CROS_PARTITIONS = ((KERNEL, KERNEL), (ROOTFS, 'rootfs')) 48 49 50# 51# Payload operation types. 52# 53class OpType(object): 54 """Container for operation type constants.""" 55 _CLASS = update_metadata_pb2.InstallOperation 56 REPLACE = _CLASS.REPLACE 57 REPLACE_BZ = _CLASS.REPLACE_BZ 58 SOURCE_COPY = _CLASS.SOURCE_COPY 59 SOURCE_BSDIFF = _CLASS.SOURCE_BSDIFF 60 ZERO = _CLASS.ZERO 61 DISCARD = _CLASS.DISCARD 62 REPLACE_XZ = _CLASS.REPLACE_XZ 63 PUFFDIFF = _CLASS.PUFFDIFF 64 BROTLI_BSDIFF = _CLASS.BROTLI_BSDIFF 65 ALL = (REPLACE, REPLACE_BZ, SOURCE_COPY, SOURCE_BSDIFF, ZERO, 66 DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF) 67 NAMES = { 68 REPLACE: 'REPLACE', 69 REPLACE_BZ: 'REPLACE_BZ', 70 SOURCE_COPY: 'SOURCE_COPY', 71 SOURCE_BSDIFF: 'SOURCE_BSDIFF', 72 ZERO: 'ZERO', 73 DISCARD: 'DISCARD', 74 REPLACE_XZ: 'REPLACE_XZ', 75 PUFFDIFF: 'PUFFDIFF', 76 BROTLI_BSDIFF: 'BROTLI_BSDIFF', 77 } 78 79 def __init__(self): 80 pass 81 82 83# 84# Checked and hashed reading of data. 85# 86def IntPackingFmtStr(size, is_unsigned): 87 """Returns an integer format string for use by the struct module. 88 89 Args: 90 size: the integer size in bytes (2, 4 or 8) 91 is_unsigned: whether it is signed or not 92 93 Returns: 94 A format string for packing/unpacking integer values; assumes network byte 95 order (big-endian). 96 97 Raises: 98 PayloadError if something is wrong with the arguments. 99 """ 100 # Determine the base conversion format. 101 if size == 2: 102 fmt = 'h' 103 elif size == 4: 104 fmt = 'i' 105 elif size == 8: 106 fmt = 'q' 107 else: 108 raise PayloadError('unsupport numeric field size (%s)' % size) 109 110 # Signed or unsigned? 111 if is_unsigned: 112 fmt = fmt.upper() 113 114 # Make it network byte order (big-endian). 115 fmt = '!' + fmt 116 117 return fmt 118 119 120def Read(file_obj, length, offset=None, hasher=None): 121 """Reads binary data from a file. 122 123 Args: 124 file_obj: an open file object 125 length: the length of the data to read 126 offset: an offset to seek to prior to reading; this is an absolute offset 127 from either the beginning (non-negative) or end (negative) of the 128 file. (optional) 129 hasher: a hashing object to pass the read data through (optional) 130 131 Returns: 132 A string containing the read data. 133 134 Raises: 135 PayloadError if a read error occurred or not enough data was read. 136 """ 137 if offset is not None: 138 if offset >= 0: 139 file_obj.seek(offset) 140 else: 141 file_obj.seek(offset, 2) 142 143 try: 144 data = file_obj.read(length) 145 except IOError as e: 146 raise PayloadError('error reading from file (%s): %s' % (file_obj.name, e)) 147 148 if len(data) != length: 149 raise PayloadError( 150 'reading from file (%s) too short (%d instead of %d bytes)' % 151 (file_obj.name, len(data), length)) 152 153 if hasher: 154 hasher.update(data) 155 156 return data 157 158 159# 160# Formatting functions. 161# 162def FormatExtent(ex, block_size=0): 163 end_block = ex.start_block + ex.num_blocks 164 if block_size: 165 return '%d->%d * %d' % (ex.start_block, end_block, block_size) 166 return '%d->%d' % (ex.start_block, end_block) 167 168 169def FormatSha256(digest): 170 """Returns a canonical string representation of a SHA256 digest.""" 171 return base64.b64encode(digest).decode('utf-8') 172 173 174# 175# Useful iterators. 176# 177def _ObjNameIter(items, base_name, reverse=False, name_format_func=None): 178 """A generic (item, name) tuple iterators. 179 180 Args: 181 items: the sequence of objects to iterate on 182 base_name: the base name for all objects 183 reverse: whether iteration should be in reverse order 184 name_format_func: a function to apply to the name string 185 186 Yields: 187 An iterator whose i-th invocation returns (items[i], name), where name == 188 base_name + '[i]' (with a formatting function optionally applied to it). 189 """ 190 idx, inc = (len(items), -1) if reverse else (1, 1) 191 if reverse: 192 items = reversed(items) 193 for item in items: 194 item_name = '%s[%d]' % (base_name, idx) 195 if name_format_func: 196 item_name = name_format_func(item, item_name) 197 yield (item, item_name) 198 idx += inc 199 200 201def _OperationNameFormatter(op, op_name): 202 return '%s(%s)' % (op_name, OpType.NAMES.get(op.type, '?')) 203 204 205def OperationIter(operations, base_name, reverse=False): 206 """An (item, name) iterator for update operations.""" 207 return _ObjNameIter(operations, base_name, reverse=reverse, 208 name_format_func=_OperationNameFormatter) 209 210 211def ExtentIter(extents, base_name, reverse=False): 212 """An (item, name) iterator for operation extents.""" 213 return _ObjNameIter(extents, base_name, reverse=reverse) 214 215 216def SignatureIter(sigs, base_name, reverse=False): 217 """An (item, name) iterator for signatures.""" 218 return _ObjNameIter(sigs, base_name, reverse=reverse) 219