custominstall: style updates

This commit is contained in:
Ian Burgwin
2020-01-24 01:59:29 -08:00
parent 8d3e09cc29
commit 48e1636588

View File

@@ -33,13 +33,16 @@ TITLE_ALIGN_SIZE = 0x8000
# size to read at a time when copying files
READ_SIZE = 0x200000
# Placeholder for SDPathErrors
class SDPathError(Exception): pass
class SDPathError(Exception):
pass
class CustomInstall():
def __init__(self, boot9, movable, cias, sd, skip_contents=False):
self.event = Events()
self.log_lines = [] # Stores all info messages for user to view
self.log_lines = [] # Stores all info messages for user to view
self.crypto = CryptoEngine(boot9=boot9)
self.crypto.setup_sd_key_from_file(movable)
@@ -67,7 +70,8 @@ class CustomInstall():
[sd_path, id1s] = self.get_sd_path()
try:
if len(id1s) > 1:
raise SDPathError(f'There are multiple id1 directories for id0 {crypto.id0.hex()}, please remove extra directories')
raise SDPathError(f'There are multiple id1 directories for id0 {crypto.id0.hex()}, '
f'please remove extra directories')
elif len(id1s) == 0:
raise SDPathError(f'Could not find a suitable id1 directory for id0 {crypto.id0.hex()}')
except SDPathError:
@@ -148,22 +152,23 @@ class CustomInstall():
# write the tmd
enc_path = content_root_cmd + '/' + tmd_filename
self.log(f'Writing {enc_path}...')
with cia.open_raw_section(CIASection.TitleMetadata) as s, open(join(content_root, tmd_filename), 'wb') as o:
self.copy_with_progress(s, o, cia.sections[CIASection.TitleMetadata].size, enc_path)
with cia.open_raw_section(CIASection.TitleMetadata) as s:
with open(join(content_root, tmd_filename), 'wb') as o:
self.copy_with_progress(s, o, cia.sections[CIASection.TitleMetadata].size, enc_path)
# write each content
for c in cia.content_info:
content_filename = c.id + '.app'
for co in cia.content_info:
content_filename = co.id + '.app'
if is_dlc:
dir_index = format((c.cindex // 256), '08x')
dir_index = format((co.cindex // 256), '08x')
enc_path = content_root_cmd + f'/{dir_index}/{content_filename}'
out_path = join(content_root, dir_index, content_filename)
else:
enc_path = content_root_cmd + '/' + content_filename
out_path = join(content_root, content_filename)
self.log(f'Writing {enc_path}...')
with cia.open_raw_section(c.cindex) as s, open(out_path, 'wb') as o:
self.copy_with_progress(s, o, c.size, enc_path)
with cia.open_raw_section(co.cindex) as s, open(out_path, 'wb') as o:
self.copy_with_progress(s, o, co.size, enc_path)
# generate a blank save
if cia.tmd.save_size:
@@ -193,9 +198,9 @@ class CustomInstall():
id_bytes = bytes.fromhex(record.id)[::-1]
cmac_data += record.cindex.to_bytes(4, 'little') + id_bytes
c = crypto.create_cmac_object(Keyslot.CMACSDNAND)
c.update(sha256(cmac_data).digest())
content_ids[record.cindex] = (id_bytes, c.digest())
cmac_ncch = crypto.create_cmac_object(Keyslot.CMACSDNAND)
cmac_ncch.update(sha256(cmac_data).digest())
content_ids[record.cindex] = (id_bytes, cmac_ncch.digest())
# add content IDs up to the last one
ids_by_index = [CMD_MISSING] * (highest_index + 1)
@@ -213,12 +218,12 @@ class CustomInstall():
installed_ids.sort(key=lambda x: int.from_bytes(x, 'little'))
final = (cmd_id.to_bytes(4, 'little')
+ len(ids_by_index).to_bytes(4, 'little')
+ len(installed_ids).to_bytes(4, 'little')
+ (1).to_bytes(4, 'little'))
c = crypto.create_cmac_object(Keyslot.CMACSDNAND)
c.update(final)
final += c.digest()
+ len(ids_by_index).to_bytes(4, 'little')
+ len(installed_ids).to_bytes(4, 'little')
+ (1).to_bytes(4, 'little'))
cmac_cmd_header = crypto.create_cmac_object(Keyslot.CMACSDNAND)
cmac_cmd_header.update(final)
final += cmac_cmd_header.digest()
final += b''.join(ids_by_index)
final += b''.join(installed_ids)
@@ -265,9 +270,6 @@ class CustomInstall():
title_info_entries[cia.tmd.title_id] = b''.join(title_info_entry_data)
with cia.open_raw_section(CIASection.Ticket) as t:
ticket_data = t.read()
finalize_entry_data = [
# magic
b'TITLE\0',
@@ -318,14 +320,13 @@ class CustomInstall():
self.log('FINAL STEP:\nRun custom-install-finalize through homebrew launcher.')
self.log('This will install a ticket and seed if required.')
def get_sd_path(self):
sd_path = join(self.sd, 'Nintendo 3DS', self.crypto.id0.hex())
id1s = []
for d in scandir(sd_path):
if d.is_dir() and len(d.name) == 32:
try:
#id1_tmp = bytes.fromhex(d.name)
# id1_tmp = bytes.fromhex(d.name)
pass
except ValueError:
continue
@@ -333,7 +334,6 @@ class CustomInstall():
id1s.append(d.name)
return [sd_path, id1s]
def log(self, message, mtype=0, errorname=None):
"""Logs an Message with a type. Format is similar to python errors
@@ -344,15 +344,15 @@ class CustomInstall():
optionally, errorname can be a custom name as a string to identify errors easily
"""
if errorname == None:
if errorname:
errorname += ": "
else:
# No errorname provided
errorname = ""
else:
errorname += ": "
types = [
"", # Type 0
"Warning: ", # Type 1
"Error: " # Type 2
"", # Type 0
"Warning: ", # Type 1
"Error: " # Type 2
]
# Example: "Warning: UninformativeError: An error occured, try again.""
msg_with_type = types[mtype] + errorname + str(message)
@@ -360,6 +360,7 @@ class CustomInstall():
self.event.on_log_msg(msg_with_type)
return msg_with_type
if __name__ == "__main__":
parser = ArgumentParser(description='Manually install a CIA to the SD card for a Nintendo 3DS system.')
parser.add_argument('cia', help='CIA files', nargs='+')
@@ -368,14 +369,13 @@ if __name__ == "__main__":
parser.add_argument('--sd', help='path to SD root')
parser.add_argument('--skip-contents', help="don't add contents, only add title info entry", action='store_true')
args = parser.parse_args()
installer = CustomInstall(boot9=args.boot9,
cias=args.cia,
movable=args.movable,
sd=args.sd,
skip_contents=(args.skip_contents or False))
cias=args.cia,
movable=args.movable,
sd=args.sd,
skip_contents=(args.skip_contents or False))
def log_handle(msg):
print(msg)