Skip to content

Commit 74e8d20

Browse files
committed
coreinit: Handle SD mounting permission in FSGetMountSource
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
1 parent fde7230 commit 74e8d20

File tree

5 files changed

+157
-22
lines changed

5 files changed

+157
-22
lines changed

src/Cafe/CafeSystem.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,27 @@ namespace CafeSystem
914914
return sGameInfo_ForegroundTitle.GetBase().GetArgStr();
915915
}
916916

917+
CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group)
918+
{
919+
if (sLaunchModeIsStandalone)
920+
return CosCapabilityBits::All;
921+
auto& update = sGameInfo_ForegroundTitle.GetUpdate();
922+
if (update.IsValid())
923+
{
924+
ParsedCosXml* cosXml = update.GetCosInfo();
925+
if (cosXml)
926+
return cosXml->GetCapabilityBits(group);
927+
}
928+
auto& base = sGameInfo_ForegroundTitle.GetBase();
929+
if(base.IsValid())
930+
{
931+
ParsedCosXml* cosXml = base.GetCosInfo();
932+
if (cosXml)
933+
return cosXml->GetCapabilityBits(group);
934+
}
935+
return CosCapabilityBits::All;
936+
}
937+
917938
// when switching titles custom parameters can be passed, returns true if override args are used
918939
bool GetOverrideArgStr(std::vector<std::string>& args)
919940
{

src/Cafe/CafeSystem.h

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include "Cafe/TitleList/TitleId.h"
55
#include "config/CemuConfig.h"
66

7+
enum class CosCapabilityBits : uint64;
8+
enum class CosCapabilityGroup : uint32;
9+
710
namespace CafeSystem
811
{
912
class SystemImplementation
@@ -41,6 +44,7 @@ namespace CafeSystem
4144
std::string GetForegroundTitleName();
4245
std::string GetForegroundTitleArgStr();
4346
uint32 GetForegroundTitleOlvAccesskey();
47+
CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group);
4448

4549
void ShutdownTitle();
4650

src/Cafe/OS/libs/coreinit/coreinit_FS.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include "coreinit_IPC.h"
1212
#include "Cafe/Filesystem/fsc.h"
1313
#include "coreinit_IPCBuf.h"
14+
#include "Cafe/CafeSystem.h"
15+
#include "Cafe/TitleList/TitleInfo.h"
1416

1517
#define FS_CB_PLACEHOLDER_FINISHCMD (MPTR)(0xF122330E)
1618

@@ -94,6 +96,14 @@ namespace coreinit
9496
// so we can just hard code it. Other mount types are not (yet) supported.
9597
if (mountSourceType == MOUNT_TYPE::SD)
9698
{
99+
// check for SD card permissions (from cos.xml)
100+
// One Piece relies on failing here, otherwise it will call FSGetMountSource in an infinite loop
101+
CosCapabilityBitsFS perms = static_cast<CosCapabilityBitsFS>(CafeSystem::GetForegroundTitleCosCapabilities(CosCapabilityGroup::FS));
102+
if(!HAS_FLAG(perms, CosCapabilityBitsFS::SDCARD_MOUNT))
103+
{
104+
cemuLog_logOnce(LogType::Force, "Title is trying to access SD card mount info without having SD card permissions. This may not be a bug");
105+
return FS_RESULT::END_ITERATION;
106+
}
97107
mountSourceInfo->sourceType = 0;
98108
strcpy(mountSourceInfo->path, "/sd");
99109
return FS_RESULT::SUCCESS;

src/Cafe/TitleList/TitleInfo.cpp

+36-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
#include "TitleInfo.h"
2-
32
#include "Cafe/Filesystem/fscDeviceHostFS.h"
43
#include "Cafe/Filesystem/FST/FST.h"
5-
64
#include "pugixml.hpp"
75
#include "Common/FileStream.h"
8-
96
#include <zarchive/zarchivereader.h>
107
#include "config/ActiveSettings.h"
8+
#include "util/helpers/helpers.h"
119

1210
// detect format by reading file header/footer
1311
CafeTitleFileType DetermineCafeSystemFileType(fs::path filePath)
@@ -709,10 +707,41 @@ std::string TitleInfo::GetInstallPath() const
709707
{
710708
TitleId titleId = GetAppTitleId();
711709
TitleIdParser tip(titleId);
712-
std::string tmp;
710+
std::string tmp;
713711
if (tip.IsSystemTitle())
714-
tmp = fmt::format("sys/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
715-
else
716-
tmp = fmt::format("usr/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
712+
tmp = fmt::format("sys/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
713+
else
714+
tmp = fmt::format("usr/title/{:08x}/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
717715
return tmp;
718716
}
717+
718+
ParsedCosXml* ParsedCosXml::Parse(uint8* xmlData, size_t xmlLen)
719+
{
720+
pugi::xml_document app_doc;
721+
if (!app_doc.load_buffer_inplace(xmlData, xmlLen))
722+
return nullptr;
723+
724+
const auto root = app_doc.child("app");
725+
if (!root)
726+
return nullptr;
727+
728+
ParsedCosXml* parsedCos = new ParsedCosXml();
729+
730+
auto node = root.child("argstr");
731+
if (node)
732+
parsedCos->argstr = node.text().as_string();
733+
734+
// parse permissions
735+
auto permissionsNode = root.child("permissions");
736+
for(uint32 permissionIndex = 0; permissionIndex < 19; ++permissionIndex)
737+
{
738+
std::string permissionName = fmt::format("p{}", permissionIndex);
739+
auto permissionNode = permissionsNode.child(permissionName.c_str());
740+
if (!permissionNode)
741+
break;
742+
parsedCos->permissions[permissionIndex].group = static_cast<CosCapabilityGroup>(ConvertString<uint32>(permissionNode.child("group").text().as_string(), 10));
743+
parsedCos->permissions[permissionIndex].mask = static_cast<CosCapabilityBits>(ConvertString<uint64>(permissionNode.child("mask").text().as_string(), 16));
744+
}
745+
746+
return parsedCos;
747+
}

src/Cafe/TitleList/TitleInfo.h

+86-15
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,95 @@ struct ParsedAppXml
2626
uint32 sdk_version;
2727
};
2828

29+
enum class CosCapabilityGroup : uint32
30+
{
31+
None = 0,
32+
BSP = 1,
33+
DK = 3,
34+
USB = 9,
35+
UHS = 12,
36+
FS = 11,
37+
MCP = 13,
38+
NIM = 14,
39+
ACT = 15,
40+
FPD = 16,
41+
BOSS = 17,
42+
ACP = 18,
43+
PDM = 19,
44+
AC = 20,
45+
NDM = 21,
46+
NSEC = 22
47+
};
48+
49+
enum class CosCapabilityBits : uint64
50+
{
51+
All = 0xFFFFFFFFFFFFFFFFull
52+
};
53+
54+
enum class CosCapabilityBitsFS : uint64
55+
{
56+
ODD_READ = (1llu << 0),
57+
ODD_WRITE = (1llu << 1),
58+
ODD_RAW_OPEN = (1llu << 2),
59+
ODD_MOUNT = (1llu << 3),
60+
SLCCMPT_READ = (1llu << 4),
61+
SLCCMPT_WRITE = (1llu << 5),
62+
SLCCMPT_RAW_OPEN = (1llu << 6),
63+
SLCCMPT_MOUNT = (1llu << 7),
64+
SLC_READ = (1llu << 8),
65+
SLC_WRITE = (1llu << 9),
66+
SLC_RAW_OPEN = (1llu << 10),
67+
SLC_MOUNT = (1llu << 11),
68+
MLC_READ = (1llu << 12),
69+
MLC_WRITE = (1llu << 13),
70+
MLC_RAW_OPEN = (1llu << 14),
71+
MLC_MOUNT = (1llu << 15),
72+
SDCARD_READ = (1llu << 16),
73+
SDCARD_WRITE = (1llu << 17),
74+
SDCARD_RAW_OPEN = (1llu << 18),
75+
SDCARD_MOUNT = (1llu << 19),
76+
HFIO_READ = (1llu << 20),
77+
HFIO_WRITE = (1llu << 21),
78+
HFIO_RAW_OPEN = (1llu << 22),
79+
HFIO_MOUNT = (1llu << 23),
80+
RAMDISK_READ = (1llu << 24),
81+
RAMDISK_WRITE = (1llu << 25),
82+
RAMDISK_RAW_OPEN = (1llu << 26),
83+
RAMDISK_MOUNT = (1llu << 27),
84+
USB_READ = (1llu << 28),
85+
USB_WRITE = (1llu << 29),
86+
USB_RAW_OPEN = (1llu << 30),
87+
USB_MOUNT = (1llu << 31),
88+
OTHER_READ = (1llu << 32),
89+
OTHER_WRITE = (1llu << 33),
90+
OTHER_RAW_OPEN = (1llu << 34),
91+
OTHER_MOUNT = (1llu << 35)
92+
};
93+
ENABLE_BITMASK_OPERATORS(CosCapabilityBitsFS);
94+
2995
struct ParsedCosXml
3096
{
97+
public:
98+
3199
std::string argstr;
32100

33-
static ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen)
101+
struct Permission
34102
{
35-
pugi::xml_document app_doc;
36-
if (!app_doc.load_buffer_inplace(xmlData, xmlLen))
37-
return nullptr;
38-
39-
const auto root = app_doc.child("app");
40-
if (!root)
41-
return nullptr;
103+
CosCapabilityGroup group{CosCapabilityGroup::None};
104+
CosCapabilityBits mask{CosCapabilityBits::All};
105+
};
106+
Permission permissions[19]{};
42107

43-
ParsedCosXml* parsedCos = new ParsedCosXml();
108+
static ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen);
44109

45-
for (const auto& child : root.children())
110+
CosCapabilityBits GetCapabilityBits(CosCapabilityGroup group) const
111+
{
112+
for (const auto& perm : permissions)
46113
{
47-
std::string_view name = child.name();
48-
if (name == "argstr")
49-
parsedCos->argstr = child.text().as_string();
114+
if (perm.group == group)
115+
return perm.mask;
50116
}
51-
return parsedCos;
117+
return CosCapabilityBits::All;
52118
}
53119
};
54120

@@ -151,7 +217,7 @@ class TitleInfo
151217
// cos.xml
152218
std::string GetArgStr() const;
153219

154-
// meta.xml also contains a version which seems to match the one from app.xml
220+
// meta.xml also contains a version field which seems to match the one from app.xml
155221
// 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
156222

157223
TitleIdParser::TITLE_TYPE GetTitleType();
@@ -160,6 +226,11 @@ class TitleInfo
160226
return m_parsedMetaXml;
161227
}
162228

229+
ParsedCosXml* GetCosInfo()
230+
{
231+
return m_parsedCosXml;
232+
}
233+
163234
std::string GetPrintPath() const; // formatted path including type and WUA subpath. Intended for logging and user-facing information
164235
std::string GetInstallPath() const; // installation subpath, relative to storage base. E.g. "usr/title/.../..." or "sys/title/.../..."
165236

0 commit comments

Comments
 (0)