diff --git a/Source/Core/Common/NandPaths.cpp b/Source/Core/Common/NandPaths.cpp index 1fcbab38be..ec43b38484 100644 --- a/Source/Core/Common/NandPaths.cpp +++ b/Source/Core/Common/NandPaths.cpp @@ -58,6 +58,35 @@ std::string GetTMDFileName(u64 _titleID, FromWhichRoot from) return GetTitleContentPath(_titleID, from) + "title.tmd"; } +bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id) +{ + std::string expected_prefix = RootUserPath(from) + "/title/"; + if (!StringBeginsWith(path, expected_prefix)) + { + return false; + } + + // Try to find a title ID in the remaining path. + std::string subdirectory = path.substr(expected_prefix.size()); + std::vector components = SplitString(subdirectory, '/'); + if (components.size() < 2) + { + return false; + } + + u32 title_id_high, title_id_low; + if (!AsciiToHex(components[0], title_id_high) || !AsciiToHex(components[1], title_id_low)) + { + return false; + } + + if (title_id != nullptr) + { + *title_id = (static_cast(title_id_high) << 32) | title_id_low; + } + return true; +} + std::string EscapeFileName(const std::string& filename) { // Prevent paths from containing special names like ., .., ..., ...., and so on diff --git a/Source/Core/Common/NandPaths.h b/Source/Core/Common/NandPaths.h index 0a7738664c..6ef53a9912 100644 --- a/Source/Core/Common/NandPaths.h +++ b/Source/Core/Common/NandPaths.h @@ -29,6 +29,9 @@ std::string GetTitleDataPath(u64 _titleID, FromWhichRoot from); std::string GetTitleContentPath(u64 _titleID, FromWhichRoot from); std::string GetTMDFileName(u64 _titleID, FromWhichRoot from); +// Returns whether a path is within an installed title's directory. +bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id = nullptr); + // Escapes characters that are invalid or have special meanings in the host file system std::string EscapeFileName(const std::string& filename); // Escapes characters that are invalid or have special meanings in the host file system diff --git a/Source/Core/Core/IOS/FS/FS.cpp b/Source/Core/Core/IOS/FS/FS.cpp index 3ebad9c46a..50e8a47b28 100644 --- a/Source/Core/Core/IOS/FS/FS.cpp +++ b/Source/Core/Core/IOS/FS/FS.cpp @@ -21,6 +21,8 @@ #include "Common/NandPaths.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/IOS/ES/ES.h" +#include "Core/IOS/ES/Formats.h" #include "Core/IOS/FS/FileIO.h" namespace IOS @@ -326,6 +328,18 @@ IPCCommandResult FS::GetAttribute(const IOCtlRequest& request) u8 OtherPerm = 0x3; // read/write u8 Attributes = 0x00; // no attributes + // Hack: if the path that is being accessed is within an installed title directory, get the + // UID/GID from the installed title TMD. + u64 title_id; + if (IsTitlePath(Filename, Common::FROM_SESSION_ROOT, &title_id)) + { + IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(title_id); + if (tmd.IsValid()) + { + GroupID = tmd.GetGroupId(); + } + } + if (File::IsDirectory(Filename)) { INFO_LOG(IOS_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set", diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 6eae92bf72..9059269308 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -216,6 +216,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; case IOCTL_WFSI_INIT: + { INFO_LOG(IOS, "IOCTL_WFSI_INIT"); if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0) { @@ -223,7 +224,15 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) return_error_code = IPC_EINVAL; break; } + m_title_id_str = StringFromFormat( + "%c%c%c%c", static_cast(m_title_id >> 24), static_cast(m_title_id >> 16), + static_cast(m_title_id >> 8), static_cast(m_title_id)); + + IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(m_title_id); + m_group_id = tmd.GetGroupId(); + m_group_id_str = StringFromFormat("%c%c", m_group_id >> 8, m_group_id & 0xFF); break; + } case IOCTL_WFSI_SET_DEVICE_NAME: INFO_LOG(IOS, "IOCTL_WFSI_SET_DEVICE_NAME"); @@ -233,20 +242,16 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_APPLY_TITLE_PROFILE: INFO_LOG(IOS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); - m_base_extract_path = StringFromFormat( - "/vol/%s/_install/%c%c%c%c/content", m_device_name.c_str(), - static_cast(m_tmd.GetTitleId() >> 24), static_cast(m_tmd.GetTitleId() >> 16), - static_cast(m_tmd.GetTitleId() >> 8), static_cast(m_tmd.GetTitleId())); + m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(), + m_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); break; case IOCTL_WFSI_LOAD_DOL: { - std::string path = StringFromFormat( - "/vol/%s/_install/%c%c%c%c/content", m_device_name.c_str(), - static_cast(m_title_id >> 24), static_cast(m_title_id >> 16), - static_cast(m_title_id >> 8), static_cast(m_title_id)); + std::string path = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), + m_group_id_str.c_str(), m_title_id_str.c_str()); u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18); u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14); diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 77e4a827f6..5ed9ee21eb 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -53,6 +53,9 @@ private: IOS::ES::TMDReader m_tmd; std::string m_base_extract_path; u64 m_title_id; + std::string m_title_id_str; + u16 m_group_id; + std::string m_group_id_str; ARCUnpacker m_arc_unpacker;