diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index 3c84ac5c..5ca6b775 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -52,7 +52,7 @@ struct FSPath { FSPath() {} - FSPath(u32 type, std::vector vec) : type(type) { + FSPath(u32 type, const std::vector& vec) : type(type) { switch (type) { case PathType::Binary: binary = std::move(vec); @@ -90,7 +90,7 @@ struct FileSession { bool isOpen; FileSession(ArchiveBase* archive, const FSPath& filePath, FILE* fd, bool isOpen = true) : - archive(archive), path(path), fd(fd), isOpen(isOpen) {} + archive(archive), path(filePath), fd(fd), isOpen(isOpen) {} }; struct ArchiveSession { diff --git a/include/fs/archive_ncch.hpp b/include/fs/archive_ncch.hpp index 90ee1c02..d76513e3 100644 --- a/include/fs/archive_ncch.hpp +++ b/include/fs/archive_ncch.hpp @@ -18,4 +18,10 @@ public: auto cxi = mem.getCXI(); return (cxi != nullptr && cxi->hasRomFS()); } + + // Returns whether the cart has an ExeFS (All executable carts should have an ExeFS. This is just here to be safe) + bool hasExeFS() { + auto cxi = mem.getCXI(); + return (cxi != nullptr && cxi->hasExeFS()); + } }; \ No newline at end of file diff --git a/src/core/fs/archive_ncch.cpp b/src/core/fs/archive_ncch.cpp index 54ff4812..7557b639 100644 --- a/src/core/fs/archive_ncch.cpp +++ b/src/core/fs/archive_ncch.cpp @@ -1,6 +1,14 @@ #include "fs/archive_ncch.hpp" #include +// The part of the NCCH archive we're trying to access. Depends on the first 4 bytes of the binary file path +namespace PathType { + enum : u32 { + RomFS = 0, + ExeFS = 2 + }; +}; + CreateFileResult SelfNCCHArchive::createFile(const FSPath& path, u64 size) { Helpers::panic("[SelfNCCH] CreateFile not yet supported"); return CreateFileResult::Success; @@ -20,8 +28,8 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe // Where to read the file from. (https://www.3dbrew.org/wiki/Filesystem_services#SelfNCCH_File_Path_Data_Format) // We currently only know how to read from an NCCH's RomFS, ie type = 0 const u32 type = *(u32*)&path.binary[0]; // TODO: Get rid of UB here - if (type != 0) { - Helpers::panic("Read from NCCH's non-RomFS section!"); + if (type != PathType::RomFS && type != PathType::ExeFS) { + Helpers::panic("Read from NCCH's non-RomFS & non-exeFS section!"); } return NoFile; // No file descriptor needed for RomFS @@ -37,7 +45,15 @@ ArchiveBase* SelfNCCHArchive::openArchive(const FSPath& path) { } std::optional SelfNCCHArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) { - if (!hasRomFS()) { + const FSPath& path = file->path; // Path of the file + const u32 type = *(u32*)&path.binary[0]; // Type of the path + + if (type == PathType::RomFS && !hasRomFS()) { + Helpers::panic("Tried to read file from non-existent RomFS"); + return std::nullopt; + } + + if (type == PathType::ExeFS && !hasExeFS()) { Helpers::panic("Tried to read file from non-existent RomFS"); return std::nullopt; } @@ -48,22 +64,42 @@ std::optional SelfNCCHArchive::readFile(FileSession* file, u64 offset, u32 } auto cxi = mem.getCXI(); - const u32 romFSSize = cxi->romFS.size; - const u32 romFSOffset = cxi->romFS.offset; - if ((offset >> 32) || (offset >= romFSSize) || (offset + size >= romFSSize)) { - Helpers::panic("Tried to read from SelfNCCH with too big of an offset"); - } - IOFile& ioFile = mem.CXIFile; - if (!ioFile.seek(cxi->fileOffset + romFSOffset + offset + 0x1000)) { - Helpers::panic("Failed to seek while reading from RomFS"); + + // Seek to file offset depending on if we're reading from RomFS, ExeFS, etc + switch (type) { + case PathType::RomFS: { + const u32 romFSSize = cxi->romFS.size; + const u32 romFSOffset = cxi->romFS.offset; + if ((offset >> 32) || (offset >= romFSSize) || (offset + size >= romFSSize)) { + Helpers::panic("Tried to read from SelfNCCH with too big of an offset"); + } + + if (!ioFile.seek(cxi->fileOffset + romFSOffset + offset + 0x1000)) { + Helpers::panic("Failed to seek while reading from RomFS"); + } + break; + } + + case PathType::ExeFS: { + const u32 exeFSSize = cxi->exeFS.size; + const u32 exeFSOffset = cxi->exeFS.offset; + if ((offset >> 32) || (offset >= exeFSSize) || (offset + size >= exeFSSize)) { + Helpers::panic("Tried to read from SelfNCCH with too big of an offset"); + } + + if (!ioFile.seek(cxi->fileOffset + exeFSOffset + offset)) { // TODO: Not sure if this needs the + 0x1000 + Helpers::panic("Failed to seek while reading from ExeFS"); + } + break; + } } std::unique_ptr data(new u8[size]); auto [success, bytesRead] = ioFile.readBytes(&data[0], size); if (!success) { - Helpers::panic("Failed to read from RomFS"); + Helpers::panic("Failed to read from NCCH archive"); } for (u64 i = 0; i < bytesRead; i++) {