blob: 42c91c2600afee544cd019f83b67413c44d244c6 [file] [log] [blame]
Amin Hassanif94b6432018-01-26 17:39:47 -08001#
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 Arnold553b0ec2013-01-26 01:00:39 -080016
17"""Utilities for update payload processing."""
18
Allie Wood12f59aa2015-04-06 11:05:12 -070019from __future__ import print_function
20
Amin Hassanib05a65a2017-12-18 15:15:32 -080021from update_payload import update_metadata_pb2
22from update_payload.error import PayloadError
Gilad Arnold553b0ec2013-01-26 01:00:39 -080023
24
25#
26# Constants.
27#
Alex Deymocf6f30d2015-06-11 13:51:46 -070028PSEUDO_EXTENT_MARKER = (1L << 64) - 1 # UINT64_MAX
Gilad Arnold553b0ec2013-01-26 01:00:39 -080029
Gilad Arnold5502b562013-03-08 13:22:31 -080030SIG_ASN1_HEADER = (
31 '\x30\x31\x30\x0d\x06\x09\x60\x86'
32 '\x48\x01\x65\x03\x04\x02\x01\x05'
33 '\x00\x04\x20'
34)
35
Alex Deymoef497352015-10-15 09:14:58 -070036CHROMEOS_MAJOR_PAYLOAD_VERSION = 1
37BRILLO_MAJOR_PAYLOAD_VERSION = 2
38
Allie Wood12f59aa2015-04-06 11:05:12 -070039INPLACE_MINOR_PAYLOAD_VERSION = 1
40SOURCE_MINOR_PAYLOAD_VERSION = 2
Sen Jiangd6122bb2015-12-11 10:27:04 -080041OPSRCHASH_MINOR_PAYLOAD_VERSION = 3
Amin Hassani5ef5d452017-08-04 13:10:59 -070042PUFFDIFF_MINOR_PAYLOAD_VERSION = 4
Gilad Arnold553b0ec2013-01-26 01:00:39 -080043
44#
45# Payload operation types.
46#
47class OpType(object):
48 """Container for operation type constants."""
Alex Deymo28466772015-09-11 17:16:44 -070049 _CLASS = update_metadata_pb2.InstallOperation
Gilad Arnold553b0ec2013-01-26 01:00:39 -080050 REPLACE = _CLASS.REPLACE
51 REPLACE_BZ = _CLASS.REPLACE_BZ
52 MOVE = _CLASS.MOVE
53 BSDIFF = _CLASS.BSDIFF
Allie Woodc11dc732015-02-18 15:53:05 -080054 SOURCE_COPY = _CLASS.SOURCE_COPY
55 SOURCE_BSDIFF = _CLASS.SOURCE_BSDIFF
Alex Deymo28466772015-09-11 17:16:44 -070056 ZERO = _CLASS.ZERO
57 DISCARD = _CLASS.DISCARD
58 REPLACE_XZ = _CLASS.REPLACE_XZ
Amin Hassani5ef5d452017-08-04 13:10:59 -070059 PUFFDIFF = _CLASS.PUFFDIFF
Amin Hassaniefa62d92017-11-09 13:46:56 -080060 BROTLI_BSDIFF = _CLASS.BROTLI_BSDIFF
Alex Deymo28466772015-09-11 17:16:44 -070061 ALL = (REPLACE, REPLACE_BZ, MOVE, BSDIFF, SOURCE_COPY, SOURCE_BSDIFF, ZERO,
Amin Hassaniefa62d92017-11-09 13:46:56 -080062 DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF)
Gilad Arnold553b0ec2013-01-26 01:00:39 -080063 NAMES = {
64 REPLACE: 'REPLACE',
65 REPLACE_BZ: 'REPLACE_BZ',
66 MOVE: 'MOVE',
67 BSDIFF: 'BSDIFF',
Allie Woodc11dc732015-02-18 15:53:05 -080068 SOURCE_COPY: 'SOURCE_COPY',
Alex Deymo28466772015-09-11 17:16:44 -070069 SOURCE_BSDIFF: 'SOURCE_BSDIFF',
70 ZERO: 'ZERO',
71 DISCARD: 'DISCARD',
Sen Jiangc2538fa2016-02-24 14:15:02 -080072 REPLACE_XZ: 'REPLACE_XZ',
Amin Hassani5ef5d452017-08-04 13:10:59 -070073 PUFFDIFF: 'PUFFDIFF',
Amin Hassaniefa62d92017-11-09 13:46:56 -080074 BROTLI_BSDIFF: 'BROTLI_BSDIFF',
Gilad Arnold553b0ec2013-01-26 01:00:39 -080075 }
76
77 def __init__(self):
78 pass
79
80
81#
Gilad Arnold382df5c2013-05-03 12:49:28 -070082# Checked and hashed reading of data.
Gilad Arnold553b0ec2013-01-26 01:00:39 -080083#
Gilad Arnold5502b562013-03-08 13:22:31 -080084def IntPackingFmtStr(size, is_unsigned):
85 """Returns an integer format string for use by the struct module.
86
87 Args:
88 size: the integer size in bytes (2, 4 or 8)
89 is_unsigned: whether it is signed or not
Allie Wood12f59aa2015-04-06 11:05:12 -070090
Gilad Arnold5502b562013-03-08 13:22:31 -080091 Returns:
92 A format string for packing/unpacking integer values; assumes network byte
93 order (big-endian).
Allie Wood12f59aa2015-04-06 11:05:12 -070094
Gilad Arnold5502b562013-03-08 13:22:31 -080095 Raises:
96 PayloadError if something is wrong with the arguments.
Gilad Arnold5502b562013-03-08 13:22:31 -080097 """
98 # Determine the base conversion format.
99 if size == 2:
100 fmt = 'h'
101 elif size == 4:
102 fmt = 'i'
103 elif size == 8:
104 fmt = 'q'
105 else:
106 raise PayloadError('unsupport numeric field size (%s)' % size)
107
108 # Signed or unsigned?
109 if is_unsigned:
110 fmt = fmt.upper()
111
112 # Make it network byte order (big-endian).
113 fmt = '!' + fmt
114
115 return fmt
116
117
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800118def Read(file_obj, length, offset=None, hasher=None):
119 """Reads binary data from a file.
120
121 Args:
122 file_obj: an open file object
123 length: the length of the data to read
124 offset: an offset to seek to prior to reading; this is an absolute offset
125 from either the beginning (non-negative) or end (negative) of the
126 file. (optional)
127 hasher: a hashing object to pass the read data through (optional)
Allie Wood12f59aa2015-04-06 11:05:12 -0700128
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800129 Returns:
130 A string containing the read data.
Allie Wood12f59aa2015-04-06 11:05:12 -0700131
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800132 Raises:
133 PayloadError if a read error occurred or not enough data was read.
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800134 """
135 if offset is not None:
136 if offset >= 0:
137 file_obj.seek(offset)
138 else:
139 file_obj.seek(offset, 2)
140
141 try:
142 data = file_obj.read(length)
143 except IOError, e:
144 raise PayloadError('error reading from file (%s): %s' % (file_obj.name, e))
145
146 if len(data) != length:
147 raise PayloadError(
148 'reading from file (%s) too short (%d instead of %d bytes)' %
149 (file_obj.name, len(data), length))
150
151 if hasher:
152 hasher.update(data)
153
154 return data
155
156
157#
158# Formatting functions.
159#
160def FormatExtent(ex, block_size=0):
161 end_block = ex.start_block + ex.num_blocks
162 if block_size:
163 return '%d->%d * %d' % (ex.start_block, end_block, block_size)
164 else:
165 return '%d->%d' % (ex.start_block, end_block)
166
167
168def FormatSha256(digest):
169 """Returns a canonical string representation of a SHA256 digest."""
Gilad Arnolda7aa0bc2013-11-12 08:18:08 -0800170 return digest.encode('base64').strip()
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800171
172
173#
174# Useful iterators.
175#
176def _ObjNameIter(items, base_name, reverse=False, name_format_func=None):
177 """A generic (item, name) tuple iterators.
178
179 Args:
180 items: the sequence of objects to iterate on
181 base_name: the base name for all objects
182 reverse: whether iteration should be in reverse order
183 name_format_func: a function to apply to the name string
Allie Wood12f59aa2015-04-06 11:05:12 -0700184
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800185 Yields:
186 An iterator whose i-th invocation returns (items[i], name), where name ==
187 base_name + '[i]' (with a formatting function optionally applied to it).
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800188 """
189 idx, inc = (len(items), -1) if reverse else (1, 1)
Gilad Arnolde4beff72015-07-16 14:14:03 -0700190 if reverse:
191 items = reversed(items)
Gilad Arnold553b0ec2013-01-26 01:00:39 -0800192 for item in items:
193 item_name = '%s[%d]' % (base_name, idx)
194 if name_format_func:
195 item_name = name_format_func(item, item_name)
196 yield (item, item_name)
197 idx += inc
198
199
200def _OperationNameFormatter(op, op_name):
201 return '%s(%s)' % (op_name, OpType.NAMES.get(op.type, '?'))
202
203
204def OperationIter(operations, base_name, reverse=False):
205 """An (item, name) iterator for update operations."""
206 return _ObjNameIter(operations, base_name, reverse=reverse,
207 name_format_func=_OperationNameFormatter)
208
209
210def ExtentIter(extents, base_name, reverse=False):
211 """An (item, name) iterator for operation extents."""
212 return _ObjNameIter(extents, base_name, reverse=reverse)
213
214
215def SignatureIter(sigs, base_name, reverse=False):
216 """An (item, name) iterator for signatures."""
217 return _ObjNameIter(sigs, base_name, reverse=reverse)