mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 14:45:41 +12:00
Merge pull request #7 from wheremyfoodat/DSP-n-FS-work
Better DSP & FS HLE
This commit is contained in:
commit
9ca66f4157
11 changed files with 234 additions and 58 deletions
|
@ -204,10 +204,11 @@ public:
|
|||
virtual u64 getFreeBytes() = 0;
|
||||
virtual FSResult createFile(const FSPath& path, u64 size) = 0;
|
||||
virtual FSResult deleteFile(const FSPath& path) = 0;
|
||||
virtual FormatInfo getFormatInfo(const FSPath& path) {
|
||||
|
||||
virtual Rust::Result<FormatInfo, FSResult> getFormatInfo(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str());
|
||||
// Return a dummy struct just to avoid the UB of not returning anything, even if we panic
|
||||
return FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false };
|
||||
return Ok(FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false });
|
||||
}
|
||||
|
||||
virtual FSResult createDirectory(const FSPath& path) {
|
||||
|
@ -224,6 +225,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<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
|
||||
|
|
|
@ -17,6 +17,10 @@ public:
|
|||
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
||||
std::optional<u32> 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.
|
||||
};
|
|
@ -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<ArchiveBase*, FSResult> openArchive(const FSPath& path) override;
|
||||
Rust::Result<DirectorySession, FSResult> openDirectory(const FSPath& path) override;
|
||||
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
||||
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||
|
||||
void format(const FSPath& path, const FormatInfo& info) override;
|
||||
Rust::Result<FormatInfo, FSResult> 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();
|
||||
|
|
|
@ -146,6 +146,7 @@ private:
|
|||
// File operations
|
||||
void handleFileOperation(u32 messagePointer, Handle file);
|
||||
void closeFile(u32 messagePointer, Handle file);
|
||||
void flushFile(u32 messagePointer, Handle file);
|
||||
void readFile(u32 messagePointer, Handle file);
|
||||
void writeFile(u32 messagePointer, Handle file);
|
||||
void getFileSize(u32 messagePointer, Handle file);
|
||||
|
|
|
@ -25,13 +25,11 @@ class FSService {
|
|||
SDMCArchive sdmc;
|
||||
NCCHArchive ncch;
|
||||
|
||||
ExtSaveDataArchive extSaveData_nand;
|
||||
ExtSaveDataArchive extSaveData_cart;
|
||||
ExtSaveDataArchive extSaveData_sdmc;
|
||||
ExtSaveDataArchive sharedExtSaveData_nand;
|
||||
ExtSaveDataArchive sharedExtSaveData_cart;
|
||||
|
||||
ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath);
|
||||
std::optional<Handle> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||
Rust::Result<Handle, FSResult> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||
Rust::Result<Handle, FSResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
||||
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
||||
FSPath readPath(u32 type, u32 pointer, u32 size);
|
||||
|
@ -43,6 +41,7 @@ class FSService {
|
|||
void controlArchive(u32 messagePointer);
|
||||
void deleteFile(u32 messagePointer);
|
||||
void formatSaveData(u32 messagePointer);
|
||||
void formatThisUserSaveData(u32 messagePointer);
|
||||
void getFreeBytes(u32 messagePointer);
|
||||
void getFormatInfo(u32 messagePointer);
|
||||
void getPriority(u32 messagePointer);
|
||||
|
@ -59,8 +58,8 @@ class FSService {
|
|||
u32 priority;
|
||||
|
||||
public:
|
||||
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),
|
||||
FSService(Memory& mem, Kernel& kernel) : mem(mem), saveData(mem),
|
||||
sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"),
|
||||
sdmc(mem), selfNcch(mem), ncch(mem), kernel(kernel)
|
||||
{}
|
||||
|
||||
|
|
|
@ -53,4 +53,4 @@ Simply drag and drop a ROM to the executable if supported, or invoke the executa
|
|||
Nintendo 3DS is a registered trademark of Nintendo Co., Ltd.
|
||||
|
||||

|
||||
Here's a panda it go blep
|
||||
Here's a panda it go blep
|
||||
|
|
|
@ -38,12 +38,27 @@ FSResult ExtSaveDataArchive::deleteFile(const FSPath& path) {
|
|||
fs::path p = IOFile::getAppData() / backingFolder;
|
||||
p += fs::path(path.utf16_string).make_preferred();
|
||||
|
||||
if (fs::is_directory(p)) {
|
||||
Helpers::panic("ExtSaveData::DeleteFile: Tried to delete directory");
|
||||
}
|
||||
|
||||
if (!fs::is_regular_file(p)) {
|
||||
return FSResult::FileNotFound;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
bool success = fs::remove(p, ec);
|
||||
return success ? FSResult::Success : FSResult::FileNotFound;
|
||||
|
||||
// It might still be possible for fs::remove to fail, if there's eg an open handle to a file being deleted
|
||||
// In this case, print a warning, but still return success for now
|
||||
if (!success) {
|
||||
Helpers::warn("ExtSaveData::DeleteFile: fs::remove failed\n");
|
||||
}
|
||||
|
||||
return FSResult::Success;
|
||||
}
|
||||
|
||||
Helpers::panic("ExtSaveDataArchive::DeleteFile: Failed");
|
||||
Helpers::panic("ExtSaveDataArchive::DeleteFile: Unknown path type");
|
||||
return FSResult::Success;
|
||||
}
|
||||
|
||||
|
@ -70,11 +85,29 @@ 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<ArchiveBase*, FSResult> ExtSaveDataArchive::openArchive(const FSPath& path) {
|
||||
if (path.type != PathType::Binary || path.binary.size() != 12) {
|
||||
Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive");
|
||||
}
|
||||
|
||||
// TODO: Readd the format check. I didn't manage to fix it sadly
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,34 @@ FSResult SaveDataArchive::createDirectory(const FSPath& path) {
|
|||
}
|
||||
|
||||
FSResult SaveDataArchive::deleteFile(const FSPath& path) {
|
||||
Helpers::panic("[SaveData] Unimplemented DeleteFile");
|
||||
if (path.type == PathType::UTF16) {
|
||||
if (!isPathSafe<PathType::UTF16>(path))
|
||||
Helpers::panic("Unsafe path in SaveData::DeleteFile");
|
||||
|
||||
fs::path p = IOFile::getAppData() / "SaveData";
|
||||
p += fs::path(path.utf16_string).make_preferred();
|
||||
|
||||
if (fs::is_directory(p)) {
|
||||
Helpers::panic("SaveData::DeleteFile: Tried to delete directory");
|
||||
}
|
||||
|
||||
if (!fs::is_regular_file(p)) {
|
||||
return FSResult::FileNotFound;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
bool success = fs::remove(p, ec);
|
||||
|
||||
// It might still be possible for fs::remove to fail, if there's eg an open handle to a file being deleted
|
||||
// In this case, print a warning, but still return success for now
|
||||
if (!success) {
|
||||
Helpers::warn("SaveData::DeleteFile: fs::remove failed\n");
|
||||
}
|
||||
|
||||
return FSResult::Success;
|
||||
}
|
||||
|
||||
Helpers::panic("SaveDataArchive::DeleteFile: Unknown path type");
|
||||
return FSResult::Success;
|
||||
}
|
||||
|
||||
|
@ -93,9 +120,36 @@ Rust::Result<DirectorySession, FSResult> SaveDataArchive::openDirectory(const FS
|
|||
return Err(FSResult::Success);
|
||||
}
|
||||
|
||||
ArchiveBase::FormatInfo SaveDataArchive::getFormatInfo(const FSPath& path) {
|
||||
//Helpers::panic("Unimplemented SaveData::GetFormatInfo");
|
||||
return FormatInfo{ .size = 0, .numOfDirectories = 255, .numOfFiles = 255, .duplicateData = false };
|
||||
Rust::Result<ArchiveBase::FormatInfo, FSResult> SaveDataArchive::getFormatInfo(const FSPath& path) {
|
||||
const fs::path formatInfoPath = getFormatInfoPath();
|
||||
IOFile file(formatInfoPath, "rb");
|
||||
|
||||
// If the file failed to open somehow, we return that the archive is not formatted
|
||||
if (!file.isOpen()) {
|
||||
return Err(FSResult::NotFormatted);
|
||||
}
|
||||
|
||||
FormatInfo ret;
|
||||
auto [success, bytesRead] = file.readBytes(&ret, sizeof(FormatInfo));
|
||||
if (!success || bytesRead != sizeof(FormatInfo)) {
|
||||
Helpers::warn("SaveData::GetFormatInfo: Format file exists but was not properly read into the FormatInfo struct");
|
||||
return Err(FSResult::NotFormatted);
|
||||
}
|
||||
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
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<ArchiveBase*, FSResult> SaveDataArchive::openArchive(const FSPath& path) {
|
||||
|
@ -104,6 +158,12 @@ Rust::Result<ArchiveBase*, FSResult> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ FileDescriptor SDMCArchive::openFile(const FSPath& path, const FilePerms& perms)
|
|||
|
||||
Rust::Result<ArchiveBase*, FSResult> SDMCArchive::openArchive(const FSPath& path) {
|
||||
printf("SDMCArchive::OpenArchive: Failed\n");
|
||||
return Ok((ArchiveBase*)nullptr);
|
||||
return Err(FSResult::NotFormatted);
|
||||
}
|
||||
|
||||
std::optional<u32> SDMCArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "ipc.hpp"
|
||||
#include "kernel.hpp"
|
||||
|
||||
namespace FileOps {
|
||||
|
@ -7,6 +8,7 @@ namespace FileOps {
|
|||
GetSize = 0x08040000,
|
||||
SetSize = 0x08050080,
|
||||
Close = 0x08080000,
|
||||
Flush = 0x08090000,
|
||||
SetPriority = 0x080A0040,
|
||||
OpenLinkFile = 0x080C0000
|
||||
};
|
||||
|
@ -41,7 +43,30 @@ void Kernel::closeFile(u32 messagePointer, Handle fileHandle) {
|
|||
Helpers::panic("Called CloseFile on non-existent file");
|
||||
}
|
||||
|
||||
p->getData<FileSession>()->isOpen = false;
|
||||
FileSession* session = p->getData<FileSession>();
|
||||
session->isOpen = false;
|
||||
if (session->fd != nullptr) {
|
||||
fclose(session->fd);
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0808, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void Kernel::flushFile(u32 messagePointer, Handle fileHandle) {
|
||||
logFileIO("Flushed file %X\n", fileHandle);
|
||||
|
||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||
if (p == nullptr) [[unlikely]] {
|
||||
Helpers::panic("Called FlushFile on non-existent file");
|
||||
}
|
||||
|
||||
FileSession* session = p->getData<FileSession>();
|
||||
if (session->fd != nullptr) {
|
||||
fflush(session->fd);
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0809, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
|
@ -58,6 +83,8 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
|||
Helpers::panic("Called ReadFile on non-existent file");
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0802, 2, 2));
|
||||
|
||||
FileSession* file = p->getData<FileSession>();
|
||||
if (!file->isOpen) {
|
||||
Helpers::panic("Tried to read closed file");
|
||||
|
@ -126,6 +153,7 @@ void Kernel::writeFile(u32 messagePointer, Handle fileHandle) {
|
|||
IOFile f(file->fd);
|
||||
auto [success, bytesWritten] = f.writeBytes(data.get(), size);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0803, 2, 2));
|
||||
if (!success) {
|
||||
Helpers::panic("Kernel::WriteFile failed");
|
||||
} else {
|
||||
|
@ -146,6 +174,7 @@ void Kernel::setFileSize(u32 messagePointer, Handle fileHandle) {
|
|||
if (!file->isOpen) {
|
||||
Helpers::panic("Tried to get size of closed file");
|
||||
}
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0805, 1, 0));
|
||||
|
||||
if (file->fd) {
|
||||
const u64 newSize = mem.read64(messagePointer + 4);
|
||||
|
@ -174,6 +203,7 @@ void Kernel::getFileSize(u32 messagePointer, Handle fileHandle) {
|
|||
if (!file->isOpen) {
|
||||
Helpers::panic("Tried to get size of closed file");
|
||||
}
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0804, 3, 0));
|
||||
|
||||
if (file->fd) {
|
||||
IOFile f(file->fd);
|
||||
|
@ -212,6 +242,7 @@ void Kernel::openLinkFile(u32 messagePointer, Handle fileHandle) {
|
|||
// However we do seek properly on every file access so this shouldn't matter
|
||||
cloneFile.data = new FileSession(*file);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x080C, 1, 2));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 12, handle);
|
||||
}
|
||||
|
@ -231,5 +262,6 @@ void Kernel::setFilePriority(u32 messagePointer, Handle fileHandle) {
|
|||
}
|
||||
file->priority = priority;
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x080A, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
|
@ -21,6 +21,7 @@ namespace FSCommands {
|
|||
OpenArchive = 0x080C00C2,
|
||||
ControlArchive = 0x080D0144,
|
||||
CloseArchive = 0x080E0080,
|
||||
FormatThisUserSaveData = 0x080F0180,
|
||||
GetFreeBytes = 0x08120080,
|
||||
IsSdmcDetected = 0x08170000,
|
||||
GetFormatInfo = 0x084500C2,
|
||||
|
@ -45,23 +46,29 @@ 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
|
||||
const auto sdmcPath = IOFile::getAppData() / "SDMC"; // Create SDMC directory
|
||||
const auto nandSharedpath = IOFile::getAppData() / ".." / "SharedFiles" / "NAND";
|
||||
|
||||
if (!fs::is_directory(nandPath)) {
|
||||
fs::create_directories(nandPath);
|
||||
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;
|
||||
|
||||
|
||||
if (!fs::is_directory(nandSharedpath)) {
|
||||
fs::create_directories(nandSharedpath);
|
||||
}
|
||||
|
||||
if (!fs::is_directory(cartPath)) {
|
||||
fs::create_directories(cartPath);
|
||||
if (!fs::is_directory(sdmcPath)) {
|
||||
fs::create_directories(sdmcPath);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -69,22 +76,10 @@ ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) {
|
|||
case ArchiveID::SelfNCCH: return &selfNcch;
|
||||
case ArchiveID::SaveData: return &saveData;
|
||||
case ArchiveID::ExtSaveData:
|
||||
if (archivePath.type == PathType::Binary) {
|
||||
switch (archivePath.binary[0]) {
|
||||
case 0: return &extSaveData_nand;
|
||||
case 1: return &extSaveData_cart;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return &extSaveData_sdmc;
|
||||
|
||||
case ArchiveID::SharedExtSaveData:
|
||||
if (archivePath.type == PathType::Binary) {
|
||||
switch (archivePath.binary[0]) {
|
||||
case 0: return &sharedExtSaveData_nand;
|
||||
case 1: return &sharedExtSaveData_cart;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return &sharedExtSaveData_nand;
|
||||
|
||||
case ArchiveID::SDMC: return &sdmc;
|
||||
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
|
||||
|
@ -121,12 +116,12 @@ Rust::Result<Handle, FSResult> FSService::openDirectoryHandle(ArchiveBase* archi
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<Handle> FSService::openArchiveHandle(u32 archiveID, const FSPath& path) {
|
||||
Rust::Result<Handle, FSResult> FSService::openArchiveHandle(u32 archiveID, const FSPath& path) {
|
||||
ArchiveBase* archive = getArchiveFromID(archiveID, path);
|
||||
|
||||
if (archive == nullptr) [[unlikely]] {
|
||||
Helpers::panic("OpenArchive: Tried to open unknown archive %d.", archiveID);
|
||||
return std::nullopt;
|
||||
return Err(FSResult::NotFormatted);
|
||||
}
|
||||
|
||||
Rust::Result<ArchiveBase*, FSResult> res = archive->openArchive(path);
|
||||
|
@ -135,10 +130,10 @@ std::optional<Handle> FSService::openArchiveHandle(u32 archiveID, const FSPath&
|
|||
auto& archiveObject = kernel.getObjects()[handle];
|
||||
archiveObject.data = new ArchiveSession(res.unwrap(), path);
|
||||
|
||||
return handle;
|
||||
return Ok(handle);
|
||||
}
|
||||
else {
|
||||
return std::nullopt;
|
||||
return Err(res.unwrapErr());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,6 +156,7 @@ void FSService::handleSyncRequest(u32 messagePointer) {
|
|||
case FSCommands::CloseArchive: closeArchive(messagePointer); break;
|
||||
case FSCommands::DeleteFile: deleteFile(messagePointer); break;
|
||||
case FSCommands::FormatSaveData: formatSaveData(messagePointer); break;
|
||||
case FSCommands::FormatThisUserSaveData: formatThisUserSaveData(messagePointer); break;
|
||||
case FSCommands::GetFreeBytes: getFreeBytes(messagePointer); break;
|
||||
case FSCommands::GetFormatInfo: getFormatInfo(messagePointer); break;
|
||||
case FSCommands::GetPriority: getPriority(messagePointer); break;
|
||||
|
@ -216,14 +212,15 @@ void FSService::openArchive(u32 messagePointer) {
|
|||
auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize);
|
||||
log("FS::OpenArchive(archive ID = %d, archive path type = %d)\n", archiveID, archivePathType);
|
||||
|
||||
std::optional<Handle> handle = openArchiveHandle(archiveID, archivePath);
|
||||
Rust::Result<Handle, FSResult> res = openArchiveHandle(archiveID, archivePath);
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x80C, 3, 0));
|
||||
if (handle.has_value()) {
|
||||
if (res.isOk()) {
|
||||
mem.write32(messagePointer + 4, ResultCode::Success);
|
||||
mem.write64(messagePointer + 8, handle.value());
|
||||
mem.write64(messagePointer + 8, res.unwrap());
|
||||
} else {
|
||||
log("FS::OpenArchive: Failed to open archive with id = %d\n", archiveID);
|
||||
mem.write32(messagePointer + 4, ResultCode::Failure);
|
||||
log("FS::OpenArchive: Failed to open archive with id = %d. Error %08X\n", archiveID, (u32)res.unwrapErr());
|
||||
mem.write32(messagePointer + 4, static_cast<u32>(res.unwrapErr()));
|
||||
mem.write64(messagePointer + 8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,16 +408,25 @@ void FSService::getFormatInfo(u32 messagePointer) {
|
|||
Helpers::panic("OpenArchive: Tried to open unknown archive %d.", archiveID);
|
||||
}
|
||||
|
||||
ArchiveBase::FormatInfo info = archive->getFormatInfo(path);
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x845, 5, 0));
|
||||
mem.write32(messagePointer + 4, ResultCode::Success);
|
||||
mem.write32(messagePointer + 8, info.size);
|
||||
mem.write32(messagePointer + 12, info.numOfDirectories);
|
||||
mem.write32(messagePointer + 16, info.numOfFiles);
|
||||
mem.write8(messagePointer + 20, info.duplicateData ? 1 : 0);
|
||||
Rust::Result<ArchiveBase::FormatInfo, FSResult> res = archive->getFormatInfo(path);
|
||||
|
||||
// If the FormatInfo was returned, write them to the output buffer. Otherwise, write an error code.
|
||||
if (res.isOk()) {
|
||||
ArchiveBase::FormatInfo info = res.unwrap();
|
||||
mem.write32(messagePointer + 4, ResultCode::Success);
|
||||
mem.write32(messagePointer + 8, info.size);
|
||||
mem.write32(messagePointer + 12, info.numOfDirectories);
|
||||
mem.write32(messagePointer + 16, info.numOfFiles);
|
||||
mem.write8(messagePointer + 20, info.duplicateData ? 1 : 0);
|
||||
} else {
|
||||
mem.write32(messagePointer + 4, static_cast<u32>(res.unwrapErr()));
|
||||
}
|
||||
}
|
||||
|
||||
void FSService::formatSaveData(u32 messagePointer) {
|
||||
log("FS::FormatSaveData\n");
|
||||
|
||||
const u32 archiveID = mem.read32(messagePointer + 4);
|
||||
if (archiveID != ArchiveID::SaveData)
|
||||
Helpers::panic("FS::FormatSaveData: Archive is not SaveData");
|
||||
|
@ -440,13 +446,43 @@ 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
|
||||
};
|
||||
|
||||
saveData.format(path, info);
|
||||
|
||||
printf("Stubbed FS::FormatSaveData. File num: %d, directory num: %d\n", fileNum, directoryNum);
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x84C, 1, 0));
|
||||
mem.write32(messagePointer + 4, ResultCode::Success);
|
||||
}
|
||||
|
||||
void FSService::formatThisUserSaveData(u32 messagePointer) {
|
||||
log("FS::FormatThisUserSaveData\n");
|
||||
|
||||
const u32 blockSize = mem.read32(messagePointer + 4);
|
||||
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
|
||||
const u32 fileNum = mem.read32(messagePointer + 12); // Max number of files
|
||||
const u32 directoryBucketNum = mem.read32(messagePointer + 16); // Not sure what a directory bucket is...?
|
||||
const u32 fileBucketNum = mem.read32(messagePointer + 20); // Same here
|
||||
const bool duplicateData = mem.read8(messagePointer + 24) != 0;
|
||||
|
||||
ArchiveBase::FormatInfo info {
|
||||
.size = blockSize * 0x200,
|
||||
.numOfDirectories = directoryNum,
|
||||
.numOfFiles = fileNum,
|
||||
.duplicateData = duplicateData
|
||||
};
|
||||
FSPath emptyPath;
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x080F, 1, 0));
|
||||
saveData.format(emptyPath, info);
|
||||
}
|
||||
|
||||
void FSService::controlArchive(u32 messagePointer) {
|
||||
const Handle archiveHandle = mem.read64(messagePointer + 4);
|
||||
const u32 action = mem.read32(messagePointer + 12);
|
||||
|
|
Loading…
Add table
Reference in a new issue