From 812c8ffbbac200f1d1ab0429fd7e8546b8e6899c Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 10 Dec 2024 00:09:43 +0200 Subject: [PATCH] Make filesystem decent, part 1 --- include/fs/archive_base.hpp | 29 +++++++++++++++ src/core/fs/archive_card_spi.cpp | 2 +- src/core/fs/archive_ext_save_data.cpp | 45 +++++++++++++----------- src/core/fs/archive_ncch.cpp | 4 +-- src/core/fs/archive_save_data.cpp | 12 +++---- src/core/fs/archive_sdmc.cpp | 20 +++++------ src/core/fs/archive_self_ncch.cpp | 4 +-- src/core/fs/archive_system_save_data.cpp | 12 +++---- src/core/fs/archive_twl_photo.cpp | 2 +- src/core/fs/archive_twl_sound.cpp | 2 +- src/core/fs/archive_user_save_data.cpp | 18 ++++++---- src/core/services/service_manager.cpp | 1 + 12 files changed, 95 insertions(+), 56 deletions(-) diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index d899d1a6e..475ca50e9 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -90,6 +90,14 @@ struct FSPath { }; } } + + bool isUTF16() const { return type == PathType::UTF16; } + bool isASCII() const { return type == PathType::ASCII; } + bool isBinary() const { return type == PathType::Binary; } + // This is not called "isEmpty()" to make obvious that we're talking about an empty-type path, NOT an empty text path + bool isEmptyType() const { return type == PathType::Empty; } + + bool isTextPath() const { return isUTF16() || isASCII(); } }; struct FilePerms { @@ -259,6 +267,27 @@ class ArchiveBase { virtual std::optional readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0; ArchiveBase(Memory& mem) : mem(mem) {} + + bool isSafeTextPath(const FSPath& path) { + if (path.type == PathType::UTF16) { + return isPathSafe(path); + } else if (path.type == PathType::ASCII){ + return isPathSafe(path); + } + + Helpers::panic("ArchiveBase::IsSafeTextPath: Invalid path"); + } + + // Appends a 3DS path to an std::filesystem::path + void appendPath(std::filesystem::path& diskPath, const FSPath& guestPath) { + if (guestPath.type == PathType::UTF16) { + diskPath += std::filesystem::path(guestPath.utf16_string).make_preferred(); + } else if (guestPath.type == PathType::ASCII) { + diskPath += std::filesystem::path(guestPath.string).make_preferred(); + } else [[unlikely]] { + Helpers::panic("ArchiveBase::AppendPath: Invalid 3DS path"); + } + } }; struct ArchiveResource { diff --git a/src/core/fs/archive_card_spi.cpp b/src/core/fs/archive_card_spi.cpp index db1b5fded..965ae9822 100644 --- a/src/core/fs/archive_card_spi.cpp +++ b/src/core/fs/archive_card_spi.cpp @@ -26,7 +26,7 @@ FileDescriptor CardSPIArchive::openFile(const FSPath& path, const FilePerms& per } Rust::Result CardSPIArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for CardSPIArchive::OpenArchive"); } diff --git a/src/core/fs/archive_ext_save_data.cpp b/src/core/fs/archive_ext_save_data.cpp index 4b57f2457..2aaa157e2 100644 --- a/src/core/fs/archive_ext_save_data.cpp +++ b/src/core/fs/archive_ext_save_data.cpp @@ -7,12 +7,13 @@ HorizonResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) { if (size == 0) Helpers::panic("ExtSaveData file does not support size == 0"); - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) - Helpers::panic("Unsafe path in ExtSaveData::CreateFile"); + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { + Helpers::panic("Unsafe path in ExtSaveData::OpenFile"); + } fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::exists(p)) return Result::FS::AlreadyExists; @@ -28,17 +29,17 @@ HorizonResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) { return Result::FS::FileTooLarge; } - Helpers::panic("ExtSaveDataArchive::OpenFile: Failed"); + Helpers::panic("ExtSaveDataArchive::CreateFile: Failed"); return Result::Success; } HorizonResult ExtSaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (path.isTextPath()) { + if (!isSafeTextPath(path)) Helpers::panic("Unsafe path in ExtSaveData::DeleteFile"); fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_directory(p)) { Helpers::panic("ExtSaveData::DeleteFile: Tried to delete directory"); @@ -65,15 +66,16 @@ HorizonResult ExtSaveDataArchive::deleteFile(const FSPath& path) { } FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in ExtSaveData::OpenFile"); + } if (perms.create()) Helpers::panic("[ExtSaveData] Can't open file with create flag"); fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::exists(p)) { // Return file descriptor if the file exists IOFile file(p.string().c_str(), "r+b"); // According to Citra, this ignores the OpenFlags field and always opens as r+b? TODO: Check @@ -88,7 +90,7 @@ FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& } HorizonResult ExtSaveDataArchive::renameFile(const FSPath& oldPath, const FSPath& newPath) { - if (oldPath.type != PathType::UTF16 || newPath.type != PathType::UTF16) { + if (!oldPath.isUTF16() || !newPath.isUTF16()) { Helpers::panic("Invalid path type for ExtSaveData::RenameFile"); } @@ -125,15 +127,18 @@ HorizonResult ExtSaveDataArchive::renameFile(const FSPath& oldPath, const FSPath } HorizonResult ExtSaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in ExtSaveData::OpenFile"); } fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); + + if (fs::is_directory(p)) { + return Result::FS::AlreadyExists; + } - if (fs::is_directory(p)) return Result::FS::AlreadyExists; if (fs::is_regular_file(p)) { Helpers::panic("File path passed to ExtSaveData::CreateDirectory"); } @@ -156,7 +161,7 @@ std::string ExtSaveDataArchive::getExtSaveDataPathFromBinary(const FSPath& path) } Rust::Result ExtSaveDataArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Binary || path.binary.size() != 12) { + if (!path.isBinary() || path.binary.size() != 12) { Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive"); } @@ -172,12 +177,12 @@ Rust::Result ExtSaveDataArchive::openArchive(const } Rust::Result ExtSaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (path.isTextPath()) { + if (!isSafeTextPath(path)) Helpers::panic("Unsafe path in ExtSaveData::OpenDirectory"); fs::path p = IOFile::getAppData() / backingFolder; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_regular_file(p)) { printf("ExtSaveData: OpenArchive used with a file path"); diff --git a/src/core/fs/archive_ncch.cpp b/src/core/fs/archive_ncch.cpp index d5a4bab5e..5844bbdae 100644 --- a/src/core/fs/archive_ncch.cpp +++ b/src/core/fs/archive_ncch.cpp @@ -32,7 +32,7 @@ HorizonResult NCCHArchive::deleteFile(const FSPath& path) { } FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type != PathType::Binary || path.binary.size() != 20) { + if (!path.isBinary() || path.binary.size() != 20) { Helpers::panic("NCCHArchive::OpenFile: Invalid path"); } @@ -49,7 +49,7 @@ FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) } Rust::Result NCCHArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Binary || path.binary.size() != 16) { + if (!path.isBinary() || path.binary.size() != 16) { Helpers::panic("NCCHArchive::OpenArchive: Invalid path"); } diff --git a/src/core/fs/archive_save_data.cpp b/src/core/fs/archive_save_data.cpp index 0bdb9e01d..35bc93e4d 100644 --- a/src/core/fs/archive_save_data.cpp +++ b/src/core/fs/archive_save_data.cpp @@ -5,7 +5,7 @@ namespace fs = std::filesystem; HorizonResult SaveDataArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in SaveData::CreateFile"); @@ -39,7 +39,7 @@ HorizonResult SaveDataArchive::createFile(const FSPath& path, u64 size) { } HorizonResult SaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::OpenFile"); } @@ -63,7 +63,7 @@ HorizonResult SaveDataArchive::createDirectory(const FSPath& path) { } HorizonResult SaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::DeleteFile"); } @@ -96,7 +96,7 @@ HorizonResult SaveDataArchive::deleteFile(const FSPath& path) { } FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::OpenFile"); } @@ -132,7 +132,7 @@ FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result SaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::OpenDirectory"); } @@ -193,7 +193,7 @@ void SaveDataArchive::format(const FSPath& path, const ArchiveBase::FormatInfo& } Rust::Result SaveDataArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for SaveData archive: %d\n", path.type); return Err(Result::FS::NotFoundInvalid); } diff --git a/src/core/fs/archive_sdmc.cpp b/src/core/fs/archive_sdmc.cpp index 97b02b9ed..f5f999f34 100644 --- a/src/core/fs/archive_sdmc.cpp +++ b/src/core/fs/archive_sdmc.cpp @@ -4,13 +4,13 @@ namespace fs = std::filesystem; HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in SDMC::CreateFile"); } fs::path p = IOFile::getAppData() / "SDMC"; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::exists(p)) { return Result::FS::AlreadyExists; @@ -39,13 +39,13 @@ HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) { } HorizonResult SDMCArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in SDMC::DeleteFile"); } fs::path p = IOFile::getAppData() / "SDMC"; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_directory(p)) { Helpers::panic("SDMC::DeleteFile: Tried to delete directory"); @@ -171,13 +171,13 @@ Rust::Result SDMCArchive::openDirectory(const F return Err(Result::FS::UnexpectedFileOrDir); } - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) { + if (path.isTextPath()) { + if (!isSafeTextPath(path)) { Helpers::panic("Unsafe path in SDMC::OpenDirectory"); } fs::path p = IOFile::getAppData() / "SDMC"; - p += fs::path(path.utf16_string).make_preferred(); + appendPath(p, path); if (fs::is_regular_file(p)) { printf("SDMC: OpenDirectory used with a file path"); @@ -197,7 +197,7 @@ Rust::Result SDMCArchive::openDirectory(const F Rust::Result SDMCArchive::openArchive(const FSPath& path) { // TODO: Fail here if the SD is disabled in the connfig. - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for SDMC::OpenArchive"); } diff --git a/src/core/fs/archive_self_ncch.cpp b/src/core/fs/archive_self_ncch.cpp index 9369152d5..4d73300c5 100644 --- a/src/core/fs/archive_self_ncch.cpp +++ b/src/core/fs/archive_self_ncch.cpp @@ -26,7 +26,7 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe return FileError; } - if (path.type != PathType::Binary || path.binary.size() != 12) { + if (!path.isBinary() || path.binary.size() != 12) { printf("Invalid SelfNCCH path type\n"); return FileError; } @@ -42,7 +42,7 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result SelfNCCHArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Invalid path type for SelfNCCH archive: %d\n", path.type); return Err(Result::FS::NotFoundInvalid); } diff --git a/src/core/fs/archive_system_save_data.cpp b/src/core/fs/archive_system_save_data.cpp index 7cb454a25..038b2fc8e 100644 --- a/src/core/fs/archive_system_save_data.cpp +++ b/src/core/fs/archive_system_save_data.cpp @@ -4,7 +4,7 @@ namespace fs = std::filesystem; Rust::Result SystemSaveDataArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Binary) { + if (!path.isBinary()) { Helpers::panic("Unimplemented path type for SystemSaveData::OpenArchive"); } @@ -14,7 +14,7 @@ Rust::Result SystemSaveDataArchive::openArchive(con FileDescriptor SystemSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { // TODO: Validate this. Temporarily copied from SaveData archive - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::OpenFile"); } @@ -50,7 +50,7 @@ FileDescriptor SystemSaveDataArchive::openFile(const FSPath& path, const FilePer } HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::CreateFile"); } @@ -85,7 +85,7 @@ HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) { } HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::CreateDirectory"); } @@ -110,7 +110,7 @@ HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) { HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SystemSaveData::DeleteFile"); } @@ -143,7 +143,7 @@ HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) { } Rust::Result SystemSaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) { Helpers::warn("Unsafe path in SystemSaveData::OpenDirectory"); return Err(Result::FS::FileNotFoundAlt); diff --git a/src/core/fs/archive_twl_photo.cpp b/src/core/fs/archive_twl_photo.cpp index a1833c5cf..4d56a5d7e 100644 --- a/src/core/fs/archive_twl_photo.cpp +++ b/src/core/fs/archive_twl_photo.cpp @@ -26,7 +26,7 @@ FileDescriptor TWLPhotoArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result TWLPhotoArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for TWLPhotoArchive::OpenArchive"); } diff --git a/src/core/fs/archive_twl_sound.cpp b/src/core/fs/archive_twl_sound.cpp index fbe98caf5..a5f86c322 100644 --- a/src/core/fs/archive_twl_sound.cpp +++ b/src/core/fs/archive_twl_sound.cpp @@ -26,7 +26,7 @@ FileDescriptor TWLSoundArchive::openFile(const FSPath& path, const FilePerms& pe } Rust::Result TWLSoundArchive::openArchive(const FSPath& path) { - if (path.type != PathType::Empty) { + if (!path.isEmptyType()) { Helpers::panic("Unimplemented path type for TWLSoundArchive::OpenArchive"); } diff --git a/src/core/fs/archive_user_save_data.cpp b/src/core/fs/archive_user_save_data.cpp index cba9bff8a..dc5589548 100644 --- a/src/core/fs/archive_user_save_data.cpp +++ b/src/core/fs/archive_user_save_data.cpp @@ -6,13 +6,15 @@ namespace fs = std::filesystem; HorizonResult UserSaveDataArchive::createFile(const FSPath& path, u64 size) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::CreateFile"); fs::path p = IOFile::getAppData() / "SaveData"; p += fs::path(path.utf16_string).make_preferred(); - if (fs::exists(p)) return Result::FS::AlreadyExists; + if (fs::exists(p)) { + return Result::FS::AlreadyExists; + } IOFile file(p.string().c_str(), "wb"); @@ -37,8 +39,10 @@ HorizonResult UserSaveDataArchive::createFile(const FSPath& path, u64 size) { } HorizonResult UserSaveDataArchive::createDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::OpenFile"); + if (path.isUTF16()) { + if (!isPathSafe(path)) { + Helpers::panic("Unsafe path in UserSaveData::OpenFile"); + } fs::path p = IOFile::getAppData() / "SaveData"; p += fs::path(path.utf16_string).make_preferred(); @@ -56,7 +60,7 @@ HorizonResult UserSaveDataArchive::createDirectory(const FSPath& path) { } HorizonResult UserSaveDataArchive::deleteFile(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::DeleteFile"); fs::path p = IOFile::getAppData() / "SaveData"; @@ -87,7 +91,7 @@ HorizonResult UserSaveDataArchive::deleteFile(const FSPath& path) { } FileDescriptor UserSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::OpenFile"); if (perms.raw == 0 || (perms.create() && !perms.write())) Helpers::panic("[UserSaveData] Unsupported flags for OpenFile"); @@ -119,7 +123,7 @@ FileDescriptor UserSaveDataArchive::openFile(const FSPath& path, const FilePerms } Rust::Result UserSaveDataArchive::openDirectory(const FSPath& path) { - if (path.type == PathType::UTF16) { + if (path.isUTF16()) { if (!isPathSafe(path)) Helpers::panic("Unsafe path in UserSaveData::OpenDirectory"); fs::path p = IOFile::getAppData() / "SaveData"; diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 8fa88a001..e276cd23e 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -95,6 +95,7 @@ void ServiceManager::registerClient(u32 messagePointer) { // clang-format off static std::map serviceMap = { { "ac:u", KernelHandles::AC }, + { "ac:i", KernelHandles::AC }, { "act:a", KernelHandles::ACT }, { "act:u", KernelHandles::ACT }, { "am:app", KernelHandles::AM },