Skip to content

Commit

Permalink
coreinit: Handle SD mounting permission in FSGetMountSource
Browse files Browse the repository at this point in the history
One Piece requires this to not get stuck in an infinite loop on boot.

This also sets up initial infrastructure for handling cos.xml permissions
  • Loading branch information
Exzap committed Apr 6, 2024
1 parent fde7230 commit 74e8d20
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 22 deletions.
21 changes: 21 additions & 0 deletions src/Cafe/CafeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,27 @@ namespace CafeSystem
return sGameInfo_ForegroundTitle.GetBase().GetArgStr();
}

CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group)
{
if (sLaunchModeIsStandalone)
return CosCapabilityBits::All;
auto& update = sGameInfo_ForegroundTitle.GetUpdate();
if (update.IsValid())
{
ParsedCosXml* cosXml = update.GetCosInfo();
if (cosXml)
return cosXml->GetCapabilityBits(group);
}
auto& base = sGameInfo_ForegroundTitle.GetBase();
if(base.IsValid())
{
ParsedCosXml* cosXml = base.GetCosInfo();
if (cosXml)
return cosXml->GetCapabilityBits(group);
}
return CosCapabilityBits::All;
}

// when switching titles custom parameters can be passed, returns true if override args are used
bool GetOverrideArgStr(std::vector<std::string>& args)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Cafe/CafeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "Cafe/TitleList/TitleId.h"
#include "config/CemuConfig.h"

enum class CosCapabilityBits : uint64;
enum class CosCapabilityGroup : uint32;

namespace CafeSystem
{
class SystemImplementation
Expand Down Expand Up @@ -41,6 +44,7 @@ namespace CafeSystem
std::string GetForegroundTitleName();
std::string GetForegroundTitleArgStr();
uint32 GetForegroundTitleOlvAccesskey();
CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group);

void ShutdownTitle();

Expand Down
10 changes: 10 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_FS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "coreinit_IPC.h"
#include "Cafe/Filesystem/fsc.h"
#include "coreinit_IPCBuf.h"
#include "Cafe/CafeSystem.h"
#include "Cafe/TitleList/TitleInfo.h"

#define FS_CB_PLACEHOLDER_FINISHCMD (MPTR)(0xF122330E)

