From 4dc04be350985c27dff651c63f16556d3145521c Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Tue, 16 May 2023 23:37:52 +0300 Subject: [PATCH] [FS] Formatting archives v1 --- include/fs/archive_base.hpp | 4 ++++ include/fs/archive_ext_save_data.hpp | 4 ++++ include/fs/archive_save_data.hpp | 8 +++++++- src/core/fs/archive_ext_save_data.cpp | 17 +++++++++++++++++ src/core/fs/archive_save_data.cpp | 22 ++++++++++++++++++++-- src/core/services/fs.cpp | 16 +++++++++++++++- 6 files changed, 67 insertions(+), 4 deletions(-) diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index 4e5f99f1..8de78ad3 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -224,6 +224,10 @@ public: return Err(FSResult::FileNotFound); } + virtual void format(const FSPath& path, const FormatInfo& info) { + Helpers::panic("Unimplemented Format for %s archive", name().c_str()); + } + // Read size bytes from a file starting at offset "offset" into a certain buffer in memory // Returns the number of bytes read, or nullopt if the read failed virtual std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0; diff --git a/include/fs/archive_ext_save_data.hpp b/include/fs/archive_ext_save_data.hpp index b2eab9b7..95c822e9 100644 --- a/include/fs/archive_ext_save_data.hpp +++ b/include/fs/archive_ext_save_data.hpp @@ -17,6 +17,10 @@ public: FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override; std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override; + // Takes in a binary ExtSaveData path, outputs a combination of the backing folder with the low and high save entries of the path + // Used for identifying the archive format info files + std::string getExtSaveDataPathFromBinary(const FSPath& path); + 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/fs/archive_save_data.hpp b/include/fs/archive_save_data.hpp index 4bc0a15e..f7642955 100644 --- a/include/fs/archive_save_data.hpp +++ b/include/fs/archive_save_data.hpp @@ -11,13 +11,19 @@ public: FSResult createDirectory(const FSPath& path) override; FSResult createFile(const FSPath& path, u64 size) override; FSResult deleteFile(const FSPath& path) override; - FormatInfo getFormatInfo(const FSPath& path) override; Rust::Result 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; + void format(const FSPath& path, const FormatInfo& info) override; + FormatInfo getFormatInfo(const FSPath& path) override; + + std::filesystem::path getFormatInfoPath() { + return IOFile::getAppData() / "FormatInfo" / "SaveData.format"; + } + // Returns whether the cart has save data or not bool cartHasSaveData() { auto cxi = mem.getCXI(); diff --git a/src/core/fs/archive_ext_save_data.cpp b/src/core/fs/archive_ext_save_data.cpp index 375ba8bc..51b89aca 100644 --- a/src/core/fs/archive_ext_save_data.cpp +++ b/src/core/fs/archive_ext_save_data.cpp @@ -70,11 +70,28 @@ FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& return FileError; } +std::string ExtSaveDataArchive::getExtSaveDataPathFromBinary(const FSPath& path) { + // TODO: Remove punning here + const u32 mediaType = *(u32*)&path.binary[0]; + const u32 saveLow = *(u32*)&path.binary[4]; + const u32 saveHigh = *(u32*)&path.binary[8]; + + // TODO: Should the media type be used here + return backingFolder + std::to_string(saveLow) + std::to_string(saveHigh); +} + Rust::Result ExtSaveDataArchive::openArchive(const FSPath& path) { if (path.type != PathType::Binary || path.binary.size() != 12) { Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive"); } + // Create a format info path in the style of AppData/FormatInfo/Cartridge10390390194.format + fs::path formatInfopath = IOFile::getAppData() / "FormatInfo" / (getExtSaveDataPathFromBinary(path) + ".format"); + // Format info not found so the archive is not formatted + if (!fs::is_regular_file(formatInfopath)) { + return isShared ? Err(FSResult::NotFormatted) : Err(FSResult::NotFoundInvalid); + } + return Ok((ArchiveBase*)this); } diff --git a/src/core/fs/archive_save_data.cpp b/src/core/fs/archive_save_data.cpp index 4e8051ac..a25ba08f 100644 --- a/src/core/fs/archive_save_data.cpp +++ b/src/core/fs/archive_save_data.cpp @@ -94,8 +94,20 @@ Rust::Result SaveDataArchive::openDirectory(const FS } ArchiveBase::FormatInfo SaveDataArchive::getFormatInfo(const FSPath& path) { - //Helpers::panic("Unimplemented SaveData::GetFormatInfo"); - return FormatInfo{ .size = 0, .numOfDirectories = 255, .numOfFiles = 255, .duplicateData = false }; + Helpers::panic("Unimplemented SaveData::GetFormatInfo"); +} + +void SaveDataArchive::format(const FSPath& path, const ArchiveBase::FormatInfo& info) { + const fs::path saveDataPath = IOFile::getAppData() / "SaveData"; + const fs::path formatInfoPath = getFormatInfoPath(); + + // Delete all contents by deleting the directory then recreating it + fs::remove_all(saveDataPath); + fs::create_directories(saveDataPath); + + // Write format info on disk + IOFile file(formatInfoPath, "wb"); + file.writeBytes(&info, sizeof(info)); } Rust::Result SaveDataArchive::openArchive(const FSPath& path) { @@ -104,6 +116,12 @@ Rust::Result SaveDataArchive::openArchive(const FSPath& return Err(FSResult::NotFoundInvalid); } + const fs::path formatInfoPath = getFormatInfoPath(); + // Format info not found so the archive is not formatted + if (!fs::is_regular_file(formatInfoPath)) { + return Err(FSResult::NotFormatted); + } + return Ok((ArchiveBase*)this); } diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index b790e229..39766130 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -48,6 +48,7 @@ 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 + const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info namespace fs = std::filesystem; // TODO: SDMC, etc @@ -62,6 +63,10 @@ void FSService::initializeFilesystem() { if (!fs::is_directory(savePath)) { fs::create_directories(savePath); } + + if (!fs::is_directory(formatPath)) { + fs::create_directories(formatPath); + } } ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) { @@ -440,9 +445,18 @@ void FSService::formatSaveData(u32 messagePointer) { const u32 fileNum = mem.read32(messagePointer + 24); // Max number of files const u32 directoryBucketNum = mem.read32(messagePointer + 28); // Not sure what a directory bucket is...? const u32 fileBucketNum = mem.read32(messagePointer + 32); // Same here - const bool duplicateData = mem.read8(messagePointer + 36) != 0; + const bool duplicateData = mem.read8(messagePointer + 36) != 0; + + ArchiveBase::FormatInfo info { + .size = blockSize * 0x200, + .numOfDirectories = directoryNum, + .numOfFiles = fileNum, + .duplicateData = duplicateData + }; printf("Stubbed FS::FormatSaveData. File num: %d, directory num: %d\n", fileNum, directoryNum); + saveData.format(path, info); + mem.write32(messagePointer, IPC::responseHeader(0x84C, 1, 0)); mem.write32(messagePointer + 4, ResultCode::Success); }