import sys
import os
import hashlib
import errno
import stat
import datetime
def usage():
print('\n Usage: imgcovert.py <cmd> <input> <output>')
print(' <cmd>: sparse or unsparse')
print(' <input>: input image file')
print(' <output>: ouput image file\n')
return
def get_fill_cnt(inputfile: str, blocksize: int) -> int:
flags = os.O_WRONLY
modes = stat.S_IWUSR | stat.S_IRUSR
size = os.path.getsize(inputfile)
fill_cnt = 0
if size % blocksize != 0:
fill_cnt = blocksize - size % blocksize
indata = os.fdopen(os.open(inputfile, flags, modes), 'a')
for _ in range(fill_cnt):
indata.write("\0")
indata.close()
return fill_cnt
def get_gap_blocksize(length: int, size: int) -> int:
if length < size:
cnt = 2
elif length < (size * 2):
cnt = 3
else:
cnt = 4
return cnt
def get_block_cnt(inputfile: str, blocksize: int) -> int:
size = os.path.getsize(inputfile)
if blocksize != 0:
totalblocks = size / blocksize
else:
sys.exit(1)
if (size % blocksize) != 0:
print("len is not eq n * blocksize: ", size, totalblocks)
return totalblocks
def get_crc_value(inputfile: str, blocksize: int):
totalblocks = get_block_cnt(inputfile, blocksize)
with open(inputfile, 'rb') as indata:
ind = 0
md5 = hashlib.md5()
while (ind < totalblocks):
md5.update(indata.read(blocksize))
ind += 1
return md5.hexdigest()
def unsparse(sparseimagefile: str, imagefile: str):
with open(sparseimagefile, 'r') as header:
magic_mumber = header.readline()
version = header.readline()
blocksize = int(header.readline())
total_blocks = int(header.readline())
crc_value = header.readline()
input_crc_value = header.readline()
table_numbers = int(header.readline())
table = []
flags = os.O_CREAT | os.O_RDWR
modes = stat.S_IWUSR | stat.S_IRUSR
i = 0
while (i < table_numbers):
start = int(header.readline())
end = int(header.readline())
table.append([start, end])
i += 1
fill_cnt = int(header.readline())
length = header.tell()
with open(sparseimagefile, 'rb') as inputrow:
inputrow.seek(get_gap_blocksize(length, blocksize) * blocksize)
output = os.fdopen(os.open(imagefile, flags, modes), 'wb')
output.truncate(total_blocks * blocksize)
md5 = hashlib.md5()
for block in table:
cnt = block[1] - block[0]
output.seek(block[0] * blocksize)
indata = inputrow.read(cnt * blocksize)
md5.update(indata)
output.write(indata)
output.close()
print("RawFileCRC: ", get_crc_value(imagefile, blocksize), crc_value)
print("SparseCRC: ", md5.hexdigest(), input_crc_value)
with open(imagefile, 'r+') as output:
output.truncate(total_blocks * blocksize - fill_cnt)
return
def is_empty_block(buff: list, size: int) -> bool:
ind = 0
while (ind < size):
if buff[ind] != 0:
return False
ind += 1
return True
def process_block(inputrow, blocksize, outputtemp, blockid, total_blocks) -> int:
ind = 0
start = -1
table_numbers = 0
while (ind < total_blocks):
indata = inputrow.read(blocksize)
if len(indata) != blocksize:
print("error Block", ind, len(indata))
if is_empty_block(indata, blocksize):
if start != -1:
blockid.append([start, ind])
table_numbers += 1
start = -1
else:
outputtemp.write(indata)
if start == -1:
start = ind
ind += 1
if start != -1:
blockid.append([start, ind])
table_numbers += 1
start = -1
return table_numbers
def get_raw_datafile(imagefile: str, blockid, total_blocks: int, blocksize: int) -> int:
temp_file = imagefile + ".tempfile"
flags = os.O_CREAT | os.O_RDWR
modes = stat.S_IWUSR | stat.S_IRUSR
table_numbers = 0
with open(imagefile, 'rb') as inputrow, os.fdopen(os.open(temp_file, flags, modes), 'wb') as outputtemp:
table_numbers = process_block(inputrow, blocksize, outputtemp, blockid, total_blocks)
return table_numbers
def sparse(imagefile: str, sparseimagefile: str):
temp_file = imagefile + ".tempfile"
magic_number = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
version = 1.0
blocksize = 4096
table_numbers = 0
blockid = []
flags = os.O_CREAT | os.O_RDWR
modes = stat.S_IWUSR | stat.S_IRUSR
fill_cnt = get_fill_cnt(imagefile, blocksize)
total_blocks = get_block_cnt(imagefile, blocksize)
table_numbers = get_raw_datafile(imagefile, blockid, total_blocks, blocksize)
outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'w')
outputrow.write("%s\n" % (magic_number))
outputrow.write("%s\n" % (version))
outputrow.write("%s\n" % (blocksize))
outputrow.write("%s\n" % (int(total_blocks)))
outputrow.write("%s\n" % (get_crc_value(imagefile, blocksize)))
outputrow.write("%s\n" % (get_crc_value(temp_file, blocksize)))
outputrow.write("%s\n" % (table_numbers))
for block in blockid:
outputrow.write("%s\n" % (block[0]))
outputrow.write("%s\n" % (block[1]))
outputrow.write("%s\n" % (int(fill_cnt)))
outputrow.truncate(get_gap_blocksize(outputrow.tell(), blocksize) * blocksize)
outputrow.close()
outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'ab')
outputtemp = os.fdopen(os.open(temp_file, flags, modes), 'rb')
blocknum = get_block_cnt(temp_file, blocksize)
i = 0
while (i < blocknum):
outputrow.write(outputtemp.read(blocksize))
i += 1
outputtemp.close()
outputrow.close()
os.remove(temp_file)
with open(imagefile, 'r+') as output:
output.truncate(int(total_blocks) * int(blocksize) - int(fill_cnt))
if __name__ == '__main__':
if len(sys.argv) != 4:
usage()
sys.exit()
CMD = str(sys.argv[1])
INPUT_FILE = str(sys.argv[2])
OUTPUT_FILE = str(sys.argv[3])
if CMD == 'unsparse':
unsparse(INPUT_FILE, OUTPUT_FILE)
elif CMD == 'sparse':
sparse(INPUT_FILE, OUTPUT_FILE)
else:
usage()