140681896Sopenharmony_ci#!/usr/bin/env python3
240681896Sopenharmony_ci# -*- coding: utf-8 -*-
340681896Sopenharmony_ci
440681896Sopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
540681896Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
640681896Sopenharmony_ci# you may not use this file except in compliance with the License.
740681896Sopenharmony_ci# You may obtain a copy of the License at
840681896Sopenharmony_ci#
940681896Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
1040681896Sopenharmony_ci#
1140681896Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
1240681896Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
1340681896Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1440681896Sopenharmony_ci# See the License for the specific language governing permissions and
1540681896Sopenharmony_ci# limitations under the License.
1640681896Sopenharmony_ciimport bisect
1740681896Sopenharmony_ciimport copy
1840681896Sopenharmony_ciimport os
1940681896Sopenharmony_ciimport struct
2040681896Sopenharmony_ciimport tempfile
2140681896Sopenharmony_cifrom hashlib import sha256
2240681896Sopenharmony_ci
2340681896Sopenharmony_cifrom log_exception import UPDATE_LOGGER
2440681896Sopenharmony_cifrom blocks_manager import BlocksManager
2540681896Sopenharmony_cifrom utils import OPTIONS_MANAGER
2640681896Sopenharmony_cifrom utils import EXTEND_VALUE
2740681896Sopenharmony_cifrom utils import FILE_MAP_ZERO_KEY
2840681896Sopenharmony_cifrom utils import FILE_MAP_NONZERO_KEY
2940681896Sopenharmony_cifrom utils import FILE_MAP_COPY_KEY
3040681896Sopenharmony_cifrom utils import MAX_BLOCKS_PER_GROUP
3140681896Sopenharmony_cifrom utils import UPDATE_BIN_FILE_NAME
3240681896Sopenharmony_cifrom utils import FORBIDEN_UPDATE_IMAGE_SET
3340681896Sopenharmony_ci
3440681896Sopenharmony_ci
3540681896Sopenharmony_ciclass FullUpdateImage:
3640681896Sopenharmony_ci    """
3740681896Sopenharmony_ci    Full image processing class
3840681896Sopenharmony_ci    """
3940681896Sopenharmony_ci
4040681896Sopenharmony_ci    def __init__(self, target_package_images_dir,
4140681896Sopenharmony_ci                 full_img_list, full_img_name_list,
4240681896Sopenharmony_ci                 verse_script, full_image_path_list,
4340681896Sopenharmony_ci                 no_zip=False):
4440681896Sopenharmony_ci        self.target_package_images_dir = target_package_images_dir
4540681896Sopenharmony_ci        self.full_img_list = full_img_list
4640681896Sopenharmony_ci        self.full_img_name_list = full_img_name_list
4740681896Sopenharmony_ci        self.verse_script = verse_script
4840681896Sopenharmony_ci        self.full_image_path_list = full_image_path_list
4940681896Sopenharmony_ci        self.no_zip = no_zip
5040681896Sopenharmony_ci
5140681896Sopenharmony_ci    def update_full_image(self):
5240681896Sopenharmony_ci        """
5340681896Sopenharmony_ci        Processing of the full image
5440681896Sopenharmony_ci        :return full_image_content_len_list: full image content length list
5540681896Sopenharmony_ci        :return full_image_file_obj_list: full image temporary file list
5640681896Sopenharmony_ci        """
5740681896Sopenharmony_ci        full_image_file_obj_list = []
5840681896Sopenharmony_ci        full_image_content_len_list = []
5940681896Sopenharmony_ci        for idx, each_name in enumerate(self.full_img_list):
6040681896Sopenharmony_ci            full_image_content = self.get_full_image_content(
6140681896Sopenharmony_ci                self.full_image_path_list[idx])
6240681896Sopenharmony_ci            img_name = self.full_img_name_list[idx][:-4]
6340681896Sopenharmony_ci            if full_image_content is False:
6440681896Sopenharmony_ci                UPDATE_LOGGER.print_log(
6540681896Sopenharmony_ci                    "Get full image content failed!",
6640681896Sopenharmony_ci                    log_type=UPDATE_LOGGER.ERROR_LOG)
6740681896Sopenharmony_ci                return False, False
6840681896Sopenharmony_ci            each_img = tempfile.NamedTemporaryFile(
6940681896Sopenharmony_ci                dir=self.target_package_images_dir,
7040681896Sopenharmony_ci                prefix="full_image%s" % img_name, mode='wb')
7140681896Sopenharmony_ci            each_img.write(full_image_content)
7240681896Sopenharmony_ci            each_img.seek(0)
7340681896Sopenharmony_ci            full_image_content_len_list.append(len(full_image_content))
7440681896Sopenharmony_ci            full_image_file_obj_list.append(each_img)
7540681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
7640681896Sopenharmony_ci                "Image %s full processing completed" % img_name)
7740681896Sopenharmony_ci        update_image_set = set(self.full_img_list) - FORBIDEN_UPDATE_IMAGE_SET
7840681896Sopenharmony_ci        if not self.no_zip and len(update_image_set) != 0:
7940681896Sopenharmony_ci            # No zip mode (no script command)
8040681896Sopenharmony_ci            image_write_cmd = self.verse_script.full_image_update(UPDATE_BIN_FILE_NAME)
8140681896Sopenharmony_ci            cmd = '%s_WRITE_FLAG%s' % (UPDATE_BIN_FILE_NAME, image_write_cmd)
8240681896Sopenharmony_ci            if each_name not in FORBIDEN_UPDATE_IMAGE_SET:
8340681896Sopenharmony_ci                self.verse_script.add_command(cmd=cmd)
8440681896Sopenharmony_ci
8540681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
8640681896Sopenharmony_ci            "All full image processing completed! image count: %d" %
8740681896Sopenharmony_ci            len(self.full_img_list))
8840681896Sopenharmony_ci        return full_image_content_len_list, full_image_file_obj_list
8940681896Sopenharmony_ci
9040681896Sopenharmony_ci    @staticmethod
9140681896Sopenharmony_ci    def get_full_image_content(each_name):
9240681896Sopenharmony_ci        """
9340681896Sopenharmony_ci        Obtain the full image content.
9440681896Sopenharmony_ci        :param each_name: image name
9540681896Sopenharmony_ci        :return content: full image content if available; false otherwise
9640681896Sopenharmony_ci        """
9740681896Sopenharmony_ci        each_image_path = each_name
9840681896Sopenharmony_ci        if not os.path.exists(each_image_path):
9940681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
10040681896Sopenharmony_ci                "The file is missing "
10140681896Sopenharmony_ci                "from the target package, "
10240681896Sopenharmony_ci                "the component: %s cannot be full update processed. " %
10340681896Sopenharmony_ci                each_image_path)
10440681896Sopenharmony_ci            return False
10540681896Sopenharmony_ci        with open(each_image_path, 'rb') as f_r:
10640681896Sopenharmony_ci            content = f_r.read()
10740681896Sopenharmony_ci        return content
10840681896Sopenharmony_ci
10940681896Sopenharmony_ci
11040681896Sopenharmony_ciclass IncUpdateImage:
11140681896Sopenharmony_ci    """
11240681896Sopenharmony_ci    Increment update image class
11340681896Sopenharmony_ci    """
11440681896Sopenharmony_ci
11540681896Sopenharmony_ci    def __init__(self, image_path, map_path):
11640681896Sopenharmony_ci        """
11740681896Sopenharmony_ci        Initialize the inc image.
11840681896Sopenharmony_ci        :param image_path: img file path
11940681896Sopenharmony_ci        :param map_path: map file path
12040681896Sopenharmony_ci        """
12140681896Sopenharmony_ci        self.image_path = image_path
12240681896Sopenharmony_ci        self.map_path = map_path
12340681896Sopenharmony_ci        self.offset_value_list = []
12440681896Sopenharmony_ci        self.care_block_range = None
12540681896Sopenharmony_ci        self.extended_range = None
12640681896Sopenharmony_ci        self.reserved_blocks = BlocksManager("0")
12740681896Sopenharmony_ci        self.file_map = []
12840681896Sopenharmony_ci        self.offset_index = []
12940681896Sopenharmony_ci        self.block_size = None
13040681896Sopenharmony_ci        self.total_blocks = None
13140681896Sopenharmony_ci        self.parse_raw_image_file(image_path, map_path)
13240681896Sopenharmony_ci
13340681896Sopenharmony_ci    def parse_raw_image_file(self, image_path, map_path):
13440681896Sopenharmony_ci        """
13540681896Sopenharmony_ci        Parse the .img file.
13640681896Sopenharmony_ci        :param image_path: img file path
13740681896Sopenharmony_ci        :param map_path: map file path
13840681896Sopenharmony_ci        """
13940681896Sopenharmony_ci        self.block_size = block_size = 4096
14040681896Sopenharmony_ci        self.total_blocks = total_blocks = \
14140681896Sopenharmony_ci            os.path.getsize(self.image_path) // self.block_size
14240681896Sopenharmony_ci        reference = b'\0' * self.block_size
14340681896Sopenharmony_ci        with open(image_path, 'rb') as f_r:
14440681896Sopenharmony_ci            care_value_list, offset_value_list = [], []
14540681896Sopenharmony_ci            nonzero_blocks = []
14640681896Sopenharmony_ci            for i in range(self.total_blocks):
14740681896Sopenharmony_ci                blocks_data = f_r.read(self.block_size)
14840681896Sopenharmony_ci                if blocks_data != reference:
14940681896Sopenharmony_ci                    nonzero_blocks.append(i)
15040681896Sopenharmony_ci                    nonzero_blocks.append(i + 1)
15140681896Sopenharmony_ci            self.care_block_range = BlocksManager(nonzero_blocks)
15240681896Sopenharmony_ci            care_value_list = list(self.care_block_range.range_data)
15340681896Sopenharmony_ci            for idx, value in enumerate(care_value_list):
15440681896Sopenharmony_ci                if idx != 0 and (idx + 1) % 2 == 0:
15540681896Sopenharmony_ci                    be_value = int(care_value_list[idx - 1])
15640681896Sopenharmony_ci                    af_value = int(care_value_list[idx])
15740681896Sopenharmony_ci                    file_tell = be_value * block_size
15840681896Sopenharmony_ci                    offset_value_list.append(
15940681896Sopenharmony_ci                        (be_value, af_value - be_value,
16040681896Sopenharmony_ci                         file_tell, None))
16140681896Sopenharmony_ci
16240681896Sopenharmony_ci            self.offset_index = [i[0] for i in offset_value_list]
16340681896Sopenharmony_ci            self.offset_value_list = offset_value_list
16440681896Sopenharmony_ci            extended_range = \
16540681896Sopenharmony_ci                self.care_block_range.extend_value_to_blocks(EXTEND_VALUE)
16640681896Sopenharmony_ci            all_blocks = BlocksManager(range_data=(0, total_blocks))
16740681896Sopenharmony_ci            self.extended_range = \
16840681896Sopenharmony_ci                extended_range.get_intersect_with_other(all_blocks). \
16940681896Sopenharmony_ci                get_subtract_with_other(self.care_block_range)
17040681896Sopenharmony_ci            self.parse_block_map_file(map_path, f_r)
17140681896Sopenharmony_ci
17240681896Sopenharmony_ci    def parse_block_map_file(self, map_path, image_file_r):
17340681896Sopenharmony_ci        """
17440681896Sopenharmony_ci        Parses the map file for blocks where files are contained in the image.
17540681896Sopenharmony_ci        :param map_path: map file path
17640681896Sopenharmony_ci        :param image_file_r: file reading object
17740681896Sopenharmony_ci        :return:
17840681896Sopenharmony_ci        """
17940681896Sopenharmony_ci        remain_range = self.care_block_range
18040681896Sopenharmony_ci        temp_file_map = {}
18140681896Sopenharmony_ci
18240681896Sopenharmony_ci        with open(map_path, 'r') as f_r:
18340681896Sopenharmony_ci            # Read the .map file and process each line.
18440681896Sopenharmony_ci            for each_line in f_r.readlines():
18540681896Sopenharmony_ci                each_map_path, ranges_value = each_line.split(None, 1)
18640681896Sopenharmony_ci                each_range = BlocksManager(ranges_value)
18740681896Sopenharmony_ci                each_range = each_range.get_subtract_with_other(BlocksManager("0"))
18840681896Sopenharmony_ci                # each_range may not contained in the remain range.
18940681896Sopenharmony_ci                intersect_range = each_range.get_intersect_with_other(remain_range)
19040681896Sopenharmony_ci                if each_range.size() != intersect_range.size():
19140681896Sopenharmony_ci                    each_range = intersect_range
19240681896Sopenharmony_ci                temp_file_map[each_map_path] = each_range
19340681896Sopenharmony_ci                # After the processing is complete,
19440681896Sopenharmony_ci                # remove each_range from remain_range.
19540681896Sopenharmony_ci                remain_range = remain_range.get_subtract_with_other(each_range)
19640681896Sopenharmony_ci        reserved_blocks = self.reserved_blocks
19740681896Sopenharmony_ci        # Remove reserved blocks from all blocks.
19840681896Sopenharmony_ci        remain_range = remain_range.get_subtract_with_other(reserved_blocks)
19940681896Sopenharmony_ci
20040681896Sopenharmony_ci        # Divide all blocks into zero_blocks
20140681896Sopenharmony_ci        # (if there are many) and nonzero_blocks.
20240681896Sopenharmony_ci        zero_blocks_list = []
20340681896Sopenharmony_ci        nonzero_blocks_list = []
20440681896Sopenharmony_ci        nonzero_groups_list = []
20540681896Sopenharmony_ci        default_zero_block = ('\0' * self.block_size).encode()
20640681896Sopenharmony_ci
20740681896Sopenharmony_ci        nonzero_blocks_list, nonzero_groups_list, zero_blocks_list = \
20840681896Sopenharmony_ci            self.apply_remain_range(
20940681896Sopenharmony_ci                default_zero_block, image_file_r, nonzero_blocks_list,
21040681896Sopenharmony_ci                nonzero_groups_list, remain_range, zero_blocks_list)
21140681896Sopenharmony_ci
21240681896Sopenharmony_ci        temp_file_map = self.get_file_map(
21340681896Sopenharmony_ci            nonzero_blocks_list, nonzero_groups_list,
21440681896Sopenharmony_ci            reserved_blocks, temp_file_map, zero_blocks_list)
21540681896Sopenharmony_ci        self.file_map = temp_file_map
21640681896Sopenharmony_ci
21740681896Sopenharmony_ci    def apply_remain_range(self, *args):
21840681896Sopenharmony_ci        """
21940681896Sopenharmony_ci        Implement traversal processing of remain_range.
22040681896Sopenharmony_ci        """
22140681896Sopenharmony_ci        default_zero_block, image_file_r, \
22240681896Sopenharmony_ci            nonzero_blocks_list, nonzero_groups_list, \
22340681896Sopenharmony_ci            remain_range, zero_blocks_list = args
22440681896Sopenharmony_ci        for start_value, end_value in remain_range:
22540681896Sopenharmony_ci            for each_value in range(start_value, end_value):
22640681896Sopenharmony_ci                # bisect 二分查找,b在self.offset_index中的位置
22740681896Sopenharmony_ci                idx = bisect.bisect_right(self.offset_index, each_value) - 1
22840681896Sopenharmony_ci                chunk_start, _, file_pos, fill_data = \
22940681896Sopenharmony_ci                    self.offset_value_list[idx]
23040681896Sopenharmony_ci                data = self.get_file_data(self.block_size, chunk_start,
23140681896Sopenharmony_ci                                          default_zero_block, each_value,
23240681896Sopenharmony_ci                                          file_pos, fill_data, image_file_r)
23340681896Sopenharmony_ci
23440681896Sopenharmony_ci                zero_blocks_list, nonzero_blocks_list, nonzero_groups_list = \
23540681896Sopenharmony_ci                    self.get_zero_nonzero_blocks_list(
23640681896Sopenharmony_ci                        data, default_zero_block, each_value,
23740681896Sopenharmony_ci                        nonzero_blocks_list, nonzero_groups_list,
23840681896Sopenharmony_ci                        zero_blocks_list)
23940681896Sopenharmony_ci        return nonzero_blocks_list, nonzero_groups_list, zero_blocks_list
24040681896Sopenharmony_ci
24140681896Sopenharmony_ci    @staticmethod
24240681896Sopenharmony_ci    def get_file_map(*args):
24340681896Sopenharmony_ci        """
24440681896Sopenharmony_ci        Obtain the file map.
24540681896Sopenharmony_ci        nonzero_blocks_list nonzero blocks list,
24640681896Sopenharmony_ci        nonzero_groups_list nonzero groups list,
24740681896Sopenharmony_ci        reserved_blocks reserved blocks ,
24840681896Sopenharmony_ci        temp_file_map temporary file map,
24940681896Sopenharmony_ci        zero_blocks_list zero block list
25040681896Sopenharmony_ci        :return temp_file_map file map
25140681896Sopenharmony_ci        """
25240681896Sopenharmony_ci        nonzero_blocks_list, nonzero_groups_list, \
25340681896Sopenharmony_ci            reserved_blocks, temp_file_map, zero_blocks_list = args
25440681896Sopenharmony_ci        if nonzero_blocks_list:
25540681896Sopenharmony_ci            nonzero_groups_list.append(nonzero_blocks_list)
25640681896Sopenharmony_ci        if zero_blocks_list:
25740681896Sopenharmony_ci            temp_file_map[FILE_MAP_ZERO_KEY] = \
25840681896Sopenharmony_ci                BlocksManager(range_data=zero_blocks_list)
25940681896Sopenharmony_ci        if nonzero_groups_list:
26040681896Sopenharmony_ci            for i, blocks in enumerate(nonzero_groups_list):
26140681896Sopenharmony_ci                temp_file_map["%s-%d" % (FILE_MAP_NONZERO_KEY, i)] = \
26240681896Sopenharmony_ci                    BlocksManager(range_data=blocks)
26340681896Sopenharmony_ci        if reserved_blocks:
26440681896Sopenharmony_ci            temp_file_map[FILE_MAP_COPY_KEY] = reserved_blocks
26540681896Sopenharmony_ci        return temp_file_map
26640681896Sopenharmony_ci
26740681896Sopenharmony_ci    @staticmethod
26840681896Sopenharmony_ci    def get_zero_nonzero_blocks_list(*args):
26940681896Sopenharmony_ci        """
27040681896Sopenharmony_ci        Get zero_blocks_list, nonzero_blocks_list, and nonzero_groups_list.
27140681896Sopenharmony_ci        data: block data,
27240681896Sopenharmony_ci        default_zero_block: default to zero block,
27340681896Sopenharmony_ci        each_value: each value,
27440681896Sopenharmony_ci        nonzero_blocks_list: nonzero_blocks_list,
27540681896Sopenharmony_ci        nonzero_groups_list: nonzero_groups_list,
27640681896Sopenharmony_ci        zero_blocks_list: zero_blocks_list,
27740681896Sopenharmony_ci        :return new_zero_blocks_list: new zero blocks list,
27840681896Sopenharmony_ci        :return new_nonzero_blocks_list: new nonzero blocks list,
27940681896Sopenharmony_ci        :return new_nonzero_groups_list: new nonzero groups list.
28040681896Sopenharmony_ci        """
28140681896Sopenharmony_ci        data, default_zero_block, each_value, \
28240681896Sopenharmony_ci            nonzero_blocks_list, nonzero_groups_list, \
28340681896Sopenharmony_ci            zero_blocks_list = args
28440681896Sopenharmony_ci        # Check whether the data block is equal to the default zero_blocks.
28540681896Sopenharmony_ci        if data == default_zero_block:
28640681896Sopenharmony_ci            zero_blocks_list.append(each_value)
28740681896Sopenharmony_ci            zero_blocks_list.append(each_value + 1)
28840681896Sopenharmony_ci        else:
28940681896Sopenharmony_ci            nonzero_blocks_list.append(each_value)
29040681896Sopenharmony_ci            nonzero_blocks_list.append(each_value + 1)
29140681896Sopenharmony_ci            # The number of nonzero_blocks is greater than
29240681896Sopenharmony_ci            # or equal to the upper limit.
29340681896Sopenharmony_ci            if len(nonzero_blocks_list) >= MAX_BLOCKS_PER_GROUP:
29440681896Sopenharmony_ci                nonzero_groups_list.append(nonzero_blocks_list)
29540681896Sopenharmony_ci                nonzero_blocks_list = []
29640681896Sopenharmony_ci        new_zero_blocks_list, new_nonzero_blocks_list, \
29740681896Sopenharmony_ci            new_nonzero_groups_list = \
29840681896Sopenharmony_ci            copy.copy(zero_blocks_list), \
29940681896Sopenharmony_ci            copy.copy(nonzero_blocks_list),\
30040681896Sopenharmony_ci            copy.copy(nonzero_groups_list)
30140681896Sopenharmony_ci        return new_zero_blocks_list, new_nonzero_blocks_list, \
30240681896Sopenharmony_ci            new_nonzero_groups_list
30340681896Sopenharmony_ci
30440681896Sopenharmony_ci    @staticmethod
30540681896Sopenharmony_ci    def get_file_data(*args):
30640681896Sopenharmony_ci        """
30740681896Sopenharmony_ci        Get the file data.
30840681896Sopenharmony_ci        block_size: blocksize,
30940681896Sopenharmony_ci        chunk_start: the start position of chunk,
31040681896Sopenharmony_ci        default_zero_block: default to zero blocks,
31140681896Sopenharmony_ci        each_value: each_value,
31240681896Sopenharmony_ci        file_pos: file position,
31340681896Sopenharmony_ci        fill_data: data,
31440681896Sopenharmony_ci        image_file_r: read file object,
31540681896Sopenharmony_ci        :return data: Get the file data.
31640681896Sopenharmony_ci        """
31740681896Sopenharmony_ci        block_size, chunk_start, default_zero_block, each_value, \
31840681896Sopenharmony_ci            file_pos, fill_data, image_file_r = args
31940681896Sopenharmony_ci        if file_pos is not None:
32040681896Sopenharmony_ci            file_pos += (each_value - chunk_start) * block_size
32140681896Sopenharmony_ci            image_file_r.seek(file_pos, os.SEEK_SET)
32240681896Sopenharmony_ci            data = image_file_r.read(block_size)
32340681896Sopenharmony_ci        else:
32440681896Sopenharmony_ci            if fill_data == default_zero_block[:4]:
32540681896Sopenharmony_ci                data = default_zero_block
32640681896Sopenharmony_ci            else:
32740681896Sopenharmony_ci                data = None
32840681896Sopenharmony_ci        return data
32940681896Sopenharmony_ci
33040681896Sopenharmony_ci    def range_sha256(self, ranges):
33140681896Sopenharmony_ci        """
33240681896Sopenharmony_ci        range sha256 hash content
33340681896Sopenharmony_ci        :param ranges: ranges value
33440681896Sopenharmony_ci        :return:
33540681896Sopenharmony_ci        """
33640681896Sopenharmony_ci        hash_obj = sha256()
33740681896Sopenharmony_ci        for data in self.__get_blocks_set_data(ranges):
33840681896Sopenharmony_ci            hash_obj.update(data)
33940681896Sopenharmony_ci        return hash_obj.hexdigest()
34040681896Sopenharmony_ci
34140681896Sopenharmony_ci    def write_range_data_2_fd(self, ranges, file_obj):
34240681896Sopenharmony_ci        """
34340681896Sopenharmony_ci        write range data to fd
34440681896Sopenharmony_ci        :param ranges: ranges obj
34540681896Sopenharmony_ci        :param file_obj: file obj
34640681896Sopenharmony_ci        :return:
34740681896Sopenharmony_ci        """
34840681896Sopenharmony_ci        for data in self.__get_blocks_set_data(ranges):
34940681896Sopenharmony_ci            file_obj.write(data)
35040681896Sopenharmony_ci
35140681896Sopenharmony_ci    def get_ranges(self, ranges):
35240681896Sopenharmony_ci        """
35340681896Sopenharmony_ci        get ranges value
35440681896Sopenharmony_ci        :param ranges: ranges
35540681896Sopenharmony_ci        :return: ranges value
35640681896Sopenharmony_ci        """
35740681896Sopenharmony_ci        return [each_data for each_data in self.__get_blocks_set_data(ranges)]
35840681896Sopenharmony_ci
35940681896Sopenharmony_ci    def __get_blocks_set_data(self, blocks_set_data):
36040681896Sopenharmony_ci        """
36140681896Sopenharmony_ci        Get the range data.
36240681896Sopenharmony_ci        """
36340681896Sopenharmony_ci        with open(self.image_path, 'rb') as f_r:
36440681896Sopenharmony_ci            for start, end in blocks_set_data:
36540681896Sopenharmony_ci                diff_value = end - start
36640681896Sopenharmony_ci                idx = bisect.bisect_right(self.offset_index, start) - 1
36740681896Sopenharmony_ci                chunk_start, chunk_len, file_pos, fill_data = \
36840681896Sopenharmony_ci                    self.offset_value_list[idx]
36940681896Sopenharmony_ci
37040681896Sopenharmony_ci                remain = chunk_len - (start - chunk_start)
37140681896Sopenharmony_ci                this_read = min(remain, diff_value)
37240681896Sopenharmony_ci                if file_pos is not None:
37340681896Sopenharmony_ci                    pos = file_pos + ((start - chunk_start) * self.block_size)
37440681896Sopenharmony_ci                    f_r.seek(pos, os.SEEK_SET)
37540681896Sopenharmony_ci                    yield f_r.read(this_read * self.block_size)
37640681896Sopenharmony_ci                else:
37740681896Sopenharmony_ci                    yield fill_data * (this_read * (self.block_size >> 2))
37840681896Sopenharmony_ci                diff_value -= this_read
37940681896Sopenharmony_ci
38040681896Sopenharmony_ci                while diff_value > 0:
38140681896Sopenharmony_ci                    idx += 1
38240681896Sopenharmony_ci                    chunk_start, chunk_len, file_pos, fill_data = \
38340681896Sopenharmony_ci                        self.offset_value_list[idx]
38440681896Sopenharmony_ci                    this_read = min(chunk_len, diff_value)
38540681896Sopenharmony_ci                    if file_pos is not None:
38640681896Sopenharmony_ci                        f_r.seek(file_pos, os.SEEK_SET)
38740681896Sopenharmony_ci                        yield f_r.read(this_read * self.block_size)
38840681896Sopenharmony_ci                    else:
38940681896Sopenharmony_ci                        yield fill_data * (this_read * (self.block_size >> 2))
39040681896Sopenharmony_ci                    diff_value -= this_read