diff --git a/include/fs/archive_system_save_data.hpp b/include/fs/archive_system_save_data.hpp index fcba5e731..9548e1903 100644 --- a/include/fs/archive_system_save_data.hpp +++ b/include/fs/archive_system_save_data.hpp @@ -6,7 +6,7 @@ class SystemSaveDataArchive : public ArchiveBase { SystemSaveDataArchive(Memory& mem) : ArchiveBase(mem) {} u64 getFreeBytes() override { - Helpers::panic("Unimplemented GetFreeBytes for SystemSaveData archive"); + Helpers::warn("Unimplemented GetFreeBytes for SystemSaveData archive"); return 32_MB; } @@ -14,14 +14,10 @@ class SystemSaveDataArchive : public ArchiveBase { //HorizonResult createDirectory(const FSPath& path) override; HorizonResult createFile(const FSPath& path, u64 size) override; - - HorizonResult deleteFile(const FSPath& path) override { - Helpers::panic("Unimplemented DeleteFile for SystemSaveData archive"); - return Result::Success; - }; + HorizonResult deleteFile(const FSPath& path) override; Rust::Result openArchive(const FSPath& path) override; - //Rust::Result openDirectory(const FSPath& path) override; + Rust::Result openDirectory(const FSPath& path) override; FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override; diff --git a/include/services/boss.hpp b/include/services/boss.hpp index b2ea1363b..57452e2d6 100644 --- a/include/services/boss.hpp +++ b/include/services/boss.hpp @@ -28,6 +28,7 @@ class BOSSService { void registerStorageEntry(u32 messagePointer); void registerTask(u32 messagePointer); void sendProperty(u32 messagePointer); + void setOptoutFlag(u32 messagePointer); void startTask(u32 messagePointer); void unregisterStorage(u32 messagePointer); void unregisterTask(u32 messagePointer); diff --git a/include/services/fs.hpp b/include/services/fs.hpp index dbaf8a1b2..435dc5a62 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -46,11 +46,13 @@ class FSService { // Service commands void abnegateAccessRight(u32 messagePointer); + void cardSlotIsInserted(u32 messagePointer); void createDirectory(u32 messagePointer); void createExtSaveData(u32 messagePointer); void createFile(u32 messagePointer); void closeArchive(u32 messagePointer); void controlArchive(u32 messagePointer); + void deleteDirectory(u32 messagePointer); void deleteExtSaveData(u32 messagePointer); void deleteFile(u32 messagePointer); void formatSaveData(u32 messagePointer); diff --git a/src/core/fs/archive_save_data.cpp b/src/core/fs/archive_save_data.cpp index 8ac51b316..0bdb9e01d 100644 --- a/src/core/fs/archive_save_data.cpp +++ b/src/core/fs/archive_save_data.cpp @@ -64,8 +64,9 @@ HorizonResult SaveDataArchive::createDirectory(const FSPath& path) { HorizonResult SaveDataArchive::deleteFile(const FSPath& path) { if (path.type == PathType::UTF16) { - if (!isPathSafe(path)) + if (!isPathSafe(path)) { Helpers::panic("Unsafe path in SaveData::DeleteFile"); + } fs::path p = IOFile::getAppData() / "SaveData"; p += fs::path(path.utf16_string).make_preferred(); diff --git a/src/core/fs/archive_sdmc.cpp b/src/core/fs/archive_sdmc.cpp index 8e6010eb4..232335d07 100644 --- a/src/core/fs/archive_sdmc.cpp +++ b/src/core/fs/archive_sdmc.cpp @@ -4,7 +4,37 @@ namespace fs = std::filesystem; HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) { - Helpers::panic("[SDMC] CreateFile not yet supported"); + if (path.type == PathType::UTF16) { + if (!isPathSafe(path)) { + Helpers::panic("Unsafe path in SDMC::CreateFile"); + } + + fs::path p = IOFile::getAppData() / "SDMC"; + p += fs::path(path.utf16_string).make_preferred(); + + if (fs::exists(p)) { + return Result::FS::AlreadyExists; + } + + IOFile file(p.string().c_str(), "wb"); + + // If the size is 0, leave the file empty and return success + if (size == 0) { + file.close(); + return Result::Success; + } + + // If it is not empty, seek to size - 1 and write a 0 to create a file of size "size" + else if (file.seek(size - 1, SEEK_SET) && file.writeBytes("", 1).second == 1) { + file.close(); + return Result::Success; + } + + file.close(); + return Result::FS::FileTooLarge; + } + + Helpers::panic("SDMC::CreateFile: Failed"); return Result::Success; } diff --git a/src/core/fs/archive_system_save_data.cpp b/src/core/fs/archive_system_save_data.cpp index 4f63dc631..f8e4ad4ec 100644 --- a/src/core/fs/archive_system_save_data.cpp +++ b/src/core/fs/archive_system_save_data.cpp @@ -82,4 +82,63 @@ HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) { Helpers::panic("SystemSaveData::CreateFile: Failed"); return Result::Success; +} + + +HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) { + if (path.type == PathType::UTF16) { + if (!isPathSafe(path)) { + Helpers::panic("Unsafe path in SystemSaveData::DeleteFile"); + } + + fs::path p = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData"; + p += fs::path(path.utf16_string).make_preferred(); + + if (fs::is_directory(p)) { + Helpers::panic("SystemSaveData::DeleteFile: Tried to delete directory"); + } + + if (!fs::is_regular_file(p)) { + return Result::FS::FileNotFoundAlt; + } + + 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("SystemSaveData::DeleteFile: fs::remove failed\n"); + } + + return Result::Success; + } + + Helpers::panic("SystemSaveData::DeleteFile: Unknown path type"); + return Result::Success; +} + +Rust::Result SystemSaveDataArchive::openDirectory(const FSPath& path) { + if (path.type == PathType::UTF16) { + if (!isPathSafe(path)) { + Helpers::panic("Unsafe path in SystemSaveData::OpenDirectory"); + } + + fs::path p = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData"; + p += fs::path(path.utf16_string).make_preferred(); + + if (fs::is_regular_file(p)) { + printf("SystemSaveData: OpenDirectory used with a file path"); + return Err(Result::FS::UnexpectedFileOrDir); + } + + if (fs::is_directory(p)) { + return Ok(DirectorySession(this, p)); + } else { + return Err(Result::FS::FileNotFoundAlt); + } + } + + Helpers::panic("SystemSaveData::OpenDirectory: Unimplemented path type"); + return Err(Result::Success); } \ No newline at end of file diff --git a/src/core/services/boss.cpp b/src/core/services/boss.cpp index 621830db8..30190cd33 100644 --- a/src/core/services/boss.cpp +++ b/src/core/services/boss.cpp @@ -7,6 +7,7 @@ namespace BOSSCommands { UnregisterStorage = 0x00030000, GetTaskStorageInfo = 0x00040000, RegisterNewArrivalEvent = 0x00080002, + SetOptoutFlag = 0x00090040, GetOptoutFlag = 0x000A0000, RegisterTask = 0x000B00C2, UnregisterTask = 0x000C0082, @@ -53,6 +54,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) { case BOSSCommands::RegisterStorageEntry: registerStorageEntry(messagePointer); break; case BOSSCommands::RegisterTask: registerTask(messagePointer); break; case BOSSCommands::SendProperty: sendProperty(messagePointer); break; + case BOSSCommands::SetOptoutFlag: setOptoutFlag(messagePointer); break; case BOSSCommands::StartTask: startTask(messagePointer); break; case BOSSCommands::UnregisterStorage: unregisterStorage(messagePointer); break; case BOSSCommands::UnregisterTask: unregisterTask(messagePointer); break; @@ -66,6 +68,15 @@ void BOSSService::initializeSession(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void BOSSService::setOptoutFlag(u32 messagePointer) { + const s8 flag = static_cast(mem.read8(messagePointer + 4)); + log("BOSS::SetOptoutFlag (flag = %d)\n", flag); + optoutFlag = flag; + + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void BOSSService::getOptoutFlag(u32 messagePointer) { log("BOSS::GetOptoutFlag\n"); mem.write32(messagePointer, IPC::responseHeader(0xA, 2, 0)); diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 0ecc792bd..1c243a57e 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -16,6 +16,8 @@ namespace FSCommands { OpenFile = 0x080201C2, OpenFileDirectly = 0x08030204, DeleteFile = 0x08040142, + DeleteDirectory = 0x08060142, + DeleteDirectoryRecursively = 0x08070142, CreateFile = 0x08080202, CreateDirectory = 0x08090182, OpenDirectory = 0x080B0102, @@ -26,6 +28,7 @@ namespace FSCommands { GetFreeBytes = 0x08120080, IsSdmcDetected = 0x08170000, IsSdmcWritable = 0x08180000, + CardSlotIsInserted = 0x08210000, AbnegateAccessRight = 0x08400040, GetFormatInfo = 0x084500C2, GetArchiveResource = 0x08490040, @@ -160,11 +163,13 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) { void FSService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case FSCommands::CardSlotIsInserted: cardSlotIsInserted(messagePointer); break; case FSCommands::CreateDirectory: createDirectory(messagePointer); break; case FSCommands::CreateExtSaveData: createExtSaveData(messagePointer); break; case FSCommands::CreateFile: createFile(messagePointer); break; case FSCommands::ControlArchive: controlArchive(messagePointer); break; case FSCommands::CloseArchive: closeArchive(messagePointer); break; + case FSCommands::DeleteDirectory: deleteDirectory(messagePointer); break; case FSCommands::DeleteExtSaveData: deleteExtSaveData(messagePointer); break; case FSCommands::DeleteFile: deleteFile(messagePointer); break; case FSCommands::FormatSaveData: formatSaveData(messagePointer); break; @@ -414,6 +419,18 @@ void FSService::deleteFile(u32 messagePointer) { mem.write32(messagePointer + 4, static_cast(res)); } +void FSService::deleteDirectory(u32 messagePointer) { + const Handle archiveHandle = Handle(mem.read64(messagePointer + 8)); + const u32 filePathType = mem.read32(messagePointer + 16); + const u32 filePathSize = mem.read32(messagePointer + 20); + const u32 filePathPointer = mem.read32(messagePointer + 28); + log("FS::DeleteDirectory\n"); + + Helpers::warn("Stubbed FS::DeleteDirectory call!"); + mem.write32(messagePointer, IPC::responseHeader(0x806, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void FSService::getFormatInfo(u32 messagePointer) { const u32 archiveID = mem.read32(messagePointer + 4); const u32 pathType = mem.read32(messagePointer + 8); @@ -690,4 +707,13 @@ void FSService::isSdmcWritable(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x818, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, writeProtected ? 0 : 1); +} + +void FSService::cardSlotIsInserted(u32 messagePointer) { + log("FS::CardSlotIsInserted\n"); + constexpr bool cardInserted = false; + + mem.write32(messagePointer, IPC::responseHeader(0x821, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write8(messagePointer + 8, cardInserted ? 1 : 0); } \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 6cef4b434..1685aee13 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 }, + { "act:a", KernelHandles::ACT }, { "act:u", KernelHandles::ACT }, { "am:app", KernelHandles::AM }, { "APT:S", KernelHandles::APT }, // TODO: APT:A, APT:S and APT:U are slightly different