From c8b7316581a8081e5b9f7d767c27db5c0a4db906 Mon Sep 17 00:00:00 2001 From: MasaGratoR Date: Fri, 2 Oct 2026 20:22:56 +0200 Subject: [PATCH 1/4] Add Trails in the Sky 2nd Chapter to ApplicationsWithDynamicHeap (#2870) --- stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp index 93f983fc1..a1f88ae37 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp @@ -51,6 +51,11 @@ namespace ams::mitm::fs { /* Unknown heap sensitivity. */ { 0x01002C9022770000, 16_MB, 0_MB }, + /* Trails in the Sky 2nd Chapter. */ + /* Requirement ~16 MB.*/ + /* No particular heap sensitivity. */ + { 0x01007A2027548000, 8_MB, 0_MB }, + /* STAR WARS: Knights of the Old Republic II: The Sith Lords. */ /* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */ /* Unknown heap sensitivity. */ From f5cd912604c342faf884e776b1aaaa5f9b3b5e98 Mon Sep 17 00:00:00 2001 From: hexkyz Date: Tue, 6 Oct 2026 02:25:38 +0100 Subject: [PATCH 2/4] dns.mitm: implement mitm for the new c-ares resolver and update serializer code --- .../stratosphere/socket/socket_types.hpp | 35 +- .../source/dns_mitm/dnsmitm_resolver_impl.cpp | 182 +++++++++ .../source/dns_mitm/dnsmitm_resolver_impl.hpp | 20 +- .../serializer/serializer_impls_addrinfo.cpp | 42 +- .../serializer/serializer_impls_ares.cpp | 380 ++++++++++++++++++ .../serializer/serializer_impls_hostent.cpp | 16 +- .../serializer/serializer_impls_in_addr.cpp | 2 + .../serializer_impls_sockaddrin_6.cpp | 2 +- .../serializer/serializer_impls_string.cpp | 3 + .../ams_mitm/source/dns_mitm/sfdnsres_shim.c | 103 +++++ .../ams_mitm/source/dns_mitm/sfdnsres_shim.h | 8 + 11 files changed, 769 insertions(+), 24 deletions(-) create mode 100644 stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_ares.cpp diff --git a/libraries/libstratosphere/include/stratosphere/socket/socket_types.hpp b/libraries/libstratosphere/include/stratosphere/socket/socket_types.hpp index 8547cf821..b9bd3a0bf 100644 --- a/libraries/libstratosphere/include/stratosphere/socket/socket_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/socket/socket_types.hpp @@ -158,7 +158,40 @@ namespace ams::socket { char *ai_canonname; AddrInfo *ai_next; }; - + + /* NOTE: We are using the c-ares structs under ams::socket. */ + /* Should we include c-ares instead somewhere? */ + struct ares_addrinfo_node { + int ai_ttl; + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + struct ares_addrinfo_node *ai_next; + }; + + struct ares_addrinfo_cname { + int ttl; + char *alias; + char *name; + struct ares_addrinfo_cname *next; + }; + + struct ares_addrinfo { + struct ares_addrinfo_cname *cnames; + struct ares_addrinfo_node *nodes; + char *name; + }; + + struct ares_addrinfo_hints { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + }; + struct TimeVal { long tv_sec; long tv_usec; diff --git a/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.cpp b/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.cpp index 5daf6421b..0d514c6ce 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.cpp +++ b/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.cpp @@ -21,6 +21,20 @@ #include "sfdnsres_shim.h" namespace ams::mitm::socket::resolver { + + namespace { + + struct AresAddrInfoQuery { + std::string hostname; + ams::socket::InAddrT redirect_addr; + u16 redirect_port; + const struct ams::socket::ares_addrinfo_hints *hint; + }; + + std::map> g_ares_addr_info_queries; + ssize_t g_current_ares_addr_info_query_id; + + } ssize_t SerializeRedirectedHostEnt(u8 * const dst, size_t dst_size, const char *hostname, ams::socket::InAddrT redirect_addr) { struct in_addr addr = { .s_addr = redirect_addr }; @@ -85,6 +99,97 @@ namespace ams::mitm::socket::resolver { AMS_ABORT_UNLESS(result >= 0); return result; } + + ssize_t QueueAresAddrInfoQuery(const char *hostname, ams::socket::InAddrT redirect_addr, u16 redirect_port, const struct ams::socket::ares_addrinfo_hints *hint) { + ssize_t query_id = g_current_ares_addr_info_query_id; + + AresAddrInfoQuery query; + query.hostname = hostname; + query.redirect_addr = redirect_addr; + query.redirect_port = redirect_port; + query.hint = hint; + + g_ares_addr_info_queries.emplace(query_id, std::make_unique(query)); + + /* NOTE: This really just increases ad infinitum. Should we bother checking it? */ + ++g_current_ares_addr_info_query_id; + + return query_id; + } + + ssize_t DequeueAresAddrInfoQuery(u8 * const dst, size_t dst_size, u32 query_id) { + AresAddrInfoQuery *query = nullptr; + + for (auto it = g_ares_addr_info_queries.begin(); it != g_ares_addr_info_queries.end(); ++it) { + if (it->first == static_cast(query_id)) { + query = it->second.get(); + break; + } + } + + if (query == nullptr) { + return 0; + } + + struct ams::socket::ares_addrinfo_node node = { + .ai_ttl = 0, + .ai_flags = AF_UNSPEC, + .ai_family = 0, + .ai_socktype = 0, + .ai_protocol = 0, + .ai_addrlen = 0, + .ai_next = nullptr, + }; + + if (query->hint != nullptr) { + std::memcpy(reinterpret_cast(std::addressof(node.ai_flags)), reinterpret_cast(query->hint), sizeof(struct ams::socket::ares_addrinfo_hints)); + } + + switch (node.ai_family) { + case AF_UNSPEC: node.ai_family = AF_INET; break; + case AF_INET: node.ai_family = AF_INET; break; + case AF_INET6: AMS_ABORT("Redirected INET6 not supported"); break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + if (node.ai_socktype == 0) { + node.ai_socktype = SOCK_STREAM; + } + + if (node.ai_protocol == 0) { + node.ai_protocol = IPPROTO_TCP; + } + + const struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_port = ams::socket::InetHtons(query->redirect_port), + .sin_addr = { .s_addr = query->redirect_addr }, + .sin_zero = {}, + }; + + node.ai_addrlen = sizeof(sin); + node.ai_addr = (struct sockaddr *)(std::addressof(sin)); + + struct ams::socket::ares_addrinfo ai { + .cnames = nullptr, + .nodes = std::addressof(node), + .name = const_cast(query->hostname.c_str()), + }; + + const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ai); + AMS_ABORT_UNLESS(result >= 0); + g_ares_addr_info_queries.erase(query_id); + return result; + } + + void CancelAresAddrInfoQuery(u32 query_id) { + for (auto it = g_ares_addr_info_queries.begin(); it != g_ares_addr_info_queries.end(); ++it) { + if (it->first == static_cast(query_id)) { + g_ares_addr_info_queries.erase(it); + break; + } + } + } Result ResolverImpl::GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out out_host_error, sf::Out out_errno, const sf::OutBuffer &out_hostent, sf::Out out_size) { AMS_UNUSED(cancel_handle, client_pid, use_nsd_resolve); @@ -208,6 +313,83 @@ namespace ams::mitm::socket::resolver { R_SUCCEED(); } + + Result ResolverImpl::ReportTelemetry(const sf::ClientProcessId &client_pid, const sf::InBuffer &telemetry, u32 version) { + /* NOTE: As of 23.0.0 this command does nothing. We mitm it anyway for future proofing. */ + AMS_UNUSED(client_pid, telemetry, version); + R_SUCCEED(); + } + + Result ResolverImpl::QueryAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_retval, sf::Out out_errno) { + AMS_UNUSED(client_pid, fd, options_version, options, num_options); + + const char *hostname = reinterpret_cast(node.GetPointer()); + + LogDebug("[%016lx]: QueryAddrInfoRequestWithOptions(%s, %s)\n", m_client_info.program_id.value, hostname, reinterpret_cast(srv.GetPointer())); + + R_UNLESS(hostname != nullptr, sm::mitm::ResultShouldForwardToSession()); + + ams::socket::InAddrT redirect_addr = {}; + R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession()); + + u16 port = 0; + if (srv.GetPointer() != nullptr) { + for (const char *cur = reinterpret_cast(srv.GetPointer()); *cur != 0; ++cur) { + AMS_ABORT_UNLESS(std::isdigit(static_cast(*cur))); + port *= 10; + port += *cur - '0'; + } + } + + LogDebug("[%016lx]: Queueing redirection %s:%u to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF); + + const bool use_hint = serialized_hint.GetPointer() != nullptr; + struct ams::socket::ares_addrinfo_hints hint = {}; + if (use_hint) { + AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0); + } + + const auto query_id = QueueAresAddrInfoQuery(hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr); + + LogDebug("[%016lx]: Queued query with id 0x%lx\n", m_client_info.program_id.value, query_id); + + /* Forward the query. The provided socket EventFd must be signalled by having bsdsocket write 1 to the associated socket. */ + /* This is fine though, we only care about replacing with our redirection during fetch. */ + R_TRY(sfdnsresQueryAddrInfoRequestWithOptionsFwd(m_forward_service.get(), static_cast(client_pid.GetValue().value), node.GetPointer(), node.GetSize(), srv.GetPointer(), srv.GetSize(), serialized_hint.GetPointer(), serialized_hint.GetSize(), reinterpret_cast(out_query_id.GetPointer()), fd, options_version, options.GetPointer(), options.GetSize(), num_options, reinterpret_cast(out_retval.GetPointer()), reinterpret_cast(out_errno.GetPointer()))); + + /* Replace with our own query. */ + *out_query_id = query_id; + *out_retval = 0; + *out_errno = 0; + + R_SUCCEED(); + } + + Result ResolverImpl::FetchAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out out_size, sf::Out out_retval, sf::Out out_errno) { + AMS_UNUSED(client_pid, version); + + LogDebug("[%016lx]: FetchAddrInfoRequestWithOptions(%d)\n", m_client_info.program_id.value, query_id); + + const auto size = DequeueAresAddrInfoQuery(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), query_id); + + LogDebug("[%016lx]: Dequeued query with size 0x%lx\n", m_client_info.program_id.value, size); + + *out_size = size; + *out_retval = 0; + *out_errno = 0; + + R_SUCCEED(); + } + + Result ResolverImpl::CancelQuery(const sf::ClientProcessId &client_pid, u32 query_id) { + AMS_UNUSED(client_pid); + + LogDebug("[%016lx]: CancelQuery(%d)\n", m_client_info.program_id.value, query_id); + + CancelAresAddrInfoQuery(query_id); + + R_SUCCEED(); + } Result ResolverImpl::AtmosphereReloadHostsFile() { /* Perform a hosts file reload. */ diff --git a/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.hpp b/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.hpp index 0b4036969..91ae3b819 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.hpp +++ b/stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.hpp @@ -16,11 +16,15 @@ #pragma once #include -#define AMS_DNS_MITM_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostByNameRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out out_host_error, sf::Out out_errno, const sf::OutBuffer &out_hostent, sf::Out out_size), (cancel_handle, client_pid, use_nsd_resolve, name, out_host_error, out_errno, out_hostent, out_size)) \ - AMS_SF_METHOD_INFO(C, H, 6, Result, GetAddrInfoRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out out_errno, sf::Out out_retval, sf::Out out_size), (cancel_handle, client_pid, use_nsd_resolve, node, srv, serialized_hint, out_addrinfo, out_errno, out_retval, out_size)) \ - AMS_SF_METHOD_INFO(C, H, 10, Result, GetHostByNameRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_host_error, sf::Out out_errno), (client_pid, name, out_hostent, out_size, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \ - AMS_SF_METHOD_INFO(C, H, 12, Result, GetAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out out_size, sf::Out out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_host_error, sf::Out out_errno), (client_pid, node, srv, serialized_hint, out_addrinfo, out_size, out_retval, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \ +#define AMS_DNS_MITM_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostByNameRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out out_host_error, sf::Out out_errno, const sf::OutBuffer &out_hostent, sf::Out out_size), (cancel_handle, client_pid, use_nsd_resolve, name, out_host_error, out_errno, out_hostent, out_size)) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, GetAddrInfoRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out out_errno, sf::Out out_retval, sf::Out out_size), (cancel_handle, client_pid, use_nsd_resolve, node, srv, serialized_hint, out_addrinfo, out_errno, out_retval, out_size)) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, GetHostByNameRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_host_error, sf::Out out_errno), (client_pid, name, out_hostent, out_size, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 12, Result, GetAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out out_size, sf::Out out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_host_error, sf::Out out_errno), (client_pid, node, srv, serialized_hint, out_addrinfo, out_size, out_retval, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 16, Result, ReportTelemetry, (const sf::ClientProcessId &client_pid, const sf::InBuffer &telemetry, u32 version), (client_pid, telemetry, version), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 100, Result, QueryAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_retval, sf::Out out_errno), (client_pid, node, srv, serialized_hint, out_query_id, fd, options_version, options, num_options, out_retval, out_errno), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 102, Result, FetchAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out out_size, sf::Out out_retval, sf::Out out_errno), (client_pid, query_id, version, out_addrinfo, out_size, out_retval, out_errno), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 104, Result, CancelQuery, (const sf::ClientProcessId &client_pid, u32 query_id), (client_pid, query_id), hos::Version_23_0_0) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereReloadHostsFile, (), ()) AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::socket::resolver, IResolver, AMS_DNS_MITM_INTERFACE_INFO, 0x5935F91A) @@ -44,7 +48,11 @@ namespace ams::mitm::socket::resolver { Result GetAddrInfoRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out out_errno, sf::Out out_retval, sf::Out out_size); Result GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_host_error, sf::Out out_errno); Result GetAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out out_size, sf::Out out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_host_error, sf::Out out_errno); - + Result ReportTelemetry(const sf::ClientProcessId &client_pid, const sf::InBuffer &telemetry, u32 version); + Result QueryAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &node, const sf::InAutoSelectBuffer &srv, const sf::InAutoSelectBuffer &serialized_hint, sf::Out out_query_id, u32 fd, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out out_retval, sf::Out out_errno); + Result FetchAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, u32 query_id, u32 version, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out out_size, sf::Out out_retval, sf::Out out_errno); + Result CancelQuery(const sf::ClientProcessId &client_pid, u32 query_id); + /* Extension commands. */ Result AtmosphereReloadHostsFile(); }; diff --git a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_addrinfo.cpp b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_addrinfo.cpp index efbc79a15..f1e1934a0 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_addrinfo.cpp +++ b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_addrinfo.cpp @@ -190,14 +190,20 @@ namespace ams::mitm::socket::resolver::serializer { return rc; } } else { - if (dst_size - (cur - dst) < addr_info.ai_addrlen) { + if (hos::GetVersion() >= hos::Version_23_0_0) { + /* 23.0.0 fixed this by returning an error instead. */ rc = -1; return rc; - } + } else { + if (dst_size - (cur - dst) < addr_info.ai_addrlen) { + rc = -1; + return rc; + } - /* NOTE: This is clearly a nintendo bug, see the accompanying note in FromBufferInternalImpl */ - std::memmove(cur, std::addressof(addr_info.ai_addr), addr_info.ai_addrlen); - rc = addr_info.ai_addrlen; + /* NOTE: This is clearly a nintendo bug, see the accompanying note in FromBufferInternalImpl */ + std::memmove(cur, std::addressof(addr_info.ai_addr), addr_info.ai_addrlen); + rc = addr_info.ai_addrlen; + } } cur += rc; } @@ -317,6 +323,7 @@ namespace ams::mitm::socket::resolver::serializer { } else if (IsAfInet(out.ai_family)) { out.ai_addr = static_cast *>(ams::socket::impl::Alloc(sizeof(SockAddrInType))); if (out.ai_addr == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } @@ -328,6 +335,7 @@ namespace ams::mitm::socket::resolver::serializer { } else if (IsAfInet6(out.ai_family)) { out.ai_addr = static_cast *>(ams::socket::impl::Alloc(sizeof(SockAddrIn6Type))); if (out.ai_addr == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } @@ -337,17 +345,24 @@ namespace ams::mitm::socket::resolver::serializer { return rc; } } else { - out.ai_addr = static_cast(ams::socket::impl::Alloc(out.ai_addrlen)); - if (out.ai_addr == nullptr) { + if (hos::GetVersion() >= hos::Version_23_0_0) { + /* 23.0.0 fixed this by returning an error instead. */ + ams::socket::SetLastError(ams::socket::Errno::EInval); rc = -1; return rc; - } + } else { + out.ai_addr = static_cast(ams::socket::impl::Alloc(out.ai_addrlen)); + if (out.ai_addr == nullptr) { + rc = -1; + return rc; + } - /* NOTE: This is *clearly* a nintendo bug. */ - /* They obviously intend to copy to the buffer they just allocated, but instead they copy to the addrinfo structure itself. */ - /* Probably &out.ai_addr instead of &out.ai_addr[0]? Either way, we'll implement what they do, but... */ - std::memcpy(std::addressof(out.ai_addr), cur, out.ai_addrlen); - rc = out.ai_addrlen; + /* NOTE: This is *clearly* a nintendo bug. */ + /* They obviously intend to copy to the buffer they just allocated, but instead they copy to the addrinfo structure itself. */ + /* Probably &out.ai_addr instead of &out.ai_addr[0]? Either way, we'll implement what they do, but... */ + std::memcpy(std::addressof(out.ai_addr), cur, out.ai_addrlen); + rc = out.ai_addrlen; + } } cur += rc; } @@ -368,6 +383,7 @@ namespace ams::mitm::socket::resolver::serializer { } else if (tmp_value == AddrInfoMagic) { out.ai_next = static_cast(ams::socket::impl::Alloc(sizeof(T))); if (out.ai_next == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } diff --git a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_ares.cpp b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_ares.cpp new file mode 100644 index 000000000..92adf8cab --- /dev/null +++ b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_ares.cpp @@ -0,0 +1,380 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "../dnsmitm_debug.hpp" +#include "../socket_allocator.hpp" +#include "serializer.hpp" + +namespace ams::mitm::socket::resolver::serializer { + + namespace { + + /* NOTE: This is local to the nn::socket::resolver::serializer namespace. */ + struct AddrInfoNodeCname { + struct ams::socket::ares_addrinfo_node *node; + char *ai_canonname; + }; + + constexpr inline u32 AresMagic = 0xBEEFCAFE; + + template + concept IsAresAddrInfo = std::same_as; + + template + concept IsAresAddrInfoHints = std::same_as; + + template + concept IsAresAddrInfoNode = std::same_as; + + template + concept IsAddrInfoNodeCname = std::same_as; + + template requires IsAresAddrInfoNode || IsAddrInfoNodeCname + using SockAddrInType = typename std::conditional || std::same_as, struct sockaddr_in, struct sockaddr_in>::type; + + template requires IsAresAddrInfoNode || IsAddrInfoNodeCname + using SockAddrIn6Type = typename std::conditional || std::same_as, struct sockaddr_in6, struct sockaddr_in6>::type; + + template requires IsAresAddrInfoNode || IsAddrInfoNodeCname + constexpr bool IsAfInet(const auto ai_family) { + if constexpr (std::same_as || std::same_as) { + /* NOTE: Keep this in case a nn::socket::AddrInfo equivalent is ever implemented for c-ares. */ + /* As of 23.0.0 only the ares_addrinfo struct is supported in the serializer. */ + return ai_family == AF_INET; + } else { + return ai_family == AF_INET; + } + } + + template requires IsAresAddrInfoNode || IsAddrInfoNodeCname + constexpr bool IsAfInet6(const auto ai_family) { + if constexpr (std::same_as || std::same_as) { + /* NOTE: Keep this in case a nn::socket::AddrInfo equivalent is ever implemented for c-ares. */ + /* As of 23.0.0 only the ares_addrinfo struct is supported in the serializer. */ + return ai_family == AF_INET6; + } else { + return ai_family == AF_INET6; + } + } + + template requires IsAresAddrInfoNode + size_t AddrInfoNodeSizeOf(const T *ares_addr_info_node) { + size_t rc = 6 * sizeof(u32); + + if (ares_addr_info_node->ai_addr == nullptr) { + rc += sizeof(u32); + } else if (IsAfInet(ares_addr_info_node->ai_family)) { + rc += DNSSerializer::SizeOf(*reinterpret_cast *>(ares_addr_info_node->ai_addr)); + } else if (IsAfInet6(ares_addr_info_node->ai_family)) { + rc += DNSSerializer::SizeOf(*reinterpret_cast *>(ares_addr_info_node->ai_addr)); + } else if (ares_addr_info_node->ai_addrlen == 0) { + rc += sizeof(u32); + } else { + rc += ares_addr_info_node->ai_addrlen; + } + + if (ares_addr_info_node->ai_next == nullptr) { + rc += sizeof(u32); + } + + return rc; + } + + template requires IsAresAddrInfo + size_t SizeOfImpl(const T &in) { + size_t rc = 0; + + const T *ares_addr_info = std::addressof(in); + for (const struct ams::socket::ares_addrinfo_node *ares_addr_info_node = ares_addr_info->nodes; ares_addr_info_node != nullptr; ares_addr_info_node = ares_addr_info_node->ai_next) { + rc += AddrInfoNodeSizeOf(ares_addr_info_node); + } + + return rc; + } + + template requires IsAresAddrInfoHints + size_t SizeOfImpl(const T &) { + return 5 * sizeof(u32); + } + + template requires IsAddrInfoNodeCname + ssize_t ToBufferInternalImpl(u8 * const dst, size_t dst_size, const T &addr_info_node_cname) { + ssize_t rc = -1; + u8 *cur = dst; + + { + const u32 value = AresMagic; + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(addr_info_node_cname.node->ai_flags); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(addr_info_node_cname.node->ai_family); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(addr_info_node_cname.node->ai_socktype); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(addr_info_node_cname.node->ai_protocol); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(addr_info_node_cname.node->ai_addrlen); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + if (addr_info_node_cname.node->ai_addr == nullptr || addr_info_node_cname.node->ai_addrlen == 0) { + const u32 value = 0; + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + } else if (IsAfInet(addr_info_node_cname.node->ai_family)) { + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast *>(addr_info_node_cname.node->ai_addr))) == -1) { + return rc; + } + } else if (IsAfInet6(addr_info_node_cname.node->ai_family)) { + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast *>(addr_info_node_cname.node->ai_addr))) == -1) { + return rc; + } + } else { + rc = -1; + return rc; + } + cur += rc; + } + + { + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), addr_info_node_cname.ai_canonname)) == -1) { + return rc; + } + cur += rc; + } + + if (addr_info_node_cname.node->ai_next == nullptr) { + const u32 value = 0; + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + rc = cur - dst; + return rc; + } + + template requires IsAresAddrInfo + ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) { + ssize_t rc = -1; + u8 *cur = dst; + std::memset(dst, 0, dst_size); + + const size_t required = DNSSerializer::SizeOf(in); + if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, required, __LINE__)) == -1) { + return rc; + } + + AddrInfoNodeCname addr_info_node_cname; + const T *ares_addr_info = std::addressof(in); + if (ares_addr_info->cnames != nullptr) { + const struct ams::socket::ares_addrinfo_cname *ares_addr_info_cname; + for (ares_addr_info_cname = ares_addr_info->cnames; ares_addr_info_cname->next != nullptr; ares_addr_info_cname = ares_addr_info_cname->next) { + /* Do nothing. */ + } + addr_info_node_cname.ai_canonname = ares_addr_info_cname->name; + } else { + addr_info_node_cname.ai_canonname = ares_addr_info->name; + } + + for (struct ams::socket::ares_addrinfo_node *ares_addr_info_node = ares_addr_info->nodes; ares_addr_info_node != nullptr; ares_addr_info_node = ares_addr_info_node->ai_next) { + addr_info_node_cname.node = ares_addr_info_node; + if ((rc = ToBufferInternalImpl(cur, dst_size, addr_info_node_cname)) == -1) { + return rc; + } + + addr_info_node_cname.ai_canonname = nullptr; + cur += rc; + } + + rc = cur - dst; + return rc; + } + + template requires IsAresAddrInfoHints + ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) { + ssize_t rc = -1; + u8 *cur = dst; + + const size_t required = DNSSerializer::SizeOf(in); + if (dst_size < required) { + return rc; + } + + { + const u32 value = AresMagic; + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(in.ai_flags); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(in.ai_family); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(in.ai_socktype); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + { + const u32 value = static_cast(in.ai_protocol); + if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) { + return rc; + } + cur += rc; + } + + return rc; + } + + template requires IsAresAddrInfoHints + ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) { + ssize_t rc = 0; + const u8 *cur = src; + + const size_t required = DNSSerializer::SizeOf(out); + if (src_size < required) { + ams::socket::SetLastError(ams::socket::Errno::ENoSpc); + rc = -1; + return rc; + } + + std::memset(std::addressof(out), 0, sizeof(out)); + + u32 tmp_value; + + { + if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) { + return rc; + } else if (tmp_value != AresMagic) { + return rc; + } + cur += rc; + } + + { + if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) { + return rc; + } + out.ai_flags = static_cast(tmp_value); + cur += rc; + } + + { + if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) { + return rc; + } + out.ai_family = static_cast(tmp_value); + cur += rc; + } + + { + if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) { + return rc; + } + out.ai_socktype = static_cast(tmp_value); + cur += rc; + } + + { + if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) { + return rc; + } + out.ai_protocol = static_cast(tmp_value); + cur += rc; + } + + rc = cur - src; + return rc; + } + + } + + template<> size_t DNSSerializer::SizeOf(const struct ams::socket::ares_addrinfo &in) { + return SizeOfImpl(in); + } + + template<> size_t DNSSerializer::SizeOf(const struct ams::socket::ares_addrinfo_hints &in) { + return SizeOfImpl(in); + } + + /* NOTE: DNSSerializer::FromBuffer doesn't exist for ares_addrinfo, only DNSSerializer::ToBuffer does. */ + /* Official software pairs it with the old addrinfo DNSSerializer::FromBuffer instead. */ + template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct ams::socket::ares_addrinfo &in) { + return ToBufferImpl(dst, dst_size, in); + } + + template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct ams::socket::ares_addrinfo_hints &in) { + return ToBufferImpl(dst, dst_size, in); + } + + template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::ares_addrinfo_hints &out, const u8 *src, size_t src_size) { + return FromBufferImpl(out, src, src_size); + } +} diff --git a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_hostent.cpp b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_hostent.cpp index e62d87d12..55c0dbfb4 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_hostent.cpp +++ b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_hostent.cpp @@ -55,8 +55,9 @@ namespace ams::mitm::socket::resolver::serializer { rc += DNSSerializer::SizeOf((const char **)(in.h_aliases), dummy); rc += sizeof(u32); rc += sizeof(u32); - rc += DNSSerializer::SizeOf((const InAddrType **)(in.h_addr_list), dummy); - + if (IsAfInet(in.h_addrtype)) { + rc += DNSSerializer::SizeOf((const InAddrType **)(in.h_addr_list), dummy); + } return rc; } @@ -150,7 +151,16 @@ namespace ams::mitm::socket::resolver::serializer { cur += rc; InAddrType **addrs = nullptr; - if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) { + if (IsAfInet(out.h_addrtype)) { + if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) { + return rc; + } + } else if (IsAfInet6(out.h_addrtype)) { + if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) { + return rc; + } + } else { + rc = -1; return rc; } out.h_addr_list = (char **)addrs; diff --git a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_in_addr.cpp b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_in_addr.cpp index 564b67f31..765d7a84f 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_in_addr.cpp +++ b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_in_addr.cpp @@ -159,6 +159,7 @@ namespace ams::mitm::socket::resolver::serializer { out = static_cast(ams::socket::impl::Alloc((count + 1) * sizeof(T *))); if (out == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } @@ -167,6 +168,7 @@ namespace ams::mitm::socket::resolver::serializer { for (u32 i = 0; i < count; ++i) { out[i] = static_cast(ams::socket::impl::Alloc(sizeof(T))); if (out[i] == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } diff --git a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_sockaddrin_6.cpp b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_sockaddrin_6.cpp index d5271037b..dc4d0126a 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_sockaddrin_6.cpp +++ b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_sockaddrin_6.cpp @@ -31,7 +31,7 @@ namespace ams::mitm::socket::resolver::serializer { rc += sizeof(u16); rc += sizeof(u16); rc += sizeof(u32); - rc += DNSSerializer::SizeOf(in.sin6_addr); + rc += sizeof(in.sin6_addr); /* NOTE: There is no DNSSerializer::SizeOf for in6_addr. */ rc += sizeof(u32); return rc; } diff --git a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_string.cpp b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_string.cpp index 33ff98991..ae97f2423 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_string.cpp +++ b/stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_string.cpp @@ -76,6 +76,7 @@ namespace ams::mitm::socket::resolver::serializer { out = static_cast(ams::socket::impl::Alloc(len)); if (out == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); return -1; } @@ -152,6 +153,7 @@ namespace ams::mitm::socket::resolver::serializer { out = static_cast(ams::socket::impl::Alloc((count + 1) * sizeof(char *))); if (out == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } @@ -162,6 +164,7 @@ namespace ams::mitm::socket::resolver::serializer { const size_t len = std::strlen(reinterpret_cast(cur)); out[i] = static_cast(ams::socket::impl::Alloc(len + 1)); if (out[i] == nullptr) { + ams::socket::SetLastError(ams::socket::Errno::ENoMem); rc = -1; return rc; } diff --git a/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c b/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c index cfd3d6107..01c6a9cd1 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c +++ b/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c @@ -95,3 +95,106 @@ Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, cons return rc; } +Result sfdnsresReportTelemetryFwd(Service *s, u64 process_id, const void *telemetry, size_t telemetry_size, u32 version) { + const struct { + u32 version; + u32 padding; + u64 process_id; + } in = { version, 0, process_id }; + + return serviceMitmDispatchIn(s, 16, in, + .buffer_attrs = { + SfBufferAttr_HipcAutoSelect | SfBufferAttr_In + }, + .buffers = { + { telemetry, telemetry_size } + }, + .in_send_pid = true, + .override_pid = process_id, + ); +} + +Result sfdnsresQueryAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, u32 *out_query_id, u32 fd, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_rv, s32 *out_errno) { + const struct { + u32 fd; + u32 options_version; + u32 num_options; + u32 padding; + u64 process_id; + } in = { fd, options_version, num_options, 0, process_id }; + struct { + u32 query_id; + s32 rv; + s32 errno; + } out; + + Result rc = serviceMitmDispatchInOut(s, 100, in, out, + .buffer_attrs = { + SfBufferAttr_HipcAutoSelect | SfBufferAttr_In, + SfBufferAttr_HipcAutoSelect | SfBufferAttr_In, + SfBufferAttr_HipcAutoSelect | SfBufferAttr_In, + SfBufferAttr_HipcAutoSelect | SfBufferAttr_In + }, + .buffers = { + { node, node_size }, + { srv, srv_size }, + { hint, hint_size }, + { option, option_size } + }, + .in_send_pid = true, + .override_pid = process_id, + ); + + if (R_SUCCEEDED(rc)) { + if (out_query_id) *out_query_id = out.query_id; + if (out_rv) *out_rv = out.rv; + if (out_errno) *out_errno = out.errno; + } + + return rc; +} + +Result sfdnsresFetchAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, u32 query_id, u32 version, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, s32 *out_errno) { + const struct { + u32 query_id; + u32 version; + u64 process_id; + } in = { query_id, version, process_id }; + struct { + u32 size; + s32 rv; + s32 errno; + } out; + + Result rc = serviceMitmDispatchInOut(s, 102, in, out, + .buffer_attrs = { + SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out + }, + .buffers = { + { out_ai, out_ai_size } + }, + .in_send_pid = true, + .override_pid = process_id, + ); + + if (R_SUCCEEDED(rc)) { + if (out_size) *out_size = out.size; + if (out_rv) *out_rv = out.rv; + if (out_errno) *out_errno = out.errno; + } + + return rc; +} + +Result sfdnsresCancelQueryFwd(Service *s, u64 process_id, u32 query_id) { + const struct { + u32 query_id; + u32 padding; + u64 process_id; + } in = { query_id, 0, process_id }; + + return serviceMitmDispatchIn(s, 104, in, + .in_send_pid = true, + .override_pid = process_id, + ); +} \ No newline at end of file diff --git a/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h b/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h index 07f3fa94e..ae3878373 100644 --- a/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h +++ b/stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h @@ -16,6 +16,14 @@ Result sfdnsresGetHostByNameRequestWithOptionsFwd(Service *s, u64 process_id, co Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno); +Result sfdnsresReportTelemetryFwd(Service *s, u64 process_id, const void *telemetry, size_t telemetry_size, u32 version); + +Result sfdnsresQueryAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, u32 *out_query_id, u32 fd, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_rv, s32 *out_errno); + +Result sfdnsresFetchAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, u32 query_id, u32 version, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, s32 *out_errno); + +Result sfdnsresCancelQueryFwd(Service *s, u64 process_id, u32 query_id); + #ifdef __cplusplus } #endif \ No newline at end of file From 36cc9a9f490da37dd1d5f958ee9a256be132cc1d Mon Sep 17 00:00:00 2001 From: fl0be <73857764+fl0be@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:02:20 +0200 Subject: [PATCH 3/4] set state Initialized/Created for Shared/Transfer mem type (#2873) --- libraries/libstratosphere/source/os/os_shared_memory.cpp | 3 +++ libraries/libstratosphere/source/os/os_transfer_memory.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/libraries/libstratosphere/source/os/os_shared_memory.cpp b/libraries/libstratosphere/source/os/os_shared_memory.cpp index e16ecb0b8..491470c71 100644 --- a/libraries/libstratosphere/source/os/os_shared_memory.cpp +++ b/libraries/libstratosphere/source/os/os_shared_memory.cpp @@ -33,6 +33,9 @@ namespace ams::os { /* Create the critical section. */ util::ConstructAt(shared_memory->cs_shared_memory); + + /* Set state to initialized. */ + shared_memory->state = SharedMemoryType::State_Initialized; } } diff --git a/libraries/libstratosphere/source/os/os_transfer_memory.cpp b/libraries/libstratosphere/source/os/os_transfer_memory.cpp index 3051d45f5..d0f172e3f 100644 --- a/libraries/libstratosphere/source/os/os_transfer_memory.cpp +++ b/libraries/libstratosphere/source/os/os_transfer_memory.cpp @@ -33,6 +33,9 @@ namespace ams::os { /* Create the critical section. */ util::ConstructAt(tmem->cs_transfer_memory); + + /* Set state to created. */ + tmem->state = TransferMemoryType::State_Created; } } From 0e9cd964c094946df14926b6c81a631b603a30f0 Mon Sep 17 00:00:00 2001 From: hexkyz Date: Fri, 9 Oct 2026 20:09:52 +0100 Subject: [PATCH 4/4] fs.mitm: mitm StorageForBatchRead as well as previously missing FileSystem/DataStorage commands --- .../fs/common/fs_file_storage.hpp | 8 +- .../fs/fs_istorage_for_batch_read.hpp | 96 +++++++++++ .../stratosphere/fs/fs_remote_storage.hpp | 62 +++++-- .../fs_storage_service_object_adapter.hpp | 80 +++++++-- .../fssrv_storage_interface_adapter.hpp | 53 ++++++ .../sf/fssrv_sf_istorage_for_batch_read.hpp | 31 ++++ .../source/fs/common/fs_file_storage.cpp | 22 +-- .../fssrv/fssrv_storage_interface_adapter.cpp | 14 +- .../source/fs_mitm/fs_mitm_service.cpp | 152 +++++++++++++++--- .../source/fs_mitm/fs_mitm_service.hpp | 38 +++-- .../ams_mitm/source/fs_mitm/fs_shim.c | 133 +++++++++++---- .../ams_mitm/source/fs_mitm/fs_shim.h | 26 +-- .../fs_mitm/fsmitm_layered_romfs_storage.cpp | 126 +++++++++++++-- .../fs_mitm/fsmitm_layered_romfs_storage.hpp | 4 +- .../ams_mitm/source/fs_mitm/fsmitm_romfs.cpp | 9 +- .../ams_mitm/source/fs_mitm/fsmitm_romfs.hpp | 2 +- 16 files changed, 717 insertions(+), 139 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_istorage_for_batch_read.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_istorage_for_batch_read.hpp diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp index d42d30b9a..2c9a95c90 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp @@ -70,11 +70,11 @@ namespace ams::fs { virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result Flush() override; - virtual Result GetSize(s64 *out_size) override; virtual Result SetSize(s64 size) override; + virtual Result GetSize(s64 *out_size) override; virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; - + /* ACCURATE_TO_VERSION: Unknown */ class FileStorageBasedFileSystem : public FileStorage { NON_COPYABLE(FileStorageBasedFileSystem); @@ -86,7 +86,7 @@ namespace ams::fs { Result Initialize(std::shared_ptr base_file_system, const fs::Path &path, fs::OpenMode mode); }; - + class FileHandleStorage : public IStorage, public impl::Newable { private: static constexpr s64 InvalidSize = -1; @@ -114,5 +114,5 @@ namespace ams::fs { virtual Result SetSize(s64 size) override; virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; - + } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage_for_batch_read.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage_for_batch_read.hpp new file mode 100644 index 000000000..0ea004b93 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage_for_batch_read.hpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::fs { + + class IStorageForBatchRead : public IStorage { + public: + virtual ~IStorageForBatchRead() { /* ... */ } + + virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) = 0; + }; + + class ReadOnlyStorageAdapterForBatchRead : public IStorageForBatchRead { + private: + std::shared_ptr m_shared_storage; + std::unique_ptr m_unique_storage; + IStorageForBatchRead *m_storage; + public: + explicit ReadOnlyStorageAdapterForBatchRead(IStorageForBatchRead *s) : m_unique_storage(s) { + m_storage = m_unique_storage.get(); + } + explicit ReadOnlyStorageAdapterForBatchRead(std::shared_ptr s) : m_shared_storage(s) { + m_storage = m_shared_storage.get(); + } + explicit ReadOnlyStorageAdapterForBatchRead(std::unique_ptr s) : m_unique_storage(std::move(s)) { + m_storage = m_unique_storage.get(); + } + explicit ReadOnlyStorageAdapterForBatchRead(IStorage *s) : m_unique_storage(static_cast(s)) { + m_storage = m_unique_storage.get(); + } + explicit ReadOnlyStorageAdapterForBatchRead(std::shared_ptr s) : m_shared_storage(std::static_pointer_cast(s)) { + m_storage = m_shared_storage.get(); + } + explicit ReadOnlyStorageAdapterForBatchRead(std::unique_ptr s) : m_unique_storage(std::unique_ptr(static_cast(s.release()))) { + m_storage = m_unique_storage.get(); + } + + virtual ~ReadOnlyStorageAdapterForBatchRead() { /* ... */ } + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override { + R_RETURN(m_storage->Read(offset, buffer, size)); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + /* TODO: Better result? Is it possible to get a more specific one? */ + AMS_UNUSED(offset, buffer, size); + R_THROW(fs::ResultUnsupportedOperation()); + } + + virtual Result Flush() override { + R_RETURN(m_storage->Flush()); + } + + virtual Result SetSize(s64 size) override { + /* TODO: Better result? Is it possible to get a more specific one? */ + AMS_UNUSED(size); + R_THROW(fs::ResultUnsupportedOperation()); + } + + virtual Result GetSize(s64 *out) override { + R_RETURN(m_storage->GetSize(out)); + } + + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + R_RETURN(m_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); + } + + virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override { + /* TODO */ + AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in); + R_THROW(fs::ResultUnsupportedOperation()); + } + }; + + template + concept PointerToStorageForBatchRead = ::ams::util::RawOrSmartPointerTo; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp index 170281161..60977e944 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include #include namespace ams::fs { @@ -33,29 +34,72 @@ namespace ams::fs { public: virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(fsStorageRead(std::addressof(m_base_storage), offset, buffer, size)); - }; + } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_RETURN(fsStorageWrite(std::addressof(m_base_storage), offset, buffer, size)); - }; + } virtual Result Flush() override { R_RETURN(fsStorageFlush(std::addressof(m_base_storage))); - }; + } + + virtual Result SetSize(s64 size) override { + R_RETURN(fsStorageSetSize(std::addressof(m_base_storage), size)); + } virtual Result GetSize(s64 *out_size) override { R_RETURN(fsStorageGetSize(std::addressof(m_base_storage), out_size)); - }; - - virtual Result SetSize(s64 size) override { - R_RETURN(fsStorageSetSize(std::addressof(m_base_storage), size)); - }; + } virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { /* TODO: How to deal with this? */ AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size); R_THROW(fs::ResultUnsupportedOperation()); - }; + } + }; + + class RemoteStorageForBatchRead : public IStorageForBatchRead, public impl::Newable { + NON_COPYABLE(RemoteStorageForBatchRead); + NON_MOVEABLE(RemoteStorageForBatchRead); + private: + ::FsStorageForBatchRead m_base_storage; + public: + RemoteStorageForBatchRead(::FsStorageForBatchRead &s) : m_base_storage(s) { /* ... */} + + virtual ~RemoteStorageForBatchRead() { fsStorageForBatchReadClose(std::addressof(m_base_storage)); } + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override { + R_RETURN(fsStorageForBatchReadRead(std::addressof(m_base_storage), offset, buffer, size)); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + R_RETURN(fsStorageForBatchReadWrite(std::addressof(m_base_storage), offset, buffer, size)); + } + + virtual Result Flush() override { + R_RETURN(fsStorageForBatchReadFlush(std::addressof(m_base_storage))); + } + + virtual Result SetSize(s64 size) override { + R_RETURN(fsStorageForBatchReadSetSize(std::addressof(m_base_storage), size)); + } + + virtual Result GetSize(s64 *out_size) override { + R_RETURN(fsStorageForBatchReadGetSize(std::addressof(m_base_storage), out_size)); + } + + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + /* TODO: How to deal with this? */ + AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size); + R_THROW(fs::ResultUnsupportedOperation()); + } + + virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override { + /* TODO */ + AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in); + R_THROW(fs::ResultUnsupportedOperation()); + } }; #endif diff --git a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_storage_service_object_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_storage_service_object_adapter.hpp index 66d95124a..3c5d847ac 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_storage_service_object_adapter.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_storage_service_object_adapter.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include #include namespace ams::fs::impl { @@ -33,22 +34,22 @@ namespace ams::fs::impl { virtual Result Read(s64 offset, void *buffer, size_t size) override final { R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast(size))); } - - virtual Result GetSize(s64 *out) override final { - R_RETURN(m_x->GetSize(out)); - } - - virtual Result Flush() override final { - R_RETURN(m_x->Flush()); - } - + virtual Result Write(s64 offset, const void *buffer, size_t size) override final { R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast(size))); } - + + virtual Result Flush() override final { + R_RETURN(m_x->Flush()); + } + virtual Result SetSize(s64 size) override final { R_RETURN(m_x->SetSize(size)); } + + virtual Result GetSize(s64 *out) override final { + R_RETURN(m_x->GetSize(out)); + } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { AMS_UNUSED(src, src_size); @@ -72,5 +73,64 @@ namespace ams::fs::impl { } } }; + + template + class StorageServiceObjectAdapterForBatchRead : public ::ams::fs::impl::Newable, public ::ams::fs::IStorageForBatchRead { + NON_COPYABLE(StorageServiceObjectAdapterForBatchRead); + NON_MOVEABLE(StorageServiceObjectAdapterForBatchRead); + private: + sf::SharedPointer m_x; + public: + explicit StorageServiceObjectAdapterForBatchRead(sf::SharedPointer &&o) : m_x(o) { /* ... */} + virtual ~StorageServiceObjectAdapterForBatchRead() { /* ... */ } + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override final { + R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast(size))); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override final { + R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast(size))); + } + + virtual Result Flush() override final { + R_RETURN(m_x->Flush()); + } + + virtual Result SetSize(s64 size) override final { + R_RETURN(m_x->SetSize(size)); + } + + virtual Result GetSize(s64 *out) override final { + R_RETURN(m_x->GetSize(out)); + } + + virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { + AMS_UNUSED(src, src_size); + switch (op_id) { + case OperationId::Invalidate: + { + fs::QueryRangeInfo dummy_range_info; + R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast(op_id), offset, size)); + } + case OperationId::QueryRange: + { + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); + + R_RETURN(m_x->OperateRange(reinterpret_cast(dst), static_cast(op_id), offset, size)); + } + default: + { + R_THROW(fs::ResultUnsupportedOperateRangeForStorageServiceObjectAdapter()); + } + } + } + + virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override final { + /* TODO */ + AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in); + R_THROW(fs::ResultUnsupportedOperation()); + } + }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp index 1c08fb513..e397fb26f 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp @@ -18,10 +18,12 @@ #include #include #include +#include namespace ams::fs { class IStorage; + class IStorageForBatchRead; } @@ -44,6 +46,16 @@ namespace ams::fssrv::impl { Result OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size); }; static_assert(fssrv::sf::IsIStorage); + + class StorageInterfaceAdapterForBatchRead : public StorageInterfaceAdapter { + NON_COPYABLE(StorageInterfaceAdapterForBatchRead); + public: + explicit StorageInterfaceAdapterForBatchRead(std::shared_ptr &&storage) : StorageInterfaceAdapter(storage) { /* ... */ } + public: + /* Command API. */ + Result BatchRead(const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in); + }; + static_assert(fssrv::sf::IsIStorageForBatchRead); #if defined(ATMOSPHERE_OS_HORIZON) class RemoteStorage { @@ -82,6 +94,47 @@ namespace ams::fssrv::impl { } }; static_assert(fssrv::sf::IsIStorage); + + class RemoteStorageForBatchRead { + NON_COPYABLE(RemoteStorageForBatchRead); + NON_MOVEABLE(RemoteStorageForBatchRead); + private: + ::FsStorageForBatchRead m_base_storage; + public: + RemoteStorageForBatchRead(::FsStorageForBatchRead &s) : m_base_storage(s) { /* ... */} + + virtual ~RemoteStorageForBatchRead() { fsStorageForBatchReadClose(std::addressof(m_base_storage)); } + public: + Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size) { + R_RETURN(fsStorageForBatchReadRead(std::addressof(m_base_storage), offset, buffer.GetPointer(), size)); + } + + Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { + R_RETURN(fsStorageForBatchReadWrite(std::addressof(m_base_storage), offset, buffer.GetPointer(), size)); + } + + Result Flush(){ + R_RETURN(fsStorageForBatchReadFlush(std::addressof(m_base_storage))); + } + + Result SetSize(s64 size) { + R_RETURN(fsStorageForBatchReadSetSize(std::addressof(m_base_storage), size)); + } + + Result GetSize(ams::sf::Out out) { + R_RETURN(fsStorageForBatchReadGetSize(std::addressof(m_base_storage), out.GetPointer())); + } + + Result OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size) { + static_assert(sizeof(::FsRangeInfo) == sizeof(fs::StorageQueryRangeInfo)); + R_RETURN(fsStorageForBatchReadOperateRange(std::addressof(m_base_storage), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(out.GetPointer()))); + } + + Result BatchRead(const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in) { + R_RETURN(fsStorageForBatchReadBatchRead(std::addressof(m_base_storage), out0.GetPointer(), out1.GetPointer(), out2.GetPointer(), out3.GetPointer(), out4.GetPointer(), out5.GetPointer(), out6.GetPointer(), in.GetPointer())); + } + }; + static_assert(fssrv::sf::IsIStorageForBatchRead); #endif } diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_istorage_for_batch_read.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_istorage_for_batch_read.hpp new file mode 100644 index 000000000..1ce5ea885 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_istorage_for_batch_read.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include + +#define AMS_FSSRV_I_STORAGE_FOR_BATCH_READ_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, Read, (s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size), (offset, buffer, size)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, Write, (s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size), (offset, buffer, size)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, Flush, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, SetSize, (s64 size), (size)) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, GetSize, (ams::sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, OperateRange, (ams::sf::Out out, s32 op_id, s64 offset, s64 size), (out, op_id, offset, size)) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, BatchRead, (const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in), (out0, out1, out2, out3, out4, out5, out6, in)) + +AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IStorageForBatchRead, AMS_FSSRV_I_STORAGE_FOR_BATCH_READ_INTERFACE_INFO, 0xCD2D5606) diff --git a/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp index 816bd0a1a..431125b0b 100644 --- a/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp +++ b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp @@ -58,6 +58,11 @@ namespace ams::fs { Result FileStorage::Flush() { R_RETURN(m_base_file->Flush()); } + + Result FileStorage::SetSize(s64 size) { + m_size = InvalidSize; + R_RETURN(m_base_file->SetSize(size)); + } Result FileStorage::GetSize(s64 *out_size) { R_TRY(this->UpdateSize()); @@ -65,11 +70,6 @@ namespace ams::fs { R_SUCCEED(); } - Result FileStorage::SetSize(s64 size) { - m_size = InvalidSize; - R_RETURN(m_base_file->SetSize(size)); - } - Result FileStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { switch (op_id) { case OperationId::Invalidate: @@ -102,7 +102,7 @@ namespace ams::fs { R_SUCCEED(); } - + Result FileHandleStorage::UpdateSize() { R_SUCCEED_IF(m_size != InvalidSize); R_RETURN(GetFileSize(std::addressof(m_size), m_handle)); @@ -149,6 +149,11 @@ namespace ams::fs { Result FileHandleStorage::Flush() { R_RETURN(FlushFile(m_handle)); } + + Result FileHandleStorage::SetSize(s64 size) { + m_size = InvalidSize; + R_RETURN(SetFileSize(m_handle, size)); + } Result FileHandleStorage::GetSize(s64 *out_size) { R_TRY(this->UpdateSize()); @@ -156,11 +161,6 @@ namespace ams::fs { R_SUCCEED(); } - Result FileHandleStorage::SetSize(s64 size) { - m_size = InvalidSize; - R_RETURN(SetFileSize(m_handle, size)); - } - Result FileHandleStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { AMS_UNUSED(src, src_size); diff --git a/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp b/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp index b466d2be3..93fa37bd2 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp @@ -30,7 +30,7 @@ namespace ams::fssrv::impl { })); } - Result StorageInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { + Result StorageInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { /* Check pre-conditions. */ R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); R_UNLESS(0 <= size, fs::ResultInvalidSize()); @@ -42,16 +42,16 @@ namespace ams::fssrv::impl { R_RETURN(m_base_storage->Write(offset, buffer.GetPointer(), size)); } - Result StorageInterfaceAdapter::Flush() { + Result StorageInterfaceAdapter::Flush() { R_RETURN(m_base_storage->Flush()); } - Result StorageInterfaceAdapter::SetSize(s64 size) { + Result StorageInterfaceAdapter::SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_RETURN(m_base_storage->SetSize(size)); } - Result StorageInterfaceAdapter::GetSize(ams::sf::Out out) { + Result StorageInterfaceAdapter::GetSize(ams::sf::Out out) { R_RETURN(m_base_storage->GetSize(out.GetPointer())); } @@ -72,5 +72,11 @@ namespace ams::fssrv::impl { R_SUCCEED(); } + + Result StorageInterfaceAdapterForBatchRead::BatchRead(const ams::sf::OutNonSecureBuffer &out0, const ams::sf::OutNonSecureBuffer &out1, const ams::sf::OutNonSecureBuffer &out2, const ams::sf::OutNonSecureBuffer &out3, const ams::sf::OutNonSecureBuffer &out4, const ams::sf::OutNonSecureBuffer &out5, const ams::sf::OutNonSecureBuffer &out6, const ams::sf::InBuffer &in) { + /* TODO */ + AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in); + R_THROW(fs::ResultUnsupportedOperation()); + } } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp index adaad71e2..9902fc8ff 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp @@ -67,6 +67,11 @@ namespace ams::mitm::fs { constexpr ALWAYS_INLINE auto MakeSharedStorage(Arguments &&... args) { return sf::CreateSharedObjectEmplaced(std::forward(args)...); } + + template + constexpr ALWAYS_INLINE auto MakeSharedStorageForBatchRead(Arguments &&... args) { + return sf::CreateSharedObjectEmplaced(std::forward(args)...); + } Result OpenHblWebContentFileSystem(sf::Out> &out, ncm::ProgramId program_id) { /* Verify eligibility. */ @@ -94,7 +99,7 @@ namespace ams::mitm::fs { R_SUCCEED(); } - Result OpenProgramSpecificWebContentFileSystem(sf::Out> &out, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id) { + Result OpenProgramSpecificWebContentFileSystem(sf::Out> &out, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool with_attributes) { /* Directory must exist. */ R_UNLESS(HasSdManualHtmlContent(program_id), sm::mitm::ResultShouldForwardToSession()); @@ -121,8 +126,10 @@ namespace ams::mitm::fs { /* Try to open the existing fs. */ FsFileSystem base_fs; bool opened_base_fs = false; - if (with_id) { - opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdFwd(fwd, std::addressof(base_fs), static_cast(program_id), filesystem_type, path->str)); + if (with_attributes) { + opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdFwd(fwd, std::addressof(base_fs), path->str, FsContentAttributes_None, static_cast(program_id), filesystem_type)); + } else if (with_id) { + opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdObsoleteFwd(fwd, std::addressof(base_fs), path->str, static_cast(program_id), filesystem_type)); } else { opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithPatchFwd(fwd, std::addressof(base_fs), static_cast(program_id), filesystem_type)); } @@ -141,7 +148,7 @@ namespace ams::mitm::fs { R_SUCCEED(); } - Result OpenWebContentFileSystem(sf::Out> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool try_program_specific) { + Result OpenWebContentFileSystem(sf::Out> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool with_attributes, bool try_program_specific) { /* Check first that we're a web applet opening web content. */ R_UNLESS(ncm::IsWebAppletId(client_program_id), sm::mitm::ResultShouldForwardToSession()); R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession()); @@ -153,7 +160,7 @@ namespace ams::mitm::fs { R_UNLESS(try_program_specific, sm::mitm::ResultShouldForwardToSession()); /* If we're not opening a HBL filesystem, just try to open a generic one. */ - R_RETURN(OpenProgramSpecificWebContentFileSystem(out, program_id, filesystem_type, fwd, path, with_id)); + R_RETURN(OpenProgramSpecificWebContentFileSystem(out, program_id, filesystem_type, fwd, path, with_id, with_attributes)); } } @@ -169,12 +176,17 @@ namespace ams::mitm::fs { } } - Result FsMitmService::OpenFileSystemWithPatch(sf::Out> out, ncm::ProgramId program_id, u32 _filesystem_type) { - R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast(_filesystem_type), m_forward_service.get(), nullptr, false, m_client_info.override_status.IsProgramSpecific())); + Result FsMitmService::OpenFileSystemWithPatch(sf::Out> out, ncm::ProgramId program_id, u32 file_system_proxy_type) { + R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast(file_system_proxy_type), m_forward_service.get(), nullptr, false, false, m_client_info.override_status.IsProgramSpecific())); } - Result FsMitmService::OpenFileSystemWithId(sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type) { - R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast(_filesystem_type), m_forward_service.get(), std::addressof(path), true, m_client_info.override_status.IsProgramSpecific())); + Result FsMitmService::OpenFileSystemWithIdObsolete(sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 file_system_proxy_type) { + R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast(file_system_proxy_type), m_forward_service.get(), std::addressof(path), true, false, m_client_info.override_status.IsProgramSpecific())); + } + + Result FsMitmService::OpenFileSystemWithId(sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, ncm::ProgramId program_id, u32 file_system_proxy_type) { + AMS_UNUSED(content_attributes); + R_RETURN(OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast(file_system_proxy_type), m_forward_service.get(), std::addressof(path), true, true, m_client_info.override_status.IsProgramSpecific())); } Result FsMitmService::OpenSdCardFileSystem(sf::Out> out) { @@ -195,7 +207,7 @@ namespace ams::mitm::fs { R_SUCCEED(); } - Result FsMitmService::OpenSaveDataFileSystem(sf::Out> out, u8 _space_id, const fs::SaveDataAttribute &attribute) { + Result FsMitmService::OpenSaveDataFileSystem(sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { /* We only want to intercept saves for games, right now. */ const bool is_game_or_hbl = m_client_info.override_status.IsHbl() || ncm::IsApplicationId(m_client_info.program_id); R_UNLESS(is_game_or_hbl, sm::mitm::ResultShouldForwardToSession()); @@ -210,12 +222,12 @@ namespace ams::mitm::fs { R_UNLESS(attribute.type == fs::SaveDataType::Account, sm::mitm::ResultShouldForwardToSession()); /* Get enum type for space id. */ - auto space_id = static_cast(_space_id); + auto _space_id = static_cast(space_id); /* Verify we can open the save. */ static_assert(sizeof(fs::SaveDataAttribute) == sizeof(::FsSaveDataAttribute)); FsFileSystem save_fs; - R_UNLESS(R_SUCCEEDED(fsOpenSaveDataFileSystemFwd(m_forward_service.get(), std::addressof(save_fs), space_id, reinterpret_cast(std::addressof(attribute)))), sm::mitm::ResultShouldForwardToSession()); + R_UNLESS(R_SUCCEEDED(fsOpenSaveDataFileSystemFwd(m_forward_service.get(), std::addressof(save_fs), _space_id, reinterpret_cast(std::addressof(attribute)))), sm::mitm::ResultShouldForwardToSession()); std::unique_ptr save_ifs = std::make_unique(save_fs); /* Mount the SD card using fs.mitm's session. */ @@ -228,7 +240,7 @@ namespace ams::mitm::fs { const ncm::ProgramId application_id = attribute.program_id == ncm::InvalidProgramId ? m_client_info.program_id : attribute.program_id; char save_dir_raw_path[0x100]; - R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_raw_path, sizeof(save_dir_raw_path), application_id, space_id, attribute)); + R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_raw_path, sizeof(save_dir_raw_path), application_id, _space_id, attribute)); ams::fs::Path save_dir_path; R_TRY(save_dir_path.SetShallowBuffer(save_dir_raw_path)); @@ -270,12 +282,12 @@ namespace ams::mitm::fs { R_SUCCEED(); } - Result FsMitmService::OpenBisStorage(sf::Out> out, u32 _bis_partition_id) { - const ::FsBisPartitionId bis_partition_id = static_cast<::FsBisPartitionId>(_bis_partition_id); + Result FsMitmService::OpenBisStorage(sf::Out> out, u32 bis_partition_id) { + const ::FsBisPartitionId _bis_partition_id = static_cast<::FsBisPartitionId>(bis_partition_id); /* Try to open a storage for the partition. */ FsStorage bis_storage; - R_TRY(fsOpenBisStorageFwd(m_forward_service.get(), std::addressof(bis_storage), bis_partition_id)); + R_TRY(fsOpenBisStorageFwd(m_forward_service.get(), std::addressof(bis_storage), _bis_partition_id)); const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(bis_storage.s))}; const bool is_sysmodule = ncm::IsSystemProgramId(m_client_info.program_id); @@ -285,18 +297,18 @@ namespace ams::mitm::fs { /* Allow HBL to write to boot1 (safe firm) + package2. */ /* This is needed to not break compatibility with ChoiDujourNX, which does not check for write access before beginning an update. */ /* TODO: get fixed so that this can be turned off without causing bricks :/ */ - const bool is_package2 = (FsBisPartitionId_BootConfigAndPackage2Part1 <= bis_partition_id && bis_partition_id <= FsBisPartitionId_BootConfigAndPackage2Part6); - const bool is_boot1 = bis_partition_id == FsBisPartitionId_BootPartition2Root; + const bool is_package2 = (FsBisPartitionId_BootConfigAndPackage2Part1 <= _bis_partition_id && _bis_partition_id <= FsBisPartitionId_BootConfigAndPackage2Part6); + const bool is_boot1 = _bis_partition_id == FsBisPartitionId_BootPartition2Root; const bool can_write_bis_for_choi_support = is_hbl && (is_package2 || is_boot1); /* Set output storage. */ - if (bis_partition_id == FsBisPartitionId_BootPartition1Root) { + if (_bis_partition_id == FsBisPartitionId_BootPartition1Root) { if (IsBoot0CustomPublicKey(bis_storage)) { out.SetValue(MakeSharedStorage(std::make_shared(bis_storage, m_client_info, spl::GetSocType())), target_object_id); } else { out.SetValue(MakeSharedStorage(std::make_shared(bis_storage, m_client_info)), target_object_id); } - } else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) { + } else if (_bis_partition_id == FsBisPartitionId_CalibrationBinary) { out.SetValue(MakeSharedStorage(std::make_shared(bis_storage, m_client_info)), target_object_id); } else { if (can_write_bis || can_write_bis_for_choi_support) { @@ -328,24 +340,41 @@ namespace ams::mitm::fs { out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(m_client_info.program_id, data_storage, true)), target_object_id); R_SUCCEED(); } + + Result FsMitmService::OpenDataStorageByProgramId(sf::Out> out, ncm::ProgramId program_id) { + /* Only mitm if we should override contents for the current process. */ + R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); - Result FsMitmService::OpenDataStorageByDataId(sf::Out> out, ncm::DataId _data_id, u8 storage_id) { + /* Only mitm if there is actually an override romfs for the target program. */ + R_UNLESS(mitm::fs::HasSdRomfsContent(program_id), sm::mitm::ResultShouldForwardToSession()); + + /* Try to open the program romfs. */ + FsStorage data_storage; + R_TRY(fsOpenDataStorageByProgramIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast(program_id))); + const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))}; + + /* Get a layered storage for the program romfs. */ + out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_id, data_storage, true)), target_object_id); + R_SUCCEED(); + } + + Result FsMitmService::OpenDataStorageByDataId(sf::Out> out, ncm::DataId data_id, u8 storage_id) { /* Only mitm if we should override contents for the current process. */ R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); /* TODO: Decide how to handle DataId vs ProgramId for this API. */ - const ncm::ProgramId data_id = {_data_id.value}; + const ncm::ProgramId program_or_data_id = {data_id.value}; /* Only mitm if there is actually an override romfs. */ - R_UNLESS(mitm::fs::HasSdRomfsContent(data_id), sm::mitm::ResultShouldForwardToSession()); + R_UNLESS(mitm::fs::HasSdRomfsContent(program_or_data_id), sm::mitm::ResultShouldForwardToSession()); /* Try to open the data id. */ FsStorage data_storage; - R_TRY(fsOpenDataStorageByDataIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast(data_id), static_cast(storage_id))); + R_TRY(fsOpenDataStorageByDataIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast(program_or_data_id), static_cast(storage_id))); const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))}; /* Get a layered storage for the data id. */ - out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(data_id, data_storage, false)), target_object_id); + out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_or_data_id, data_storage, false)), target_object_id); R_SUCCEED(); } @@ -369,7 +398,80 @@ namespace ams::mitm::fs { out.SetValue(MakeSharedStorage(GetLayeredRomfsStorage(program_id, data_storage, true)), target_object_id); R_SUCCEED(); } + + Result FsMitmService::OpenDataStorageByPath(sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type) { + /* Only mitm if we should override contents for the current process. */ + R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); + + /* TODO */ + AMS_UNUSED(out, path, content_attributes, file_system_proxy_type); + R_SUCCEED(); + } + + Result FsMitmService::OpenDataStorageByCurrentProcessForBatchRead(sf::Out> out) { + /* Only mitm if we should override contents for the current process. */ + R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); + /* Only mitm if there is actually an override romfs. */ + R_UNLESS(mitm::fs::HasSdRomfsContent(m_client_info.program_id), sm::mitm::ResultShouldForwardToSession()); + + /* Try to open the process romfs. */ + FsStorageForBatchRead data_storage; + R_TRY(fsOpenDataStorageByCurrentProcessForBatchReadFwd(m_forward_service.get(), std::addressof(data_storage))); + const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))}; + + /* Get a layered storage for the program romfs (batch read variant). */ + out.SetValue(MakeSharedStorageForBatchRead(GetLayeredRomfsStorageForBatchRead(m_client_info.program_id, data_storage, true)), target_object_id); + R_SUCCEED(); + } + + Result FsMitmService::OpenDataStorageByProgramIdForBatchRead(sf::Out> out, ncm::ProgramId program_id) { + /* Only mitm if we should override contents for the current process. */ + R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); + + /* Only mitm if there is actually an override romfs for the target program. */ + R_UNLESS(mitm::fs::HasSdRomfsContent(program_id), sm::mitm::ResultShouldForwardToSession()); + + /* Try to open the program romfs. */ + FsStorageForBatchRead data_storage; + R_TRY(fsOpenDataStorageByProgramIdForBatchReadFwd(m_forward_service.get(), std::addressof(data_storage), static_cast(program_id))); + const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))}; + + /* Get a layered storage for the program romfs (batch read variant). */ + out.SetValue(MakeSharedStorageForBatchRead(GetLayeredRomfsStorageForBatchRead(program_id, data_storage, true)), target_object_id); + R_SUCCEED(); + } + + Result FsMitmService::OpenDataStorageWithProgramIndexForBatchRead(sf::Out> out, u8 program_index) { + /* Only mitm if we should override contents for the current process. */ + R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); + + /* Get the relevant program id. */ + const ncm::ProgramId program_id = g_program_index_map_info_manager.GetProgramId(m_client_info.program_id, program_index); + + /* If we don't know about the program or don't have content, forward. */ + R_UNLESS(program_id != ncm::InvalidProgramId, sm::mitm::ResultShouldForwardToSession()); + R_UNLESS(mitm::fs::HasSdRomfsContent(program_id), sm::mitm::ResultShouldForwardToSession()); + + /* Try to open the process romfs. */ + FsStorageForBatchRead data_storage; + R_TRY(fsOpenDataStorageWithProgramIndexForBatchReadFwd(m_forward_service.get(), std::addressof(data_storage), program_index)); + const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))}; + + /* Get a layered storage for the program romfs (batch read variant). */ + out.SetValue(MakeSharedStorageForBatchRead(GetLayeredRomfsStorageForBatchRead(program_id, data_storage, true)), target_object_id); + R_SUCCEED(); + } + + Result FsMitmService::OpenDataStorageByPathForBatchRead(sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type) { + /* Only mitm if we should override contents for the current process. */ + R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession()); + + /* TODO */ + AMS_UNUSED(out, path, content_attributes, file_system_proxy_type); + R_SUCCEED(); + } + Result FsMitmService::RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count) { /* Try to register with FS. */ R_TRY(fsRegisterProgramIndexMapInfoFwd(m_forward_service.get(), info_buffer.GetPointer(), info_buffer.GetSize(), info_count)); diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp index 71e87c102..ca7d1b3af 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp @@ -17,16 +17,23 @@ #include #include -#define AMS_FS_MITM_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (sf::Out> out, ncm::ProgramId program_id, u32 _filesystem_type), (out, program_id, _filesystem_type), hos::Version_2_0_0) \ - AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type), (out, path, program_id, _filesystem_type), hos::Version_2_0_0) \ - AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (sf::Out> out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (sf::Out> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \ - AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (sf::Out> out, u32 bis_partition_id), (out, bis_partition_id)) \ - AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (sf::Out> out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (sf::Out> out, ncm::DataId data_id, u8 storage_id), (out, data_id, storage_id)) \ - AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (sf::Out> out, u8 program_index), (out, program_index), hos::Version_7_0_0) \ - AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (const sf::InBuffer &info_buffer, s32 info_count), (info_buffer, info_count), hos::Version_7_0_0) +#define AMS_FS_MITM_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (sf::Out> out, ncm::ProgramId program_id, u32 file_system_proxy_type), (out, program_id, file_system_proxy_type), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithIdObsolete, (sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 file_system_proxy_type), (out, path, program_id, file_system_proxy_type), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, OpenFileSystemWithId, (sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, ncm::ProgramId program_id, u32 file_system_proxy_type), (out, path, content_attributes, program_id, file_system_proxy_type), hos::Version_16_0_0) \ + AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (sf::Out> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \ + AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (sf::Out> out, u32 bis_partition_id), (out, bis_partition_id)) \ + AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 201, Result, OpenDataStorageByProgramId, (sf::Out> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (sf::Out> out, ncm::DataId data_id, u8 storage_id), (out, data_id, storage_id)) \ + AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (sf::Out> out, u8 program_index), (out, program_index), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type), (out, path, content_attributes, file_system_proxy_type), hos::Version_13_0_0) \ + AMS_SF_METHOD_INFO(C, H, 210, Result, OpenDataStorageByCurrentProcessForBatchRead, (sf::Out> out), (out), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 211, Result, OpenDataStorageByProgramIdForBatchRead, (sf::Out> out, ncm::ProgramId program_id), (out, program_id), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 212, Result, OpenDataStorageWithProgramIndexForBatchRead, (sf::Out> out, u8 program_index), (out, program_index), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 213, Result, OpenDataStorageByPathForBatchRead, (sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type), (out, path, content_attributes, file_system_proxy_type), hos::Version_23_0_0) \ + AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (const sf::InBuffer &info_buffer, s32 info_count), (info_buffer, info_count), hos::Version_7_0_0) AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::fs, IFsMitmInterface, AMS_FS_MITM_INTERFACE_INFO, 0x7DF34ED2) @@ -77,14 +84,21 @@ namespace ams::mitm::fs { } public: /* Overridden commands. */ - Result OpenFileSystemWithPatch(sf::Out> out, ncm::ProgramId program_id, u32 _filesystem_type); - Result OpenFileSystemWithId(sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type); + Result OpenFileSystemWithPatch(sf::Out> out, ncm::ProgramId program_id, u32 file_system_proxy_type); + Result OpenFileSystemWithIdObsolete(sf::Out> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 file_system_proxy_type); + Result OpenFileSystemWithId(sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, ncm::ProgramId program_id, u32 file_system_proxy_type); Result OpenSdCardFileSystem(sf::Out> out); Result OpenSaveDataFileSystem(sf::Out> out, u8 space_id, const ams::fs::SaveDataAttribute &attribute); Result OpenBisStorage(sf::Out> out, u32 bis_partition_id); Result OpenDataStorageByCurrentProcess(sf::Out> out); + Result OpenDataStorageByProgramId(sf::Out> out, ncm::ProgramId program_id); Result OpenDataStorageByDataId(sf::Out> out, ncm::DataId data_id, u8 storage_id); Result OpenDataStorageWithProgramIndex(sf::Out> out, u8 program_index); + Result OpenDataStorageByPath(sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type); + Result OpenDataStorageByCurrentProcessForBatchRead(sf::Out> out); + Result OpenDataStorageByProgramIdForBatchRead(sf::Out> out, ncm::ProgramId program_id); + Result OpenDataStorageWithProgramIndexForBatchRead(sf::Out> out, u8 program_index); + Result OpenDataStorageByPathForBatchRead(sf::Out> out, const fssrv::sf::Path &path, u8 content_attributes, u32 file_system_proxy_type); Result RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count); }; static_assert(IsIFsMitmInterface); diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c index 7f44cb5d5..293c56451 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.c @@ -23,8 +23,46 @@ static Result _fsOpenSession(Service *s, Service* out, u32 cmd_id) { ); } -Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out) { - return _fsOpenSession(s, &out->s, 18); +Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType) { + const struct { + u32 fsType; + u64 id; + } in = { fsType, id }; + + return serviceDispatchIn(s, 7, in, + .out_num_objects = 1, + .out_objects = &out->s + ); +} + +Result fsOpenFileSystemWithIdObsoleteFwd(Service* s, FsFileSystem* out, const char* contentPath, u64 id, FsFileSystemType fsType) { + const struct { + u32 fsType; + u64 id; + } in = { fsType, id }; + + return serviceDispatchIn(s, 8, in, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize }, + .buffers = { { contentPath, FS_MAX_PATH } }, + .out_num_objects = 1, + .out_objects = &out->s + ); +} + +Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, const char* contentPath, FsContentAttributes attributes, u64 id, FsFileSystemType fsType) { + const struct { + u8 attributes; + u8 pad[3]; + u32 fsType; + u64 id; + } in = { attributes, {0}, fsType, id }; + + return serviceDispatchIn(s, 10, in, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize }, + .buffers = { { contentPath, FS_MAX_PATH } }, + .out_num_objects = 1, + .out_objects = &out->s + ); } Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id) { @@ -35,10 +73,34 @@ Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partitio ); } +Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out) { + return _fsOpenSession(s, &out->s, 18); +} + +Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr) { + const struct { + u8 save_data_space_id; + u8 pad[7]; + FsSaveDataAttribute attr; + } in = { (u8)save_data_space_id, {0}, *attr }; + + return serviceDispatchIn(s, 51, in, + .out_num_objects = 1, + .out_objects = &out->s, + ); +} + Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) { return _fsOpenSession(s, &out->s, 200); } +Result fsOpenDataStorageByProgramIdFwd(Service* s, FsStorage* out, u64 id) { + return serviceDispatchIn(s, 201, id, + .out_num_objects = 1, + .out_objects = &out->s, + ); +} + Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id) { const struct { u8 storage_id; @@ -58,48 +120,57 @@ Result fsOpenDataStorageWithProgramIndexFwd(Service* s, FsStorage* out, u8 progr ); } -Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count) { - return serviceDispatchIn(s, 810, count, - .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, - .buffers = { { buf, buf_size } }, +Result fsOpenDataStorageByPathFwd(Service* s, FsStorage* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType) { + const struct { + u8 attributes; + u8 pad[3]; + u32 fsType; + } in = { attributes, {0}, fsType }; + + return serviceDispatchIn(s, 206, in, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize }, + .buffers = { { contentPath, FS_MAX_PATH } }, + .out_num_objects = 1, + .out_objects = &out->s ); } -Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr) { - const struct { - u8 save_data_space_id; - u8 pad[7]; - FsSaveDataAttribute attr; - } in = { (u8)save_data_space_id, {0}, *attr }; +Result fsOpenDataStorageByCurrentProcessForBatchReadFwd(Service* s, FsStorageForBatchRead* out) { + return _fsOpenSession(s, &out->s, 210); +} - return serviceDispatchIn(s, 51, in, +Result fsOpenDataStorageByProgramIdForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u64 id) { + return serviceDispatchIn(s, 211, id, .out_num_objects = 1, .out_objects = &out->s, ); } -Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType) { - const struct { - u32 fsType; - u64 id; - } in = { fsType, id }; +Result fsOpenDataStorageWithProgramIndexForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u8 program_index) { + return serviceDispatchIn(s, 212, program_index, + .out_num_objects = 1, + .out_objects = &out->s, + ); +} - return serviceDispatchIn(s, 7, in, +Result fsOpenDataStorageByPathForBatchReadFwd(Service* s, FsStorageForBatchRead* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType) { + const struct { + u8 attributes; + u8 pad[3]; + u32 fsType; + } in = { attributes, {0}, fsType }; + + return serviceDispatchIn(s, 213, in, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcPointer | SfBufferAttr_FixedSize }, + .buffers = { { contentPath, FS_MAX_PATH } }, .out_num_objects = 1, .out_objects = &out->s ); } -Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath) { - const struct { - u32 fsType; - u64 id; - } in = { fsType, id }; - - return serviceDispatchIn(s, 8, in, - .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In }, - .buffers = { { contentPath, FS_MAX_PATH } }, - .out_num_objects = 1, - .out_objects = &out->s +Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count) { + return serviceDispatchIn(s, 810, count, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, + .buffers = { { buf, buf_size } }, ); -} \ No newline at end of file +} diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h index 60743b803..87002bffa 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_shim.h @@ -12,18 +12,26 @@ extern "C" { #endif /* Missing fsp-srv commands. */ -Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out); +Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType); +Result fsOpenFileSystemWithIdObsoleteFwd(Service* s, FsFileSystem* out, const char* contentPath, u64 id, FsFileSystemType fsType); +Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, const char* contentPath, FsContentAttributes attributes, u64 id, FsFileSystemType fsType); + Result fsOpenBisStorageFwd(Service* s, FsStorage* out, FsBisPartitionId partition_id); -Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out); -Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id); -Result fsOpenDataStorageWithProgramIndexFwd(Service* s, FsStorage* out, u8 program_index); - -Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count); - +Result fsOpenSdCardFileSystemFwd(Service* s, FsFileSystem* out); Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr); -Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType); -Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath); +Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out); +Result fsOpenDataStorageByProgramIdFwd(Service* s, FsStorage* out, u64 id); +Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, NcmStorageId storage_id); +Result fsOpenDataStorageWithProgramIndexFwd(Service* s, FsStorage* out, u8 program_index); +Result fsOpenDataStorageByPathFwd(Service* s, FsStorage* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType); + +Result fsOpenDataStorageByCurrentProcessForBatchReadFwd(Service* s, FsStorageForBatchRead* out); +Result fsOpenDataStorageByProgramIdForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u64 id); +Result fsOpenDataStorageWithProgramIndexForBatchReadFwd(Service* s, FsStorageForBatchRead* out, u8 program_index); +Result fsOpenDataStorageByPathForBatchReadFwd(Service* s, FsStorageForBatchRead* out, const char* contentPath, FsContentAttributes attributes, FsFileSystemType fsType); + +Result fsRegisterProgramIndexMapInfoFwd(Service* s, const void *buf, size_t buf_size, s32 count); #ifdef __cplusplus diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.cpp index f5bd6079d..b167d3170 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.cpp @@ -180,33 +180,79 @@ namespace ams::mitm::fs { CloseReference(m_impl); } - virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(m_impl->Read(offset, buffer, size)); } - + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + /* TODO: Better result code? */ + AMS_UNUSED(offset, buffer, size); + R_THROW(ams::fs::ResultUnsupportedOperation()) + } + + virtual Result Flush() override { + R_RETURN(m_impl->Flush()); + } + + virtual Result SetSize(s64 size) override { + /* TODO: Better result code? */ + AMS_UNUSED(size); + R_THROW(ams::fs::ResultUnsupportedOperation()) + } + virtual Result GetSize(s64 *out_size) override { R_RETURN(m_impl->GetSize(out_size)); } + virtual Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + R_RETURN(m_impl->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); + } + }; + + class LayeredRomfsStorageForBatchRead : public ams::fs::IStorageForBatchRead { + private: + LayeredRomfsStorageImpl *m_impl; + public: + LayeredRomfsStorageForBatchRead(LayeredRomfsStorageImpl *impl) : m_impl(impl) { + OpenReference(m_impl); + } + + virtual ~LayeredRomfsStorageForBatchRead() { + CloseReference(m_impl); + } + + virtual Result Read(s64 offset, void *buffer, size_t size) override { + R_RETURN(m_impl->Read(offset, buffer, size)); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + /* TODO: Better result code? */ + AMS_UNUSED(offset, buffer, size); + R_THROW(ams::fs::ResultUnsupportedOperation()) + } + virtual Result Flush() override { R_RETURN(m_impl->Flush()); } + + virtual Result SetSize(s64 size) override { + /* TODO: Better result code? */ + AMS_UNUSED(size); + R_THROW(ams::fs::ResultUnsupportedOperation()) + } + + virtual Result GetSize(s64 *out_size) override { + R_RETURN(m_impl->GetSize(out_size)); + } virtual Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { R_RETURN(m_impl->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } - virtual Result Write(s64 offset, const void *buffer, size_t size) override { - /* TODO: Better result code? */ - AMS_UNUSED(offset, buffer, size); - R_THROW(ams::fs::ResultUnsupportedOperation()) - } - - virtual Result SetSize(s64 size) override { - /* TODO: Better result code? */ - AMS_UNUSED(size); - R_THROW(ams::fs::ResultUnsupportedOperation()) + virtual Result BatchRead(void *out0, void *out1, void *out2, void *out3, void *out4, void *out5, void *out6, const void *in) override { + /* TODO */ + AMS_UNUSED(out0, out1, out2, out3, out4, out5, out6, in); + R_THROW(ams::fs::ResultUnsupportedOperation()); } }; @@ -261,6 +307,54 @@ namespace ams::mitm::fs { /* Return a new shared storage for the impl. */ return std::make_shared(impl); } + + std::shared_ptr GetLayeredRomfsStorageForBatchRead(ncm::ProgramId program_id, ::FsStorageForBatchRead &data_storage, bool is_process_romfs) { + /*Prepare to find or create a new storage. */ + LayeredRomfsStorageImpl *impl = nullptr; + { + std::scoped_lock lk(g_storage_set_mutex); + + /* Find an existing storage. */ + if (auto it = g_storage_set.find_key(program_id.value); it != g_storage_set.end()) { + return std::make_shared(it->GetImpl()); + } + + /* We don't have an existing storage. If we're creating process romfs, free any unreferenced process romfs. */ + /* This should help prevent too much memory in use at any time. */ + if (is_process_romfs) { + auto it = g_storage_set.begin(); + while (it != g_storage_set.end()) { + if (it->GetReferenceCount() > 0 || !it->IsProcessRomfs()) { + ++it; + } else { + auto *holder = std::addressof(*it); + it = g_storage_set.erase(it); + delete holder; + } + } + } + + /* Create a new storage. */ + { + ::FsFile data_file; + if (R_SUCCEEDED(OpenAtmosphereSdFile(std::addressof(data_file), program_id, "romfs.bin", OpenMode_Read))) { + impl = new LayeredRomfsStorageImpl(std::make_unique(new RemoteStorageForBatchRead(data_storage)), std::make_unique(new FileStorage(new RemoteFile(data_file))), program_id); + } else { + impl = new LayeredRomfsStorageImpl(std::make_unique(new RemoteStorageForBatchRead(data_storage)), nullptr, program_id); + } + } + + /* Insert holder. Reference count will now be one. */ + g_storage_set.insert(*(new LayeredRomfsStorageHolder(impl, is_process_romfs))); + } + + /* Begin initialization. When this finishes, a decref will occur. */ + AMS_ABORT_UNLESS(impl != nullptr); + impl->BeginInitialize(); + + /* Return a new shared storage for the impl. */ + return std::make_shared(impl); + } void FinalizeLayeredRomfsStorage(ncm::ProgramId program_id) { std::scoped_lock lk(g_initialization_mutex); @@ -392,6 +486,10 @@ namespace ams::mitm::fs { R_SUCCEED(); } + + Result LayeredRomfsStorageImpl::Flush() { + R_SUCCEED(); + } Result LayeredRomfsStorageImpl::GetSize(s64 *out_size) { /* Ensure we're initialized. */ @@ -403,10 +501,6 @@ namespace ams::mitm::fs { R_SUCCEED(); } - Result LayeredRomfsStorageImpl::Flush() { - R_SUCCEED(); - } - Result LayeredRomfsStorageImpl::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { AMS_UNUSED(offset, src, src_size); diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.hpp index 337e47c47..d0df1514c 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.hpp @@ -44,13 +44,13 @@ namespace ams::mitm::fs { constexpr ncm::ProgramId GetProgramId() const { return m_program_id; } Result Read(s64 offset, void *buffer, size_t size); - Result GetSize(s64 *out_size); Result Flush(); + Result GetSize(s64 *out_size); Result OperateRange(void *dst, size_t dst_size, ams::fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size); }; std::shared_ptr GetLayeredRomfsStorage(ncm::ProgramId program_id, ::FsStorage &data_storage, bool is_process_romfs); - + std::shared_ptr GetLayeredRomfsStorageForBatchRead(ncm::ProgramId program_id, ::FsStorageForBatchRead &data_storage, bool is_process_romfs); void FinalizeLayeredRomfsStorage(ncm::ProgramId program_id); } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp index a1f88ae37..314f2db8f 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp @@ -474,7 +474,7 @@ namespace ams::mitm::fs { return entry; } }; - + template class TableWriter : public DynamicTableCache { NON_COPYABLE(TableWriter); @@ -727,12 +727,12 @@ namespace ams::mitm::fs { public: DirectoryTableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : TableReader(s, ofs, sz) { /* ... */ } }; - + class FileTableReader : public TableReader { public: FileTableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : TableReader(s, ofs, sz) { /* ... */ } }; - + void Builder::VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table) { const DirectoryEntry *parent_entry = dir_table.GetEntry(parent_offset); if (AMS_UNLIKELY(parent_entry == nullptr)) { @@ -773,8 +773,7 @@ namespace ams::mitm::fs { cur_child_offset = next_child_offset; } } - - + void Builder::AddSdFiles() { /* Open Sd Card filesystem. */ FsFileSystem sd_filesystem; diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp index 5eeb7dc08..e3ae73f02 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp @@ -361,7 +361,7 @@ namespace ams::mitm::fs::romfs { private: void VisitDirectory(FsFileSystem *fs, BuildDirectoryContext *parent); void VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table); - + void AddDirectory(BuildDirectoryContext **out, BuildDirectoryContext *parent_ctx, std::unique_ptr file_ctx); void AddFile(BuildDirectoryContext *parent_ctx, std::unique_ptr file_ctx); public: