1#!/usr/bin/env python 2# coding: utf-8 3# Copyright (c) 2022 Huawei Device Co., Ltd. 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 16import sys 17import os 18import hashlib 19import errno 20import stat 21import datetime 22 23 24def usage(): 25 print('\n Usage: imgcovert.py <cmd> <input> <output>') 26 print(' <cmd>: sparse or unsparse') 27 print(' <input>: input image file') 28 print(' <output>: ouput image file\n') 29 return 30 31 32def get_fill_cnt(inputfile, blocksize): 33 flags = os.O_WRONLY 34 modes = stat.S_IWUSR | stat.S_IRUSR 35 size = os.path.getsize(inputfile) 36 fill_cnt = 0 37 if size % blocksize != 0: 38 fill_cnt = blocksize - size % blocksize 39 indata = os.fdopen(os.open(inputfile, flags, modes), 'a') 40 for _ in range(fill_cnt): 41 indata.write("\0") 42 indata.close() 43 return fill_cnt 44 45 46def get_gap_blocksize(length, size): 47 if length < size: 48 cnt = 2 49 elif length < (size * 2): 50 cnt = 3 51 else: 52 cnt = 4 53 return cnt 54 55 56def get_block_cnt(inputfile, blocksize): 57 size = os.path.getsize(inputfile) 58 if blocksize != 0: 59 totalblocks = size / blocksize 60 else: 61 sys.exit(1) 62 if (size % blocksize) != 0: 63 print("len is not eq n * blocksize: ", size, totalblocks) 64 return totalblocks 65 66 67def get_crc_value(inputfile, blocksize): 68 totalblocks = get_block_cnt(inputfile, blocksize) 69 with open(inputfile, 'rb') as indata: 70 ind = 0 71 md5 = hashlib.md5() 72 while (ind < totalblocks): 73 md5.update(indata.read(blocksize)) 74 ind += 1 75 return md5.hexdigest() 76 77 78def unsparse(sparseimagefile, imagefile): 79 with open(sparseimagefile, 'r') as header: 80 magic_mumber = header.readline() 81 version = header.readline() 82 blocksize = int(header.readline()) 83 total_blocks = int(header.readline()) 84 crc_value = header.readline() 85 input_crc_value = header.readline() 86 table_numbers = int(header.readline()) 87 table = [] 88 flags = os.O_CREAT | os.O_RDWR 89 modes = stat.S_IWUSR | stat.S_IRUSR 90 i = 0 91 while (i < table_numbers): 92 start = int(header.readline()) 93 end = int(header.readline()) 94 table.append([start, end]) 95 i += 1 96 fill_cnt = int(header.readline()) 97 length = header.tell() 98 with open(sparseimagefile, 'rb') as inputrow: 99 inputrow.seek(get_gap_blocksize(length, blocksize) * blocksize) 100 output = os.fdopen(os.open(imagefile, flags, modes), 'wb') 101 output.truncate(total_blocks * blocksize) 102 md5 = hashlib.md5() 103 for block in table: 104 cnt = block[1] - block[0] 105 output.seek(block[0] * blocksize) 106 indata = inputrow.read(cnt * blocksize) 107 md5.update(indata) 108 output.write(indata) 109 output.close() 110 print("RawFileCRC: ", get_crc_value(imagefile, blocksize), crc_value) 111 print("SparseCRC: ", md5.hexdigest(), input_crc_value) 112 with open(imagefile, 'r+') as output: 113 output.truncate(total_blocks * blocksize - fill_cnt) 114 return 115 116 117def is_empty_block(buff, size): 118 ind = 0 119 while (ind < size): 120 if buff[ind] != 0: 121 return False 122 ind += 1 123 return True 124 125 126def get_raw_datafile(imagefile, blockid, total_blocks, blocksize): 127 temp_file = imagefile + ".tempfile" 128 ind = 0 129 start = -1 130 table_numbers = 0 131 flags = os.O_CREAT | os.O_RDWR 132 modes = stat.S_IWUSR | stat.S_IRUSR 133 134 inputrow = open(imagefile, 'rb') 135 outputtemp = os.fdopen(os.open(temp_file, flags, modes), 'wb') 136 while (ind < total_blocks): 137 indata = inputrow.read(blocksize) 138 if len(indata) != blocksize: 139 print("error Block", ind, len(indata)) 140 if is_empty_block(indata, blocksize) == True: 141 if start != -1: 142 blockid.append([start, ind]) 143 table_numbers += 1 144 start = -1 145 else: 146 outputtemp.write(indata) 147 if start == -1: 148 start = ind 149 ind += 1 150 if start != -1: 151 blockid.append([start, ind]) 152 table_numbers += 1 153 start = -1 154 inputrow.close() 155 outputtemp.close() 156 return table_numbers 157 158 159def sparse(imagefile, sparseimagefile): 160 temp_file = imagefile + ".tempfile" 161 magic_number = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") 162 version = 1.0 163 blocksize = 4096 164 table_numbers = 0 165 blockid = [] 166 flags = os.O_CREAT | os.O_RDWR 167 modes = stat.S_IWUSR | stat.S_IRUSR 168 169 fill_cnt = get_fill_cnt(imagefile, blocksize) 170 total_blocks = get_block_cnt(imagefile, blocksize) 171 table_numbers = get_raw_datafile(imagefile, blockid, total_blocks, blocksize) 172 173# save the header 174 outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'w') 175 outputrow.write("%s\n" % (magic_number)) 176 outputrow.write("%s\n" % (version)) 177 outputrow.write("%s\n" % (blocksize)) 178 outputrow.write("%s\n" % (int(total_blocks))) 179 outputrow.write("%s\n" % (get_crc_value(imagefile, blocksize))) 180 outputrow.write("%s\n" % (get_crc_value(temp_file, blocksize))) 181 outputrow.write("%s\n" % (table_numbers)) 182 for block in blockid: 183 outputrow.write("%s\n" % (block[0])) 184 outputrow.write("%s\n" % (block[1])) 185 outputrow.write("%s\n" % (int(fill_cnt))) 186 outputrow.truncate(get_gap_blocksize(outputrow.tell(), blocksize) * blocksize) 187 outputrow.close() 188 189# append the raw data 190 outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'ab') 191 outputtemp = os.fdopen(os.open(temp_file, flags, modes), 'rb') 192 blocknum = get_block_cnt(temp_file, blocksize) 193 i = 0 194 while (i < blocknum): 195 outputrow.write(outputtemp.read(blocksize)) 196 i += 1 197 outputtemp.close() 198 outputrow.close() 199 os.remove(temp_file) 200 with open(imagefile, 'r+') as output: 201 output.truncate(int(total_blocks) * int(blocksize) - int(fill_cnt)) 202 203 204if __name__ == '__main__': 205 if len(sys.argv) != 4: 206 usage() 207 sys.exit() 208 CMD = str(sys.argv[1]) 209 INPUT_FILE = str(sys.argv[2]) 210 OUTPUT_FILE = str(sys.argv[3]) 211 if CMD == 'unsparse': 212 unsparse(INPUT_FILE, OUTPUT_FILE) 213 elif CMD == 'sparse': 214 sparse(INPUT_FILE, OUTPUT_FILE) 215 else: 216 usage()