Expand Down Expand Up @@ -94,6 +96,14 @@ namespace coreinit
// so we can just hard code it. Other mount types are not (yet) supported.
if (mountSourceType == MOUNT_TYPE::SD)
{
// check for SD card permissions (from cos.xml)
// One Piece relies on failing here, otherwise it will call FSGetMountSource in an infinite loop
CosCapabilityBitsFS perms = static_cast<CosCapabilityBitsFS>(CafeSystem::GetForegroundTitleCosCapabilities(CosCapabilityGroup::FS));
if(!HAS_FLAG(perms, CosCapabilityBitsFS::SDCARD_MOUNT))
{
cemuLog_logOnce(LogType::Force, "Title is trying to access SD card mount info without having SD card permissions. This may not be a bug");
return FS_RESULT::END_ITERATION;
}
mountSourceInfo->sourceType = 0;
strcpy(mountSourceInfo->path, "/sd");
return FS_RESULT::SUCCESS;
Expand Down
43 changes: 36 additions & 7 deletions src/Cafe/TitleList/TitleInfo.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#include "TitleInfo.h"

#include "Cafe/Filesystem/fscDeviceHostFS.h"
#include "Cafe/Filesystem/FST/FST.h"

#include "pugixml.hpp"
#include "Common/FileStream.h"

#include <zarchive/zarchivereader.h>
#include "config/ActiveSettings.h"
#include "util/helpers/helpers.h"

// detect format by reading file header/footer
CafeTitleFileType DetermineCafeSystemFileType(fs::path filePath)
Expand Down Expand Up @@ -709,10 +707,41 @@ std::string TitleInfo::GetInstallPath() const
{
TitleId titleId = GetAppTitleId();
TitleIdParser tip(titleId);
std::string tmp;
std::string tmp;
if (tip.IsSystemTitle())
tmp = fmt::format("sys/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
else
tmp = fmt::format("usr/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
tmp = fmt::format("sys/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
else
tmp = fmt::format("usr/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
return tmp;
}

ParsedCosXml* ParsedCosXml::Parse(uint8* xmlData, size_t xmlLen)
{
pugi::xml_document app_doc;
if (!app_doc.load_buffer_inplace(xmlData, xmlLen))
return nullptr;

const auto root = app_doc.child("app");
if (!root)
return nullptr;

ParsedCosXml* parsedCos = new ParsedCosXml();

auto node = root.child("argstr");
if (node)
parsedCos->argstr = node.text().as_string();

// parse permissions
auto permissionsNode = root.child("permissions");
for(uint32 permissionIndex = 0; permissionIndex < 19; ++permissionIndex)
{
std::string permissionName = fmt::format("p{}", permissionIndex);
auto permissionNode = permissionsNode.child(permissionName.c_str());
if (!permissionNode)
break;
parsedCos->permissions[permissionIndex].group = static_cast<CosCapabilityGroup>(ConvertString<uint32>(permissionNode.child("group").text().as_string(), 10));
parsedCos->permissions[permissionIndex].mask = static_cast<CosCapabilityBits>(ConvertString<uint64>(permissionNode.child("mask").text().as_string(), 16));
}

return parsedCos;
}
101 changes: 86 additions & 15 deletions src/Cafe/TitleList/TitleInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,95 @@ struct ParsedAppXml
uint32 sdk_version;
};

enum class CosCapabilityGroup : uint32
{
None = 0,
BSP = 1,
DK = 3,
USB = 9,
UHS = 12,
FS = 11,
MCP = 13,
NIM = 14,
ACT = 15,
FPD = 16,
BOSS = 17,
ACP = 18,
PDM = 19,
AC = 20,
NDM = 21,
NSEC = 22
};

enum class CosCapabilityBits : uint64
{
All = 0xFFFFFFFFFFFFFFFFull
};

enum class CosCapabilityBitsFS : uint64
{
ODD_READ = (1llu << 0),
ODD_WRITE = (1llu << 1),
ODD_RAW_OPEN = (1llu << 2),
ODD_MOUNT = (1llu << 3),
SLCCMPT_READ = (1llu << 4),
SLCCMPT_WRITE = (1llu << 5),
SLCCMPT_RAW_OPEN = (1llu << 6),
SLCCMPT_MOUNT = (1llu << 7),
SLC_READ = (1llu << 8),
SLC_WRITE = (1llu << 9),
SLC_RAW_OPEN = (1llu << 10),
SLC_MOUNT = (1llu << 11),
MLC_READ = (1llu << 12),
MLC_WRITE = (1llu << 13),
MLC_RAW_OPEN = (1llu << 14),
MLC_MOUNT = (1llu << 15),
SDCARD_READ = (1llu << 16),
SDCARD_WRITE = (1llu << 17),
SDCARD_RAW_OPEN = (1llu << 18),
SDCARD_MOUNT = (1llu << 19),
HFIO_READ = (1llu << 20),
HFIO_WRITE = (1llu << 21),
HFIO_RAW_OPEN = (1llu << 22),
HFIO_MOUNT = (1llu << 23),
RAMDISK_READ = (1llu << 24),
RAMDISK_WRITE = (1llu << 25),
RAMDISK_RAW_OPEN = (1llu << 26),
RAMDISK_MOUNT = (1llu << 27),
USB_READ = (1llu << 28),
USB_WRITE = (1llu << 29),
USB_RAW_OPEN = (1llu << 30),
USB_MOUNT = (1llu << 31),
OTHER_READ = (1llu << 32),
OTHER_WRITE = (1llu << 33),
OTHER_RAW_OPEN = (1llu << 34),
OTHER_MOUNT = (1llu << 35)
};
ENABLE_BITMASK_OPERATORS(CosCapabilityBitsFS);

struct ParsedCosXml
{
public:

std::string argstr;

static ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen)
struct Permission
{
pugi::xml_document app_doc;
if (!app_doc.load_buffer_inplace(xmlData, xmlLen))
return nullptr;

const auto root = app_doc.child("app");
if (!root)
return nullptr;
CosCapabilityGroup group{CosCapabilityGroup::None};
CosCapabilityBits mask{CosCapabilityBits::All};
};
Permission permissions[19]{};

ParsedCosXml* parsedCos = new ParsedCosXml();
static ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen);

for (const auto& child : root.children())
CosCapabilityBits GetCapabilityBits(CosCapabilityGroup group) const
{
for (const auto& perm : permissions)
{
std::string_view name = child.name();
if (name == "argstr")
parsedCos->argstr = child.text().as_string();
if (perm.group == group)
return perm.mask;
}
return parsedCos;
return CosCapabilityBits::All;
}
};

Expand Down Expand Up @@ -151,7 +217,7 @@ class TitleInfo
// cos.xml
std::string GetArgStr() const;

// meta.xml also contains a version which seems to match the one from app.xml
// meta.xml also contains a version field which seems to match the one from app.xml
// the titleId in meta.xml seems to be the title id of the base game for updates specifically. For AOC content it's the AOC's titleId

TitleIdParser::TITLE_TYPE GetTitleType();
Expand All @@ -160,6 +226,11 @@ class TitleInfo
return m_parsedMetaXml;
}

ParsedCosXml* GetCosInfo()
{
return m_parsedCosXml;
}

std::string GetPrintPath() const; // formatted path including type and WUA subpath. Intended for logging and user-facing information
std::string GetInstallPath() const; // installation subpath, relative to storage base. E.g. "usr/title/.../..." or "sys/title/.../..."

Expand Down

0 comments on commit 74e8d20

Please sign in to comment.