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 indata = open(inputfile, 'rb') 70 ind = 0 71 md5 = hashlib.md5() 72 while (ind < totalblocks): 73 md5.update(indata.read(blocksize)) 74 ind += 1 75 indata.close() 76 return md5.hexdigest() 77 78 79def unsparse(sparseimagefile, imagefile): 80 header = open(sparseimagefile, 'r') 81 magic_mumber = header.readline() 82 version = header.readline() 83 blocksize = int(header.readline()) 84 total_blocks = int(header.readline()) 85 crc_value = header.readline() 86 input_crc_value = header.readline() 87 table_numbers = int(header.readline()) 88 table = [] 89 flags = os.O_CREAT | os.O_RDWR 90 modes = stat.S_IWUSR | stat.S_IRUSR 91 i = 0 92 while (i < table_numbers): 93 start = int(header.readline()) 94 end = int(header.readline()) 95 table.append([start, end]) 96 i += 1 97 fill_cnt = int(header.readline()) 98 length = header.tell() 99 header.close() 100 inputrow = open(sparseimagefile, 'rb') 101 inputrow.seek(get_gap_blocksize(length, blocksize) * blocksize) 102 output = os.fdopen(os.open(imagefile, flags, modes), 'wb') 103 output.truncate(total_blocks * blocksize) 104 md5 = hashlib.md5() 105 for block in table: 106 cnt = block[1] - block[0] 107 output.seek(block[0] * blocksize) 108 indata = inputrow.read(cnt * blocksize) 109 md5.update(indata) 110 output.write(indata) 111 output.close() 112 inputrow.close() 113 print("RawFileCRC: ", get_crc_value(imagefile, blocksize), crc_value) 114 print("SparseCRC: ", md5.hexdigest(), input_crc_value) 115 output = open(imagefile, 'r+') 116 output.truncate(total_blocks * blocksize - fill_cnt) 117 output.close() 118 return 119 120 121def is_empty_block(buff, size): 122 ind = 0 123 while (ind < size): 124 if buff[ind] != 0: 125 return False 126 ind += 1 127 return True 128 129 130def get_raw_datafile(imagefile, blockid, total_blocks, blocksize): 131 temp_file = imagefile + ".tempfile" 132 ind = 0 133 start = -1 134 table_numbers = 0 135 flags = os.O_CREAT | os.O_RDWR 136 modes = stat.S_IWUSR | stat.S_IRUSR 137 138 inputrow = open(imagefile, 'rb') 139 outputtemp = os.fdopen(os.open(temp_file, flags, modes), 'wb') 140 while (ind < total_blocks): 141 indata = inputrow.read(blocksize) 142 if len(indata) != blocksize: 143 print("error Block", ind, len(indata)) 144 if is_empty_block(indata, blocksize) == True: 145 if start != -1: 146 blockid.append([start, ind]) 147 table_numbers += 1 148 start = -1 149 else: 150 outputtemp.write(indata) 151 if start == -1: 152 start = ind 153 ind += 1 154 if start != -1: 155 blockid.append([start, ind]) 156 table_numbers += 1 157 start = -1 158 inputrow.close() 159 outputtemp.close() 160 return table_numbers 161 162 163def sparse(imagefile, sparseimagefile): 164 temp_file = imagefile + ".tempfile" 165 magic_number = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") 166 version = 1.0 167 blocksize = 4096 168 table_numbers = 0 169 blockid = [] 170 flags = os.O_CREAT | os.O_RDWR 171 modes = stat.S_IWUSR | stat.S_IRUSR 172 173 fill_cnt = get_fill_cnt(imagefile, blocksize) 174 total_blocks = get_block_cnt(imagefile, blocksize) 175 table_numbers = get_raw_datafile(imagefile, blockid, total_blocks, blocksize) 176 177# save the header 178 outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'w') 179 outputrow.write("%s\n" % (magic_number)) 180 outputrow.write("%s\n" % (version)) 181 outputrow.write("%s\n" % (blocksize)) 182 outputrow.write("%s\n" % (int(total_blocks))) 183 outputrow.write("%s\n" % (get_crc_value(imagefile, blocksize))) 184 outputrow.write("%s\n" % (get_crc_value(temp_file, blocksize))) 185 outputrow.write("%s\n" % (table_numbers)) 186 for block in blockid: 187 outputrow.write("%s\n" % (block[0])) 188 outputrow.write("%s\n" % (block[1])) 189 outputrow.write("%s\n" % (int(fill_cnt))) 190 outputrow.truncate(get_gap_blocksize(outputrow.tell(), blocksize) * blocksize) 191 outputrow.close() 192 193# append the raw data 194 outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'ab') 195 outputtemp = os.fdopen(os.open(temp_file, flags, modes), 'rb') 196 blocknum = get_block_cnt(temp_file, blocksize) 197 i = 0 198 while (i < blocknum): 199 outputrow.write(outputtemp.read(blocksize)) 200 i += 1 201 outputtemp.close() 202 outputrow.close() 203 os.remove(temp_file) 204 output = open(imagefile, 'r+') 205 output.truncate(int(total_blocks) * int(blocksize) - int(fill_cnt)) 206 output.close() 207 208 209if __name__ == '__main__': 210 if len(sys.argv) != 4: 211 usage() 212 sys.exit() 213 CMD = str(sys.argv[1]) 214 INPUT_FILE = str(sys.argv[2]) 215 OUTPUT_FILE = str(sys.argv[3]) 216 if CMD == 'unsparse': 217 unsparse(INPUT_FILE, OUTPUT_FILE) 218 elif CMD == 'sparse': 219 sparse(INPUT_FILE, OUTPUT_FILE) 220 else: 221 usage()