mirror of
https://github.com/ihaveamac/custom-install.git
synced 2025-12-06 06:41:45 +00:00
custominstall: check for free space before installing, move title size calculation to separate function
This commit is contained in:
@@ -31,11 +31,16 @@ from pyctr.type.cia import CIAReader, CIAError
|
|||||||
from pyctr.type.ncch import NCCHSection
|
from pyctr.type.ncch import NCCHSection
|
||||||
from pyctr.util import roundup
|
from pyctr.util import roundup
|
||||||
|
|
||||||
is_windows = platform == 'win32'
|
|
||||||
|
|
||||||
if platform == 'msys':
|
if platform == 'msys':
|
||||||
platform = 'win32'
|
platform = 'win32'
|
||||||
|
|
||||||
|
is_windows = platform == 'win32'
|
||||||
|
|
||||||
|
if is_windows:
|
||||||
|
from ctypes import c_wchar_p, pointer, c_ulonglong, windll
|
||||||
|
else:
|
||||||
|
from os import statvfs
|
||||||
|
|
||||||
# used to run the save3ds_fuse binary next to the script
|
# used to run the save3ds_fuse binary next to the script
|
||||||
frozen = getattr(sys, 'frozen', False)
|
frozen = getattr(sys, 'frozen', False)
|
||||||
script_dir: str
|
script_dir: str
|
||||||
@@ -66,6 +71,26 @@ class InvalidCIFinishError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_free_space(path: 'Union[PathLike, bytes, str]'):
|
||||||
|
if is_windows:
|
||||||
|
lpSectorsPerCluster = c_ulonglong(0)
|
||||||
|
lpBytesPerSector = c_ulonglong(0)
|
||||||
|
lpNumberOfFreeClusters = c_ulonglong(0)
|
||||||
|
lpTotalNumberOfClusters = c_ulonglong(0)
|
||||||
|
ret = windll.kernel32.GetDiskFreeSpaceW(c_wchar_p(path), pointer(lpSectorsPerCluster),
|
||||||
|
pointer(lpBytesPerSector),
|
||||||
|
pointer(lpNumberOfFreeClusters),
|
||||||
|
pointer(lpTotalNumberOfClusters))
|
||||||
|
if not ret:
|
||||||
|
raise WindowsError
|
||||||
|
free_blocks = lpNumberOfFreeClusters.value * lpSectorsPerCluster.value
|
||||||
|
free_bytes = free_blocks * lpBytesPerSector.value
|
||||||
|
else:
|
||||||
|
stv = statvfs(path)
|
||||||
|
free_bytes = stv.f_bavail * stv.f_frsize
|
||||||
|
return free_bytes
|
||||||
|
|
||||||
|
|
||||||
def load_cifinish(path: 'Union[PathLike, bytes, str]'):
|
def load_cifinish(path: 'Union[PathLike, bytes, str]'):
|
||||||
try:
|
try:
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
@@ -146,6 +171,22 @@ def save_cifinish(path: 'Union[PathLike, bytes, str]', data: dict):
|
|||||||
out.write(b''.join(finalize_entry_data))
|
out.write(b''.join(finalize_entry_data))
|
||||||
|
|
||||||
|
|
||||||
|
def get_install_size(title: 'Union[CIAReader, CDNReader]'):
|
||||||
|
sizes = [1] * 5
|
||||||
|
|
||||||
|
if title.tmd.save_size:
|
||||||
|
# one for the data directory, one for the 00000001.sav file
|
||||||
|
sizes.extend((1, title.tmd.save_size))
|
||||||
|
|
||||||
|
for record in title.content_info:
|
||||||
|
sizes.append(record.size)
|
||||||
|
|
||||||
|
# this calculates the size to put in the Title Info Entry
|
||||||
|
title_size = sum(roundup(x, TITLE_ALIGN_SIZE) for x in sizes)
|
||||||
|
|
||||||
|
return title_size
|
||||||
|
|
||||||
|
|
||||||
class CustomInstall:
|
class CustomInstall:
|
||||||
def __init__(self, boot9, seeddb, movable, sd, cifinish_out=None,
|
def __init__(self, boot9, seeddb, movable, sd, cifinish_out=None,
|
||||||
overwrite_saves=False, skip_contents=False):
|
overwrite_saves=False, skip_contents=False):
|
||||||
@@ -196,6 +237,14 @@ class CustomInstall:
|
|||||||
readers.append(reader)
|
readers.append(reader)
|
||||||
self.readers = readers
|
self.readers = readers
|
||||||
|
|
||||||
|
def check_size(self):
|
||||||
|
total_size = 0
|
||||||
|
for r in self.readers:
|
||||||
|
total_size += get_install_size(r)
|
||||||
|
|
||||||
|
free_space = get_free_space(self.sd)
|
||||||
|
return total_size, free_space
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if frozen:
|
if frozen:
|
||||||
save3ds_fuse_path = join(script_dir, 'bin', 'save3ds_fuse')
|
save3ds_fuse_path = join(script_dir, 'bin', 'save3ds_fuse')
|
||||||
@@ -281,17 +330,7 @@ class CustomInstall:
|
|||||||
display_title = cia.tmd.title_id
|
display_title = cia.tmd.title_id
|
||||||
self.log(f'Installing {display_title}...')
|
self.log(f'Installing {display_title}...')
|
||||||
|
|
||||||
sizes = [1] * 5
|
title_size = get_install_size(cia)
|
||||||
|
|
||||||
if cia.tmd.save_size:
|
|
||||||
# one for the data directory, one for the 00000001.sav file
|
|
||||||
sizes.extend((1, cia.tmd.save_size))
|
|
||||||
|
|
||||||
for record in cia.content_info:
|
|
||||||
sizes.append(record.size)
|
|
||||||
|
|
||||||
# this calculates the size to put in the Title Info Entry
|
|
||||||
title_size = sum(roundup(x, TITLE_ALIGN_SIZE) for x in sizes)
|
|
||||||
|
|
||||||
# checks if this is dlc, which has some differences
|
# checks if this is dlc, which has some differences
|
||||||
is_dlc = tid_parts[0] == '0004008c'
|
is_dlc = tid_parts[0] == '0004008c'
|
||||||
@@ -607,6 +646,14 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
installer.prepare_titles(args.cia)
|
installer.prepare_titles(args.cia)
|
||||||
|
|
||||||
|
if not args.skip_contents:
|
||||||
|
total_size, free_space = installer.check_size()
|
||||||
|
if total_size > free_space:
|
||||||
|
installer.event.on_log_msg(f'Not enough free space.\n'
|
||||||
|
f'Combined title install size: {total_size / (1024 * 1024):0.2f} MiB\n'
|
||||||
|
f'Free space: {free_space / (1024 * 1024):0.2f} MiB')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
result, copied_3dsx = installer.start()
|
result, copied_3dsx = installer.start()
|
||||||
if result is False:
|
if result is False:
|
||||||
# save3ds_fuse failed
|
# save3ds_fuse failed
|
||||||
|
|||||||
Reference in New Issue
Block a user