diff --git a/MSET9_installer_script/errors.txt b/MSET9_installer_script/errors.txt index 5256d33..74d6c43 100644 --- a/MSET9_installer_script/errors.txt +++ b/MSET9_installer_script/errors.txt @@ -10,5 +10,10 @@ Error 09: Could not change back into SD directory. Ensure the SD Card has been r Error 10: Database problem. Follow the troubleshooting to reset the DBs. Error 11: Running as MacOS. MacOS is not supported. Error 12: Multiple ID1s, follow MSET9 Troublshooting page. +Error 13: Device doesn't exist. +Error 14: Can't open device. +Error 15: Not FAT32 formatted or corrupted filesystem. +Error 16: Unable to umount SD card. +Error 17: Root privilege is required. -MSET9 Troublshooting Page: https://3ds.hacks.guide/troubleshooting#installing-boot9strap-mset9 \ No newline at end of file +MSET9 Troublshooting Page: https://3ds.hacks.guide/troubleshooting#installing-boot9strap-mset9 diff --git a/MSET9_installer_script/mset9.command b/MSET9_installer_script/mset9.command new file mode 100755 index 0000000..ff5ea17 --- /dev/null +++ b/MSET9_installer_script/mset9.command @@ -0,0 +1,11 @@ +#!/bin/sh +if which python3 >/dev/null; then + # use exec here to release shell and thus sd card, allow it to be umounted + exec python3 "$(cd "$(dirname "$0")" && pwd)/mset9.py" +else + echo "Python 3 is not installed." + echo "Please install Python 3 and try again." + echo "https://www.python.org/downloads/" + echo "Press ENTER to exit ..." + read DUMMY +fi diff --git a/MSET9_installer_script/mset9.py b/MSET9_installer_script/mset9.py index 4394290..7ded25c 100644 --- a/MSET9_installer_script/mset9.py +++ b/MSET9_installer_script/mset9.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 -import os, platform, time, shutil, binascii +import abc, os, platform, time, binascii -VERSION = "v1.1" +VERSION = "v1.2" def prgood(content): print(f"[\033[0;32m✓\033[0m] {content}") @@ -12,16 +12,404 @@ def prbad(content): def prinfo(content): print(f"[*] {content}") -def exitOnEnter(errCode = 0): +def cleanup(remount=False): + pass + +def exitOnEnter(errCode = 0, remount=False): + cleanup(remount) input("[*] Press Enter to exit...") exit(errCode) +# wrapper for fs operations. can use pyfilesystem2 directly, +# but try to avoid extra dependency on non-darwin system +class FSWrapper(metaclass=abc.ABCMeta): + @abc.abstractmethod + def exists(self, path): + pass + @abc.abstractmethod + def mkdir(self, path): + pass + @abc.abstractmethod + def open(self, path, mode='r'): + pass + @abc.abstractmethod + def getsize(self, path): + pass + @abc.abstractmethod + def remove(self, path): + pass + @abc.abstractmethod + def rename(self, src, dst): + pass + @abc.abstractmethod + def rmtree(self, path): + pass + @abc.abstractmethod + def copytree(self, src, dst): + pass + @abc.abstractmethod + def walk(self, path, topdown=False): + pass + @abc.abstractmethod + def is_writable(self): + pass + @abc.abstractmethod + def ensurespace(self, size): + pass + @abc.abstractmethod + def close(self): + pass + @abc.abstractmethod + def reload(self): + pass + +def remove_extra(): + pass + osver = platform.system() +thisfile = os.path.abspath(__file__) +systmp = None if osver == "Darwin": - prbad("Error 11: macOS is not supported!") - prinfo("Please use a Windows or Linux computer.") - exitOnEnter() + # ======== macOS / iOS? ======== + import sys + + tmpprefix = "mset9-macos-run-" + + def tmp_cleanup(): + global tmpprefix, systmp + prinfo("Removing temporary folders...") + import tempfile, shutil + if systmp is None: + systmp = tempfile.gettempdir() + for dirname in os.listdir(systmp): + if dirname.startswith(tmpprefix): + shutil.rmtree(f"{systmp}/{dirname}") + prinfo("Temporary folders removed!") + + def run_diskutil_and_wait(command, dev): + import subprocess + return subprocess.run(["diskutil", command, dev], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode + + if len(sys.argv) < 2: + if not thisfile.startswith("/Volumes/"): + prbad("Error 01: Couldn't find Nintendo 3DS folder! Ensure that you are running this script from the root of the SD card.") + # should we add some macos specific message? + exitOnEnter() + prinfo("Resolving device...") + device = None + devid = os.stat(thisfile).st_dev + for devname in os.listdir("/dev"): + if not devname.startswith("disk"): + continue + devpath = f"/dev/{devname}" + if os.stat(devpath).st_rdev == devid: + device = devpath + break + if device is None: + #prbad("Error :") + prbad("Can't find matching device, this shouldn't happen...") + exitOnEnter() + + prinfo("Finding previous temporary folder...") + import shutil, tempfile, time + systmp = tempfile.gettempdir() + tmpdir = None + for dirname in os.listdir(systmp): + if dirname.startswith(tmpprefix): + dirpath = f"{systmp}/{dirname}" + script = f"{dirpath}/mset9.py" + if os.path.exists(script) and os.stat(script).st_mtime > os.stat(thisfile).st_mtime: + tmpdir = dirpath + break + else: + shutil.rmtree(dirpath) + if tmpdir is None: + prinfo("Creating temporary folder...") + tmpdir = tempfile.mkdtemp(prefix=tmpprefix) + shutil.copyfile(thisfile, f"{tmpdir}/mset9.py") + + prinfo("Trying to unmount SD card...") + ret = 1 + count = 0 + while count < 10: + ret = run_diskutil_and_wait("umount", device) + if ret == 0: + break + else: + count += 1 + time.sleep(1) + + if ret == 1: + prbad("Error 16: Unable to umount SD card.") + prinfo("Please ensure there's no other app using your SD card.") + #tmp_cleanup() + exitOnEnter() + + os.execlp(sys.executable, sys.executable, f"{tmpdir}/mset9.py", device) + prbad("WTF???") + + device = sys.argv[1] + if len(sys.argv) == 3: + systmp = sys.argv[2] + if not os.path.exists(device): + prbad("Error 13: Device doesn't exist.") + prinfo("Ensure your SD card is inserted properly.") + prinfo("Also, don't eject SD card itself in disk utility, unmount the partition only.") + #tmp_cleanup() + exitOnEnter() + + # auto venv + venv_path = os.path.dirname(thisfile) + venv_bin = f"{venv_path}/bin" + venv_py = f"{venv_bin}/python3" + + def activate_venv(): + global venv_path, venv_bin, venv_py, device, systmp + #import site + os.environ["PATH"] = os.pathsep.join([venv_bin, *os.environ.get("PATH", "").split(os.pathsep)]) + os.environ["VIRTUAL_ENV"] = venv_path + os.environ["VIRTUAL_ENV_PROMPT"] = "(mset9)" + + if systmp is None: + os.execlp(venv_py, venv_py, __file__, device) + else: + os.execlp(venv_py, venv_py, __file__, device, systmp) + + #prev_length = len(sys.path) + #for lib in "__LIB_FOLDERS__".split(os.pathsep): + # path = os.path.realpath(os.path.join(venv_bin, lib)) + # site.addsitedir(path) + # sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length] + #sys.real_prefix = sys.prefix + #sys.prefix = venv_path + + if "VIRTUAL_ENV" not in os.environ and os.path.exists(venv_py): + prinfo("venv found, activate it...") + activate_venv() + + try: + from pyfatfs.PyFatFS import PyFatFS + except ModuleNotFoundError: + prinfo("PyFatFS not found, setting up venv for installing automatically...") + import venv, subprocess + venv.create(venv_path, with_pip=True) + subprocess.run(["bin/pip", "install", "pyfatfs"], cwd=venv_path) + activate_venv() + + # self elevate + if os.getuid() != 0: + # run with osascript won't have raw disk access by default... + # thanks for the perfect security of macos + #args = [sys.executable, thisfile, device] + #escaped_args = map(lambda x: f"\\\"{x}\\\"", args) + #cmd = " ".join(escaped_args) + #osascript = " ".join([ + # f"do shell script \"{cmd}\"", + # "with administrator privileges", + # "without altering line endings" + #]) + #try: + # os.execlp("osascript", "osascript", "-e", osascript) + prinfo("Input the password of your computer if prompted.") + prinfo("(It won't show anything while you're typing, just type it blindly)") + try: + import tempfile + os.execlp("sudo", "sudo", sys.executable, thisfile, device, tempfile.gettempdir()) + except: + prbad("Error 17: Root privilege is required.") + #tmp_cleanup() + exitOnEnter(remount=True) + + from pyfatfs.PyFatFS import PyFatFS + from pyfatfs.FATDirectoryEntry import FATDirectoryEntry, make_lfn_entry + from pyfatfs.EightDotThree import EightDotThree + from pyfatfs._exceptions import PyFATException + import struct + + def make_8dot3_name(dir_name, parent_dir_entry): + dirs, files, _ = parent_dir_entry.get_entries() + dir_entries = [e.get_short_name() for e in dirs + files] + extsep = "." + def map_chars(name: bytes) -> bytes: + _name: bytes = b'' + for b in struct.unpack(f"{len(name)}c", name): + if b == b' ': + _name += b'' + elif ord(b) in EightDotThree.INVALID_CHARACTERS: + _name += b'_' + else: + _name += b + return _name + dir_name = dir_name.upper() + # Shorten to 8 chars; strip invalid characters + basename = os.path.splitext(dir_name)[0][0:8].strip() + if basename.isascii(): + basename = basename.encode("ascii", errors="replace") + basename = map_chars(basename).decode("ascii") + else: + basename = "HAX8D3FN" + # Shorten to 3 chars; strip invalid characters + extname = os.path.splitext(dir_name)[1][1:4].strip() + if basename.isascii(): + extname = extname.encode("ascii", errors="replace") + extname = map_chars(extname).decode("ascii") + elif len(extname) != 0: + extname = "HAX" + if len(extname) == 0: + extsep = "" + # Loop until suiting name is found + i = 0 + while len(str(i)) + 1 <= 7: + if i > 0: + maxlen = 8 - (1 + len(str(i))) + basename = f"{basename[0:maxlen]}~{i}" + short_name = f"{basename}{extsep}{extname}" + if short_name not in dir_entries: + return short_name + i += 1 + raise PyFATException("Cannot generate 8dot3 filename, " + "unable to find suiting short file name.", + errno=errno.EEXIST) + EightDotThree.make_8dot3_name = staticmethod(make_8dot3_name) + + class FatFS(FSWrapper): + def __init__(self, device): + self.device = device + self.reload() + def exists(self, path): + return self.fs.exists(path) + def mkdir(self, path): + self.fs.makedir(path) + def open(self, path, mode='r'): + return self.fs.open(path, mode) + def getsize(self, path): + return self.fs.getsize(path) + def remove(self, path): + self.fs.remove(path) + def rename(self, src, dst): + srcdir, srcname = f"/{src}".rstrip("/").rsplit("/", 1) + dstdir, dstname = f"/{dst}".rstrip("/").rsplit("/", 1) + if srcdir == dstdir and all(not EightDotThree.is_8dot3_conform(n) for n in [srcname, dstname]): + # cursed rename, lfn and same folder only + pdentry = self.fs._get_dir_entry(srcdir) + dentry = pdentry._search_entry(srcname) + lfn_entry = make_lfn_entry(dstname, dentry.name) + dentry.set_lfn_entry(lfn_entry) + self.fs.fs.update_directory_entry(pdentry) + self.fs.fs.flush_fat() + elif self.fs.getinfo(src).is_dir: + self.fs.movedir(src, dst, create=True) + else: + self.fs.move(src, dst, create=True) + def rmtree(self, path): + self.fs.removetree(path) + def copytree(self, src, dst): + self.fs.copydir(src, dst, create=True) + def walk(self, path, topdown=False): # topdown is ignored + for dir_path, dirs, files in self.fs.walk(path): + yield dir_path, list(map(lambda x: x.name, dirs)), list(map(lambda x: x.name, files)) + def is_writable(self): + try: + with self.open("test.txt", "w") as f: + f.write("test") + f.close() + self.remove("test.txt") + return True + except: + return False + def ensurespace(self, size): + try: + first = self.fs.fs.allocate_bytes(size)[0] + self.fs.fs.free_cluster_chain(first) + return True + except PyFATException: + return False + def close(self): + try: + self.fs.close() + except AttributeError: + pass + def reload(self): + self.close() + self.fs = PyFatFS(filename=self.device) + + try: + fs = FatFS(device) + except PyFATException as e: + msg = str(e) + if "Cannot open" in msg: + prbad("Error 14: Can't open device.") + prinfo("Please ensure your SD card is unmounted in disk utility.") + elif "Invalid" in msg: + prbad("Error 15: Not FAT32 formatted or corrupted filesystem.") + prinfo("Please ensure your SD card is properly formatted") + prinfo("Consult: https://wiki.hacks.guide/wiki/Formatting_an_SD_card") + #tmp_cleanup() + exitOnEnter() + + def remove_extra(): + tmp_cleanup() + + def cleanup(remount=False): + global fs, device + fs.close() + if remount: + prinfo("Trying to remount SD card...") + run_diskutil_and_wait("mount", device) + #tmp_cleanup() + + +else: + # ======== Windows / Linux ======== + import shutil + + class OSFS(FSWrapper): + def __init__(self, root): + self.root = root + self.reload() + def abs(self, path): + return os.path.join(self.root, path) + def exists(self, path): + return os.path.exists(self.abs(path)) + def mkdir(self, path): + os.mkdir(self.abs(path)) + def open(self, path, mode='r'): + return open(self.abs(path), mode) + def getsize(self, path): + return os.path.getsize(self.abs(path)) + def remove(self, path): + os.remove(self.abs(path)) + def rename(self, src, dst): + os.rename(self.abs(src), self.abs(dst)) + def rmtree(self, path): + shutil.rmtree(self.abs(path)) + def copytree(self, src, dst): + shutil.copytree(self.abs(src), self.abs(dst)) + def walk(self, path, topdown=False): + return os.walk(self.abs(path), topdown=topdown) + def is_writable(self): + writable = os.access(self.root, os.W_OK) + try: # Bodge for windows + with open("test.txt", "w") as f: + f.write("test") + f.close() + os.remove("test.txt") + except: + writable = False + return writable + def ensurespace(self, size): + return shutil.disk_usage(self.root).free >= size + def close(self): + pass + def reload(self): + try: + os.chdir(self.root) + except Exception: + prbad("Error 09: Couldn't reapply working directory, is SD card reinserted?") + exitOnEnter() + + fs = OSFS(os.path.dirname(thisfile)) def clearScreen(): if osver == "Windows": @@ -29,16 +417,8 @@ def clearScreen(): else: os.system("clear") -cwd = os.path.dirname(os.path.abspath(__file__)) -try: - os.chdir(cwd) -except Exception: - prbad("Failed to set cwd: " + cwd) - prbad("This should pretty much never happen. Try running the script again.") - exitOnEnter() - # Section: insureRoot -if not os.path.exists("Nintendo 3DS/"): +if not fs.exists("Nintendo 3DS/"): prbad("Error 01: Couldn't find Nintendo 3DS folder! Ensure that you are running this script from the root of the SD card.") prbad("If that doesn't work, eject the SD card, and put it back in your console. Turn it on and off again, then rerun this script.") prinfo(f"Current dir: {cwd}") @@ -46,17 +426,9 @@ def clearScreen(): # Section: sdWritable def writeProtectCheck(): + global fs prinfo("Checking if SD card is writeable...") - writeable = os.access(cwd, os.W_OK) - try: # Bodge for windows - with open("test.txt", "w") as f: - f.write("test") - f.close() - os.remove("test.txt") - except: - writeable = False - - if not writeable: + if not fs.is_writable(): prbad("Error 02: Your SD card is write protected! If using a full size SD card, ensure that the lock switch is facing upwards.") prinfo("Visual aid: https://nintendohomebrew.com/assets/img/nhmemes/sdlock.png") exitOnEnter() @@ -65,14 +437,13 @@ def writeProtectCheck(): # Section: SD card free space # ensure 16MB free space -freeSpace = shutil.disk_usage(cwd).free -if freeSpace < 16777216: +if not fs.ensurespace(16777216): prbad(f"Error 06: You need at least 16MB free space on your SD card, you have {(freeSpace / 1000000):.2f} bytes!") prinfo("Please free up some space and try again.") exitOnEnter() clearScreen() -print(f"MSET9 {VERSION} SETUP by zoogie and Aven") +print(f"MSET9 {VERSION} SETUP by zoogie, Aven and DannyAAM") print("What is your console model and version?") print("Old 3DS has two shoulder buttons (L and R)") print("New 3DS has four shoulder buttons (L, R, ZL, ZR)") @@ -100,7 +471,7 @@ def writeProtectCheck(): except KeyboardInterrupt: print() prgood("Goodbye!") - exitOnEnter() + exitOnEnter(remount=True) except: sysModelVerSelect = 42 if sysModelVerSelect == 1: @@ -157,7 +528,7 @@ def writeProtectCheck(): homeDataPath, miiDataPath, homeHex, miiHex = "", "", 0x0, 0x0 def sanity(): - global haxState, realId1Path, id0, id1, homeDataPath, miiDataPath, homeHex, miiHex + global fs, haxState, realId1Path, id0, id1, homeDataPath, miiDataPath, homeHex, miiHex menuExtdataGood = False miiExtdataGood = False @@ -185,15 +556,15 @@ def sanity(): if checkTitledb or checkImportdb: prbad("Error 10: Database(s) malformed or missing!") if not ( - os.path.exists(realId1Path + "/dbs/import.db") - or os.path.exists(realId1Path + "/dbs/title.db") + fs.exists(realId1Path + "/dbs/import.db") + or fs.exists(realId1Path + "/dbs/title.db") ): - if not os.path.exists(realId1Path + "/dbs"): - os.mkdir(realId1Path + "/dbs") + if not fs.exists(realId1Path + "/dbs"): + fs.mkdir(realId1Path + "/dbs") if checkTitledb: - open(realId1Path + "/dbs/title.db", "x").close() + fs.open(realId1Path + "/dbs/title.db", "x").close() if checkImportdb: - open(realId1Path + "/dbs/import.db", "x").close() + fs.open(realId1Path + "/dbs/import.db", "x").close() prinfo("Created empty databases.") prinfo("Please initialize the title database by navigating to System Settings -> Data Management -> Nintendo 3DS -> Software -> Reset, then rerun this script.") @@ -202,16 +573,16 @@ def sanity(): else: prgood("Databases look good!") - if os.path.exists(realId1Path + "/extdata/" + trigger): + if fs.exists(realId1Path + "/extdata/" + trigger): prinfo("Removing stale trigger...") - os.remove(realId1Path + "/extdata/" + trigger) + fs.remove(realId1Path + "/extdata/" + trigger) extdataRoot = realId1Path + "/extdata/00000000" prinfo("Checking for HOME Menu extdata...") for i in homeMenuExtdata: extdataRegionCheck = extdataRoot + f"/{i:08X}" - if os.path.exists(extdataRegionCheck): + if fs.exists(extdataRegionCheck): prgood(f"Detected {regionTable[i]} HOME Menu data!") homeHex = i homeDataPath = extdataRegionCheck @@ -228,7 +599,7 @@ def sanity(): prinfo("Checking for Mii Maker extdata...") for i in miiMakerExtdata: extdataRegionCheck = extdataRoot + f"/{i:08X}" - if os.path.exists(extdataRegionCheck): + if fs.exists(extdataRegionCheck): prgood("Found Mii Maker data!") miiHex = i miiDataPath = extdataRegionCheck @@ -241,38 +612,38 @@ def sanity(): exitOnEnter() def injection(): - global realId1Path, id1 + global fs, realId1Path, id1 - if not os.path.exists(id0 + "/" + hackedId1): + if not fs.exists(id0 + "/" + hackedId1): prinfo("Creating hacked ID1...") hackedId1Path = id0 + "/" + hackedId1 - os.mkdir(hackedId1Path) - os.mkdir(hackedId1Path + "/extdata") - os.mkdir(hackedId1Path + "/extdata/00000000") + fs.mkdir(hackedId1Path) + fs.mkdir(hackedId1Path + "/extdata") + fs.mkdir(hackedId1Path + "/extdata/00000000") else: prinfo("Reusing existing hacked ID1...") hackedId1Path = id0 + "/" + hackedId1 - if not os.path.exists(hackedId1Path + "/dbs"): + if not fs.exists(hackedId1Path + "/dbs"): prinfo("Copying databases to hacked ID1...") - shutil.copytree(realId1Path + "/dbs", hackedId1Path + "/dbs") + fs.copytree(realId1Path + "/dbs", hackedId1Path + "/dbs") prinfo("Copying extdata to hacked ID1...") - if not os.path.exists(hackedId1Path + f"/extdata/00000000/{homeHex:08X}"): - shutil.copytree(homeDataPath, hackedId1Path + f"/extdata/00000000/{homeHex:08X}") - if not os.path.exists(hackedId1Path + f"/extdata/00000000/{miiHex:08X}"): - shutil.copytree(miiDataPath, hackedId1Path + f"/extdata/00000000/{miiHex:08X}") + if not fs.exists(hackedId1Path + f"/extdata/00000000/{homeHex:08X}"): + fs.copytree(homeDataPath, hackedId1Path + f"/extdata/00000000/{homeHex:08X}") + if not fs.exists(hackedId1Path + f"/extdata/00000000/{miiHex:08X}"): + fs.copytree(miiDataPath, hackedId1Path + f"/extdata/00000000/{miiHex:08X}") prinfo("Injecting trigger file...") triggerFilePath = id0 + "/" + hackedId1 + "/extdata/" + trigger - if not os.path.exists(triggerFilePath): - with open(triggerFilePath, "w") as f: + if not fs.exists(triggerFilePath): + with fs.open(triggerFilePath, "w") as f: f.write("plz be haxxed mister arm9, thx") f.close() - if os.path.exists(realId1Path) and realId1BackupTag not in realId1Path: + if fs.exists(realId1Path) and realId1BackupTag not in realId1Path: prinfo("Backing up real ID1...") - os.rename(realId1Path, realId1Path + realId1BackupTag) + fs.rename(realId1Path, realId1Path + realId1BackupTag) id1 += realId1BackupTag realId1Path = f"{id0}/{id1}" else: @@ -282,12 +653,12 @@ def injection(): prgood("MSET9 successfully injected!") def remove(): - global realId1Path, id0, id1 + global fs, realId1Path, id0, id1 prinfo("Removing MSET9...") - if os.path.exists(realId1Path) and realId1BackupTag in realId1Path: + if fs.exists(realId1Path) and realId1BackupTag in realId1Path: prinfo("Renaming original Id1...") - os.rename(realId1Path, id0 + "/" + id1[:32]) + fs.rename(realId1Path, id0 + "/" + id1[:32]) else: prgood("Nothing to remove!") return @@ -295,44 +666,44 @@ def remove(): # print(id1_path, id1_root+"/"+id1[:32]) for id1Index in range(1,5): # Attempt to remove *all* hacked id1s maybeHackedId = bytes.fromhex(encodedId1s[id1Index]).decode("utf-16le") - if os.path.exists(id0 + "/" + maybeHackedId): + if fs.exists(id0 + "/" + maybeHackedId): prinfo("Deleting hacked ID1...") - shutil.rmtree(id0 + "/" + maybeHackedId) + fs.rmtree(id0 + "/" + maybeHackedId) id1 = id1[:32] realId1Path = id0 + "/" + id1 prgood("Successfully removed MSET9!") def softcheck(keyfile, expectedSize = None, crc32 = None, retval = 0): - shortname = keyfile.rsplit("/")[-1] - if not os.path.exists(keyfile): - prbad(f"{shortname} does not exist on SD card!") - return retval - elif expectedSize: - fileSize = os.path.getsize(keyfile) + global fs + split = keyfile.rsplit("/", 1) + if len(split) == 1: + dirname = "/" + filename = split[0] + else: + dirname, filename = split + if not fs.exists(keyfile): + keyfile = os.path.join(dirname, filename.upper()) # this is literally for b9 + if not fs.exists(keyfile): + prbad(f"{filename} does not exist on SD card!") + return retval + if expectedSize: + fileSize = fs.getsize(keyfile) if expectedSize != fileSize: - prbad(f"{shortname} is size {fileSize:,} bytes, not expected {expectedSize:,} bytes") + prbad(f"{filename} is size {fileSize:,} bytes, not expected {expectedSize:,} bytes") return retval elif crc32: - with open(keyfile, "rb") as f: + with fs.open(keyfile, "rb") as f: checksum = binascii.crc32(f.read()) if crc32 != checksum: - prbad(f"{shortname} was not recognized as the correct file") + prbad(f"{filename} was not recognized as the correct file") f.close() return retval f.close() - prgood(f"{shortname} looks good!") + prgood(f"{filename} looks good!") return 0 -def reapplyWorkingDir(): - try: - os.chdir(cwd) - return True - except Exception: - prbad("Error 09: Couldn't reapply working directory, is SD card reinserted?") - return False - # Section: sdwalk -for root, dirs, files in os.walk("Nintendo 3DS/", topdown=True): +for root, dirs, files in fs.walk("Nintendo 3DS/", topdown=True): for name in dirs: # If the name doesn't contain sdmc (Ignores MSET9 exploit folder) @@ -345,7 +716,7 @@ def reapplyWorkingDir(): if type(hexVerify) is int: # Check if the folder (which is either id1 or id0) has the extdata folder # if it does, it's an id1 folder - if os.path.exists(os.path.join(root, name) + "/extdata"): + if fs.exists(os.path.join(root, name) + "/extdata"): id1Count += 1 id1 = name id0 = root @@ -383,7 +754,7 @@ def reapplyWorkingDir(): exitOnEnter() clearScreen() -print(f"MSET9 {VERSION} SETUP by zoogie and Aven") +print(f"MSET9 {VERSION} SETUP by zoogie, Aven and DannyAAM") print(f"Using {consoleModel} {consoleFirmware}") print("\n-- Please type in a number then hit return --\n") @@ -402,11 +773,7 @@ def reapplyWorkingDir(): except: sysModelVerSelect = 42 - try: - os.chdir(cwd) - except Exception: - prbad("Error 09: Couldn't reapply working directory, is SD card reinserted?") - exitOnEnter() + fs.reload() if sysModelVerSelect == 1: sanity() @@ -418,11 +785,13 @@ def reapplyWorkingDir(): exitOnEnter() elif sysModelVerSelect == 3: remove() - exitOnEnter() + remove_extra() + exitOnEnter(remount=True) elif sysModelVerSelect == 4 or "exit": - prgood("Goodbye!") break else: prinfo("Invalid input, try again. Valid inputs: 1, 2, 3, 4") -time.sleep(2) \ No newline at end of file +cleanup(remount=True) +prgood("Goodbye!") +time.sleep(2)