• 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 COMPONEBT_ADDR_SIZE
26from create_update_package import COMPONEBT_ADDR_SIZE_L2
27from create_update_package import UPGRADE_RESERVE_LEN
28from create_update_package import UPGRADE_SIGNATURE_LEN
29from log_exception import UPDATE_LOGGER
30from utils import OPTIONS_MANAGER
31
32COMPINFO_LEN_OFFSET = 178
33COMPINFO_LEN_SIZE = 2
34COMPONEBT_ADDR_OFFSET = UPGRADE_FILE_HEADER_LEN
35COMPONENT_TYPE_OFFSET = COMPONEBT_ADDR_OFFSET + COMPONEBT_ADDR_SIZE + 4
36COMPONENT_TYPE_OFFSET_L2 = COMPONEBT_ADDR_OFFSET + COMPONEBT_ADDR_SIZE_L2 + 4
37COMPONENT_TYPE_SIZE = 1
38COMPONENT_SIZE_OFFSET = 11
39COMPONENT_SIZE_SIZE = 4
40
41"""
42Format
43H: unsigned short
44I: unsigned int
45B: unsigned char
46s: char[]
47"""
48COMPINFO_LEN_FMT = "H"
49COMPONEBT_TYPE_FMT = "B"
50COMPONENT_SIZE_FMT = "I"
51
52
53class UnpackPackage(object):
54    """
55    Unpack the update.bin file
56    """
57
58    def __init__(self):
59        self.count = 0
60        self.component_offset = 0
61        self.save_path = None
62
63        if OPTIONS_MANAGER.not_l2:
64            self.compinfo_size = UPGRADE_COMPINFO_SIZE
65            self.type_offset = COMPONENT_TYPE_OFFSET
66            self.addr_size = COMPONEBT_ADDR_SIZE
67        else:
68            self.compinfo_size = UPGRADE_COMPINFO_SIZE_L2
69            self.type_offset = COMPONENT_TYPE_OFFSET_L2
70            self.addr_size = COMPONEBT_ADDR_SIZE_L2
71
72        self.addr_offset = COMPONEBT_ADDR_OFFSET
73        self.size_offset = self.type_offset + COMPONENT_SIZE_OFFSET
74
75    def check_args(self):
76        if not os.access(OPTIONS_MANAGER.unpack_package_path, os.R_OK) and \
77            notos.path.exists(self.save_path):
78                UPDATE_LOGGER.print_log(
79                    "Access unpack_package_path fail! path: %s" % \
80                    OPTIONS_MANAGER.unpack_package_path, UPDATE_LOGGER.ERROR_LOG)
81                return False
82        return True
83
84    def parse_package_file(self, package_file):
85        try:
86            package_file.seek(COMPINFO_LEN_OFFSET)
87            compinfo_len_buffer = package_file.read(COMPINFO_LEN_SIZE)
88            compinfo_len = struct.unpack(COMPINFO_LEN_FMT, compinfo_len_buffer)
89        except (struct.error, IOError):
90            return False
91
92        self.count = compinfo_len[0] // self.compinfo_size
93        self.component_offset = \
94            UPGRADE_FILE_HEADER_LEN + compinfo_len[0] + \
95            UPGRADE_RESERVE_LEN + UPGRADE_SIGNATURE_LEN
96        UPDATE_LOGGER.print_log(
97                    "parse package file success! components: %d" % self.count)
98        return True
99
100    def parse_component(self, package_file):
101        try:
102            package_file.seek(self.addr_offset)
103            component_addr = package_file.read(self.addr_size)
104            component_addr = component_addr.split(b"\x00")[0].decode('utf-8')
105
106            package_file.seek(self.type_offset)
107            component_type_buffer = package_file.read(COMPONENT_TYPE_SIZE)
108            component_type = struct.unpack(COMPONEBT_TYPE_FMT, component_type_buffer)
109
110            package_file.seek(self.size_offset)
111            component_size_buffer = package_file.read(COMPONENT_SIZE_SIZE)
112            component_size = struct.unpack(COMPONENT_SIZE_FMT, component_size_buffer)
113        except (struct.error, IOError):
114            UPDATE_LOGGER.print_log(
115                "parse component failed!", UPDATE_LOGGER.ERROR_LOG)
116            return False, False, False
117
118        return component_addr, component_type[0], component_size[0]
119
120    def create_image_file(self, package_file):
121        component_name, component_type, component_size = \
122            self.parse_component(package_file)
123        if not component_name or not component_type or not component_size:
124            UPDATE_LOGGER.print_log(
125                "get component_info failed!", UPDATE_LOGGER.ERROR_LOG)
126            return False
127        component_name = component_name.strip('/')
128        if component_name == "version_list":
129            component_name = "VERSION.mbn"
130        elif component_name == "board_list":
131            component_name = "BOARD.list"
132        elif component_type == 0:
133            component_name = ''.join([component_name, '.img'])
134        elif component_type == 1:
135            component_name = ''.join([component_name, '.zip'])
136
137        image_file_path = os.path.join(self.save_path, component_name)
138
139        package_file.seek(self.component_offset)
140
141        UPDATE_LOGGER.print_log("component name: %s" % component_name)
142        UPDATE_LOGGER.print_log("component offset: %s" % self.component_offset)
143        UPDATE_LOGGER.print_log("component size: %s" % component_size)
144
145        image_fd = os.open(image_file_path, os.O_RDWR | os.O_CREAT, 0o755)
146        with os.fdopen(image_fd, "wb") as image_file:
147            image_buffer = package_file.read(component_size)
148            image_file.write(image_buffer)
149
150        self.addr_offset += self.compinfo_size
151        self.type_offset += self.compinfo_size
152        self.size_offset += self.compinfo_size
153        self.component_offset += component_size
154        UPDATE_LOGGER.print_log("Create file: %s" % image_file_path)
155        return True
156
157    def unpack_package(self):
158        """
159        Unpack the update.bin file
160        return: result
161        """
162        UPDATE_LOGGER.print_log(
163            "Start unpack updater package: %s" % OPTIONS_MANAGER.unpack_package_path)
164        filename = ''.join(['unpack_result_', time.strftime("%H%M%S", time.localtime())])
165        self.save_path = os.path.join(OPTIONS_MANAGER.target_package, filename)
166        os.makedirs(self.save_path)
167
168        if not self.check_args():
169            UPDATE_LOGGER.print_log(
170                "check args failed!", UPDATE_LOGGER.ERROR_LOG)
171            return False
172
173        with open(OPTIONS_MANAGER.unpack_package_path, "rb") as package_file:
174            if not self.parse_package_file(package_file):
175                UPDATE_LOGGER.print_log(
176                    "parse package file failed!", UPDATE_LOGGER.ERROR_LOG)
177                return False
178            for image_id in range(0, self.count):
179                UPDATE_LOGGER.print_log("Start to parse component_%d" % image_id)
180                if not self.create_image_file(package_file):
181                    UPDATE_LOGGER.print_log(
182                        "create image file failed!", UPDATE_LOGGER.ERROR_LOG)
183                    return False
184        return True
185
186