• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2022 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""
17Description : Unpack updater package
18"""
19import os
20import struct
21import time
22from create_update_package import UPGRADE_FILE_HEADER_LEN
23from create_update_package import UPGRADE_COMPINFO_SIZE
24from create_update_package import UPGRADE_COMPINFO_SIZE_L2
25from create_update_package import COMPONENT_ADDR_SIZE
26from create_update_package import COMPONENT_ADDR_SIZE_L2
27from create_update_package import UPGRADE_RESERVE_LEN
28from create_update_package import UPGRADE_SIGNATURE_LEN
29
30from create_hashdata import HASH_TYPE_SIZE
31from create_hashdata import HASH_LENGTH_SIZE
32from create_hashdata import HASH_TLV_SIZE
33from create_hashdata import UPGRADE_HASHINFO_SIZE
34from create_hashdata import CreateHash
35from create_hashdata import HashType
36
37from log_exception import UPDATE_LOGGER
38from utils import OPTIONS_MANAGER
39
40COMPINFO_LEN_OFFSET = 178
41COMPINFO_LEN_SIZE = 2
42COMPONENT_ADDR_OFFSET = UPGRADE_FILE_HEADER_LEN
43COMPONENT_TYPE_OFFSET = COMPONENT_ADDR_OFFSET + COMPONENT_ADDR_SIZE + 4
44COMPONENT_TYPE_OFFSET_L2 = COMPONENT_ADDR_OFFSET + COMPONENT_ADDR_SIZE_L2 + 4
45COMPONENT_TYPE_SIZE = 1
46COMPONENT_SIZE_OFFSET = 11
47COMPONENT_SIZE_SIZE = 4
48
49"""
50Format
51H: unsigned short
52I: unsigned int
53B: unsigned char
54s: char[]
55"""
56COMPINFO_LEN_FMT = "H"
57COMPONENT_TYPE_FMT = "B"
58COMPONENT_SIZE_FMT = "I"
59
60
61class UnpackPackage(object):
62    """
63    Unpack the update.bin file
64    """
65
66    def __init__(self):
67        self.count = 0
68        self.component_offset = 0
69        self.save_path = None
70
71        if OPTIONS_MANAGER.not_l2:
72            self.compinfo_size = UPGRADE_COMPINFO_SIZE
73            self.type_offset = COMPONENT_TYPE_OFFSET
74            self.addr_size = COMPONENT_ADDR_SIZE
75        else:
76            self.compinfo_size = UPGRADE_COMPINFO_SIZE_L2
77            self.type_offset = COMPONENT_TYPE_OFFSET_L2
78            self.addr_size = COMPONENT_ADDR_SIZE_L2
79
80        self.addr_offset = COMPONENT_ADDR_OFFSET
81        self.size_offset = self.type_offset + COMPONENT_SIZE_OFFSET
82
83    def check_args(self):
84        if not os.access(OPTIONS_MANAGER.unpack_package_path, os.R_OK) and \
85            not os.path.exists(self.save_path):
86                UPDATE_LOGGER.print_log(
87                    "Access unpack_package_path fail! path: %s" % \
88                    OPTIONS_MANAGER.unpack_package_path, UPDATE_LOGGER.ERROR_LOG)
89                return False
90        return True
91
92    def parse_package_file(self, package_file):
93        try:
94            package_file.seek(COMPINFO_LEN_OFFSET)
95            compinfo_len_buffer = package_file.read(COMPINFO_LEN_SIZE)
96            compinfo_len = struct.unpack(COMPINFO_LEN_FMT, compinfo_len_buffer)
97        except (struct.error, IOError):
98            return False
99
100        self.count = compinfo_len[0] // self.compinfo_size
101        self.component_offset = UPGRADE_FILE_HEADER_LEN + compinfo_len[0] + UPGRADE_RESERVE_LEN
102
103        try:
104            package_file.seek(self.component_offset)
105            next_tlv_type_buffer = package_file.read(HASH_TYPE_SIZE)
106            next_tlv_type = struct.unpack(COMPINFO_LEN_FMT, next_tlv_type_buffer)
107            if next_tlv_type[0] == 0x06:
108                UPDATE_LOGGER.print_log("parse update.bin in SDcard package")
109                self.component_offset += HASH_TLV_SIZE + UPGRADE_HASHINFO_SIZE + HASH_TYPE_SIZE
110                package_file.seek(self.component_offset)
111                hashdata_len_buffer = package_file.read(HASH_LENGTH_SIZE)
112                hashdata_len = struct.unpack(COMPONENT_SIZE_FMT, hashdata_len_buffer)
113                self.component_offset += HASH_LENGTH_SIZE + hashdata_len[0] + HASH_TYPE_SIZE
114            elif next_tlv_type[0] == 0x08:
115                self.component_offset += HASH_TYPE_SIZE
116
117            package_file.seek(self.component_offset)
118            sign_len_buffer = package_file.read(HASH_LENGTH_SIZE)
119            sign_len = struct.unpack(COMPONENT_SIZE_FMT, sign_len_buffer)
120            UPDATE_LOGGER.print_log(
121                "signdata offset:%d length:%d" % (self.component_offset + HASH_LENGTH_SIZE, sign_len[0]))
122            self.component_offset += HASH_LENGTH_SIZE + sign_len[0]
123        except (struct.error, IOError):
124            return False
125
126        UPDATE_LOGGER.print_log("parse package file success! components: %d" % self.count)
127        return True
128
129    def parse_component(self, package_file):
130        try:
131            package_file.seek(self.addr_offset)
132            component_addr = package_file.read(self.addr_size)
133            component_addr = component_addr.split(b"\x00")[0].decode('utf-8')
134
135            package_file.seek(self.type_offset)
136            component_type_buffer = package_file.read(COMPONENT_TYPE_SIZE)
137            component_type = struct.unpack(COMPONENT_TYPE_FMT, component_type_buffer)
138
139            package_file.seek(self.size_offset)
140            component_size_buffer = package_file.read(COMPONENT_SIZE_SIZE)
141            component_size = struct.unpack(COMPONENT_SIZE_FMT, component_size_buffer)
142        except (struct.error, IOError):
143            UPDATE_LOGGER.print_log(
144                "parse component failed!", UPDATE_LOGGER.ERROR_LOG)
145            return False, False, False
146
147        return component_addr, component_type[0], component_size[0]
148
149    def create_image_file(self, package_file):
150        component_name, component_type, component_size = \
151            self.parse_component(package_file)
152        if component_name is None or component_type is None or component_size is None:
153            UPDATE_LOGGER.print_log("get component_info failed!", UPDATE_LOGGER.ERROR_LOG)
154            return False
155        component_name = component_name.strip('/')
156        if component_name == "version_list":
157            component_name = "VERSION.mbn"
158        elif component_name == "board_list":
159            component_name = "BOARD.list"
160        elif component_type == 0:
161            component_name = ''.join([component_name, '.img'])
162        elif component_type == 1:
163            component_name = ''.join([component_name, '.zip'])
164
165        image_file_path = os.path.join(self.save_path, component_name)
166
167        package_file.seek(self.component_offset)
168
169        UPDATE_LOGGER.print_log("component name: %s" % component_name)
170        UPDATE_LOGGER.print_log("component offset: %s" % self.component_offset)
171        UPDATE_LOGGER.print_log("component size: %s" % component_size)
172
173        image_fd = os.open(image_file_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC, 0o755)
174        with os.fdopen(image_fd, "wb") as image_file:
175            image_buffer = package_file.read(component_size)
176            image_file.write(image_buffer)
177
178        self.addr_offset += self.compinfo_size
179        self.type_offset += self.compinfo_size
180        self.size_offset += self.compinfo_size
181        self.component_offset += component_size
182        UPDATE_LOGGER.print_log("Create file: %s" % image_file_path)
183        return True
184
185    def unpack_package(self):
186        """
187        Unpack the update.bin file
188        return: result
189        """
190        UPDATE_LOGGER.print_log(
191            "Start unpack updater package: %s" % OPTIONS_MANAGER.unpack_package_path)
192        filename = ''.join(['unpack_result_', time.strftime("%H%M%S", time.localtime())])
193        self.save_path = os.path.join(OPTIONS_MANAGER.target_package, filename)
194        os.makedirs(self.save_path)
195
196        if not self.check_args():
197            UPDATE_LOGGER.print_log(
198                "check args failed!", UPDATE_LOGGER.ERROR_LOG)
199            return False
200
201        with open(OPTIONS_MANAGER.unpack_package_path, "rb") as package_file:
202            if not self.parse_package_file(package_file):
203                UPDATE_LOGGER.print_log(
204                    "parse package file failed!", UPDATE_LOGGER.ERROR_LOG)
205                return False
206
207            for image_id in range(0, self.count):
208                UPDATE_LOGGER.print_log("Start to parse component_%d" % image_id)
209                if not self.create_image_file(package_file):
210                    UPDATE_LOGGER.print_log(
211                        "create image file failed!", UPDATE_LOGGER.ERROR_LOG)
212                    return False
213        return True
214
215