From 92387cb05225f2d28b1cef7bae4f4af6ad836e60 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 01:42:43 +0200 Subject: [PATCH 01/26] WFS: Implement CLOSE_2 as a clone of CLOSE. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 10 ++++++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 2 files changed, 11 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 08315c48c6..1178ce2623 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -194,6 +194,16 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFS_CLOSE_2: + { + // TODO(wfs): Figure out the exact semantics difference from the other + // close. + u16 fd = Memory::Read_U16(request.buffer_in + 0x4); + INFO_LOG(IOS, "IOCTL_WFS_CLOSE_2(%d)", fd); + ReleaseFileDescriptor(fd); + break; + } + case IOCTL_WFS_READ: case IOCTL_WFS_READ_ABSOLUTE: { diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index f509ae9ee1..dd1131b178 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -67,6 +67,7 @@ private: IOCTL_WFS_WRITE = 0x22, IOCTL_WFS_ATTACH_DETACH = 0x2d, IOCTL_WFS_ATTACH_DETACH_2 = 0x2e, + IOCTL_WFS_CLOSE_2 = 0x47, IOCTL_WFS_READ_ABSOLUTE = 0x48, }; From c81636d9a86c53671f6f13b9c15914a2117cf4b6 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 01:50:58 +0200 Subject: [PATCH 02/26] WFSI: Stub out SET_FST_BUFFER. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 7 +++++++ Source/Core/Core/IOS/WFS/WFSI.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index a2e856831e..20aea24975 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -248,6 +248,13 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; + case IOCTL_WFSI_SET_FST_BUFFER: + { + INFO_LOG(IOS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in, + request.buffer_in_size); + break; + } + case IOCTL_WFSI_LOAD_DOL: { std::string path = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 5ed9ee21eb..24e942a01d 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -84,6 +84,8 @@ private: IOCTL_WFSI_APPLY_TITLE_PROFILE = 0x89, + IOCTL_WFSI_SET_FST_BUFFER = 0x8e, + IOCTL_WFSI_LOAD_DOL = 0x90, }; }; From 56aa3cc558ead7c0e23362df2ac96131140566f0 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 03:36:53 +0200 Subject: [PATCH 03/26] WFSI: Implement both GET_TMD ioctls. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 49 +++++++++++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSI.h | 4 +++ 2 files changed, 53 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 20aea24975..cf8df1e8a6 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -4,6 +4,7 @@ #include "Core/IOS/WFS/WFSI.h" +#include #include #include #include @@ -248,6 +249,33 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; + case IOCTL_WFSI_GET_TMD: + { + u64 subtitle_id = Memory::Read_U64(request.buffer_in); + u32 address = Memory::Read_U32(request.buffer_in + 24); + INFO_LOG(IOS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id); + + u32 tmd_size; + return_error_code = GetTmd(m_group_id, m_title_id, subtitle_id, address, &tmd_size); + Memory::Write_U32(tmd_size, request.buffer_out); + break; + } + + case IOCTL_WFSI_GET_TMD_ABSOLUTE: + { + u64 subtitle_id = Memory::Read_U64(request.buffer_in); + u32 address = Memory::Read_U32(request.buffer_in + 24); + u16 group_id = Memory::Read_U16(request.buffer_in + 36); + u32 title_id = Memory::Read_U32(request.buffer_in + 32); + INFO_LOG(IOS, "IOCTL_WFSI_GET_TMD_ABSOLUTE: tid %08x, gid %04x, subtitle ID %016" PRIx64, + title_id, group_id, subtitle_id); + + u32 tmd_size; + return_error_code = GetTmd(group_id, title_id, subtitle_id, address, &tmd_size); + Memory::Write_U32(tmd_size, request.buffer_out); + break; + } + case IOCTL_WFSI_SET_FST_BUFFER: { INFO_LOG(IOS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in, @@ -309,6 +337,27 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) return GetDefaultReply(return_error_code); } + +u32 WFSI::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const +{ + // TODO(wfs): This is using a separate copy of tid/gid in wfssrv. Why? + std::string path = + StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(), + m_group_id_str.c_str(), m_title_id_str.c_str(), subtitle_id); + File::IOFile fp(WFS::NativePath(path), "rb"); + if (!fp) + { + WARN_LOG(IOS, "GetTmd: no such file or directory: %s", path.c_str()); + return WFSI_ENOENT; + } + if (address) + { + fp.ReadBytes(Memory::GetPointer(address), fp.GetSize()); + } + *size = fp.GetSize(); + return IPC_SUCCESS; +} + } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 24e942a01d..8945de1ce8 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -44,6 +44,7 @@ public: IPCCommandResult IOCtl(const IOCtlRequest& request) override; private: + u32 GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const; std::string m_device_name; mbedtls_aes_context m_aes_ctx; @@ -84,6 +85,9 @@ private: IOCTL_WFSI_APPLY_TITLE_PROFILE = 0x89, + IOCTL_WFSI_GET_TMD = 0x8a, + IOCTL_WFSI_GET_TMD_ABSOLUTE = 0x8b, + IOCTL_WFSI_SET_FST_BUFFER = 0x8e, IOCTL_WFSI_LOAD_DOL = 0x90, From e45bb77512aaa645756aceae6a6a329e634eced9 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 04:21:00 +0200 Subject: [PATCH 04/26] WFS: Add a basic GET_ATTRIBUTES implementation. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 1178ce2623..8c03f62a5c 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -136,6 +136,31 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) Memory::CopyToEmu(request.buffer_out + 2, m_home_directory.data(), m_home_directory.size()); break; + case IOCTL_WFS_GET_ATTRIBUTES: + { + std::string path = NormalizePath( + Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in))); + std::string native_path = WFS::NativePath(path); + Memory::Memset(0, request.buffer_out, request.buffer_out_size); + if (!File::Exists(native_path)) + { + INFO_LOG(IOS, "IOCTL_WFS_GET_ATTRIBUTES(%s): no such file or directory", path.c_str()); + return_error_code = WFS_ENOENT; + } + else if (File::IsDirectory(native_path)) + { + INFO_LOG(IOS, "IOCTL_WFS_GET_ATTRIBUTES(%s): directory", path.c_str()); + Memory::Write_U32(0x80000000, request.buffer_out + 4); + } + else + { + u32 size = static_cast(File::GetSize(native_path)); + INFO_LOG(IOS, "IOCTL_WFS_GET_ATTRIBUTES(%s): file with size %d", path.c_str(), size); + Memory::Write_U32(size, request.buffer_out); + } + break; + } + case IOCTL_WFS_OPEN: { u32 mode = Memory::Read_U32(request.buffer_in); From c0b3a684410968d2a9f218a7f56dffe7b75d1d80 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 04:27:53 +0200 Subject: [PATCH 05/26] WFS: Implement MKDIR. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 23 +++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 2 files changed, 24 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 8c03f62a5c..75bdddfabc 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -100,6 +100,29 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS_WFS, "IOCTL_WFS_FLUSH: doing nothing"); break; + case IOCTL_WFS_MKDIR: + { + std::string path = NormalizePath( + Memory::GetString(request.buffer_in + 34, Memory::Read_U16(request.buffer_in + 32))); + std::string native_path = WFS::NativePath(path); + + if (File::Exists(native_path)) + { + INFO_LOG(IOS, "IOCTL_WFS_MKDIR(%s): already exists", path.c_str()); + return_error_code = WFS_EEXIST; + } + else if (!File::CreateDir(native_path)) + { + INFO_LOG(IOS, "IOCTL_WFS_MKDIR(%s): no such file or directory", path.c_str()); + return_error_code = WFS_ENOENT; + } + else + { + INFO_LOG(IOS, "IOCTL_WFS_MKDIR(%s): directory created", path.c_str()); + } + break; + } + // TODO(wfs): Globbing is not really implemented, we just fake the one case // (listing /vol/*) which is required to get the installer to work. case IOCTL_WFS_GLOB_START: diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index dd1131b178..d602ca0a36 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -74,6 +74,7 @@ private: enum { WFS_EBADFD = -10026, // Invalid file descriptor. + WFS_EEXIST = -10027, // File already exists. WFS_ENOENT = -10028, // No such file or directory. }; From ef3232cd746d3f9092aff22b3a8ee6a34f717805 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 04:35:03 +0200 Subject: [PATCH 06/26] WFSI: Create meta/work/save dirs when applying title profile. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index cf8df1e8a6..ec29a7d5bb 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -247,6 +247,13 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) m_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); + for (auto dir : {"work", "meta", "save"}) + { + std::string path = StringFromFormat("/vol/%s/_install/%s/%s", m_device_name.c_str(), + m_title_id_str.c_str(), dir); + File::CreateFullPath(WFS::NativePath(path)); + } + break; case IOCTL_WFSI_GET_TMD: From dca70844a6429bbfa3249fcb17b5b68bba3fe3ab Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 04:43:03 +0200 Subject: [PATCH 07/26] WFS: Implement CREATE_OPEN along with OPEN. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 18 ++++++++++++++---- Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 75bdddfabc..5ef6fe0965 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -184,9 +184,12 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFS_CREATE_OPEN: case IOCTL_WFS_OPEN: { - u32 mode = Memory::Read_U32(request.buffer_in); + const char* ioctl_name = + request.request == IOCTL_WFS_OPEN ? "IOCTL_WFS_OPEN" : "IOCTL_WFS_CREATE_OPEN"; + u32 mode = request.request == IOCTL_WFS_OPEN ? Memory::Read_U32(request.buffer_in) : 2; u16 path_len = Memory::Read_U16(request.buffer_in + 0x20); std::string path = Memory::GetString(request.buffer_in + 0x22, path_len); @@ -201,14 +204,21 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) if (!fd_obj->Open()) { - ERROR_LOG(IOS_WFS, "IOCTL_WFS_OPEN(%s, %d): error opening file", path.c_str(), mode); + ERROR_LOG(IOS_WFS, "%s(%s, %d): error opening file", ioctl_name, path.c_str(), mode); ReleaseFileDescriptor(fd); return_error_code = WFS_ENOENT; break; } - INFO_LOG(IOS_WFS, "IOCTL_WFS_OPEN(%s, %d) -> %d", path.c_str(), mode, fd); - Memory::Write_U16(fd, request.buffer_out + 0x14); + INFO_LOG(IOS_WFS, "%s(%s, %d) -> %d", ioctl_name, path.c_str(), mode, fd); + if (request.request == IOCTL_WFS_OPEN) + { + Memory::Write_U16(fd, request.buffer_out + 0x14); + } + else + { + Memory::Write_U16(fd, request.buffer_out); + } break; } diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index d602ca0a36..bf7c58d170 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -60,6 +60,7 @@ private: IOCTL_WFS_GETCWD = 0x13, IOCTL_WFS_DELETE = 0x15, IOCTL_WFS_GET_ATTRIBUTES = 0x17, + IOCTL_WFS_CREATE_OPEN = 0x19, IOCTL_WFS_OPEN = 0x1A, IOCTL_WFS_GET_SIZE = 0x1B, IOCTL_WFS_CLOSE = 0x1E, From e79392cb8e29be8307f6afd779e74e0db5c49f53 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 04:53:32 +0200 Subject: [PATCH 08/26] WFS: Implement WRITE and WRITE_ABSOLUTE. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 39 +++++++++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 1 + 2 files changed, 40 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 5ef6fe0965..1ba9166eba 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -303,6 +303,45 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFS_WRITE: + case IOCTL_WFS_WRITE_ABSOLUTE: + { + u32 addr = Memory::Read_U32(request.buffer_in); + u32 position = Memory::Read_U32(request.buffer_in + 4); // Only for absolute. + u16 fd = Memory::Read_U16(request.buffer_in + 0xC); + u32 size = Memory::Read_U32(request.buffer_in + 8); + + bool absolute = request.request == IOCTL_WFS_WRITE_ABSOLUTE; + + FileDescriptor* fd_obj = FindFileDescriptor(fd); + if (fd_obj == nullptr) + { + ERROR_LOG(IOS, "IOCTL_WFS_WRITE: invalid file descriptor %d", fd); + return_error_code = WFS_EBADFD; + break; + } + + u64 previous_position = fd_obj->file.Tell(); + if (absolute) + { + fd_obj->file.Seek(position, SEEK_SET); + } + fd_obj->file.WriteArray(Memory::GetPointer(addr), size); + // TODO(wfs): Handle write errors. + if (absolute) + { + fd_obj->file.Seek(previous_position, SEEK_SET); + } + else + { + fd_obj->position += size; + } + + INFO_LOG(IOS, "IOCTL_WFS_WRITE: written %d bytes from FD %d (%s)", size, fd, + fd_obj->path.c_str()); + break; + } + default: // TODO(wfs): Should be returning -3. However until we have everything // properly stubbed it's easier to simulate the methods succeeding. diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index bf7c58d170..3b2f2d5f2d 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -70,6 +70,7 @@ private: IOCTL_WFS_ATTACH_DETACH_2 = 0x2e, IOCTL_WFS_CLOSE_2 = 0x47, IOCTL_WFS_READ_ABSOLUTE = 0x48, + IOCTL_WFS_WRITE_ABSOLUTE = 0x49, }; enum From 88580b8d5f17230e6916505cb195c8d8a576c068 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 05:15:08 +0200 Subject: [PATCH 09/26] WFSI: Fix install directories creation. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index ec29a7d5bb..cb661b0f38 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -226,8 +226,8 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) 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)); + "%c%c%c%c", static_cast(m_title_id >> 56), static_cast(m_title_id >> 48), + static_cast(m_title_id >> 40), static_cast(m_title_id >> 32)); IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(m_title_id); m_group_id = tmd.GetGroupId(); @@ -243,17 +243,27 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_APPLY_TITLE_PROFILE: INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); - m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(), - m_title_id_str.c_str()); + std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str()); + if (File::IsDirectory(WFS::NativePath(install_directory))) + { + File::DeleteDirRecursively(WFS::NativePath(install_directory)); + } + + m_base_extract_path = + StringFromFormat("%s/%s/content", install_directory.c_str(), m_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); for (auto dir : {"work", "meta", "save"}) { - std::string path = StringFromFormat("/vol/%s/_install/%s/%s", m_device_name.c_str(), - m_title_id_str.c_str(), dir); + std::string path = + StringFromFormat("%s/%s/%s", install_directory.c_str(), m_title_id_str.c_str(), dir); File::CreateFullPath(WFS::NativePath(path)); } + std::string group_path = + StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(), m_group_id_str.c_str()); + File::CreateFullPath(WFS::NativePath(group_path)); + break; case IOCTL_WFSI_GET_TMD: From e6e00f6c8d58b3393ed029747fce155d2e84c3c7 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 06:10:11 +0200 Subject: [PATCH 10/26] WFSI: Implement install finalization. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 38 +++++++++++++++++++++++++++---- Source/Core/Core/IOS/WFS/WFSI.h | 6 +++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index cb661b0f38..70f03b4281 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -98,6 +98,8 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) u32 tmd_addr = Memory::Read_U32(request.buffer_in); u32 tmd_size = Memory::Read_U32(request.buffer_in + 4); + m_continue_install = Memory::Read_U32(request.buffer_in + 36); + INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE"); constexpr u32 MAX_TMD_SIZE = 0x4000; @@ -122,6 +124,13 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) memcpy(m_aes_key, ticket.GetTitleKey(m_ios.GetIOSC()).data(), sizeof(m_aes_key)); mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128); + m_title_id = m_tmd.GetTitleId(); + 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)); + m_group_id = m_tmd.GetGroupId(); + m_group_id_str = StringFromFormat("%c%c", m_group_id >> 8, m_group_id & 0xFF); + break; } @@ -205,6 +214,23 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFSI_FINALIZE_IMPORT: + { + // TODO(wfs): Handle patches. + std::string title_install_dir = + StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(), m_title_id_str.c_str()); + std::string title_final_dir = StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), + m_group_id_str.c_str(), m_title_id_str.c_str()); + File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir)); + + std::string tmd_path = + StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(), + m_group_id_str.c_str(), m_title_id_str.c_str(), m_title_id); + File::IOFile tmd_file(WFS::NativePath(tmd_path), "wb"); + tmd_file.WriteBytes(m_tmd.GetBytes().data(), m_tmd.GetBytes().size()); + break; + } + case IOCTL_WFSI_DELETE_TITLE: // Bytes 0-4: ?? // Bytes 4-8: game id @@ -226,8 +252,8 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } m_title_id_str = StringFromFormat( - "%c%c%c%c", static_cast(m_title_id >> 56), static_cast(m_title_id >> 48), - static_cast(m_title_id >> 40), static_cast(m_title_id >> 32)); + "%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(); @@ -241,10 +267,11 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; case IOCTL_WFSI_APPLY_TITLE_PROFILE: + { INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str()); - if (File::IsDirectory(WFS::NativePath(install_directory))) + if (!m_continue_install && File::IsDirectory(WFS::NativePath(install_directory))) { File::DeleteDirRecursively(WFS::NativePath(install_directory)); } @@ -252,19 +279,22 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) m_base_extract_path = StringFromFormat("%s/%s/content", install_directory.c_str(), m_title_id_str.c_str()); File::CreateFullPath(WFS::NativePath(m_base_extract_path)); + File::CreateDir(WFS::NativePath(m_base_extract_path)); for (auto dir : {"work", "meta", "save"}) { std::string path = StringFromFormat("%s/%s/%s", install_directory.c_str(), m_title_id_str.c_str(), dir); - File::CreateFullPath(WFS::NativePath(path)); + File::CreateDir(WFS::NativePath(path)); } std::string group_path = StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(), m_group_id_str.c_str()); File::CreateFullPath(WFS::NativePath(group_path)); + File::CreateDir(WFS::NativePath(group_path)); break; + } case IOCTL_WFSI_GET_TMD: { diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 8945de1ce8..01f9e30831 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -58,6 +58,10 @@ private: u16 m_group_id; std::string m_group_id_str; + // Set on PREPARE_DEVICE when the next profile application should not delete + // temporary install files. + u32 m_continue_install = 0; + ARCUnpacker m_arc_unpacker; enum @@ -73,6 +77,8 @@ private: IOCTL_WFSI_IMPORT_CONTENT = 0x04, IOCTL_WFSI_FINALIZE_CONTENT = 0x05, + IOCTL_WFSI_FINALIZE_IMPORT = 0x06, + IOCTL_WFSI_DELETE_TITLE = 0x17, IOCTL_WFSI_IMPORT_TITLE = 0x2f, From 2a8d9a53b7a8e7fc855766ab5415405bda642510 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Wed, 16 Aug 2017 06:50:18 +0200 Subject: [PATCH 11/26] WFS: Share error codes with WFSI. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 4 ++-- Source/Core/Core/IOS/WFS/WFSI.h | 5 ----- Source/Core/Core/IOS/WFS/WFSSRV.h | 14 +++++++------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 70f03b4281..274850451d 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -355,7 +355,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) if (!fp) { WARN_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str()); - return_error_code = WFSI_ENOENT; + return_error_code = WFS_ENOENT; break; } @@ -395,7 +395,7 @@ u32 WFSI::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* if (!fp) { WARN_LOG(IOS, "GetTmd: no such file or directory: %s", path.c_str()); - return WFSI_ENOENT; + return WFS_ENOENT; } if (address) { diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 01f9e30831..b7a7747218 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -64,11 +64,6 @@ private: ARCUnpacker m_arc_unpacker; - enum - { - WFSI_ENOENT = -12000, - }; - enum { IOCTL_WFSI_PREPARE_DEVICE = 0x02, diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index 3b2f2d5f2d..a5697f28fc 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -22,6 +22,13 @@ namespace WFS std::string NativePath(const std::string& wfs_path); } +enum +{ + WFS_EBADFD = -10026, // Invalid file descriptor. + WFS_EEXIST = -10027, // File already exists. + WFS_ENOENT = -10028, // No such file or directory. +}; + namespace Device { class WFSSRV : public Device @@ -73,13 +80,6 @@ private: IOCTL_WFS_WRITE_ABSOLUTE = 0x49, }; - enum - { - WFS_EBADFD = -10026, // Invalid file descriptor. - WFS_EEXIST = -10027, // File already exists. - WFS_ENOENT = -10028, // No such file or directory. - }; - struct FileDescriptor { bool in_use; From 15f25783a8b9e2ca1aa6821beb842a4e22764387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 16 Aug 2017 23:33:34 +0200 Subject: [PATCH 12/26] WFS: Implement RENAME. --- Source/Core/Core/IOS/WFS/WFSSRV.cpp | 32 +++++++++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSSRV.h | 12 ++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 1ba9166eba..4b6cc1e03d 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -4,6 +4,7 @@ #include "Core/IOS/WFS/WFSSRV.h" +#include #include #include #include @@ -184,6 +185,17 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFS_RENAME: + case IOCTL_WFS_RENAME_2: + { + const std::string source_path = + Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in)); + const std::string dest_path = + Memory::GetString(request.buffer_in + 512 + 2, Memory::Read_U16(request.buffer_in + 512)); + return_error_code = Rename(source_path, dest_path); + break; + } + case IOCTL_WFS_CREATE_OPEN: case IOCTL_WFS_OPEN: { @@ -353,6 +365,26 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) return GetDefaultReply(return_error_code); } +s32 WFSSRV::Rename(std::string source, std::string dest) const +{ + source = NormalizePath(source); + dest = NormalizePath(dest); + + INFO_LOG(IOS_WFS, "IOCTL_WFS_RENAME: %s to %s", source.c_str(), dest.c_str()); + + const bool opened = std::any_of(m_fds.begin(), m_fds.end(), + [&](const auto& fd) { return fd.in_use && fd.path == source; }); + + if (opened) + return WFS_FILE_IS_OPENED; + + // TODO(wfs): Handle other rename failures + if (!File::Rename(WFS::NativePath(source), WFS::NativePath(dest))) + return WFS_ENOENT; + + return IPC_SUCCESS; +} + std::string WFSSRV::NormalizePath(const std::string& path) const { std::string expanded; diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.h b/Source/Core/Core/IOS/WFS/WFSSRV.h index a5697f28fc..a970ba1da0 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.h +++ b/Source/Core/Core/IOS/WFS/WFSSRV.h @@ -24,9 +24,11 @@ std::string NativePath(const std::string& wfs_path); enum { - WFS_EBADFD = -10026, // Invalid file descriptor. - WFS_EEXIST = -10027, // File already exists. - WFS_ENOENT = -10028, // No such file or directory. + WFS_EINVAL = -10003, // Invalid argument. + WFS_EBADFD = -10026, // Invalid file descriptor. + WFS_EEXIST = -10027, // File already exists. + WFS_ENOENT = -10028, // No such file or directory. + WFS_FILE_IS_OPENED = -10032, // Cannot perform operation on an opened file. }; namespace Device @@ -38,6 +40,8 @@ public: IPCCommandResult IOCtl(const IOCtlRequest& request) override; + s32 Rename(std::string source, std::string dest) const; + private: // WFS device name, e.g. msc01/msc02. std::string m_device_name; @@ -66,6 +70,7 @@ private: IOCTL_WFS_GET_HOMEDIR = 0x12, IOCTL_WFS_GETCWD = 0x13, IOCTL_WFS_DELETE = 0x15, + IOCTL_WFS_RENAME = 0x16, IOCTL_WFS_GET_ATTRIBUTES = 0x17, IOCTL_WFS_CREATE_OPEN = 0x19, IOCTL_WFS_OPEN = 0x1A, @@ -75,6 +80,7 @@ private: IOCTL_WFS_WRITE = 0x22, IOCTL_WFS_ATTACH_DETACH = 0x2d, IOCTL_WFS_ATTACH_DETACH_2 = 0x2e, + IOCTL_WFS_RENAME_2 = 0x41, IOCTL_WFS_CLOSE_2 = 0x47, IOCTL_WFS_READ_ABSOLUTE = 0x48, IOCTL_WFS_WRITE_ABSOLUTE = 0x49, From e004709b695c1947c4f5bf595b97bb0325ddbc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Aug 2017 01:41:13 +0200 Subject: [PATCH 13/26] WFSI: Implement CHECK_HAS_SPACE. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 17 +++++++++++++++++ Source/Core/Core/IOS/WFS/WFSI.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 274850451d..9f3344d971 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -373,6 +373,23 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFSI_CHECK_HAS_SPACE: + WARN_LOG(IOS, "IOCTL_WFSI_CHECK_HAS_SPACE: returning true"); + + // TODO(wfs): implement this properly. + // 1 is returned if there is free space, 0 otherwise. + // + // WFSI builds a path depending on the import state + // /vol/VOLUME_ID/title/GROUP_ID/GAME_ID + // /vol/VOLUME_ID/_install/GAME_ID + // then removes everything after the last path separator ('/') + // it then calls WFSISrvGetFreeBlkNum (ioctl 0x5a, aliased to 0x5b) with that path. + // If the ioctl fails, WFSI returns 0. + // If the ioctl succeeds, WFSI returns 0 or 1 depending on the three u32s in the input buffer + // and the three u32s returned by WFSSRV (TODO: figure out what it does) + return_error_code = 1; + break; + default: // TODO(wfs): Should be returning an error. However until we have // everything properly stubbed it's easier to simulate the methods diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index b7a7747218..d0ab4094d7 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -92,6 +92,8 @@ private: IOCTL_WFSI_SET_FST_BUFFER = 0x8e, IOCTL_WFSI_LOAD_DOL = 0x90, + + IOCTL_WFSI_CHECK_HAS_SPACE = 0x95, }; }; } // namespace Device From 5ed3a3f12d8b3eabd539b212455353ed367cb700 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 17 Aug 2017 03:56:26 +0200 Subject: [PATCH 14/26] WFSI: Get the patch info from PREPARE_DEVICE. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 4 +++- Source/Core/Core/IOS/WFS/WFSI.h | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 9f3344d971..22f70ac912 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -98,9 +98,11 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) u32 tmd_addr = Memory::Read_U32(request.buffer_in); u32 tmd_size = Memory::Read_U32(request.buffer_in + 4); + m_patch_type = Memory::Read_U32(request.buffer_in + 32); m_continue_install = Memory::Read_U32(request.buffer_in + 36); - INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE"); + INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: patch type %d, continue install: %s", + m_patch_type, m_continue_install ? "true" : "false"); constexpr u32 MAX_TMD_SIZE = 0x4000; if (tmd_size > MAX_TMD_SIZE) diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index d0ab4094d7..8898f0e8ec 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -60,7 +60,11 @@ private: // Set on PREPARE_DEVICE when the next profile application should not delete // temporary install files. - u32 m_continue_install = 0; + bool m_continue_install = false; + + // Set on PREPARE_DEVICE to indicate that the install is a patch and not a + // standalone title. + u32 m_patch_type = 0; ARCUnpacker m_arc_unpacker; From aa445806a53bdd3628884ccf3082937ff50e02e4 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 17 Aug 2017 13:22:12 +0200 Subject: [PATCH 15/26] WFSI: Rename a few ioctl handlers. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 12 ++++++------ Source/Core/Core/IOS/WFS/WFSI.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 22f70ac912..be7f8e2c08 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -187,12 +187,12 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } - case IOCTL_WFSI_FINALIZE_PROFILE: - case IOCTL_WFSI_FINALIZE_CONTENT: + case IOCTL_WFSI_IMPORT_CONTENT_END: + case IOCTL_WFSI_IMPORT_PROFILE_END: { - const char* ioctl_name = request.request == IOCTL_WFSI_FINALIZE_PROFILE ? - "IOCTL_WFSI_FINALIZE_PROFILE" : - "IOCTL_WFSI_FINALIZE_CONTENT"; + const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE_END ? + "IOCTL_WFSI_IMPORT_PROFILE_END" : + "IOCTL_WFSI_IMPORT_CONTENT_END"; INFO_LOG(IOS_WFS, "%s", ioctl_name); auto callback = [this](const std::string& filename, const std::vector& bytes) { @@ -216,7 +216,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } - case IOCTL_WFSI_FINALIZE_IMPORT: + case IOCTL_WFSI_FINALIZE_TITLE_INSTALL: { // TODO(wfs): Handle patches. std::string title_install_dir = diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 8898f0e8ec..8f69c35cdc 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -74,9 +74,9 @@ private: IOCTL_WFSI_PREPARE_CONTENT = 0x03, IOCTL_WFSI_IMPORT_CONTENT = 0x04, - IOCTL_WFSI_FINALIZE_CONTENT = 0x05, + IOCTL_WFSI_IMPORT_CONTENT_END = 0x05, - IOCTL_WFSI_FINALIZE_IMPORT = 0x06, + IOCTL_WFSI_FINALIZE_TITLE_INSTALL = 0x06, IOCTL_WFSI_DELETE_TITLE = 0x17, IOCTL_WFSI_IMPORT_TITLE = 0x2f, @@ -86,7 +86,7 @@ private: IOCTL_WFSI_PREPARE_PROFILE = 0x86, IOCTL_WFSI_IMPORT_PROFILE = 0x87, - IOCTL_WFSI_FINALIZE_PROFILE = 0x88, + IOCTL_WFSI_IMPORT_PROFILE_END = 0x88, IOCTL_WFSI_APPLY_TITLE_PROFILE = 0x89, From db24c94c6ee28b28520099ff15e1ff047808420d Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 17 Aug 2017 16:00:11 +0200 Subject: [PATCH 16/26] WFSI: More work to support patching: split off current_tid/gid and import_tid/gid --- Source/Core/Core/IOS/WFS/WFSI.cpp | 126 +++++++++++++++++++----------- Source/Core/Core/IOS/WFS/WFSI.h | 27 +++++-- 2 files changed, 103 insertions(+), 50 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index be7f8e2c08..e31891ec1c 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -21,6 +21,20 @@ #include "Core/IOS/WFS/WFSSRV.h" #include "DiscIO/NANDContentLoader.h" +namespace +{ +std::string TitleIdStr(u64 tid) +{ + return StringFromFormat("%c%c%c%c", static_cast(tid >> 24), static_cast(tid >> 16), + static_cast(tid >> 8), static_cast(tid)); +} + +std::string GroupIdStr(u16 gid) +{ + return StringFromFormat("%c%c", gid >> 8, gid & 0xFF); +} +} // namespace + namespace IOS { namespace HLE @@ -87,6 +101,24 @@ WFSI::WFSI(Kernel& ios, const std::string& device_name) : Device(ios, device_nam { } +void WFSI::SetCurrentTitleIdAndGroupId(u64 tid, u16 gid) +{ + m_current_title_id = tid; + m_current_group_id = gid; + + m_current_title_id_str = TitleIdStr(tid); + m_current_group_id_str = GroupIdStr(gid); +} + +void WFSI::SetImportTitleIdAndGroupId(u64 tid, u16 gid) +{ + m_import_title_id = tid; + m_import_group_id = gid; + + m_import_title_id_str = TitleIdStr(tid); + m_import_group_id_str = GroupIdStr(gid); +} + IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) { s32 return_error_code = IPC_SUCCESS; @@ -98,7 +130,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) u32 tmd_addr = Memory::Read_U32(request.buffer_in); u32 tmd_size = Memory::Read_U32(request.buffer_in + 4); - m_patch_type = Memory::Read_U32(request.buffer_in + 32); + m_patch_type = static_cast(Memory::Read_U32(request.buffer_in + 32)); m_continue_install = Memory::Read_U32(request.buffer_in + 36); INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: patch type %d, continue install: %s", @@ -126,13 +158,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) memcpy(m_aes_key, ticket.GetTitleKey(m_ios.GetIOSC()).data(), sizeof(m_aes_key)); mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128); - m_title_id = m_tmd.GetTitleId(); - 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)); - m_group_id = m_tmd.GetGroupId(); - m_group_id_str = StringFromFormat("%c%c", m_group_id >> 8, m_group_id & 0xFF); - + SetImportTitleIdAndGroupId(m_tmd.GetTitleId(), m_tmd.GetGroupId()); break; } @@ -219,15 +245,16 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_FINALIZE_TITLE_INSTALL: { // TODO(wfs): Handle patches. - std::string title_install_dir = - StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(), m_title_id_str.c_str()); - std::string title_final_dir = StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), - m_group_id_str.c_str(), m_title_id_str.c_str()); + std::string title_install_dir = StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(), + m_import_title_id_str.c_str()); + std::string title_final_dir = + StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), + m_import_group_id_str.c_str(), m_import_title_id_str.c_str()); File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir)); - std::string tmd_path = - StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(), - m_group_id_str.c_str(), m_title_id_str.c_str(), m_title_id); + std::string tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", + m_device_name.c_str(), m_import_group_id_str.c_str(), + m_import_title_id_str.c_str(), m_import_title_id); File::IOFile tmd_file(WFS::NativePath(tmd_path), "wb"); tmd_file.WriteBytes(m_tmd.GetBytes().data(), m_tmd.GetBytes().size()); break; @@ -247,19 +274,16 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_INIT: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_INIT"); - if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0) + u64 tid; + if (GetIOS()->GetES()->GetTitleId(&tid) < 0) { ERROR_LOG(IOS_WFS, "IOCTL_WFSI_INIT: Could not get title id."); 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); + IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(tid); + SetCurrentTitleIdAndGroupId(tmd.GetTitleId(), tmd.GetGroupId()); break; } @@ -272,29 +296,40 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) { INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); - std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str()); - if (!m_continue_install && File::IsDirectory(WFS::NativePath(install_directory))) + if (m_patch_type == NOT_A_PATCH) { - File::DeleteDirRecursively(WFS::NativePath(install_directory)); + std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str()); + if (!m_continue_install && File::IsDirectory(WFS::NativePath(install_directory))) + { + File::DeleteDirRecursively(WFS::NativePath(install_directory)); + } + + m_base_extract_path = StringFromFormat("%s/%s/content", install_directory.c_str(), + m_import_title_id_str.c_str()); + File::CreateFullPath(WFS::NativePath(m_base_extract_path)); + File::CreateDir(WFS::NativePath(m_base_extract_path)); + + for (auto dir : {"work", "meta", "save"}) + { + std::string path = StringFromFormat("%s/%s/%s", install_directory.c_str(), + m_import_title_id_str.c_str(), dir); + File::CreateDir(WFS::NativePath(path)); + } + + std::string group_path = StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(), + m_import_group_id_str.c_str()); + File::CreateFullPath(WFS::NativePath(group_path)); + File::CreateDir(WFS::NativePath(group_path)); } - - m_base_extract_path = - StringFromFormat("%s/%s/content", install_directory.c_str(), m_title_id_str.c_str()); - File::CreateFullPath(WFS::NativePath(m_base_extract_path)); - File::CreateDir(WFS::NativePath(m_base_extract_path)); - - for (auto dir : {"work", "meta", "save"}) + else { - std::string path = - StringFromFormat("%s/%s/%s", install_directory.c_str(), m_title_id_str.c_str(), dir); - File::CreateDir(WFS::NativePath(path)); + m_base_extract_path = + StringFromFormat("/vol/%s/title/%s/%s/_patch/content", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); + File::CreateFullPath(WFS::NativePath(m_base_extract_path)); + File::CreateDir(WFS::NativePath(m_base_extract_path)); } - std::string group_path = - StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(), m_group_id_str.c_str()); - File::CreateFullPath(WFS::NativePath(group_path)); - File::CreateDir(WFS::NativePath(group_path)); - break; } @@ -305,7 +340,8 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id); u32 tmd_size; - return_error_code = GetTmd(m_group_id, m_title_id, subtitle_id, address, &tmd_size); + return_error_code = + GetTmd(m_current_group_id, m_current_title_id, subtitle_id, address, &tmd_size); Memory::Write_U32(tmd_size, request.buffer_out); break; } @@ -334,8 +370,9 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_LOAD_DOL: { - 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()); + std::string path = + StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_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); @@ -406,10 +443,9 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) u32 WFSI::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const { - // TODO(wfs): This is using a separate copy of tid/gid in wfssrv. Why? std::string path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(), - m_group_id_str.c_str(), m_title_id_str.c_str(), subtitle_id); + GroupIdStr(group_id).c_str(), TitleIdStr(title_id).c_str(), subtitle_id); File::IOFile fp(WFS::NativePath(path), "rb"); if (!fp) { diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 8f69c35cdc..9711819a6d 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -45,6 +45,10 @@ public: private: u32 GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const; + + void SetCurrentTitleIdAndGroupId(u64 tid, u16 gid); + void SetImportTitleIdAndGroupId(u64 tid, u16 gid); + std::string m_device_name; mbedtls_aes_context m_aes_ctx; @@ -53,10 +57,15 @@ 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; + + u64 m_current_title_id; + std::string m_current_title_id_str; + u16 m_current_group_id; + std::string m_current_group_id_str; + u64 m_import_title_id; + std::string m_import_title_id_str; + u16 m_import_group_id; + std::string m_import_group_id_str; // Set on PREPARE_DEVICE when the next profile application should not delete // temporary install files. @@ -64,7 +73,13 @@ private: // Set on PREPARE_DEVICE to indicate that the install is a patch and not a // standalone title. - u32 m_patch_type = 0; + enum PatchType + { + NOT_A_PATCH, + PATCH_TYPE_1, + PATCH_TYPE_2, + }; + PatchType m_patch_type = NOT_A_PATCH; ARCUnpacker m_arc_unpacker; @@ -97,6 +112,8 @@ private: IOCTL_WFSI_LOAD_DOL = 0x90, + IOCTL_WFSI_FINALIZE_PATCH_INSTALL = 0x91, + IOCTL_WFSI_CHECK_HAS_SPACE = 0x95, }; }; From 76bbfbb511a968831f134d5bdf4da636ab8f19a3 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 17 Aug 2017 16:10:36 +0200 Subject: [PATCH 17/26] WFSI: Adapt FINALIZE_TITLE_INSTALL for patch support. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 38 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index e31891ec1c..029530139d 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -244,22 +244,40 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_FINALIZE_TITLE_INSTALL: { - // TODO(wfs): Handle patches. - std::string title_install_dir = StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(), - m_import_title_id_str.c_str()); - std::string title_final_dir = - StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), - m_import_group_id_str.c_str(), m_import_title_id_str.c_str()); - File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir)); + std::string tmd_path; + if (m_patch_type == NOT_A_PATCH) + { + std::string title_install_dir = StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(), + m_import_title_id_str.c_str()); + std::string title_final_dir = + StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), + m_import_group_id_str.c_str(), m_import_title_id_str.c_str()); + File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir)); + + tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", + m_device_name.c_str(), m_import_group_id_str.c_str(), + m_import_title_id_str.c_str(), m_import_title_id); + } + else + { + std::string patch_dir = + StringFromFormat("/vol/%s/title/%s/%s/_patch", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); + File::DeleteDirRecursively(WFS::NativePath(patch_dir)); + + tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", + m_device_name.c_str(), m_current_group_id_str.c_str(), + m_current_title_id_str.c_str(), m_import_title_id); + } - std::string tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", - m_device_name.c_str(), m_import_group_id_str.c_str(), - m_import_title_id_str.c_str(), m_import_title_id); File::IOFile tmd_file(WFS::NativePath(tmd_path), "wb"); tmd_file.WriteBytes(m_tmd.GetBytes().data(), m_tmd.GetBytes().size()); break; } + case IOCTL_WFSI_FINALIZE_PATCH_INSTALL: + break; + case IOCTL_WFSI_DELETE_TITLE: // Bytes 0-4: ?? // Bytes 4-8: game id From a641609857d95f6d9eea19abcd3a8b7d251172c5 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Thu, 17 Aug 2017 16:45:39 +0200 Subject: [PATCH 18/26] WFSI: Implement patch install finalization. --- Source/Core/Common/FileUtil.cpp | 14 ++++++++++---- Source/Core/Common/FileUtil.h | 5 +++-- Source/Core/Core/IOS/WFS/WFSI.cpp | 11 +++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 725d5134c5..84647fd4e9 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -521,7 +521,7 @@ bool DeleteDirRecursively(const std::string& directory) } // Create directory and copy contents (does not overwrite existing files) -void CopyDir(const std::string& source_path, const std::string& dest_path) +void CopyDir(const std::string& source_path, const std::string& dest_path, bool destructive) { if (source_path == dest_path) return; @@ -562,10 +562,16 @@ void CopyDir(const std::string& source_path, const std::string& dest_path) { if (!Exists(dest)) File::CreateFullPath(dest + DIR_SEP); - CopyDir(source, dest); + CopyDir(source, dest, destructive); + } + else if (!Exists(dest) && !destructive) + { + Copy(source, dest); + } + else + { + Rename(source, dest); } - else if (!Exists(dest)) - File::Copy(source, dest); #ifdef _WIN32 } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index 398abc748e..007fb3c541 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -156,8 +156,9 @@ bool DeleteDirRecursively(const std::string& directory); // Returns the current directory std::string GetCurrentDir(); -// Create directory and copy contents (does not overwrite existing files) -void CopyDir(const std::string& source_path, const std::string& dest_path); +// Create directory and copy contents (optionally overwrites existing files) +void CopyDir(const std::string& source_path, const std::string& dest_path, + bool destructive = false); // Set the current directory to given directory bool SetCurrentDir(const std::string& directory); diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 029530139d..519cc585c7 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -276,7 +276,18 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) } case IOCTL_WFSI_FINALIZE_PATCH_INSTALL: + { + INFO_LOG(IOS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL"); + if (m_patch_type != NOT_A_PATCH) + { + std::string current_title_dir = + StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); + std::string patch_dir = current_title_dir + "/_patch"; + File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true); + } break; + } case IOCTL_WFSI_DELETE_TITLE: // Bytes 0-4: ?? From 742356338662a8d63503d9e806e01c7d8a9ed094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Aug 2017 20:31:49 +0200 Subject: [PATCH 19/26] WFSI: Fix the TMD size check. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 519cc585c7..f65143f2bf 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -136,8 +136,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: patch type %d, continue install: %s", m_patch_type, m_continue_install ? "true" : "false"); - constexpr u32 MAX_TMD_SIZE = 0x4000; - if (tmd_size > MAX_TMD_SIZE) + if (!IOS::ES::IsValidTMDSize(tmd_size)) { ERROR_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size); return_error_code = IPC_EINVAL; From c1817b2c6d72d7abb951c76a4f0c3b38023b856e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Aug 2017 11:23:38 +0200 Subject: [PATCH 20/26] WFSI: Rename 2 ioctls to better reflect their purposes. * IOCTL_WFSI_PREPARE_DEVICE -> IOCTL_WFSI_IMPORT_TITLE_INIT (equivalent of ES_ImportTitleInit, also the official name) * IOCTL_WFSI_IMPORT_TITLE -> IOCTL_WFSI_IMPORT_TITLE_CANCEL (equivalent of ES_ImportTitleCancel) --- Source/Core/Core/IOS/WFS/WFSI.cpp | 12 ++++++------ Source/Core/Core/IOS/WFS/WFSI.h | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index f65143f2bf..3adf893669 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -125,7 +125,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) switch (request.request) { - case IOCTL_WFSI_PREPARE_DEVICE: + case IOCTL_WFSI_IMPORT_TITLE_INIT: { u32 tmd_addr = Memory::Read_U32(request.buffer_in); u32 tmd_size = Memory::Read_U32(request.buffer_in + 4); @@ -133,12 +133,12 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) m_patch_type = static_cast(Memory::Read_U32(request.buffer_in + 32)); m_continue_install = Memory::Read_U32(request.buffer_in + 36); - INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: patch type %d, continue install: %s", + INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: patch type %d, continue install: %s", m_patch_type, m_continue_install ? "true" : "false"); if (!IOS::ES::IsValidTMDSize(tmd_size)) { - ERROR_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size); + ERROR_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: TMD size too large (%d)", tmd_size); return_error_code = IPC_EINVAL; break; } @@ -279,7 +279,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL"); if (m_patch_type != NOT_A_PATCH) { - std::string current_title_dir = + std::string current_title_dir = StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(), m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); std::string patch_dir = current_title_dir + "/_patch"; @@ -295,8 +295,8 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) WARN_LOG(IOS_WFS, "IOCTL_WFSI_DELETE_TITLE: unimplemented"); break; - case IOCTL_WFSI_IMPORT_TITLE: - WARN_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE: unimplemented"); + case IOCTL_WFSI_IMPORT_TITLE_CANCEL: + WARN_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL: unimplemented"); break; case IOCTL_WFSI_INIT: diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 9711819a6d..62158e50a0 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -67,11 +67,11 @@ private: u16 m_import_group_id; std::string m_import_group_id_str; - // Set on PREPARE_DEVICE when the next profile application should not delete + // Set on IMPORT_TITLE_INIT when the next profile application should not delete // temporary install files. bool m_continue_install = false; - // Set on PREPARE_DEVICE to indicate that the install is a patch and not a + // Set on IMPORT_TITLE_INIT to indicate that the install is a patch and not a // standalone title. enum PatchType { @@ -85,7 +85,7 @@ private: enum { - IOCTL_WFSI_PREPARE_DEVICE = 0x02, + IOCTL_WFSI_IMPORT_TITLE_INIT = 0x02, IOCTL_WFSI_PREPARE_CONTENT = 0x03, IOCTL_WFSI_IMPORT_CONTENT = 0x04, @@ -94,7 +94,7 @@ private: IOCTL_WFSI_FINALIZE_TITLE_INSTALL = 0x06, IOCTL_WFSI_DELETE_TITLE = 0x17, - IOCTL_WFSI_IMPORT_TITLE = 0x2f, + IOCTL_WFSI_IMPORT_TITLE_CANCEL = 0x2f, IOCTL_WFSI_INIT = 0x81, IOCTL_WFSI_SET_DEVICE_NAME = 0x82, From f0aeeeaef6de42a0233967c914e7454953898861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Aug 2017 14:14:53 +0200 Subject: [PATCH 21/26] WFSI: Implement internal Cancel{Title,Patch}Import. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 49 +++++++++++++++++++++++++++++++ Source/Core/Core/IOS/WFS/WFSI.h | 3 ++ 2 files changed, 52 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 3adf893669..f23cc78724 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -488,6 +488,55 @@ u32 WFSI::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* return IPC_SUCCESS; } +static s32 DeleteTemporaryFiles(const std::string& device_name, u64 title_id) +{ + File::Delete(WFS::NativePath( + StringFromFormat("/vol/%s/tmp/%016" PRIx64 ".ini", device_name.c_str(), title_id))); + File::Delete(WFS::NativePath( + StringFromFormat("/vol/%s/tmp/%016" PRIx64 ".ppcini", device_name.c_str(), title_id))); + return IPC_SUCCESS; +} + +s32 WFSI::CancelTitleImport(bool continue_install) +{ + m_arc_unpacker.Reset(); + + if (!continue_install) + { + File::DeleteDirRecursively( + WFS::NativePath(StringFromFormat("/vol/%s/_install", m_device_name.c_str()))); + } + + DeleteTemporaryFiles(m_device_name, m_import_title_id); + + return IPC_SUCCESS; +} + +s32 WFSI::CancelPatchImport(bool continue_install) +{ + m_arc_unpacker.Reset(); + + if (!continue_install) + { + File::DeleteDirRecursively(WFS::NativePath( + StringFromFormat("/vol/%s/title/%s/%s/_patch", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_title_id_str.c_str()))); + + if (m_patch_type == PatchType::PATCH_TYPE_2) + { + // Move back _default.dol to default.dol. + const std::string content_dir = + StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); + File::Rename(WFS::NativePath(content_dir + "/_default.dol"), + WFS::NativePath(content_dir + "/default.dol")); + } + } + + DeleteTemporaryFiles(m_device_name, m_current_title_id); + + return IPC_SUCCESS; +} } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 62158e50a0..d6f07dfb9b 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -49,6 +49,9 @@ private: void SetCurrentTitleIdAndGroupId(u64 tid, u16 gid); void SetImportTitleIdAndGroupId(u64 tid, u16 gid); + s32 CancelTitleImport(bool continue_install); + s32 CancelPatchImport(bool continue_install); + std::string m_device_name; mbedtls_aes_context m_aes_ctx; From 5cc18bf116395a274914db42c41c93bb6d5a9b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Aug 2017 14:17:04 +0200 Subject: [PATCH 22/26] WFSI: Add missing functionality to ImportTitleInit. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index f23cc78724..2f609d1832 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -136,6 +136,16 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: patch type %d, continue install: %s", m_patch_type, m_continue_install ? "true" : "false"); + if (m_patch_type == PatchType::PATCH_TYPE_2) + { + const std::string content_dir = + StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(), + m_current_group_id_str.c_str(), m_current_title_id_str.c_str()); + + File::Rename(WFS::NativePath(content_dir + "/default.dol"), + WFS::NativePath(content_dir + "/_default.dol")); + } + if (!IOS::ES::IsValidTMDSize(tmd_size)) { ERROR_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: TMD size too large (%d)", tmd_size); @@ -158,6 +168,12 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128); SetImportTitleIdAndGroupId(m_tmd.GetTitleId(), m_tmd.GetGroupId()); + + if (m_patch_type == PatchType::PATCH_TYPE_1) + CancelPatchImport(m_continue_install); + else if (m_patch_type == PatchType::NOT_A_PATCH) + CancelTitleImport(m_continue_install); + break; } From 8a5d24ab4b6726637c279089204180c6b4fb8bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Aug 2017 18:32:42 +0200 Subject: [PATCH 23/26] WFSI: Implement IOCTL_WFSI_IMPORT_TITLE_CANCEL. It gets called for cleaning up whenever something goes wrong, and also when cancelling an update. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 2f609d1832..8a33d66721 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -312,8 +312,20 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; case IOCTL_WFSI_IMPORT_TITLE_CANCEL: - WARN_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL: unimplemented"); + { + INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL"); + + bool continue_install = Memory::Read_U32(request.buffer_in) != 0; + if (m_patch_type == PatchType::NOT_A_PATCH) + return_error_code = CancelTitleImport(continue_install); + else if (m_patch_type == PatchType::PATCH_TYPE_1 || m_patch_type == PatchType::PATCH_TYPE_2) + return_error_code = CancelPatchImport(continue_install); + else + return_error_code = WFS_EINVAL; + + m_tmd = {}; break; + } case IOCTL_WFSI_INIT: { From 70cb0cb1267e01e65698b69f71abd3e90ece1f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Fri, 18 Aug 2017 01:40:15 +0200 Subject: [PATCH 24/26] WFSI: Implement GET_VERSION. This ioctl writes a constant value to the output buffer. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 5 +++++ Source/Core/Core/IOS/WFS/WFSI.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 8a33d66721..ddf55b8acf 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -311,6 +311,11 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) WARN_LOG(IOS_WFS, "IOCTL_WFSI_DELETE_TITLE: unimplemented"); break; + case IOCTL_WFSI_GET_VERSION: + INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_VERSION"); + Memory::Write_U32(0x20, request.buffer_out); + break; + case IOCTL_WFSI_IMPORT_TITLE_CANCEL: { INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL"); diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index d6f07dfb9b..6d3346d097 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -97,6 +97,9 @@ private: IOCTL_WFSI_FINALIZE_TITLE_INSTALL = 0x06, IOCTL_WFSI_DELETE_TITLE = 0x17, + + IOCTL_WFSI_GET_VERSION = 0x1b, + IOCTL_WFSI_IMPORT_TITLE_CANCEL = 0x2f, IOCTL_WFSI_INIT = 0x81, From 344228ec10b38d90611dcc03216551457465a12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Fri, 18 Aug 2017 01:46:21 +0200 Subject: [PATCH 25/26] WFSI: Implement noop ioctl 0x8f. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 3 +++ Source/Core/Core/IOS/WFS/WFSI.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index ddf55b8acf..0b23a19419 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -429,6 +429,9 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) break; } + case IOCTL_WFSI_NOOP: + break; + case IOCTL_WFSI_LOAD_DOL: { std::string path = diff --git a/Source/Core/Core/IOS/WFS/WFSI.h b/Source/Core/Core/IOS/WFS/WFSI.h index 6d3346d097..d37ea76d09 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.h +++ b/Source/Core/Core/IOS/WFS/WFSI.h @@ -116,6 +116,8 @@ private: IOCTL_WFSI_SET_FST_BUFFER = 0x8e, + IOCTL_WFSI_NOOP = 0x8f, + IOCTL_WFSI_LOAD_DOL = 0x90, IOCTL_WFSI_FINALIZE_PATCH_INSTALL = 0x91, From ef888ef16846fc946cc6ed52a934999a407ea095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 20 Aug 2017 11:06:42 +0200 Subject: [PATCH 26/26] WFS: Fix logging types. --- Source/Core/Core/IOS/WFS/WFSI.cpp | 12 ++++++------ Source/Core/Core/IOS/WFS/WFSSRV.cpp | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Source/Core/Core/IOS/WFS/WFSI.cpp b/Source/Core/Core/IOS/WFS/WFSI.cpp index 0b23a19419..a0d8610bde 100644 --- a/Source/Core/Core/IOS/WFS/WFSI.cpp +++ b/Source/Core/Core/IOS/WFS/WFSI.cpp @@ -292,7 +292,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_FINALIZE_PATCH_INSTALL: { - INFO_LOG(IOS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL"); + INFO_LOG(IOS_WFS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL"); if (m_patch_type != NOT_A_PATCH) { std::string current_title_dir = @@ -398,7 +398,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) { u64 subtitle_id = Memory::Read_U64(request.buffer_in); u32 address = Memory::Read_U32(request.buffer_in + 24); - INFO_LOG(IOS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id); + INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id); u32 tmd_size; return_error_code = @@ -413,7 +413,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) u32 address = Memory::Read_U32(request.buffer_in + 24); u16 group_id = Memory::Read_U16(request.buffer_in + 36); u32 title_id = Memory::Read_U32(request.buffer_in + 32); - INFO_LOG(IOS, "IOCTL_WFSI_GET_TMD_ABSOLUTE: tid %08x, gid %04x, subtitle ID %016" PRIx64, + INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD_ABSOLUTE: tid %08x, gid %04x, subtitle ID %016" PRIx64, title_id, group_id, subtitle_id); u32 tmd_size; @@ -424,7 +424,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) case IOCTL_WFSI_SET_FST_BUFFER: { - INFO_LOG(IOS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in, + INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in, request.buffer_in_size); break; } @@ -477,7 +477,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request) } case IOCTL_WFSI_CHECK_HAS_SPACE: - WARN_LOG(IOS, "IOCTL_WFSI_CHECK_HAS_SPACE: returning true"); + WARN_LOG(IOS_WFS, "IOCTL_WFSI_CHECK_HAS_SPACE: returning true"); // TODO(wfs): implement this properly. // 1 is returned if there is free space, 0 otherwise. @@ -513,7 +513,7 @@ u32 WFSI::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* File::IOFile fp(WFS::NativePath(path), "rb"); if (!fp) { - WARN_LOG(IOS, "GetTmd: no such file or directory: %s", path.c_str()); + WARN_LOG(IOS_WFS, "GetTmd: no such file or directory: %s", path.c_str()); return WFS_ENOENT; } if (address) diff --git a/Source/Core/Core/IOS/WFS/WFSSRV.cpp b/Source/Core/Core/IOS/WFS/WFSSRV.cpp index 4b6cc1e03d..4bea8b7444 100644 --- a/Source/Core/Core/IOS/WFS/WFSSRV.cpp +++ b/Source/Core/Core/IOS/WFS/WFSSRV.cpp @@ -109,17 +109,17 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) if (File::Exists(native_path)) { - INFO_LOG(IOS, "IOCTL_WFS_MKDIR(%s): already exists", path.c_str()); + INFO_LOG(IOS_WFS, "IOCTL_WFS_MKDIR(%s): already exists", path.c_str()); return_error_code = WFS_EEXIST; } else if (!File::CreateDir(native_path)) { - INFO_LOG(IOS, "IOCTL_WFS_MKDIR(%s): no such file or directory", path.c_str()); + INFO_LOG(IOS_WFS, "IOCTL_WFS_MKDIR(%s): no such file or directory", path.c_str()); return_error_code = WFS_ENOENT; } else { - INFO_LOG(IOS, "IOCTL_WFS_MKDIR(%s): directory created", path.c_str()); + INFO_LOG(IOS_WFS, "IOCTL_WFS_MKDIR(%s): directory created", path.c_str()); } break; } @@ -168,18 +168,18 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) Memory::Memset(0, request.buffer_out, request.buffer_out_size); if (!File::Exists(native_path)) { - INFO_LOG(IOS, "IOCTL_WFS_GET_ATTRIBUTES(%s): no such file or directory", path.c_str()); + INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_ATTRIBUTES(%s): no such file or directory", path.c_str()); return_error_code = WFS_ENOENT; } else if (File::IsDirectory(native_path)) { - INFO_LOG(IOS, "IOCTL_WFS_GET_ATTRIBUTES(%s): directory", path.c_str()); + INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_ATTRIBUTES(%s): directory", path.c_str()); Memory::Write_U32(0x80000000, request.buffer_out + 4); } else { u32 size = static_cast(File::GetSize(native_path)); - INFO_LOG(IOS, "IOCTL_WFS_GET_ATTRIBUTES(%s): file with size %d", path.c_str(), size); + INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_ATTRIBUTES(%s): file with size %d", path.c_str(), size); Memory::Write_U32(size, request.buffer_out); } break; @@ -269,7 +269,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) // TODO(wfs): Figure out the exact semantics difference from the other // close. u16 fd = Memory::Read_U16(request.buffer_in + 0x4); - INFO_LOG(IOS, "IOCTL_WFS_CLOSE_2(%d)", fd); + INFO_LOG(IOS_WFS, "IOCTL_WFS_CLOSE_2(%d)", fd); ReleaseFileDescriptor(fd); break; } @@ -328,7 +328,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) FileDescriptor* fd_obj = FindFileDescriptor(fd); if (fd_obj == nullptr) { - ERROR_LOG(IOS, "IOCTL_WFS_WRITE: invalid file descriptor %d", fd); + ERROR_LOG(IOS_WFS, "IOCTL_WFS_WRITE: invalid file descriptor %d", fd); return_error_code = WFS_EBADFD; break; } @@ -349,7 +349,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request) fd_obj->position += size; } - INFO_LOG(IOS, "IOCTL_WFS_WRITE: written %d bytes from FD %d (%s)", size, fd, + INFO_LOG(IOS_WFS, "IOCTL_WFS_WRITE: written %d bytes from FD %d (%s)", size, fd, fd_obj->path.c_str()); break; }