From f90a266bb44bd9cd4b3e2835bcbb9457c7960252 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 3 Apr 2023 01:19:52 +0300 Subject: [PATCH] [FS] Rehaul to implement all the different things ExtSaveData can target --- include/fs/archive_ext_save_data.hpp | 7 +++-- include/services/fs.hpp | 18 +++++++------ src/core/fs/archive_ext_save_data.cpp | 32 ++++++++++++++++++---- src/core/services/fs.cpp | 38 ++++++++++++++++++++------- 4 files changed, 71 insertions(+), 24 deletions(-) diff --git a/include/fs/archive_ext_save_data.hpp b/include/fs/archive_ext_save_data.hpp index 207ab455..eeef3b46 100644 --- a/include/fs/archive_ext_save_data.hpp +++ b/include/fs/archive_ext_save_data.hpp @@ -3,17 +3,20 @@ class ExtSaveDataArchive : public ArchiveBase { public: - ExtSaveDataArchive(Memory& mem) : ArchiveBase(mem) {} + ExtSaveDataArchive(Memory& mem, const std::string& folder, bool isShared = false) : ArchiveBase(mem), + isShared(isShared), backingFolder(folder) {} u64 getFreeBytes() override { Helpers::panic("ExtSaveData::GetFreeBytes unimplemented"); return 0; } - std::string name() override { return "ExtSaveData"; } + std::string name() override { return "ExtSaveData::" + backingFolder; } FSResult createFile(const FSPath& path, u64 size) override; FSResult deleteFile(const FSPath& path) override; ArchiveBase* openArchive(const FSPath& path) override; + Rust::Result openDirectory(const FSPath& path) override; FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override; std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override; bool isShared = false; + std::string backingFolder; // Backing folder for the archive. Can be NAND, Gamecard or SD depending on the archive path. }; \ No newline at end of file diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 960caaa6..27944c13 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -22,12 +22,15 @@ class FSService { // The different filesystem archives (Save data, SelfNCCH, SDMC, NCCH, ExtData, etc) SelfNCCHArchive selfNcch; SaveDataArchive saveData; - ExtSaveDataArchive extSaveData; - ExtSaveDataArchive sharedExtSaveData; SDMCArchive sdmc; NCCHArchive ncch; - ArchiveBase* getArchiveFromID(u32 id); + ExtSaveDataArchive extSaveData_nand; + ExtSaveDataArchive extSaveData_cart; + ExtSaveDataArchive sharedExtSaveData_nand; + ExtSaveDataArchive sharedExtSaveData_cart; + + ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath); std::optional openArchiveHandle(u32 archiveID, const FSPath& path); Rust::Result openDirectoryHandle(ArchiveBase* archive, const FSPath& path); std::optional openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms); @@ -53,11 +56,10 @@ class FSService { u32 priority; public: - FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), extSaveData(mem), sharedExtSaveData(mem), sdmc(mem), - selfNcch(mem), ncch(mem), kernel(kernel) - { - sharedExtSaveData.isShared = true; // Need to do this here because templates and virtual classes do not mix well - } + FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem), extSaveData_nand(mem, "NAND"), + sharedExtSaveData_nand(mem, "NAND", true), extSaveData_cart(mem, "CartSave"), sharedExtSaveData_cart(mem, "CartSave", true), + sdmc(mem), selfNcch(mem), ncch(mem), kernel(kernel) + {} void reset(); void handleSyncRequest(u32 messagePointer); diff --git a/src/core/fs/archive_ext_save_data.cpp b/src/core/fs/archive_ext_save_data.cpp index c9f336c3..409de5df 100644 --- a/src/core/fs/archive_ext_save_data.cpp +++ b/src/core/fs/archive_ext_save_data.cpp @@ -11,7 +11,7 @@ FSResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in ExtSaveData::CreateFile"); - fs::path p = IOFile::getAppData() / "NAND"; + fs::path p = IOFile::getAppData() / backingFolder; p += fs::path(path.utf16_string).make_preferred(); if (fs::exists(p)) @@ -35,7 +35,7 @@ FSResult ExtSaveDataArchive::deleteFile(const FSPath& path) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in ExtSaveData::DeleteFile"); - fs::path p = IOFile::getAppData() / "NAND"; + fs::path p = IOFile::getAppData() / backingFolder; p += fs::path(path.utf16_string).make_preferred(); std::error_code ec; @@ -55,7 +55,7 @@ FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& if (perms.create()) Helpers::panic("[ExtSaveData] Can't open file with create flag"); - fs::path p = IOFile::getAppData() / "NAND"; + fs::path p = IOFile::getAppData() / backingFolder; p += fs::path(path.utf16_string).make_preferred(); if (fs::exists(p)) { // Return file descriptor if the file exists @@ -75,11 +75,33 @@ ArchiveBase* ExtSaveDataArchive::openArchive(const FSPath& path) { Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive"); } - if (path.binary[0] != 0) Helpers::panic("ExtSaveData: Tried to access something other than NAND. ID: %02X", path.binary[0]); - return this; } +Rust::Result ExtSaveDataArchive::openDirectory(const FSPath& path) { + if (path.type == PathType::UTF16) { + if (!isPathSafe(path)) + Helpers::panic("Unsafe path in ExtSaveData::OpenDirectory"); + + fs::path p = IOFile::getAppData() / backingFolder; + p += fs::path(path.utf16_string).make_preferred(); + + if (fs::is_regular_file(p)) { + printf("ExtSaveData: OpenArchive used with a file path"); + return Err(FSResult::UnexpectedFileOrDir); + } + + if (fs::is_directory(p)) { + return Ok(DirectorySession(this, p)); + } else { + return Err(FSResult::FileNotFound); + } + } + + Helpers::panic("ExtSaveDataArchive::OpenDirectory: Unimplemented path type"); + return Err(FSResult::Success); +} + std::optional ExtSaveDataArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) { Helpers::panic("ExtSaveDataArchive::ReadFile: Failed"); return std::nullopt; diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 9f5ae451..3642fa20 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -41,6 +41,7 @@ void FSService::reset() { // Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM. void FSService::initializeFilesystem() { const auto nandPath = IOFile::getAppData() / "NAND"; // Create NAND + const auto cartPath = IOFile::getAppData() / "CartSave"; // Create cartridge save folder for use with ExtSaveData const auto savePath = IOFile::getAppData() / "SaveData"; // Create SaveData namespace fs = std::filesystem; // TODO: SDMC, etc @@ -49,17 +50,37 @@ void FSService::initializeFilesystem() { fs::create_directories(nandPath); } + if (!fs::is_directory(cartPath)) { + fs::create_directories(cartPath); + } + if (!fs::is_directory(savePath)) { fs::create_directories(savePath); } } -ArchiveBase* FSService::getArchiveFromID(u32 id) { +ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) { switch (id) { case ArchiveID::SelfNCCH: return &selfNcch; case ArchiveID::SaveData: return &saveData; - case ArchiveID::ExtSaveData: return &extSaveData; - case ArchiveID::SharedExtSaveData: return &sharedExtSaveData; + case ArchiveID::ExtSaveData: + if (archivePath.type == PathType::Binary) { + switch (archivePath.binary[0]) { + case 0: return &extSaveData_nand; + case 1: return &extSaveData_cart; + } + } + return nullptr; + + case ArchiveID::SharedExtSaveData: + if (archivePath.type == PathType::Binary) { + switch (archivePath.binary[0]) { + case 0: return &sharedExtSaveData_nand; + case 1: return &sharedExtSaveData_cart; + } + } + return nullptr; + case ArchiveID::SDMC: return &sdmc; case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI default: @@ -96,7 +117,7 @@ Rust::Result FSService::openDirectoryHandle(ArchiveBase* archi } std::optional FSService::openArchiveHandle(u32 archiveID, const FSPath& path) { - ArchiveBase* archive = getArchiveFromID(archiveID); + ArchiveBase* archive = getArchiveFromID(archiveID, path); if (archive == nullptr) [[unlikely]] { Helpers::panic("OpenArchive: Tried to open unknown archive %d.", archiveID); @@ -264,15 +285,14 @@ void FSService::openFileDirectly(u32 messagePointer) { const u32 attributes = mem.read32(messagePointer + 32); const u32 archivePathPointer = mem.read32(messagePointer + 40); const u32 filePathPointer = mem.read32(messagePointer + 48); - log("FS::OpenFileDirectly\n"); - ArchiveBase* archive = getArchiveFromID(archiveID); + auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize); + ArchiveBase* archive = getArchiveFromID(archiveID, archivePath); + if (archive == nullptr) [[unlikely]] { Helpers::panic("OpenFileDirectly: Tried to open unknown archive %d.", archiveID); } - - auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize); auto filePath = readPath(filePathType, filePathPointer, filePathSize); const FilePerms perms(openFlags); @@ -344,7 +364,7 @@ void FSService::getFormatInfo(u32 messagePointer) { const auto path = readPath(pathType, pathPointer, pathSize); log("FS::GetFormatInfo(archive ID = %d, archive path type = %d)\n", archiveID, pathType); - ArchiveBase* archive = getArchiveFromID(archiveID); + ArchiveBase* archive = getArchiveFromID(archiveID, path); if (archive == nullptr) [[unlikely]] { Helpers::panic("OpenArchive: Tried to open unknown archive %d.", archiveID); }