static GameCoin ReadGameCoinData() { std::string nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = extdata_archive_factory.Open(archive_path); if (!archive_result.Succeeded()) { LOG_ERROR(Service_PTM, "Could not open the PTM SharedExtSaveData archive!"); return default_game_coin; } FileSys::Path gamecoin_path("/gamecoin.dat"); FileSys::Mode open_mode = {}; open_mode.read_flag.Assign(1); auto gamecoin_result = (*archive_result)->OpenFile(gamecoin_path, open_mode); if (!gamecoin_result.Succeeded()) { LOG_ERROR(Service_PTM, "Could not open the game coin data file!"); return default_game_coin; } u16 result; auto gamecoin = std::move(gamecoin_result).Unwrap(); GameCoin gamecoin_data; gamecoin->Read(0, sizeof(GameCoin), reinterpret_cast<u8*>(&gamecoin_data)); gamecoin->Close(); return gamecoin_data; }
static void WriteGameCoinData(GameCoin gamecoin_data) { std::string nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = extdata_archive_factory.Open(archive_path); std::unique_ptr<FileSys::ArchiveBackend> archive; FileSys::Path gamecoin_path("/gamecoin.dat"); // If the archive didn't exist, create the files inside if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { // Format the archive to create the directories extdata_archive_factory.Format(archive_path, FileSys::ArchiveFormatInfo()); // Open it again to get a valid archive now that the folder exists archive = extdata_archive_factory.Open(archive_path).Unwrap(); // Create the game coin file archive->CreateFile(gamecoin_path, sizeof(GameCoin)); } else { ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); archive = std::move(archive_result).Unwrap(); } FileSys::Mode open_mode = {}; open_mode.write_flag.Assign(1); // Open the file and write the default gamecoin information auto gamecoin_result = archive->OpenFile(gamecoin_path, open_mode); if (gamecoin_result.Succeeded()) { auto gamecoin = std::move(gamecoin_result).Unwrap(); gamecoin->Write(0, sizeof(GameCoin), true, reinterpret_cast<const u8*>(&gamecoin_data)); gamecoin->Close(); } }
/** * FS_User::OpenArchive service function * Inputs: * 1 : Archive ID * 2 : Archive low path type * 3 : Archive low path size * 4 : (LowPathSize << 14) | 2 * 5 : Archive low path * Outputs: * 1 : Result of function, 0 on success, otherwise error code * 2 : Archive handle lower word (unused) * 3 : Archive handle upper word (same as file handle) */ static void OpenArchive(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); u32 archivename_size = cmd_buff[3]; u32 archivename_ptr = cmd_buff[5]; FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); DEBUG_LOG(KERNEL, "archive_path=%s", archive_path.DebugStr().c_str()); if (archive_path.GetType() != FileSys::Empty) { ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; return; } ResultVal<Handle> handle = Kernel::OpenArchive(archive_id); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { // cmd_buff[2] isn't used according to 3dmoo's implementation. cmd_buff[3] = *handle; } else { ERROR_LOG(KERNEL, "failed to get a handle for archive"); } DEBUG_LOG(KERNEL, "called"); }
void Init() { AddService(new PTM_Play_Interface); AddService(new PTM_Sysm_Interface); AddService(new PTM_U_Interface); shell_open = true; battery_is_charging = true; // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); // If the archive didn't exist, create the files inside if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { // Format the archive to create the directories Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); // Open it again to get a valid archive now that the folder exists archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); FileSys::Path gamecoin_path("gamecoin.dat"); FileSys::Mode open_mode = {}; open_mode.write_flag = 1; open_mode.create_flag = 1; // Open the file and write the default gamecoin information auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); if (gamecoin_result.Succeeded()) { auto gamecoin = gamecoin_result.MoveFrom(); gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); gamecoin->backend->Close(); } } }
Module::Module() { // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't // exist std::string nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = extdata_archive_factory.Open(archive_path); // If the archive didn't exist, write the default game coin file if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { WriteGameCoinData(default_game_coin); } }
/** * FS_User::OpenFileDirectly service function * Inputs: * 1 : Transaction * 2 : Archive ID * 3 : Archive low path type * 4 : Archive low path size * 5 : File low path type * 6 : File low path size * 7 : Flags * 8 : Attributes * 9 : (ArchiveLowPathSize << 14) | 0x802 * 10 : Archive low path * 11 : (FileLowPathSize << 14) | 2 * 12 : File low path * Outputs: * 1 : Result of function, 0 on success, otherwise error code * 3 : File handle */ static void OpenFileDirectly(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); u32 archivename_size = cmd_buff[4]; auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]); u32 filename_size = cmd_buff[6]; FileSys::Mode mode; mode.hex = cmd_buff[7]; u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. u32 archivename_ptr = cmd_buff[10]; u32 filename_ptr = cmd_buff[12]; FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); FileSys::Path file_path(filename_type, filename_size, filename_ptr); DEBUG_LOG(KERNEL, "archive_path=%s file_path=%s, mode=%u attributes=%d", archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); if (archive_path.GetType() != FileSys::Empty) { ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; return; } // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id); cmd_buff[1] = archive_handle.Code().raw; if (archive_handle.Failed()) { ERROR_LOG(KERNEL, "failed to get a handle for archive"); return; } // cmd_buff[2] isn't used according to 3dmoo's implementation. cmd_buff[3] = *archive_handle; ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { cmd_buff[3] = *handle; } else { ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); } DEBUG_LOG(KERNEL, "called"); }