diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index eaa55006..7565e4aa 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -208,6 +208,11 @@ public: return FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false }; } + virtual FSResult createDirectory(const FSPath& path) { + Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str()); + return FSResult::AlreadyExists; + } + // Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed) virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0; diff --git a/include/fs/archive_save_data.hpp b/include/fs/archive_save_data.hpp index a10a8b0d..b07a461c 100644 --- a/include/fs/archive_save_data.hpp +++ b/include/fs/archive_save_data.hpp @@ -8,6 +8,7 @@ public: u64 getFreeBytes() override { Helpers::panic("SaveData::GetFreeBytes unimplemented"); return 0; } std::string name() override { return "SaveData"; } + 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; diff --git a/include/services/fs.hpp b/include/services/fs.hpp index 67ea472c..3eef198f 100644 --- a/include/services/fs.hpp +++ b/include/services/fs.hpp @@ -37,6 +37,7 @@ class FSService { FSPath readPath(u32 type, u32 pointer, u32 size); // Service commands + void createDirectory(u32 messagePointer); void createFile(u32 messagePointer); void closeArchive(u32 messagePointer); void controlArchive(u32 messagePointer); diff --git a/src/core/fs/archive_save_data.cpp b/src/core/fs/archive_save_data.cpp index e6aa0db1..d14c684d 100644 --- a/src/core/fs/archive_save_data.cpp +++ b/src/core/fs/archive_save_data.cpp @@ -9,6 +9,30 @@ FSResult SaveDataArchive::createFile(const FSPath& path, u64 size) { return FSResult::Success; } +FSResult SaveDataArchive::createDirectory(const FSPath& path) { + if (!cartHasSaveData()) { + printf("Tried to create SaveData dir without save data\n"); + return FSResult::FileNotFound; + } + + if (path.type == PathType::UTF16) { + if (!isPathSafe(path)) + Helpers::panic("Unsafe path in SaveData::OpenFile"); + + fs::path p = IOFile::getAppData() / "SaveData"; + p += fs::path(path.utf16_string).make_preferred(); + + if (fs::is_directory(p)) + return FSResult::AlreadyExists; + if (fs::is_regular_file(p)) { + Helpers::panic("File path passed to SaveData::CreateDirectory"); + } + + bool success = fs::create_directory(p); + return success ? FSResult::Success : FSResult::UnexpectedFileOrDir; + } +} + FSResult SaveDataArchive::deleteFile(const FSPath& path) { Helpers::panic("[SaveData] Unimplemented DeleteFile"); return FSResult::Success; diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 0f421b9d..5689c486 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -4,6 +4,7 @@ #include "ipc.hpp" #ifdef CreateFile // windows.h defines CreateFile & DeleteFile because of course it does. +#undef CreateDirectory #undef CreateFile #undef DeleteFile #endif @@ -15,6 +16,7 @@ namespace FSCommands { OpenFileDirectly = 0x08030204, DeleteFile = 0x08040142, CreateFile = 0x08080202, + CreateDirectory = 0x08090182, OpenDirectory = 0x080B0102, OpenArchive = 0x080C00C2, ControlArchive = 0x080D0144, @@ -152,6 +154,7 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) { void FSService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case FSCommands::CreateDirectory: createDirectory(messagePointer); break; case FSCommands::CreateFile: createFile(messagePointer); break; case FSCommands::ControlArchive: controlArchive(messagePointer); break; case FSCommands::CloseArchive: closeArchive(messagePointer); break; @@ -257,6 +260,29 @@ void FSService::openFile(u32 messagePointer) { } } +void FSService::createDirectory(u32 messagePointer) { + log("FS::CreateDirectory\n"); + + const Handle archiveHandle = (Handle)mem.read64(messagePointer + 8); + const u32 pathType = mem.read32(messagePointer + 16); + const u32 pathSize = mem.read32(messagePointer + 20); + const u32 pathPointer = mem.read32(messagePointer + 32); + + KernelObject* archiveObject = kernel.getObject(archiveHandle, KernelObjectType::Archive); + if (archiveObject == nullptr) [[unlikely]] { + log("FS::CreateDirectory: Invalid archive handle %d\n", archiveHandle); + mem.write32(messagePointer + 4, ResultCode::Failure); + return; + } + + ArchiveBase* archive = archiveObject->getData()->archive; + const auto dirPath = readPath(pathType, pathPointer, pathSize); + const FSResult res = archive->createDirectory(dirPath); + + mem.write32(messagePointer, IPC::responseHeader(0x809, 1, 0)); + mem.write32(messagePointer + 4, static_cast(res)); +} + void FSService::openDirectory(u32 messagePointer) { log("FS::OpenDirectory\n"); const Handle archiveHandle = (Handle)mem.read64(messagePointer + 4); @@ -384,7 +410,7 @@ void FSService::getFormatInfo(u32 messagePointer) { ArchiveBase::FormatInfo info = archive->getFormatInfo(path); mem.write32(messagePointer, IPC::responseHeader(0x845, 5, 0)); - mem.write32(messagePointer + 4, ResultCode::Success); + mem.write32(messagePointer + 4, -1); mem.write32(messagePointer + 8, info.size); mem.write32(messagePointer + 12, info.numOfDirectories); mem.write32(messagePointer + 16, info.numOfFiles);