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 24import 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 ZUCCHINI = _CLASS.ZUCCHINI 66 ALL = (REPLACE, REPLACE_BZ, SOURCE_COPY, SOURCE_BSDIFF, ZERO, 67 DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF, ZUCCHINI) 68 NAMES = { 69 REPLACE: 'REPLACE', 70 REPLACE_BZ: 'REPLACE_BZ', 71 SOURCE_COPY: 'SOURCE_COPY', 72 SOURCE_BSDIFF: 'SOURCE_BSDIFF', 73 ZERO: 'ZERO', 74 DISCARD: 'DISCARD', 75 REPLACE_XZ: 'REPLACE_XZ', 76 PUFFDIFF: 'PUFFDIFF', 77 BROTLI_BSDIFF: 'BROTLI_BSDIFF', 78 ZUCCHINI: 'ZUCCHINI', 79 } 80 81 def __init__(self): 82 pass 83 84 85# 86# Checked and hashed reading of data. 87# 88def IntPackingFmtStr(size, is_unsigned): 89 """Returns an integer format string for use by the struct module. 90 91 Args: 92 size: the integer size in bytes (2, 4 or 8) 93 is_unsigned: whether it is signed or not 94 95 Returns: 96 A format string for packing/unpacking integer values; assumes network byte 97 order (big-endian). 98 99 Raises: 100 PayloadError if something is wrong with the arguments. 101 """ 102 # Determine the base conversion format. 103 if size == 2: 104 fmt = 'h' 105 elif size == 4: 106 fmt = 'i' 107 elif size == 8: 108 fmt = 'q' 109 else: 110 raise PayloadError('unsupport numeric field size (%s)' % size) 111 112 # Signed or unsigned? 113 if is_unsigned: 114 fmt = fmt.upper() 115 116 # Make it network byte order (big-endian). 117 fmt = '!' + fmt 118 119 return fmt 120 121 122def Read(file_obj, length, offset=None, hasher=None): 123 """Reads binary data from a file. 124 125 Args: 126 file_obj: an open file object 127 length: the length of the data to read 128 offset: an offset to seek to prior to reading; this is an absolute offset 129 from either the beginning (non-negative) or end (negative) of the 130 file. (optional) 131 hasher: a hashing object to pass the read data through (optional) 132 133 Returns: 134 A string containing the read data. 135 136 Raises: 137 PayloadError if a read error occurred or not enough data was read. 138 """ 139 if offset is not None: 140 if offset >= 0: 141 file_obj.seek(offset) 142 else: 143 file_obj.seek(offset, 2) 144 145 try: 146 data = file_obj.read(length) 147 except IOError as e: 148 raise PayloadError('error reading from file (%s): %s' % (file_obj.name, e)) 149 150 if len(data) != length: 151 raise PayloadError( 152 'reading from file (%s) too short (%d instead of %d bytes)' % 153 (file_obj.name, len(data), length)) 154 155 if hasher: 156 hasher.update(data) 157 158 return data 159 160 161# 162# Formatting functions. 163# 164def FormatExtent(ex, block_size=0): 165 end_block = ex.start_block + ex.num_blocks 166 if block_size: 167 return '%d->%d * %d' % (ex.start_block, end_block, block_size) 168 return '%d->%d' % (ex.start_block, end_block) 169 170 171def FormatSha256(digest): 172 """Returns a canonical string representation of a SHA256 digest.""" 173 return base64.b64encode(digest).decode('utf-8') 174 175 176# 177# Useful iterators. 178# 179def _ObjNameIter(items, base_name, reverse=False, name_format_func=None): 180 """A generic (item, name) tuple iterators. 181 182 Args: 183 items: the sequence of objects to iterate on 184 base_name: the base name for all objects 185 reverse: whether iteration should be in reverse order 186 name_format_func: a function to apply to the name string 187 188 Yields: 189 An iterator whose i-th invocation returns (items[i], name), where name == 190 base_name + '[i]' (with a formatting function optionally applied to it). 191 """ 192 idx, inc = (len(items), -1) if reverse else (1, 1) 193 if reverse: 194 items = reversed(items) 195 for item in items: 196 item_name = '%s[%d]' % (base_name, idx) 197 if name_format_func: 198 item_name = name_format_func(item, item_name) 199 yield (item, item_name) 200 idx += inc 201 202 203def _OperationNameFormatter(op, op_name): 204 return '%s(%s)' % (op_name, OpType.NAMES.get(op.type, '?')) 205 206 207def OperationIter(operations, base_name, reverse=False): 208 """An (item, name) iterator for update operations.""" 209 return _ObjNameIter(operations, base_name, reverse=reverse, 210 name_format_func=_OperationNameFormatter) 211 212 213def ExtentIter(extents, base_name, reverse=False): 214 """An (item, name) iterator for operation extents.""" 215 return _ObjNameIter(extents, base_name, reverse=reverse) 216 217 218def SignatureIter(sigs, base_name, reverse=False): 219 """An (item, name) iterator for signatures.""" 220 return _ObjNameIter(sigs, base_name, reverse=reverse) 221