#!/usr/bin/python #=========================================================================== # This script parses "partition.xml" and creates numerous output files # specifically, partition.bin, rawprogram.xml # REFERENCES # $Header: //components/rel/boot.bf/3.1.1/boot_images/core/storage/tools/ptool/msp.py#1 $ # $DateTime: 2014/09/09 14:47:07 $ # $Author: pwbldsvc $ # when who what, where, why # -------- --- ------------------------------------------------------- # 2012-03-29 ah Warning message displayed *last* now if warnings happen # 2012-03-12 ah Better warning if attempting to write to a PHY partition other than 0 # 2012-02-24 ah Much cleaner code - fixes for configurable sector sizes # 2011-10-19 ah Allow patching of rawprogram files for PHY partitions other than 0 # 2011-09-23 ah Patching now supports NumPartitions that isn't fixed to 128 # 2011-09-21 ah added "msp failed" messages # 2011-09-07 ah log name change - fixes for Linux os.system # 2011-08-17 ah If testsparse.py exists, performing additional safety check # 2011-08-12 ah Better use of noprompt option (-n) # 2011-08-09 ah -t option specifies output directory for files # 2011-08-01 ah Bug fix whhen patching DISK # 2011-07-26 ah Much better error messages # 2011-07-21 ah Major changes, now using getopt(), patching/writing can be all one step # 2011-07-13 ah Better error messages for user experience # 2011-06-01 ah Improved singleimage support for GPT # 2011-05-26 ah Handles sparse files and "zeroout" tag # 2011-05-17 ah Removed auto-patching MBR - must manually patch just like in GPT # 2011-05-02 ah No longer querying for /proc/partitions by default (user must ask now) # 2011-03-22 ah Enforcing that msp can't patch/write to partitions other than USER # 2011-03-22 ah Fixed memory bug with large file writing, fixed bug with SINGLEIMAGE creation (i.e. append) # 2011-03-16 ah Fixed memory bug with large file patching and read/write permissions for # SCons and singleimage.bin, Now need user input when patching DISK, "sync" command for linux # 2011-03-09 ah Replaces msp.exe - compatible with Linux and Windows # does not need cygwin, cleaner code, more error checking # 2011-02-14 ah Changed 'dd' to 'cat' to avoid error happening on Win7 # 2010-10-26 ah Now "patches" partition table on the fly, adds warnings before nuking drive # 2010-10-22 ah Used to replace msp.exe - can program cards and singleimages.bin # Copyright (c) 2007-2010, 2017 Qualcomm Technologies, Inc. # All Rights Reserved. # Confidential and Proprietary - Qualcomm Technologies, Inc. # ===========================================================================*/ import struct, os, sys, getopt import math,traceback import re import codecs from types import * import time from time import sleep import subprocess as sub from time import strftime, localtime from xml.etree import ElementTree as ET #from elementtree.ElementTree import ElementTree from xml.etree.ElementTree import Element, SubElement, Comment, tostring from xml.dom import minidom DiskSectors = 0 BLOCK_SIZE = 0x200 TABLE_ENTRY_0 = 0x1BE TABLE_ENTRY_1 = 0x1CE TABLE_ENTRY_2 = 0x1DE TABLE_ENTRY_3 = 0x1EE EMMCBLD_MAX_DISK_SIZE_IN_BYTES = (64*1024*1024*1024*1024) # 64TB - Terabytes MAX_FILE_SIZE_BEFORE_SPLIT = (10*1024*1024) #MAX_FILE_SIZE_BEFORE_SPLIT = (2048) # testing purposes ExtendedPartitionBegins = 0 bytes_read = 0 FileNotFoundShowWarning = 0 SECTOR_SIZE = 512 disk_size = None def reset_device_log(): try: log_fp = open('log_msp.txt', 'w') except Exception, x: print "\nERROR: Can't create the file log_msp.txt" print "REASON: %s" % x print "This might be because the file is open and locked" print "Or because you are running this from a read-only location\n" sys.exit() print "\nCREATED log_msp.txt\n" log_fp.close() def device_log(message, display=1): try: log_fp = open('log_msp.txt', 'a') except Exception, x: print "ERROR: could not open 'log_msp.txt'" print "REASON: %s" % x return try: log_fp.write("%s %s\n" % (strftime("%H:%M:%S", localtime()),message)) except Exception, x: print "ERROR: could not write to 'log_msp.txt'" print "REASON: %s" % x return if display==1: print message log_fp.close() def ReadSectors(opfile,NumSectors): try: return opfile.read(NumSectors*SECTOR_SIZE) except Exception, x: PrintBigError("Could not complete the read") device_log("REASON: %s" % (x)) reset_device_log() device_log("\nmsp.py is running from CWD: %s\n" % os.getcwd()) def EnsureDirectoryExists(filename): dir = os.path.dirname(filename) try: os.stat(dir) except Exception, x: os.makedirs(dir) def PrintBigWarning(sz): device_log("\t _ ") device_log("\t (_) ") device_log("\t__ ____ _ _ __ _ __ _ _ __ __ _ ") device_log("\t\\ \\ /\\ / / _` | '__| '_ \\| | '_ \\ / _` |") device_log("\t \\ V V / (_| | | | | | | | | | | (_| |") device_log("\t \\_/\\_/ \\__,_|_| |_| |_|_|_| |_|\\__, |") device_log("\t __/ |") device_log("\t |___/ \n") if len(sz)>0: device_log(sz) def PrintBigError(sz): device_log("\t _________________ ___________ ") device_log("\t| ___| ___ \\ ___ \\ _ | ___ \\") device_log("\t| |__ | |_/ / |_/ / | | | |_/ /") device_log("\t| __|| /| /| | | | / ") device_log("\t| |___| |\\ \\| |\\ \\\\ \\_/ / |\\ \\ ") device_log("\t\\____/\\_| \\_\\_| \\_|\\___/\\_| \\_|\n") device_log("\nERROR - ERROR - ERROR - ERROR - ERROR\n") if len(sz)>0: device_log(sz) device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit(1) def PrettyPrintArray(bytes_read): Bytes = struct.unpack("%dB" % len(bytes_read),bytes_read) for k in range(len(Bytes)/SECTOR_SIZE): print "-"*78 for j in range(32): for i in range(16): sys.stdout.write("%.2X " % Bytes[i+j*16]) sys.stdout.write("\t") for i in range(16): sys.stdout.write("%c" % Bytes[i+j*16]) print " " print " " def external_call(command, capture_output=True): errors = None output = None try: if capture_output: if sys.platform.startswith("linux"): p = sub.Popen(command, stdout=sub.PIPE, stderr=sub.PIPE, shell=True) else: p = sub.Popen(command, stdout=sub.PIPE, stderr=sub.PIPE) output, errors = p.communicate() else: os.system(command) except Exception, e: print output device_log("Error executing command '%s' (%s)" % (str(command), e)) #clean_up() device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit(1) finally: #if not output is None: # device_log("Result: %s" % output) if (not errors is None) and (not errors == ""): device_log("Process stderr: %s" % errors) return output def HandleNUM_DISK_SECTORS(field): if type(field) is not str: #print "returning since this is not a string" return field m = re.search("NUM_DISK_SECTORS-(\d+)", field) if type(m) is not NoneType: if DiskSizeInBytes > 0 : field = int((DiskSizeInBytes/SECTOR_SIZE)-int(m.group(1))) # here I know DiskSizeInBytes else: field = int((EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE)+int(m.group(1))) # I make this a gigantic number for sorting (PLUS not MINUS here) if type(field) is not str: return field m = re.search("NUM_DISK_SECTORS", field) if type(m) is not NoneType: if DiskSizeInBytes > 0 : field = int((DiskSizeInBytes/SECTOR_SIZE)) else: field = int((EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE)) if type(field) is not str: return field field = int(field) return field def ReturnParsedValues(element): global SECTOR_SIZE MyDict = { 'filename':'','file_sector_offset':'0','label':'','num_partition_sectors':'0', 'physical_partition_number':'0','size_in_KB':'0','sparse':'false','start_byte_hex':'0x0','start_sector':'0', 'function':'none','arg0':'0','arg1':'0','value':'0','byte_offset':'0','size_in_bytes':'4','SECTOR_SIZE_IN_BYTES':'512' } for name, value in element.items(): ##device_log("\t\tName: '%s'=>'%s' " % (name,value)) MyDict[name]=value if 'SECTOR_SIZE_IN_BYTES' in MyDict: SECTOR_SIZE = int(MyDict['SECTOR_SIZE_IN_BYTES']) if 'num_sectors' in MyDict: ## Legacy name used in original partition.xml MyDict['num_partition_sectors'] = MyDict['num_sectors'] if 'offset' in MyDict: ## Legacy name used in original partition.xml MyDict['file_sector_offset'] = MyDict['offset'] MyDict['num_partition_sectors'] = HandleNUM_DISK_SECTORS(MyDict['num_partition_sectors']) # Means field can have 'NUM_DISK_SECTORS-5.' type of contents MyDict['start_sector'] = HandleNUM_DISK_SECTORS(MyDict['start_sector']) # Means field can have 'NUM_DISK_SECTORS-5.' type of contents MyDict['file_sector_offset'] = HandleNUM_DISK_SECTORS(MyDict['file_sector_offset']) # Means field can have 'NUM_DISK_SECTORS-5.' type of contents MyDict['physical_partition_number'] = int(MyDict['physical_partition_number']) MyDict['byte_offset'] = int(float(MyDict['byte_offset'])) MyDict['size_in_bytes'] = int(float(MyDict['size_in_bytes'])) # These only affect patching m = re.search("CRC32\((\d+).?,(\d+).?\)", MyDict['value']) if type(m) is not NoneType: MyDict['value'] = 0 MyDict['function'] = "CRC32" MyDict['arg0'] = int(float(m.group(1))) # start_sector MyDict['arg1'] = int(float(m.group(2))) # len_in_bytes else: ## above didn't match, so try this m = re.search("CRC32\((NUM_DISK_SECTORS-\d+).?,(\d+).?\)", MyDict['value']) if type(m) is not NoneType: MyDict['value'] = 0 MyDict['function'] = "CRC32" MyDict['arg0'] = int(float( HandleNUM_DISK_SECTORS(m.group(1)) )) # start_sector MyDict['arg1'] = int(float(m.group(2))) # len_in_bytes MyDict['value'] = HandleNUM_DISK_SECTORS(MyDict['value']) # Means field can have 'NUM_DISK_SECTORS-5.' type of contents return MyDict def ParseXML(xml_filename): ## this function updates all the global arrays global WriteArray,PatchArray,ReadArray,MinDiskSizeInSectors root = ET.parse( xml_filename ) #Create an iterator iter = root.getiterator() for element in iter: #device_log("\nElement: %s" % element.tag) # Parse out include files if element.tag=="read": if element.keys(): ReadArray.append( ReturnParsedValues(element) ) else: print "ERROR: Your tag is not formed correctly\n" sys.exit(1) elif element.tag=="program": if element.keys(): WriteArray.append( ReturnParsedValues(element) ) else: print "ERROR: Your tag is not formed correctly\n" sys.exit(1) elif element.tag=="patch": if element.keys(): PatchArray.append( ReturnParsedValues(element) ) else: print "ERROR: Your tag is not formed correctly\n" sys.exit(1) #print "\n\n-------------READ -----------------------------------\n\n\n" #for Read in ReadArray: # print Read #print "\n\n-------------WRITE -----------------------------------\n\n\n" #for Write in WriteArray: # print Write #print "\n\n-------------PATCH -----------------------------------\n\n\n" #for Patch in PatchArray: # print Patch #print "------------------------------------------------\n\n\n" def ReturnArrayFromCommaSeparatedList(sz): temp = re.sub("\s+|\n"," ",sz) temp = re.sub("^\s+","",temp) temp = re.sub("\s+$","",temp) return temp.split(',') def find_file(filename, search_paths): device_log("\n\n\tLooking for '%s'"%filename) device_log("\t"+"-"*40) for x in search_paths: #device_log("\tSearching '%s'"%x) temp = os.path.join(x, filename) device_log("\tSearching for **%s**" % temp) if os.path.exists(temp): device_log("\n\t**Found %s (%i bytes)" % (temp,os.path.getsize(temp))) return temp ## search cwd last device_log("\tSearching '%s'"%os.getcwd()) if os.path.exists(filename): device_log("\n\t**Found %s (%i bytes)" % (filename,os.path.getsize(filename))) return filename device_log("\tCound't find file OR perhaps you don't have permission to run os.stat() on this file\n") return None def DoubleCheckDiskSize(): if os.path.basename(Filename)=="singleimage.bin": return if noprompt is True: return if sys.platform.startswith("win"): device_log("\n\nTesting of OS detected disk size correctly...\n") Size = AvailablePartitions[Filename] TrueSize = Size count = 0 # Windows workaround to get the correct number of sectors fp = open(Filename, 'rb') fp.seek(int(Size)) try: while True: fp.read(SECTOR_SIZE) if count % 128 == 0: sys.stdout.write(".") count += 1 except Exception, x: TrueSize = fp.tell() fp.close() if TrueSize != Size and Size<=(64*1024*1024*1024): PrintBigWarning(" ") device_log("NOTE: This OS has *not* detected the correct size of the disk") device_log("\nSECTORS: Size=%i, TrueSize=%i, Difference=%i sectors (%s)" % (Size/SECTOR_SIZE,TrueSize/SECTOR_SIZE,(TrueSize-Size)/SECTOR_SIZE,ReturnSizeString(TrueSize-Size))) device_log("This means the backup GPT header will *not* be located at the true last sector") device_log("This is only an issue if you care :) It will be off by %s" % ReturnSizeString(TrueSize-Size)) device_log("\nNOTE: This program *can't* write to the end of the disk, OS limitation") else: device_log("\n\nAll is well\n") def PerformRead(): global ReadArray, search_paths, interactive, Filename device_log("\t _ _ ") device_log("\t | (_) ") device_log("\t _ __ ___ __ _ __| |_ _ __ __ _ ") device_log("\t| '__/ _ \\/ _` |/ _` | | '_ \\ / _` |") device_log("\t| | | __/ (_| | (_| | | | | | (_| |") device_log("\t|_| \\___|\\__,_|\\__,_|_|_| |_|\\__, |") device_log("\t __/ |") device_log("\t |___/ ") CurrentSector = 0 for ReadCmd in ReadArray: ## device_log("\nRead %d sectors (%s) from sector %d and save to '%s'\n" % (ReadCmd['num_partition_sectors'],ReturnSizeString(ReadCmd['num_partition_sectors']*SECTOR_SIZE),ReadCmd['start_sector'],ReadCmd['filename'])) if ReadCmd['physical_partition_number']!=0: ## msp tool can only write to PHY partition 0 device_log("WARNING '%s' for physical_partition_number=%d (only 0 is accessible) THIS MIGHT FAIL" % (ReadCmd['filename'],ReadCmd['physical_partition_number'])) if len(ReadCmd['filename'])==0: device_log("WARNING filename was not specified, skipping this read") continue if ReadCmd['num_partition_sectors']==0: device_log("WARNING num_partition_sectors was 0, skipping this read") continue if interactive is True: device_log("Do you want to perform this read? (Y|n|q)",0) loadfile = raw_input("Do you want to perform this read? (Y|n|q)") if loadfile=='Y' or loadfile=='y' or loadfile=='': pass elif loadfile=='q' or loadfile=='Q': device_log("\nmsp.py exiting by user pressing Q (quit) - Log is log_msp.txt\n\n") sys.exit() else: continue try: if os.path.basename(Filename)=="singleimage.bin": Filename = OutputFolder+os.path.basename(Filename) opfile = open(Filename, "r+b") ## Filename = '\\.\PHYSICALDRIVE1' #device_log("Opened '%s', cwd=%s" % (Filename, os.getcwd() )) except: PrintBigError("") device_log("Could not open Filename=%s, cwd=%s" % (Filename, os.getcwd() )) if sys.platform.startswith("linux"): print "\t _ ___" print "\t | | |__ \\" print "\t ___ _ _ __| | ___ ) |" print "\t/ __| | | |/ _` |/ _ \\ / /" print "\t\\__ \\ |_| | (_| | (_) |_|" print "\t|___/\\__,_|\\__,_|\\___/(_)\n" device_log("\tDon't forget you need SUDO with this program") device_log("\tsudo python msp.py partition.xml /dev/sdx (where x is the device node)") else: device_log("\t ___ _ _ _ _ _ ___ ") device_log("\t / _ \\ | | (_) (_) | | | | |__ \\ ") device_log("\t/ /_\\ \\ __| |_ __ ___ _ _ __ _ ___| |_ _ __ __ _| |_ ___ _ __ ) |") device_log("\t| _ |/ _` | '_ ` _ \\| | '_ \\| / __| __| '__/ _` | __|/ _ \\| '__| / / ") device_log("\t| | | | (_| | | | | | | | | | | \\__ \\ |_| | | (_| | |_| (_) | | |_| ") device_log("\t\\_| |_/\\__,_|_| |_| |_|_|_| |_|_|___/\\__|_| \\__,_|\\__|\\___/|_| (_) \n\n") device_log("\n"+"-"*78) device_log("\tThis program needs to be run as Administrator!!") device_log("-"*78+"\n") device_log("-"*78) device_log("\tTo fix, you must open a CMD prompt with \"Run as administrator\"") device_log("-"*78+"\n") device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit() device_log("\n\tOpened %s" % Filename) if ReadCmd['start_sector'] < 0: device_log("start sector is less than 0 - skipping this instruction, most likely for GPT HACK") continue if ReadCmd['start_sector'] > int(DiskSizeInBytes/SECTOR_SIZE): PrintBigError("") device_log("\nERROR: Start sector (%i) is BIGGER than the disk (%i sectors)" % (ReadCmd['start_sector'],int(DiskSizeInBytes/SECTOR_SIZE))) device_log("\nERROR: Your device is TOO SMALL to handle this partition info") device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit(1) try: opfile.seek(int(ReadCmd['start_sector']*SECTOR_SIZE)) except: PrintBigError("Could not move to sector %d on %s" % (ReadCmd['start_sector'],Filename)) device_log("\tMoved to sector %d on %s" % (ReadCmd['start_sector'],Filename)) size = int(ReadCmd['num_partition_sectors']*SECTOR_SIZE) device_log("\tAttempting to read %i bytes" % (size)) try: bytes_read = opfile.read(size) except: PrintBigError("Could not read %d bytes in %s" % (size,ReadCmd['filename'])) device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit() try: opfile.close() except: device_log("\tWARNING: Can't close the file?") #sys.exit() pass try: ipfile = open(ReadCmd['filename'], "wb") except: PrintBigError("Could not create filename=%s, cwd=%s" % (ReadCmd['filename'], os.getcwd() )) sys.exit(1) try: ipfile.write(bytes_read) except: PrintBigError("") device_log("Could not write to %s" % (ReadCmd['filename'])) sys.exit(1) try: ipfile.close() except: device_log("\tWARNING: Can't close the file?") #sys.exit() pass device_log("\nDone Reading Files\n") def PerformWrite(): global WriteSorted, LoadSubsetOfFiles, search_paths, interactive, Filename ThereWereWarnings = 0 device_log("\t _ ") device_log("\t (_) ") device_log("\t _ __ _ __ ___ __ _ _ __ __ _ _ __ ___ _ __ ___ _ _ __ __ _ ") device_log("\t| '_ \\| '__/ _ \\ / _` | '__/ _` | '_ ` _ \\| '_ ` _ \\| | '_ \\ / _` |") device_log("\t| |_) | | | (_) | (_| | | | (_| | | | | | | | | | | | | | | | (_| |") device_log("\t| .__/|_| \\___/ \\__, |_| \\__,_|_| |_| |_|_| |_| |_|_|_| |_|\\__, |") device_log("\t| | __/ | __/ |") device_log("\t|_| |___/ |___/ ") CurrentSector = 0 for Write in WriteSorted: # Here Write is a *sorted* entry from rawprogram.xml if Write['physical_partition_number']!=0: ## msp tool can only write to PHY partition 0 PrintBigWarning("WARNING: '%s' for physical_partition_number=%d (only 0 is accessible) THIS MIGHT FAIL" % (Write['filename'],Write['physical_partition_number'])) device_log("WARNING '%s' for physical_partition_number=%d (only 0 is accessible) THIS MIGHT FAIL" % (Write['filename'],Write['physical_partition_number'])) device_log("WARNING '%s' for physical_partition_number=%d (only 0 is accessible) THIS MIGHT FAIL" % (Write['filename'],Write['physical_partition_number'])) device_log("WARNING '%s' for physical_partition_number=%d (only 0 is accessible) THIS MIGHT FAIL" % (Write['filename'],Write['physical_partition_number'])) if len(Write['filename'])==0: continue if LoadSubsetOfFiles is True: # To be here means user only wants some of the files loaded from rawprogram0.xml if Write['filename'] in file_list: #device_log("LOAD: '%s' was specified to be programmed" % Write['filename']) pass else: #device_log("SKIPPING: '%s', it was not specified to be programmed" % Write['filename']) continue device_log("\n"+"="*78) device_log("="*78) FileWithPath = find_file(Write['filename'], search_paths) size=0 if FileWithPath is not None: size = os.path.getsize(FileWithPath) # to be here the rawprogram.xml file had to have a "filename" entry device_log("\n'%s' (%s) to partition '%s' at sector %d (at %s)\n" % (Write['filename'],ReturnSizeString(size),Write['label'],Write['start_sector'],ReturnSizeString(Write['start_sector']*SECTOR_SIZE))) if interactive is True: device_log("Do you want to load this file? (Y|n|q)",0) loadfile = raw_input("Do you want to load this file? (Y|n|q)") if loadfile=='Y' or loadfile=='y' or loadfile=='': pass elif loadfile=='q' or loadfile=='Q': device_log("\nmsp.py exiting by user pressing Q (quit) - Log is log_msp.txt\n\n") sys.exit() else: continue while FileWithPath is None: FileNotFoundShowWarning = 1 device_log("\t______ _ _ ___ ") device_log("\t| ___ \\ | | | | |__ \\ ") device_log("\t| |_/ /__ _| |_| |__ ) |") device_log("\t| __// _` | __| '_ \\ / / ") device_log("\t| | | (_| | |_| | | | |_| ") device_log("\t\\_| \\__,_|\\__|_| |_| (_) \n\n") device_log("WARNING: '%s' listed in '%s' not found\n" % (Write['filename'],rawprogram_filename)) if noprompt is True: device_log("\nUse option -s c:\\path1 -s c:\\path2 etc") PrintBigError("") device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit(1) device_log("Please provide a path for this file") device_log("Ex. \\\\somepath\\folder OR c:\\somepath\\folder\n") device_log("Enter PATH or Q to quit? ",0) temppath = raw_input("Enter PATH or Q to quit? ") if temppath=='Q' or temppath=='q' or temppath=='': device_log("\nmsp.py exiting - user pressed Q (quit) - Log is log_msp.txt\n\n") sys.exit() device_log("\n") FileWithPath = find_file(Write['filename'], [temppath]) size=0 if FileWithPath is not None: size = os.path.getsize(FileWithPath) device_log("\nShould this path be used to find other files? (Y|n|q)",0) temp = raw_input("\nShould this path be used to find other files? (Y|n|q)") if temp=='Q' or temp=='q': device_log("\nmsp.py exiting - user pressed Q (quit) - Log is log_msp.txt\n\n") sys.exit() elif temp=='Y' or temp=='y' or temp=='': search_paths.append(temppath) device_log("\n") if noprompt is False: if size==0: device_log("WARNING: This file is 0 bytes, do you want to load this file? (y|N|q)",0) loadfile = raw_input("WARNING: This file is 0 bytes, do you want to load this file? (y|N|q)") if loadfile=='N' or loadfile=='n' or loadfile=='': continue elif loadfile=='q' or loadfile=='Q': device_log("\nmsp.py exiting - user pressed Q (quit) - Log is log_msp.txt\n\n") sys.exit() else: pass if Write['num_partition_sectors']==0: Write['num_partition_sectors'] = int(size/SECTOR_SIZE) if size%SECTOR_SIZE != 0: Write['num_partition_sectors']+=1 # not an even multiple of SECTOR_SIZE, so ++ ##device_log("At start_sector %i (%.2fKB) write %i sectors" % (Write['start_sector'],Write['start_sector']*SECTOR_SIZE/1024.0,Write['num_partition_sectors'])) ##device_log("\tsize of \"%s\" is %i bytes" % (Write['filename'],size)) ##device_log("\tsize of partition listed in in \"%s\" is %i bytes" % (rawprogram_filename,Write['num_partition_sectors']*SECTOR_SIZE)) ## This below happens on files like partition0.bin, where they hold the entire partition table, ## but, only MBR is meant to be written, thus partition0.bin is 9 sectors but MBR is only 1 sector if size > (Write['num_partition_sectors']*SECTOR_SIZE): PrintBigWarning("WARNING: This complete image of size %i bytes is too big to fit on this partition of size %i bytes" % (size,Write['num_partition_sectors']*SECTOR_SIZE)) PrintBigWarning("WARNING: Only the first %i bytes of your image will be written\n\n" % (Write['num_partition_sectors']*SECTOR_SIZE)) size = Write['num_partition_sectors']*SECTOR_SIZE ThereWereWarnings = 1 ##device_log("\tAttempting to read %i bytes from \n\t\"%s\" at file_sector_offset %i" % (size,Write['filename'],Write['file_sector_offset'])) #os.getcwd()+"\\"+ try: ipfile = open(FileWithPath, "rb") except Exception, x: PrintBigError("Could not open FileWithPath=%s, cwd=%s\nREASON: %s" % (Write['filename'], os.getcwd(), x )) device_log("\tAttempting to move to sector %i (file file_sector_offset) in %s" % (Write['file_sector_offset'],Write['filename'])) try: ipfile.seek(int(Write['file_sector_offset']*SECTOR_SIZE)) except Exception, x: PrintBigError("Could not move to sector %d in %s\nREASON: %s" % (Write['file_sector_offset'],Write['filename'],x)) device_log("\tAttempting to read %i bytes" % (size)) try: if size int(DiskSizeInBytes/SECTOR_SIZE): PrintBigError("") device_log("\nERROR: Start sector (%i) is BIGGER than the disk (%i sectors)" % (Write['start_sector'],int(DiskSizeInBytes/SECTOR_SIZE))) device_log("\nERROR: Your device is TOO SMALL to handle this partition info") device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit(1) if int(Write['start_sector']) > 0: try: opfile.seek(int(Write['start_sector']*SECTOR_SIZE)) except Exception, x: PrintBigError("Could not move to sector %d on %s" % (Write['start_sector'],Filename)) device_log("REASON: %s" % (x)) device_log("\tMoved to sector %d on %s" % (Write['start_sector'],Filename)) CurrentSector = Write['start_sector'] ##device_log("size=",size) ##device_log("MAX_FILE_SIZE_BEFORE_SPLIT=",MAX_FILE_SIZE_BEFORE_SPLIT) CurrentSector += (size/SECTOR_SIZE) if size0: Remainder=1 device_log("\nNeed to break up this file, will loop %d times writing %i bytes each time" % (NumLoop+Remainder,MAX_FILE_SIZE_BEFORE_SPLIT)) TempSize=0 for a in range(NumLoop): #device_log("read %i bytes" % MAX_FILE_SIZE_BEFORE_SPLIT) try: bytes_read = ipfile.read(MAX_FILE_SIZE_BEFORE_SPLIT) except Exception, x: PrintBigError("Could not read from %s\nREASON: %s" % (FileWithPath,x)) ##device_log("\n\t%i) Packing %i Bytes [%i:%i]" % (a+1,MAX_FILE_SIZE_BEFORE_SPLIT,TempSize,TempSize+MAX_FILE_SIZE_BEFORE_SPLIT)) ##bytes_read = struct.pack("%dB" % MAX_FILE_SIZE_BEFORE_SPLIT, *Bytes[TempSize:(TempSize+MAX_FILE_SIZE_BEFORE_SPLIT)]) device_log("\t%.2i) Writing %i Bytes [%i:%i]" % (a+1,MAX_FILE_SIZE_BEFORE_SPLIT,TempSize,TempSize+MAX_FILE_SIZE_BEFORE_SPLIT)) try: opfile.write(bytes_read) except Exception, x: PrintBigError("Could not write to %s\nREASON: %s" % (Filename,x)) TempSize += MAX_FILE_SIZE_BEFORE_SPLIT ##device_log("Out of loop") a+=1 if Remainder == 1: # Need to PAD the file to be a multiple of SECTOR_SIZE bytes too #device_log("\n\t%i) Packing %i Bytes [%i:%i]" % (a,(len(Bytes)-TempSize),TempSize,len(Bytes))) #bytes_read = struct.pack("%dB" % (len(Bytes)-TempSize), *Bytes[TempSize:len(Bytes)]) device_log("\t%.2i) Writing %i Bytes [%i:%i]" % (a+1,(size-TempSize),TempSize,size)) try: bytes_read = ipfile.read(size-TempSize) except Exception, x: PrintBigError("Could not read from %s\nREASON: %s" % (FileWithPath,x)) ##device_log("len(bytes_read)=",len(bytes_read)) Remainder = len(bytes_read)%SECTOR_SIZE if Remainder != 0: device_log("\tbytes_read is not a multiple of SECTOR_SIZE (%d bytes), appending zeros" % SECTOR_SIZE) Bytes = struct.unpack("%dB" % len(bytes_read),bytes_read) ## unpack returns list, so get index 0 Temp = list(Bytes) + [0x00]*(SECTOR_SIZE-Remainder) # concat TotalSize = len(Temp) bytes_read = struct.pack("%dB" % TotalSize, *Temp) device_log("\tNow len(bytes_read)=%d" % len(bytes_read)) # At this point bytes_read is a multiple of SECTOR_SIZE #device_log("This is the final write") try: opfile.write(bytes_read) except Exception, x: PrintBigError("Could not write to %s\nREASON: %s" % (Filename,x)) ipfile.close() if os.path.basename(Filename)=="singleimage.bin": device_log("\tSingleImageSize %i bytes (%i sectors)" % (CurrentSector*SECTOR_SIZE,CurrentSector)) device_log("\tCurrentSector=%i" % CurrentSector) device_log("\tDiskSize=%i sectors" % int(DiskSizeInBytes/SECTOR_SIZE)) #device_log("\tWrote %d bytes at sector %d on %s" % (len(bytes_read),Write['start_sector'],Filename)) try: ##print opfile opfile.close() except Exception, x: device_log("\tWARNING: Can't close the file?") device_log("REASON: %s" % (x)) #sys.exit() pass device_log("\n\tWritten with") device_log("\tpython dd.py --if=%s --bs=%i --count=%i --seek=%i --of=%s" % (FileWithPath,SECTOR_SIZE,int((size-1)/SECTOR_SIZE)+1,Write['start_sector'],Filename)) device_log("\n\tVerify with") device_log("\tpython dd.py --if=%s --bs=%i --count=%i --skip=%i --of=dump.bin" % (Filename,SECTOR_SIZE,int((size-1)/SECTOR_SIZE)+1,Write['start_sector'])) device_log("\n\tSuccessfully wrote \"%s\" (%s payload) to %s" % (Write['filename'],ReturnSizeString(size),Filename)) #raw_input("Enter something: ") #if Write['filename']=="sbl3.mbn": # sys.exit() if os.path.basename(Filename)=="singleimage.bin": if CurrentSector < int(DiskSizeInBytes/SECTOR_SIZE): device_log("\n\nSingleImageSize %i bytes (%i sectors)" % (CurrentSector*SECTOR_SIZE,CurrentSector)) device_log("CurrentSector=%i" % CurrentSector) device_log("DiskSizeInBytes=%i sectors" % int(DiskSizeInBytes/SECTOR_SIZE)) device_log("\nDone Writing Files\n") return ThereWereWarnings def GetPartitions(): global Devices,AvailablePartitions if sys.platform.startswith("linux"): #device_log("This is a linux system since sys.platform='%s'" % sys.platform) device_log("-"*78 ) device_log("\tRemember - DON'T FORGET SUDO") device_log("\tRemember - DON'T FORGET SUDO") device_log("\tRemember - DON'T FORGET SUDO") device_log("-"*78+"\n") os.system("cat /proc/partitions > temp_partitions.txt") IN = open("temp_partitions.txt") output = IN.readlines() for line in output: #print line m = re.search("(\d+) (sd[a-z])$", line) if type(m) is not NoneType: Size = int(m.group(1)) Device = "/dev/"+m.group(2) #device_log("%s\tSize=%d,%.1fMB (%.2fGB) (%iKB)" % (Device,Size,int(Size)/1024.0,int(Size)/(1024.0*1024.0),int(Size)) AvailablePartitions[Device] = Size*1024.0 # linux reports in terms of 1024, else: ##device_log("This is a windows system since sys.platform='%s'" % sys.platform device_log("\t ___ _ _ _ _ _ ___ ") device_log("\t / _ \\ | | (_) (_) | | | | |__ \\ ") device_log("\t/ /_\\ \\ __| |_ __ ___ _ _ __ _ ___| |_ _ __ __ _| |_ ___ _ __ ) |") device_log("\t| _ |/ _` | '_ ` _ \\| | '_ \\| / __| __| '__/ _` | __|/ _ \\| '__| / / ") device_log("\t| | | | (_| | | | | | | | | | | \\__ \\ |_| | | (_| | |_| (_) | | |_| ") device_log("\t\\_| |_/\\__,_|_| |_| |_|_|_| |_|_|___/\\__|_| \\__,_|\\__|\\___/|_| (_) \n") device_log("-"*78 ) device_log("\tRemember - Under Win7 you must run this as Administrator") device_log("-"*78) response = external_call('wmic DISKDRIVE get DeviceID, MediaType, Model, Size') m = re.search("Access is denied", response) if type(m) is not NoneType: PrintBigError("This computer does not have correct privileges, you need administrator group privilege\n") device_log("\n"+response) response = response.replace('\r', '').strip("\n").split("\n")[1:] for line in response: m = re.search("(PHYSICALDRIVE\d+).+ (\d+) ", line) if type(m) is not NoneType: Size = int(m.group(2)) # size in bytes Device = "\\\\.\\"+m.group(1) # \\.\PHYSICALDRIVE1 AvailablePartitions[Device] = Size Devices = AvailablePartitions.keys() Devices.sort() device_log("--------------------------------Partitions Detected--------------------------------------") for device in Devices: value = AvailablePartitions[device] if value/(1024.0*1024.0*1024.0) > 31.0: device_log("%s %s\tsectors:%i <--- Not likely an SD card, careful!" % (device,ReturnSizeString(value),value/SECTOR_SIZE) ) else: device_log("%s %s\tsectors:%i" % (device,ReturnSizeString(value),value/SECTOR_SIZE)) device_log("-"*78+"\n") def PerformPatching(): global PatchArray,Patching device_log("\t _ _ _ ") device_log("\t | | | | (_) ") device_log("\t _ __ __ _| |_ ___| |__ _ _ __ __ _ ") device_log("\t| '_ \\ / _` | __|/ __| '_ \\| | '_ \\ / _` |") device_log("\t| |_) | (_| | |_| (__| | | | | | | | (_| |") device_log("\t| .__/ \\__,_|\\__|\\___|_| |_|_|_| |_|\\__, |") device_log("\t| | __/ |") device_log("\t|_| |___/ ") var = 'Y' if Patching == "DISK": var = 'N' ## user must authorize this ## PATCHING HAPPENS HERE - PATCHING HAPPENS HERE - PATCHING HAPPENS HERE for Patch in PatchArray: if Patch['physical_partition_number']!=0: ## msp tool can only write to PHY partition 0 device_log("WARNING '%s' for physical_partition_number=%d (only 0 is accessible) - THIS MIGHT FAIL" % (Patch['filename'],Patch['physical_partition_number'])) if Patching == "DISK": ## to be here means user wants to patch the actual disk if Patch['filename'] == "DISK": pass ## all is well, want to patch DISK, and this is DISK else: continue ## this was filename, so skip it else: ## to be here means were patching files, not the disk if Patch['filename'] == "DISK": continue ## want to patch FILES, but this was a DISK, so skip it else: pass ## this was filename, so let's patch it device_log("\n" + "-"*78) device_log("PATCH: (%s) %s" % (Patch['filename'],Patch['what'])) FileToOpen = Patch['filename'] if noprompt is True: # means don't bug them, i.e. automation pass else: if var=='N' or var=='n': device_log("\nWARNING: Are you sure you want to PATCH to '%s' of size %s (y|N) " % (Filename,ReturnSizeString(DiskSizeInBytes)),0) var = raw_input("\nWARNING: Are you sure you want to PATCH to '%s' of size %s (y|N) " % (Filename,ReturnSizeString(DiskSizeInBytes))) if var=='Y' or var=='y': pass else: device_log("\nmsp.py exiting - user didn't want to patch - Log is log_msp.txt\n\n") sys.exit(1) if Patching=="DISK": FileWithPath = Filename else: FileWithPath = find_file(FileToOpen, search_paths) while FileWithPath is None: FileNotFoundShowWarning = 1 device_log("\t______ _ _ ___ ") device_log("\t| ___ \\ | | | | |__ \\ ") device_log("\t| |_/ /__ _| |_| |__ ) |") device_log("\t| __// _` | __| '_ \\ / / ") device_log("\t| | | (_| | |_| | | | |_| ") device_log("\t\\_| \\__,_|\\__|_| |_| (_) \n\n") if rawprogram_filename is None: device_log("WARNING: '%s' listed in '%s' not found\n" % (FileToOpen,patch_filename)) else: device_log("WARNING: '%s' listed in '%s' not found\n" % (FileToOpen,rawprogram_filename)) if noprompt is True: device_log("\nUse option -s c:\\path1 -s c:\\path2 etc") PrintBigError("") device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit(1) device_log("Please provide a path for this file") device_log("Ex. \\\\somepath\\folder OR c:\\somepath\\folder\n") device_log("Enter PATH or Q to quit? ",0) temppath = raw_input("Enter PATH or Q to quit? ") if temppath=='Q' or temppath=='q' or temppath=='': device_log("\nmsp.py exiting - user pressed Q (quit) - Log is log_msp.txt\n\n") sys.exit() device_log("\n") FileWithPath = find_file(Write['filename'], [temppath]) size=0 if FileWithPath is not None: size = os.path.getsize(FileWithPath) device_log("\nShould this path be used to find other files? (Y|n|q)",0) temp = raw_input("\nShould this path be used to find other files? (Y|n|q)") if temp=='Q' or temp=='q': device_log("\nmsp.py exiting - user pressed Q (quit) - Log is log_msp.txt\n\n") sys.exit() elif temp=='Y' or temp=='y' or temp=='': search_paths.append(temppath) device_log("\n" ) try: opfile = open(FileWithPath, "r+b") device_log("Opened %s, cwd=%s" % (FileWithPath,os.getcwd() )) except Exception, x: PrintBigError("Could not open %s, cwd=%s\nREASON: %s" % (FileWithPath,os.getcwd(),x )) if Patch['function']=="CRC32": device_log("\t%s(%u,%u) requested " % (Patch['function'],Patch['arg0'],Patch['arg1'])) PStartSector = int(Patch['arg0']) PNumSectors = int(Patch['arg1']/SECTOR_SIZE) if PNumSectors==0 or (Patch['arg1']%SECTOR_SIZE)>0: # i.e. 640/SECTOR_SIZE means read 2 sectors worth PNumSectors+=1 try: if Patch['arg0']>64: device_log("\tPatch['arg0']=%d" % Patch['arg0']) device_log("\tPatch['arg1']=%d" % Patch['arg1']) device_log("\tmoving to sector %d-%d (%d)" % (PStartSector,(64-PNumSectors),PStartSector-(64-PNumSectors))) opfile.seek( int( (PStartSector-(64-PNumSectors) )*SECTOR_SIZE )) else: device_log("moving to sector %d (byte location %d)" % (Patch['arg0'],Patch['arg0']*SECTOR_SIZE)) opfile.seek( int(Patch['arg0']*SECTOR_SIZE)) except Exception, x: PrintBigError("Could not complete move in %s\nREASON: %s" % (FileWithPath,x)) device_log("\tMove Successful ") try: if Patch['arg0']>64: device_log("\tTrying to read %d bytes in %s" % (64*SECTOR_SIZE,FileWithPath)) bytes_read = opfile.read(64*SECTOR_SIZE) else: device_log("\tTrying to read %d bytes in %s" % (Patch['arg1'],FileWithPath)) bytes_read = opfile.read(Patch['arg1']) except Exception, x: PrintBigError("Could not read in %s\nREASON: %s" % (FileWithPath,x)) device_log("\tlen(bytes_read)=",len(bytes_read)) if Patch['arg0']>64: Bytes = struct.unpack("%dB" % (64*SECTOR_SIZE),bytes_read) ## unpack returns list, so get index 0 else: Bytes = struct.unpack("%dB" % Patch['arg1'],bytes_read) ## unpack returns list, so get index 0 if Patch['arg0']>64: #PStartSector #PNumSectors StartByte = (64-PNumSectors)*SECTOR_SIZE device_log("\tStartByte=%i"%StartByte) ##print "Patch['arg1'] is :",Patch['arg1'] Patch['value'] = CalcCRC32(Bytes[StartByte:],Patch['arg1']) else: Patch['value'] = CalcCRC32(Bytes,Patch['arg1']) device_log("\tCRC32=0x%.8X" % Patch['value']) # ELSE - patch is not a CRC if(int(Patch['start_sector'])>0): try: if Patch['start_sector']>64: device_log("moving to %d-63=%d" % (Patch['start_sector'],Patch['start_sector']-63)) opfile.seek( int((Patch['start_sector']-63)*SECTOR_SIZE)) else: device_log("moving to sector %d (byte location %d)" % (Patch['start_sector'],Patch['start_sector']*SECTOR_SIZE)) opfile.seek(int(Patch['start_sector']*SECTOR_SIZE)) except Exception, x: PrintBigError("Could not move to sector %d in %s\nREASON: %s" % (Patch['start_sector'],FileWithPath,x)) try: if Patch['start_sector']>64: bytes_read = opfile.read(64*SECTOR_SIZE) if len(bytes_read) != (64*SECTOR_SIZE): PrintBigError("Didn't get the read size 64*SECTOR_SIZE" % FileWithPath) else: bytes_read = opfile.read(SECTOR_SIZE) if len(bytes_read) != (SECTOR_SIZE): PrintBigError("Didn't get the read size SECTOR_SIZE in '%s'" % FileWithPath) except Exception, x: PrintBigError("Could not read sector %d in %s\nREASON: %s" % (Patch['start_sector'],FileWithPath,x)) device_log("success was able to read len(bytes_read)=%d" % (len(bytes_read))) # Move back to do the write try: if Patch['start_sector']>64: #device_log("moving to %d-63=%d" % (Patch['start_sector'],Patch['start_sector']-63)) opfile.seek(int((Patch['start_sector']-63)*SECTOR_SIZE)) else: #device_log("moving to sector %d (byte location %d)" % (Patch['start_sector'],Patch['start_sector']*SECTOR_SIZE)) opfile.seek(int(Patch['start_sector']*SECTOR_SIZE)) except Exception, x: PrintBigError("Could not move to sector %d in %s\nREASON: %s" % (Patch['start_sector'],FileWithPath,x)) if Patch['value'] < 0: PrintBigError("Patch value was negative. This means your DISK size is too small") device_log("At sector %d (0x%X) file_sector_offset %d (0x%X) in %s with %d (0x%X)" % (Patch['start_sector'],Patch['start_sector']*SECTOR_SIZE,Patch['byte_offset'],Patch['byte_offset'],FileWithPath,Patch['value'],Patch['value'])) #Patch['byte_offset'] if Patch['start_sector']>64: ValueList = list(struct.unpack("%dB"%(64*SECTOR_SIZE),bytes_read)) else: ValueList = list(struct.unpack("%dB"%SECTOR_SIZE,bytes_read)) # "512B" #device_log("\nBefore") #j=0 #sys.stdout.write("%.4X\t "%j) #for b in ValueList[-512:]: # sys.stdout.write("%.2X "%b) # j+=1 # #if j>64: # # break # if j%16==0: # device_log(" ") # sys.stdout.write("%.4X\t "%j) device_log("Patch value:%i"%Patch['value']) for j in range(Patch['size_in_bytes']): if Patch['start_sector']>64: #device_log("Applying patch at %d+%d=%d value=0x%.2X" % (63*SECTOR_SIZE,Patch['byte_offset']+j,63*SECTOR_SIZE+j+Patch['byte_offset'],(Patch['value']>>(j*8))&0xFF)) ValueList[63*SECTOR_SIZE+Patch['byte_offset']+j ] = (Patch['value']>>(j*8))&0xFF sys.stdout.write("%.2X " % (int(Patch['value']>>(j*8)) & 0xFF)) else: ValueList[Patch['byte_offset']+j ] = (Patch['value']>>(j*8))&0xFF #import pdb; pdb.set_trace() sys.stdout.write("%.2X " % (int(Patch['value']>>(j*8)) & 0xFF)) #for b in ValueList: # sys.stdout.write("%.2X "%b) #device_log("\nAfter") #j=0 #sys.stdout.write("%.4X\t "%j) #for b in ValueList[-512:]: # sys.stdout.write("%.2X "%b) # j+=1 # #if j>64: # # break # if j%16==0: # device_log(" ") # sys.stdout.write("%.4X\t "%j) #device_log(" ") if Patch['start_sector']>64: bytes_read = struct.pack("%dB"%(64*SECTOR_SIZE),*ValueList) else: bytes_read = struct.pack("%dB"%SECTOR_SIZE,*ValueList) device_log("(little endian)") device_log("committing patch of length %d bytes" % len(bytes_read)) try: opfile.write(bytes_read) except Exception, x: PrintBigError("Could not write %d bytes to %s\nREASON: %s" % (len(bytes_read),FileWithPath,x)) #WriteValue(fd, RawProgramInfo.start_sector, RawProgramInfo.byte_offset, RawProgramInfo.value, RawProgramInfo.size_in_bytes); try: opfile.close() except Exception, x: device_log("\tWARNING: Could not close %s" % FileWithPath) device_log("REASON: %s" % (x)) device_log("CLOSED '%s'" % FileWithPath) if sys.platform.startswith("linux"): device_log("You're on LINUX! I'm performing a SYNC for you") os.system("sync") device_log("PATCH:" , Patch['what']) device_log("DONE\n") #if Patch['what']== "Update Backup Header with Write Array Location.": # sys.exit(0) device_log("Done patching") def Usage(): print "Usage: Mass Storage Programmer - destructively writes data to disks!!\n" sudo = "" drive= "" if sys.platform.startswith("linux"): sudo = "sudo" drive= "/dev/sdb" else: print "\tYou must run as Administrator under Win7\n" drive="\\\\.\\PHYSICALDRIVE1" print "%-40s\t python msp.py" % "Display this info" print "%-40s\t%s python msp.py -r wipe_rawprogram_PHY0.xml -d %s" % ("Wipe partition info (-w)",sudo,drive) print "\n%-40s\t%s python msp.py -r rawprogram0.xml -d %s" % ("Write a device (-r)",sudo,drive) print "%-40s\t%s python msp.py -r rawprogram0.xml -d 0" % ("Create a singleimage.bin (-r)",sudo) print "%-40s\t%s python msp.py -r rawprogram0.xml -d 0 -t c:\\temp" % ("singleimage.bin stored to c:\\temp (-r)",sudo) print "%-40s\t%s python msp.py -r rawprogram0.xml -d 16777216" % ("Create an 8GB singleimage.bin (-r)",sudo) print "\n%-40s\t%s python msp.py -n -r rawprogram.xml -d %s" % ("no prompts (-n) i.e. automation",sudo,drive) print "%-40s\t%s python msp.py -i -r rawprogram.xml -d %s " % ("Interactively choose files (-i)",sudo,drive) print "%-40s\t%s python msp.py -f sbl1.mbn,sbl2.mbn -r rawprogram.xml -d %s " % ("Specify files from rawprogram.xml (-f)",sudo,drive) print "%-40s\t%s python msp.py -s c:\windows,d:\ -r rawprogram.xml -d %s " % ("Search this path for files (-s)",sudo,drive) print "\n%-40s\t%s python msp.py -p patch0.xml -d %s" % ("Patch a device (-p)",sudo,drive) print "%-40s\t%s python msp.py -p patch0.xml -d singleimage.bin" % ("Patch files to singleimage (-p)",sudo) print "%-40s\t%s python msp.py -p patch0.xml -d 16777216" % ("PRE-PATCH images for an 8GB disk (-p)",sudo) print "\n%-40s\t%s python msp.py -r rawprogram0.xml -p patch0.xml -d %s" % ("ALL IN ONE STEP",sudo,drive) print "\n"+"*"*78 print "Usage: Mass Storage Programmer - destructively writes data to disks!!" print "*"*78+"\n" def ReturnSizeString(size): if size>(1024*1024*1024): return "%.2f GB" % (size/(1024.0*1024.0*1024.0)) elif size>(1024*1024): return "%.2f MB" % (size/(1024.0*1024.0)) elif size>(1024): return "%.2f KB" % (size/(1024.0)) else: return "%i B" % (size) # A8h reflected is 15h, i.e. 10101000 <--> 00010101 def reflect(data,nBits): reflection = 0x00000000 bit = 0 for bit in range(nBits): if(data & 0x01): reflection |= (1 << ((nBits - 1) - bit)) data = (data >> 1); return reflection def PrintResetDeviceNow(): device_log("\t______ _ ") device_log("\t| ___ \\ | | ") device_log("\t| |_/ /___ ___ ___| |_ _ _ ___ _ _ _ __ ") device_log("\t| // _ | __|/ _ \\ __| | | | |/ _ \\| | | | '__|") device_log("\t| |\\ \\ __|__ \\ __/ |_ | |_| | (_) | |_| | | ") device_log("\t\\_| \\_\\___|___/\\___|\\__| \\__, |\\___/ \\__,_|_| ") device_log("\t __/ | ") device_log("\t |___/ ") device_log("\t") device_log("\t _ _ ") device_log("\t | | (_) ") device_log("\t __| | _____ ___ ___ ___ _ __ _____ __") device_log("\t / _` |/ _ \\ \\ / / |/ __|/ _ \\ | '_ \\ / _ \\ \\ /\\ / /") device_log("\t| (_| | __/\\ V /| | (__| __/ | | | | (_) \\ V V / ") device_log("\t \\__,_|\\___| \\_/ |_|\\___|\\___| |_| |_|\\___/ \\_/\\_/ \n") def TestIfSparse(test_sparse,filetotest): if test_sparse is None: PrintBigWarning("WARNING: testsparse.py is not found - Can't test if this file is SPARSE\n") else: sz = "python %s -i %s " % (test_sparse,filetotest) for path in search_paths: sz += "-s %s " % path device_log("\n"+"-"*78) device_log("-"*78) device_log("Checking if file '%s' is sparse. This is to save you from accidently" % filetotest) device_log("using a sparse file without *unsparsing* it first. That is, if you copy it over as is") device_log("it won't work (similar to a ZIP file, you want what is *inside*, not the ZIP file)") device_log("-"*78) device_log("-"*78) #filetotest_temp = find_file(filetotest, search_paths) #if filetotest_temp is None: # PrintBigError("Can't located '%s'" % filetotest) device_log(sz) response = external_call(sz) m = re.search("SPARSE FILE DETECTED", response) if type(m) is not NoneType: PrintBigError("File is sparse, can't continue - you must run 'python checksparse.py -i rawprogram0.xml'") def CalcCRC32(array,Len): k = 8; # length of unit (i.e. byte) MSB = 0; gx = 0x04C11DB7; # IEEE 32bit polynomial regs = 0xFFFFFFFF; # init to all ones regsMask = 0xFFFFFFFF; # ensure only 32 bit answer for i in range(Len): # Len=5 ; range(Len) --> [0, 1, 2, 3, 4] DataByte = array[i] DataByte = reflect( DataByte, 8 ); for j in range(k): MSB = DataByte>>(k-1) ## get MSB MSB &= 1 ## ensure just 1 bit regsMSB = (regs>>31) & 1 regs = regs<<1 ## shift regs for CRC-CCITT if regsMSB ^ MSB: ## MSB is a 1 regs = regs ^ gx ## XOR with generator poly regs = regs & regsMask; ## Mask off excess upper bits DataByte <<= 1 ## get to next bit regs = regs & regsMask ## Mask off excess upper bits ReflectedRegs = reflect(regs,32) ^ 0xFFFFFFFF; return ReflectedRegs def ReplaceDiskSizeInSectorsWithRealValue(MyArray): ## At this point I have the real size of DiskSizeInBytes, so let's fill in the blanks if they still exist for MyDict in MyArray: if int(MyDict['start_sector']) > 0 and int(MyDict['start_sector'])>(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE): MyDict['start_sector'] = (DiskSizeInBytes/SECTOR_SIZE)-(int(MyDict['start_sector'])-(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE)) if int(MyDict['num_partition_sectors']) > 0 and int(MyDict['num_partition_sectors'])>(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE): MyDict['num_partition_sectors'] = (DiskSizeInBytes/SECTOR_SIZE)-(int(MyDict['num_partition_sectors'])-(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE)) if int(MyDict['file_sector_offset']) > 0 and int(MyDict['file_sector_offset'])>(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE): MyDict['file_sector_offset'] = (DiskSizeInBytes/SECTOR_SIZE)-(int(MyDict['file_sector_offset'])-(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE)) if int(MyDict['value']) > 0 and int(MyDict['value'])>(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE): MyDict['value'] = (DiskSizeInBytes/SECTOR_SIZE)-(int(MyDict['value'])-(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE)) def CalculateMinDiskSize(): OldMinDiskSizeInSectors = 0 MinDiskSizeInSectors = 0 #Calculate the MinDiskSizeInSectors. This is a 2 step process # Once for normal partitions for Write in WriteSorted: if int(Write['start_sector']) > 0 and int(Write['start_sector'])<(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE): MinDiskSizeInSectors = (int(Write['start_sector']) + int(Write['num_partition_sectors'])) if OldMinDiskSizeInSectors != MinDiskSizeInSectors: device_log("MinDiskSizeInSectors=%i sectors (%.2fMB)" % (MinDiskSizeInSectors,MinDiskSizeInSectors*SECTOR_SIZE/(1024.0*1024.0))) OldMinDiskSizeInSectors = MinDiskSizeInSectors print "----------------------" # second time is for NUM_DISK_SECTORS-33 type of scenarios, since they will currently have # my made up value of EMMCBLD_MAX_DISK_SIZE_IN_BYTES+start_sector for Write in WriteSorted: if int(Write['start_sector']) > 0 and int(Write['start_sector'])>(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE): MinDiskSizeInSectors += int(Write['start_sector'])-(EMMCBLD_MAX_DISK_SIZE_IN_BYTES/SECTOR_SIZE) if OldMinDiskSizeInSectors != MinDiskSizeInSectors: device_log("MinDiskSizeInSectors=%i sectors (%.2fMB)" % (MinDiskSizeInSectors,MinDiskSizeInSectors*SECTOR_SIZE/(1024*1024.0))) OldMinDiskSizeInSectors = MinDiskSizeInSectors return MinDiskSizeInSectors ## ============================================================================================== ## ============================================================================================== ## ============================================================================================== ## =====main()=================================================================================== ## ============================================================================================== ## ============================================================================================== ## ============================================================================================== AvailablePartitions = {} try: opts, args = getopt.getopt(sys.argv[1:], "r:p:d:ins:f:t:vb:", ["rawprogram=", "patch=", "dest=","noprompt=", "interactive=", "search_path=","file=","location=","verbose","sectorsize"]) except getopt.GetoptError, err: # print help information and exit: Usage() PrintBigError(str(err)) test_sparse = None dd = None xml_filename = None rawprogram_filename = None patch_filename = None disk_name = None search_paths = [] file_list = [] LoadSubsetOfFiles = False interactive = False noprompt = False verbose = False Operation = 0 OPERATION_PROGRAM = 2 OPERATION_PATCH = 4 OPERATION_READ = 8 Patching = "FILES" OutputFolder = "" Filename = "singleimage.bin" DiskSizeInBytes = 0 MinDiskSizeInSectors = 0 Usage() #GetPartitions() for o, a in opts: if o in ("-r", "--rawprogram"): rawprogram_filename = a # Operation |= OPERATION_PROGRAM ## assumed here. It will be corrected later elif o in ("-b","--sectorsize"): SECTOR_SIZE = int(a) elif o in ("-t", "--location"): OutputFolder = a OutputFolder = re.sub(r"\\$","",OutputFolder) # remove final slash if it exists OutputFolder = re.sub(r"/$","",OutputFolder) # remove final slash if it exists OutputFolder += "/" # slashes will all be corrected below if sys.platform.startswith("linux"): OutputFolder = re.sub(r"\\","/",OutputFolder) # correct slashes else: OutputFolder = re.sub(r"/","\\\\",OutputFolder) # correct slashes device_log("OutputFolder='%s'"%OutputFolder) EnsureDirectoryExists(OutputFolder) # only need to call once Filename = OutputFolder + Filename elif o in ("-p", "--patch"): patch_filename = a Operation |= OPERATION_PATCH elif o in ("-d", "--dest"): disk_name = a # if a number was specified, it's size in sectors and we're making a singleimage.bin # otherwise, a drive /dev/sdb or something was specified m = re.search("^(\d+)$", disk_name) if type(m) is not NoneType: ## to be here means they specified a number must be making a single image or patching files Patching = "FILES" Filename = OutputFolder + "singleimage.bin" DiskSizeInBytes = int(int(m.group(1))*SECTOR_SIZE) # comes in as sectors, we now know the size of DiskSizeInBytes, could also be size 0!! else: ## to be here means they didn't specify a number, thus a device Filename = disk_name Patching = "DISK" ValidDiskName = False # User can also specify the singleimage.bin name, and I can treat that like it's the disk GetPartitions() if sys.platform.startswith("linux"): m = re.search("/dev/sd[a-z]", disk_name) if type(m) is not NoneType: ValidDiskName = True else: m = re.search("(PHYSICALDRIVE\d+)", disk_name) if type(m) is not NoneType: ValidDiskName = True Filename = "\\\\.\\"+m.group(1) if ValidDiskName: if Filename not in Devices: PrintBigError("%s does not exist" % Filename) DiskSizeInBytes = AvailablePartitions[Filename] else: # To be here means user did this possibly "-d singleimage.bin", i.e. to patch the singleimage.bin try: DiskSizeInBytes = os.path.getsize(disk_name) # and thus singleimage.bin must already exist except Exception, x: PrintBigError("") device_log("Can't get size of %s" % Filename) device_log("REASON: %s" % (x)) Usage() device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit() elif o in ("-i", "--interactive"): interactive = True elif o in ("-n", "--noprompt"): noprompt = True elif o in ("-v", "--verbose"): verbose = True elif o in ("-s", "--search_path"): ## also allow seperating commas for x in a.strip("\n").split(","): search_paths.append(x) elif o in ("-f", "--file_list"): ## also allow seperating files by commas, i.e. -f sbl1.mbn,slb2.mbn,etc LoadSubsetOfFiles = True for x in a.strip("\n").split(","): file_list.append(x) else: assert False, "unhandled option" if Operation==0: ## Means nothing was specified above GetPartitions() device_log("\nmsp.py exiting - Only showed options and drives detected - Log is log_msp.txt\n\n") if verbose is True: device_log("\nMass Storage Programmer (msp.py) VERSION 1.0\n"); sys.exit(1) device_log("\nSearch Paths") device_log(search_paths) device_log("\nFiles") device_log(file_list) if disk_name is None: if sys.platform.startswith("linux"): device_log("Don't forget to specify your drive, EX '-d /dev/sdb' OR '-d 0' to create a singleimage"); else: device_log("Don't foreget to specify your drive, EX '-d \\.\PHYSICALDRIVE1' OR '-d 0' to create a singleimage"); PrintBigError("You must specify a DISK, option -d") if (Operation & OPERATION_PROGRAM) > 0: if rawprogram_filename is None: PrintBigError("You must specify an \"rawprogram\" XML file for option -r") else: rawprogram_filename = find_file(rawprogram_filename, search_paths) if rawprogram_filename is None: PrintBigError("You must specify an \"rawprogram\" XML file for option -r") if (Operation & OPERATION_PATCH) > 0: if patch_filename is None: PrintBigError("You must specify an \"patch\" XML file for option -p") else: patch_filename = find_file(patch_filename, search_paths) if patch_filename is None: PrintBigError("You must specify an \"patch\" XML file for option -p") NumPhyPartitions = 0 WriteArray = [] ReadArray = [] PatchArray = [] PhyPartition = {} # Main HASH that holds all the partition info ## At this point DiskSizeInBytes is either known or equal to 0 if rawprogram_filename is not None: ParseXML(rawprogram_filename) Operation = 0 if len(WriteArray)>0: pass # Operation |= OPERATION_PROGRAM if len(ReadArray)>0: Operation |= OPERATION_READ if DiskSizeInBytes>0: if DiskSizeInBytes 0: for Write in WriteArray: #device_log("---------------- with start_sector = %i and PartitionStartSector[%i]=%i" % (Write["start_sector"],Count,PartitionStartSector[Count])) if Write['filename']=="": continue if Write["start_sector"] == PartitionStartSector[Count]: ##device_log("FOUND, len(PartitionStartSector)=%d and len(WriteSorted)=%d" % (len(PartitionStartSector),len(WriteSorted))) # To be here means I found the *next* start_sector in order, i.e. 0,100,200 etc WriteSorted.append( Write ) Count += 1 # now go to next sorted entry if len(WriteSorted) == len(PartitionStartSector): break # we're done, both arrays are the same size if len(WriteSorted) == len(PartitionStartSector): break # we're done, both arrays are the same size MinDiskSizeInSectors = CalculateMinDiskSize() print "MinDiskSizeInSectors=",MinDiskSizeInSectors print "DiskSizeInSectors =",DiskSizeInBytes/SECTOR_SIZE if DiskSizeInBytes==0: DiskSizeInBytes = int(MinDiskSizeInSectors)*SECTOR_SIZE if DiskSizeInBytes == 0: PrintBigError("") device_log("Something went wrong, couldn't determine size of disk?") if sys.platform.startswith("linux"): device_log("Did you remember to specify your drive, EX '-d /dev/sdb'"); else: device_log("Did you remember to specify your drive, EX '-d \\.\PHYSICALDRIVE1'"); device_log("\nmsp.py failed - Log is log_msp.txt\n\n") sys.exit() device_log("\nDiskSizeInBytes was set to 0, DiskSizeInBytes will be %s (%d sectors)" % (ReturnSizeString(DiskSizeInBytes),int(DiskSizeInBytes/SECTOR_SIZE))) if patch_filename is not None: Operation |= OPERATION_PATCH ParseXML(patch_filename) ReplaceDiskSizeInSectorsWithRealValue(WriteSorted) ReplaceDiskSizeInSectorsWithRealValue(ReadArray) ReplaceDiskSizeInSectorsWithRealValue(PatchArray) if (Operation & OPERATION_PROGRAM) > 0: # Can we test for sparse images? test_sparse = find_file("testsparse.py", search_paths) if os.path.basename(Filename)=="singleimage.bin": ## Wipe out any old singleimage try: opfile = open(Filename, "wb") except Exception, x: print "REASON: %s" % x print "\nERROR: Can't delete old singleimage.bin. Is it open??" sys.exit() opfile.close() device_log("\nProgramming %s of size %s" % (Filename,ReturnSizeString(DiskSizeInBytes))) if noprompt is False: if (DiskSizeInBytes/(1024.0*1024.0))>100: device_log("\nThis will be a LARGE singleimage.bin, it will take a long time, Do you want to continue? (Y|n)",0) var = raw_input("\nThis will be a LARGE singleimage.bin, it will take a long time, Do you want to continue? (Y|n)") if var=='Y' or var=='y' or var=='': pass else: device_log("\nmsp.py exiting - User didn't want to continue - Log is log_msp.txt\n\n") sys.exit() else: if noprompt is True: # means don't bug them, i.e. automation pass else: device_log("\nWARNING: Are you sure you want to write to '%s' of size %s (y|N) " % (Filename,ReturnSizeString(DiskSizeInBytes)),0) var = raw_input("\nWARNING: Are you sure you want to write to '%s' of size %s (y|N) " % (Filename,ReturnSizeString(DiskSizeInBytes))) if var=='Y' or var=='y': pass else: device_log("\nmsp.py exiting - User didn't want to continue - Log is log_msp.txt\n\n") sys.exit() if (Operation & OPERATION_READ) > 0: PerformRead() ThereWereWarnings = 0 if (Operation & OPERATION_PROGRAM) > 0 and (Operation & OPERATION_PATCH) > 0: ## Have info to do both write and patch if Filename=="singleimage.bin": # it's a singleimage, so do patching first PerformPatching() ThereWereWarnings = PerformWrite() if (Operation & OPERATION_READ) > 0: PerformRead() if verbose is True: DoubleCheckDiskSize() else: ThereWereWarnings = PerformWrite() PerformPatching() if (Operation & OPERATION_READ) > 0: PerformRead() if verbose is True: DoubleCheckDiskSize() elif (Operation & OPERATION_PROGRAM) > 0: ThereWereWarnings = PerformWrite() if (Operation & OPERATION_READ) > 0: PerformRead() device_log("\n"+"-"*78) device_log("If you wrote any partition table information (MBR0.bin, gpt_main0.bin, etc)") device_log(" ") device_log(" _ _ _ __ _ ") device_log(" | | ( ) | / _| | | ") device_log(" __| | ___ _ __ |/| |_ | |_ ___ _ __ __ _ ___| |_ ") device_log(" / _` |/ _ \\| '_ \\ | __| | _/ _ \\| '__/ _` |/ _ \\ __|") device_log(" | (_| | (_) | | | | | |_ | || (_) | | | (_| | __/ |_ ") device_log(" \\__,_|\\___/|_| |_| \\__| |_| \\___/|_| \\__, |\\___|\\__|") device_log(" __/ | ") device_log(" |___/ ") device_log(" _ _ _ ") device_log(" | | | | | | ") device_log(" | |_ ___ _ __ __ _| |_ ___| |__ ") device_log(" | __|/ _ \\ | '_ \\ / _` | __|/ __| '_ \\ ") device_log(" | |_| (_) | | |_) | (_| | |_| (__| | | |") device_log(" \\__|\\___/ | .__/ \\__,_|\\__|\\___|_| |_|") device_log(" | | ") device_log(" |_| ") device_log("\n") sudo="" if sys.platform.startswith("linux"): sudo="sudo " device_log("\tEx: %spython msp.py -p patch0.xml -d %s " % (sudo,Filename)) device_log("\t\tOr, do it all in one step") device_log("\tEx: %spython msp.py -r rawprogram0.xml -d %s -p patch0.xml" % (sudo,Filename)) device_log("-"*78) if verbose is True: DoubleCheckDiskSize() elif (Operation & OPERATION_PATCH) > 0: PerformPatching() if verbose is True: DoubleCheckDiskSize() if (Operation & OPERATION_PROGRAM) > 0: if os.path.basename(Filename)=="singleimage.bin": device_log("\nNOTE: This program does *not* pad the last partition, therefore") device_log(" singleimage.bin might be smaller than %d sectors (%.2f MB)" % (int(DiskSizeInBytes/SECTOR_SIZE),DiskSizeInBytes/(1048576.0))) device_log("\n\nSUCCESS - %s created" % Filename) device_log("SUCCESS - %s created" % Filename) device_log("SUCCESS - %s created\n" % Filename) if FileNotFoundShowWarning==1: device_log("\nWARNING: 1 or more files were *not* found, your singleimage.bin is *NOT* complete") device_log("\nWARNING: 1 or more files were *not* found, your singleimage.bin is *NOT* complete") device_log("\nWARNING: 1 or more files were *not* found, your singleimage.bin is *NOT* complete\n\n") device_log("\nmsp.py exiting SUCCESSFULLY- Log is log_msp.txt\n\n") if ThereWereWarnings == 1: PrintBigWarning("There were warnings, please see log. \n\n--------> Your image *might* not work <----------\n") sleep(2)