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