Compare commits

..

21 Commits

Author SHA1 Message Date
Michael Scire
7b6df8c2f7 boot: remove references to memalign/malloc 2021-01-19 05:23:02 -08:00
Michael Scire
3b2c2ba5a2 ams_mitm: update for new sf semantics 2021-01-19 02:34:02 -08:00
Michael Scire
88a99bc68e dmnt: update for new sf semantics 2021-01-18 18:43:36 -08:00
Michael Scire
2d7a85d14f creport: update for new sf semantics 2021-01-18 17:50:40 -08:00
Michael Scire
2801d00d98 boot2: update for new sf semantics 2021-01-18 17:35:05 -08:00
Michael Scire
57c197ec1c boot: update for new sf-semantics 2021-01-18 17:22:36 -08:00
Michael Scire
2696240566 fatal: update screen task to use native window directly 2021-01-18 16:54:55 -08:00
Michael Scire
ea9d360b14 fatal: wip (pending libnx pr) update for new sf semantics 2021-01-18 08:48:47 -08:00
Michael Scire
a63b97fbbd jpegdec: note libjpeg-turbo TODO 2021-01-18 06:35:14 -08:00
Michael Scire
6c6e698a3e libstrat: move weak HasLaunchedBootProgram to non-lto object file 2021-01-18 06:26:22 -08:00
Michael Scire
15b225f919 loader: fix failure-to-early-return in launch record management 2021-01-18 06:20:13 -08:00
Michael Scire
ac2c713ee0 util::unique_lock, update loader to new sf semantics 2021-01-18 06:18:14 -08:00
Michael Scire
6a2f8e8344 string_view: remove now unecessary comment 2021-01-18 05:44:08 -08:00
Michael Scire
54a1ba2a7e ncm: update for new sf semantics 2021-01-18 05:41:15 -08:00
Michael Scire
2c485f832c util::string_view, update pgl for new sf semantics 2021-01-18 05:20:27 -08:00
Michael Scire
6467f6f07b pm: update for new sf semantics 2021-01-17 23:12:26 -08:00
Michael Scire
4f001b4f4c erpt: update for new sf semantics 2021-01-17 22:55:39 -08:00
Michael Scire
a6e452ed9e ro: reduce memory usage by excising (unused) std::malloc 2021-01-17 22:23:19 -08:00
Michael Scire
fb6a4e28a5 ro: update for new sf semantics 2021-01-17 22:03:26 -08:00
Michael Scire
bc9da91362 sm, spl: update to use new sf semantics 2021-01-17 15:03:51 -08:00
Michael Scire
8956e3bd29 libstrat: convert to experimental new (super-accurate) sf allocation semantics 2021-01-17 07:55:32 -08:00
119 changed files with 226 additions and 6797 deletions

View File

@@ -42,16 +42,6 @@
; enabled or disabled.
; 0 = Disabled (not debug mode), 1 = Enabled (debug mode)
; enable_am_debug_mode = u8!0x0
; Controls whether dns.mitm is enabled
; 0 = Disabled, 1 = Enabled
; enable_dns_mitm = u8!0x1
; Controls whether dns.mitm uses the default redirections in addition to
; whatever is specified in the user's hosts file.
; 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents)
; add_defaults_to_dns_hosts = u8!0x1
; Controls whether dns.mitm logs to the sd card for debugging
; 0 = Disabled, 1 = Enabled
; enable_dns_mitm_debug_log = u8!0x0
[hbloader]
; Controls the size of the homebrew heap when running as applet.
; If set to zero, all available applet memory is used as heap.

View File

@@ -1,19 +1,4 @@
# Changelog
## 0.18.0
+ A new mitm module was added (`dns.mitm`).
+ This provides a highly configurable mechanism for redirecting DNS resolution requests.
+ By default atmosphère redirects resolution requests for official telemetry servers to a loopback address.
+ Documentation on how to configure `dns.mitm` to meet your more specific needs may be found [here](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/features/dns_mitm.md).
+ The service framework API (`sf`) was refactored to be more accurate to official logic and greatly reduce memory requirements.
+ The comparison of atmosphère module memory usage versus Nintendo's found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons) was updated to reflect this.
+ **Please Note**: If you are a developer using the libstratosphere service APIs, some updating may be required. Contact SciresM#0524 on discord for assistance if required.
+ A number of deprecations were removed, following a general codebase cleanup:
+ The `sm` extension to not unregister services on connection close was superseded by official opt-in logic in 11.0.0, and has been removed in favor of official logic.
+ This should have zero impact on users.
+ The temporary `hid-mitm` added in 0.9.0 has finally been removed, following over a year of deprecation.
+ There shouldn't be any homebrew in use still affected by this, but the situation will be monitored.
+ If this is somehow still a real issue, an unaffiliated hid mitm sysmodule providing the same functionality can be created and released, separate from atmosphère itself.
+ Several issues were fixed, and usability and stability were improved.
## 0.17.1
+ A number of atmosphère's modules were using more memory than their Nintendo equivalent's in 0.17.0; a number of code generatio tweaks have been applied to fix this across the board.
+ A detailed comparison of atmosphère module memory usage versus Nintendo's was made and can be found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons).

View File

@@ -25,12 +25,6 @@ set_mitm enables intercepting requests to the system settings service. It curren
+ `ns` system module and games (to allow for overriding game locales)
+ All firmware debug settings requests (to allow modification of system settings not directly exposed to the user)
## dns_mitm
dns_mitm enables intercepting requests to dns resolution services, to enable redirecting requests for specified hostnames.
For documentation, see [here](../../features/dns_mitm.md).
### Firmware Version
set_mitm intercepts the `GetFirmwareVersion` command, if the requester is `qlaunch` or `maintenance`.
It modifies the `display_version` field of the returned system version, causing the version to display

View File

@@ -1,53 +0,0 @@
# DNS.mitm
As of 0.18.0, atmosphère provides a mechanism for redirecting DNS resolution requests.
By default, atmosphère redirects resolution requests for official telemetry servers, redirecting them to a loopback address.
## Hosts files
DNS.mitm can be configured through the usage of a slightly-extended `hosts` file format, which is parsed only once on system startup.
In particular, hosts files parsed by DNS.mitm have the following extensions to the usual format:
+ `*` is treated as a wildcard character, matching any collection of 0 or more characters wherever it occurs in a hostname.
+ `%` is treated as a stand-in for the value of `nsd!environment_identifier`. This is always `lp1`, on production devices.
If multiple entries in a host file match a domain, the last-defined match is used.
Please note that homebrew may trigger a hosts file re-parse by sending the extension IPC command 65000 ("AtmosphereReloadHostsFile") to a connected `sfdnsres` session.
### Hosts file selection
Atmosphère will try to read hosts from the following file paths, in order, stopping once it successfully performs a file read:
+ (emummc only) `/atmosphere/hosts/emummc_%04lx.txt`, formatted with the emummc's id number (see `emummc.ini`).
+ (emummc only) `/atmosphere/hosts/emummc.txt`.
+ (sysmmc only) `/atmosphere/hosts/sysmmc.txt`.
+ `/atmosphere/hosts/default.txt`
If `/atmosphere/hosts/default.txt` does not exist, atmosphère will create it to contain the defaults.
### Atmosphère defaults
By default, atmosphère's default redirections are parsed **in addition to** the contents of the loaded hosts file.
This is equivalent to thinking of the loaded hosts file as having the atmosphère defaults prepended to it.
This setting is considered desirable, because it minimizes the telemetry risks if a user forgets to update a custom hosts file on a system update which changes the telemetry servers.
This behavior can be opted-out from by setting `atmosphere!add_defaults_to_dns_hosts = u8!0x0` in `system_settings.ini`.
The current default redirections are:
```
# Nintendo telemetry servers
127.0.0.1 receive-%.dg.srv.nintendo.net receive-%.er.srv.nintendo.net
```
## Debugging
On startup (or on hosts file re-parse), DNS.mitm will log both what hosts file it selected and the contents of all redirections it parses to `/atmosphere/logs/dns_mitm_startup.log`.
In addition, if the user sets `atmosphere!enable_dns_mitm_debug_log = u8!0x1` in `system_settings.ini`, DNS.mitm will log all requests to GetHostByName/GetAddrInfo to `/atmosphere/logs/dns_mitm_debug.log`. All redirections will be noted when they occur.
## Opting-out of DNS.mitm entirely
If you wish to disable DNS.mitm entirely, `system_settings.ini` can be edited to set `atmosphere!enable_dns_mitm = u8!0x0`.

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 17960517bad5d2d07effb28b744ac8d907d571e0
parent = ee2e9d50fd93721b365daf0eae1eef17c8ba62e8
commit = 6c11c07e2a7f03952a4e70eb89b47bf528de39c6
parent = 9e104bb83f1302e9f126542fbf57c7f666aae953
method = merge
cmdver = 0.4.1

View File

@@ -314,12 +314,12 @@ namespace ams::kern::board::nintendo::nx {
g_secure_applet_memory_used = false;
}
u32 GetVersionIdentifier() {
u32 value = 0;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO) << 0;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR) << 8;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR) << 16;
value |= static_cast<u64>('M') << 24;
u64 GetVersionIdentifier() {
u64 value = kern::GetTargetFirmware();
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO) << 32;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR) << 40;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR) << 48;
value |= static_cast<u64>('M') << 56;
return value;
}
@@ -584,8 +584,8 @@ namespace ams::kern::board::nintendo::nx {
f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress();
/* Set afsr1. */
f_ctx->afsr0 = GetVersionIdentifier();
f_ctx->afsr1 = static_cast<u32>(kern::GetTargetFirmware());
f_ctx->afsr0 = 0;
f_ctx->afsr1 = GetVersionIdentifier();
/* Set efsr/far. */
f_ctx->far = cpu::GetFarEl1();

View File

@@ -43,6 +43,7 @@ namespace ams::kern {
if (owner_thread->IsSuspended()) {
owner_thread->ContinueIfHasKernelWaiters();
KScheduler::SetSchedulerUpdateNeeded();
}
}
@@ -52,7 +53,6 @@ namespace ams::kern {
KThread *owner_thread = cur_thread->GetLockOwner();
if (AMS_UNLIKELY(owner_thread)) {
owner_thread->RemoveWaiter(cur_thread);
KScheduler::SetSchedulerUpdateNeeded();
}
}
}

View File

@@ -61,7 +61,6 @@
#include <stratosphere/ncm.hpp>
#include <stratosphere/nim.hpp>
#include <stratosphere/ns.hpp>
#include <stratosphere/nsd.hpp>
#include <stratosphere/patcher.hpp>
#include <stratosphere/pcv.hpp>
#include <stratosphere/pgl.hpp>
@@ -75,7 +74,6 @@
#include <stratosphere/settings.hpp>
#include <stratosphere/sf.hpp>
#include <stratosphere/sm.hpp>
#include <stratosphere/socket.hpp>
#include <stratosphere/spl.hpp>
#include <stratosphere/time.hpp>
#include <stratosphere/updater.hpp>

View File

@@ -22,9 +22,6 @@ namespace ams::emummc {
/* Get whether emummc is active. */
bool IsActive();
/* Get the active emummc id. */
u32 GetActiveId();
/* Get Nintendo redirection path. */
const char *GetNintendoDirPath();

View File

@@ -113,9 +113,6 @@ namespace ams::impl {
AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main);
AMS_DEFINE_SYSTEM_THREAD(21, erpt, IpcServer);
/* socket. */
AMS_DEFINE_SYSTEM_THREAD(29, socket, ResolverIpcServer);
/* jpegdec. */
AMS_DEFINE_SYSTEM_THREAD(21, jpegdec, Main);

View File

@@ -13,15 +13,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/dd/dd_types.hpp>
namespace ams::dd {
using ProcessHandle = ::Handle;
/* TODO gcc-11: using MemoryPermission = os::MemoryPermission; using enum os::MemoryPermission; */
enum MemoryPermission {
MemoryPermission_None = 0,
MemoryPermission_ReadOnly = (1u << 0),

View File

@@ -1,18 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/nsd/nsd_types.hpp>
#include <stratosphere/nsd/impl/device/nsd_device.hpp>

View File

@@ -1,24 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/nsd/nsd_types.hpp>
namespace ams::nsd::impl::device {
const EnvironmentIdentifier &GetEnvironmentIdentifierFromSettings();
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::nsd {
struct EnvironmentIdentifier {
static constexpr size_t Size = 8;
char value[Size];
constexpr friend bool operator==(const EnvironmentIdentifier &lhs, const EnvironmentIdentifier &rhs) {
return util::Strncmp(lhs.value, rhs.value, Size) == 0;
}
constexpr friend bool operator!=(const EnvironmentIdentifier &lhs, const EnvironmentIdentifier &rhs) {
return !(lhs == rhs);
}
};
constexpr inline const EnvironmentIdentifier EnvironmentIdentifierOfProductDevice = {"lp1"};
constexpr inline const EnvironmentIdentifier EnvironmentIdentifierOfNotProductDevice = {"dd1"};
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stratosphere/socket/socket_types.hpp>
#include <stratosphere/socket/socket_errno.hpp>
#include <stratosphere/socket/socket_api.hpp>

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/socket/socket_types.hpp>
#include <stratosphere/socket/socket_errno.hpp>
namespace ams::socket {
Errno GetLastError();
void SetLastError(Errno err);
u32 InetHtonl(u32 host);
u16 InetHtons(u16 host);
u32 InetNtohl(u32 net);
u16 InetNtohs(u16 net);
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::socket {
enum class Errno : u32 {
ESuccess = 0,
/* ... */
ENoSpc = 28,
/* ... */
};
enum class HErrno : s32 {
Netdb_Internal = -1,
Netdb_Success = 0,
Host_Not_Found = 1,
Try_Again = 2,
No_Recovery = 3,
No_Data = 4,
No_Address = No_Data,
};
enum class AiErrno : u32 {
EAi_Success = 0,
/* ... */
};
constexpr inline bool operator!(Errno e) { return e == Errno::ESuccess; }
constexpr inline bool operator!(HErrno e) { return e == HErrno::Netdb_Success; }
constexpr inline bool operator!(AiErrno e) { return e == AiErrno::EAi_Success; }
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::socket {
using InAddrT = u32;
using InPortT = u16;
using SockLenT = u32;
using NfdsT = u64;
using FdMask = u64;
constexpr inline unsigned int FdSetSize = 0x400;
template<u32 A, u32 B, u32 C, u32 D>
constexpr inline InAddrT EncodeInAddr = util::ConvertToBigEndian(InAddrT{(A << 24) | (B << 16) | (C << 8) | (D << 0)});
constexpr inline InAddrT InAddr_Any = EncodeInAddr< 0, 0, 0, 0>;
constexpr inline InAddrT InAddr_Broadcast = EncodeInAddr<255, 255, 255, 255>;
constexpr inline InAddrT InAddr_None = EncodeInAddr<255, 255, 255, 255>;
constexpr inline InAddrT InAddr_Loopback = EncodeInAddr<127, 0, 0, 1>;
enum class Protocol : s32 {
IpProto_Ip = 0,
IpProto_Icmp = 1,
IpProto_Tcp = 6,
IpProto_Udp = 17,
IpProto_UdpLite = 136,
IpProto_Raw = 255,
IpProto_Max = 256,
};
enum class Type : u32 {
Sock_Default = 0,
Sock_Stream = 1,
Sock_Dgram = 2,
Sock_Raw = 3,
Sock_SeqPacket = 5,
Sock_NonBlock = 0x20000000,
};
enum class Family : u8 {
Af_Unspec = 0,
Pf_Unspec = Af_Unspec,
Af_Inet = 2,
Pf_Inet = Af_Inet,
Af_Route = 17,
Pf_Route = Af_Route,
Af_Link = 18,
Pf_Link = Af_Link,
Af_Inet6 = 28,
Pf_Inet6 = Af_Inet6,
Af_Max = 42,
Pf_Max = Af_Max
};
struct HostEnt {
char *h_name;
char **h_aliases;
Family h_addrtype;
int h_length;
char **h_addr_list;
};
struct InAddr {
InAddrT s_addr;
};
enum class AddrInfoFlag : u32 {
Ai_None = (0 << 0),
Ai_Passive = (1 << 0),
Ai_CanonName = (1 << 1),
Ai_NumericHost = (1 << 2),
Ai_NumericServ = (1 << 3),
Ai_AddrConfig = (1 << 10),
};
struct SockAddr {
u8 sa_len;
Family sa_family;
char sa_data[14];
};
struct SockAddrIn {
u8 sin_len;
Family sin_family;
InPortT sin_port;
InAddr sin_addr;
u8 sin_zero[8];
};
static_assert(sizeof(SockAddr) == sizeof(SockAddrIn));
struct AddrInfo {
AddrInfoFlag ai_flags;
Family ai_family;
Type ai_socktype;
Protocol ai_protocol;
SockLenT ai_addrlen;
SockAddr *ai_addr;
char *ai_canonname;
AddrInfo *ai_next;
};
#define AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(__ENUM__) \
constexpr inline __ENUM__ operator | (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) | static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \
constexpr inline __ENUM__ operator |=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs | rhs; } \
constexpr inline __ENUM__ operator & (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) & static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \
constexpr inline __ENUM__ operator &=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs & rhs; } \
constexpr inline __ENUM__ operator ^ (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) ^ static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \
constexpr inline __ENUM__ operator ^=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs ^ rhs; } \
constexpr inline __ENUM__ operator ~ (__ENUM__ e) { return static_cast<__ENUM__>(~static_cast<std::underlying_type_t<__ENUM__>>(e)); }
AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(Type)
AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(AddrInfoFlag)
#undef AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS
}

View File

@@ -57,10 +57,10 @@ namespace ams::emummc {
};
/* Globals. */
constinit os::SdkMutex g_lock;
constinit ExosphereConfig g_exo_config;
constinit bool g_is_emummc;
constinit bool g_has_cached;
os::Mutex g_lock(false);
ExosphereConfig g_exo_config;
bool g_is_emummc;
bool g_has_cached;
/* Helpers. */
void CacheValues() {
@@ -110,12 +110,6 @@ namespace ams::emummc {
return g_is_emummc;
}
/* Get the active emummc id. */
u32 GetActiveId() {
CacheValues();
return g_exo_config.base_cfg.id;
}
/* Get Nintendo redirection path. */
const char *GetNintendoDirPath() {
CacheValues();

View File

@@ -73,11 +73,11 @@ namespace ams {
ams_ctx.sp = ctx->sp.x;
ams_ctx.pc = ctx->pc.x;
ams_ctx.pstate = ctx->pstate;
ams_ctx.afsr0 = static_cast<u32>(::ams::exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION));
ams_ctx.afsr0 = ctx->afsr0;
ams_ctx.afsr1 = (static_cast<u64>(::ams::exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION)) << 32) | static_cast<u64>(hos::GetVersion());
if (svc::IsKernelMesosphere()) {
ams_ctx.afsr0 |= (static_cast<u32>('M') << (BITSIZEOF(u32) - BITSIZEOF(u8)));
ams_ctx.afsr1 |= (static_cast<u64>('M') << (BITSIZEOF(u64) - BITSIZEOF(u8)));
}
ams_ctx.afsr1 = static_cast<u32>(hos::GetVersion());
ams_ctx.far = ctx->far.x;
ams_ctx.report_identifier = armGetSystemTick();

View File

@@ -899,7 +899,7 @@ namespace ams::fssystem::save {
const s64 cur_offset_end = offset + *size;
size_t cur_size = 0;
if (!util::IsAligned(cur_offset_end, this->block_size)) {
if (!util::IsAligned(offset, this->block_size)) {
const s64 aligned_size = cur_offset_end - util::AlignDown(cur_offset_end, this->block_size);
cur_size = std::min(aligned_size, static_cast<s64>(*size));
} else if (*size < this->block_size) {

View File

@@ -40,12 +40,14 @@ namespace ams::hid {
/* Helper. */
void InitializeHid() {
sm::DoWithSession([&]() {
R_ABORT_UNLESS(smInitialize());
ON_SCOPE_EXIT { smExit(); };
{
R_ABORT_UNLESS(hidInitialize());
hidInitializeNpad();
R_ABORT_UNLESS(hidSetSupportedNpadIdType(NpadIdTypes, NumNpadIdTypes));
R_ABORT_UNLESS(hidSetSupportedNpadStyleSet(HidNpadStyleSet_NpadStandard | HidNpadStyleTag_NpadSystemExt));
});
}
}
Result EnsureHidInitialized() {

View File

@@ -76,7 +76,7 @@ namespace ams::hos {
const u32 major = (hos_version_val >> 24) & 0xFF;
const u32 minor = (hos_version_val >> 16) & 0xFF;
const u32 micro = (hos_version_val >> 8) & 0xFF;
hosversionSet((BIT(31)) | (MAKEHOSVERSION(major, minor, micro)));
hosversionSet(MAKEHOSVERSION(major, minor, micro));
}
}

View File

@@ -26,7 +26,7 @@ namespace ams::ncm {
MakeContentPathFunction make_content_path_func;
bool disabled;
protected:
ContentStorageImplBase() : make_content_path_func(), disabled(false) { /* ... */ }
ContentStorageImplBase() { /* ... */ }
protected:
/* Helpers. */
Result EnsureEnabled() const {

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::nsd::impl::device {
namespace {
constexpr const char SettingsName[] = "nsd";
constexpr const char SettingsKey[] = "environment_identifier";
constinit os::SdkMutex g_environment_identifier_lock;
constinit EnvironmentIdentifier g_environment_identifier = {};
constinit bool g_determined_environment_identifier = false;
}
const EnvironmentIdentifier &GetEnvironmentIdentifierFromSettings() {
std::scoped_lock lk(g_environment_identifier_lock);
if (!g_determined_environment_identifier) {
/* Check size. */
AMS_ABORT_UNLESS(settings::fwdbg::GetSettingsItemValueSize(SettingsName, SettingsKey) != 0);
/* Get value. */
const size_t size = settings::fwdbg::GetSettingsItemValue(g_environment_identifier.value, EnvironmentIdentifier::Size, SettingsName, SettingsKey);
AMS_ABORT_UNLESS(size < EnvironmentIdentifier::Size);
AMS_ABORT_UNLESS(g_environment_identifier == EnvironmentIdentifierOfProductDevice || g_environment_identifier == EnvironmentIdentifierOfNotProductDevice);
g_determined_environment_identifier = true;
}
return g_environment_identifier;
}
}

View File

@@ -15,12 +15,25 @@
*/
#include <stratosphere.hpp>
namespace ams::result {
extern bool CallFatalOnResultAssertion;
}
namespace ams::result::impl {
NORETURN WEAK_SYMBOL void OnResultAbort(const char *file, int line, const char *func, const char *expr, Result result) {
::ams::diag::AbortImpl(file, line, func, expr, result.GetValue(), "Result Abort: %203d-%04d", result.GetModule(), result.GetDescription());
/* Assert that we should call fatal on result assertion. */
/* If we shouldn't fatal, this will abort(); */
/* If we should, we'll continue onwards. */
if (!ams::result::CallFatalOnResultAssertion) {
::ams::diag::AbortImpl(file, line, func, expr, result.GetValue(), "Result Abort: %203d-%04d", result.GetModule(), result.GetDescription());
}
/* TODO: ams::fatal:: */
fatalThrow(result.GetValue());
AMS_INFINITE_LOOP();
__builtin_unreachable();
}
NORETURN WEAK_SYMBOL void OnResultAbort(Result result) {
@@ -28,9 +41,16 @@ namespace ams::result::impl {
}
NORETURN WEAK_SYMBOL void OnResultAssertion(const char *file, int line, const char *func, const char *expr, Result result) {
::ams::diag::AssertionFailureImpl(file, line, func, expr, result.GetValue(), "Result Assertion: %203d-%04d", result.GetModule(), result.GetDescription());
/* Assert that we should call fatal on result assertion. */
/* If we shouldn't fatal, this will assert(); */
/* If we should, we'll continue onwards. */
if (!ams::result::CallFatalOnResultAssertion) {
::ams::diag::AssertionFailureImpl(file, line, func, expr, result.GetValue(), "Result Assertion: %203d-%04d", result.GetModule(), result.GetDescription());
}
/* TODO: ams::fatal:: */
fatalThrow(result.GetValue());
AMS_INFINITE_LOOP();
__builtin_unreachable();
}
NORETURN WEAK_SYMBOL void OnResultAssertion(Result result) {

View File

@@ -28,11 +28,6 @@ static Result _smAtmosphereCmdInServiceNameNoOut(SmServiceName name, Service *sr
return serviceDispatchIn(srv, cmd_id, name);
}
static Result _smAtmosphereDetachClient(Service *srv) {
u64 pid_placeholder = 0;
return serviceDispatchIn(srv, 4, pid_placeholder, .in_send_pid = true);
}
Result smAtmosphereHasService(bool *out, SmServiceName name) {
return _smAtmosphereCmdHas(out, name, 65100);
}
@@ -86,10 +81,6 @@ Result smAtmosphereOpenSession(Service *out) {
}
void smAtmosphereCloseSession(Service *srv) {
Result rc = _smAtmosphereDetachClient(srv);
if (R_FAILED(rc)) {
svcBreak(BreakReason_Panic, (uintptr_t)&rc, sizeof(rc));
}
serviceClose(srv);
}

View File

@@ -30,10 +30,7 @@ namespace ams::sm::impl {
std::scoped_lock lk(GetUserSessionMutex());
{
R_ABORT_UNLESS(smInitialize());
ON_SCOPE_EXIT {
R_ABORT_UNLESS(smDetachClient());
smExit();
};
ON_SCOPE_EXIT { smExit(); };
return f();
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::socket::impl {
void *Alloc(size_t size);
void *Calloc(size_t num, size_t size);
void Free(void *ptr);
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::socket::impl {
Errno GetLastError();
void SetLastError(Errno err);
u32 InetHtonl(u32 host);
u16 InetHtons(u16 host);
u32 InetNtohl(u32 net);
u16 InetNtohs(u16 net);
}

View File

@@ -1,83 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "socket_api.hpp"
#include "socket_allocator.hpp"
namespace ams::socket::impl {
void *Alloc(size_t size) {
/* TODO: expheap, heap generation. */
return ams::Malloc(size);
}
void *Calloc(size_t num, size_t size) {
if (void *ptr = Alloc(size * num); ptr != nullptr) {
std::memset(ptr, 0, size * num);
return ptr;
} else {
return nullptr;
}
}
void Free(void *ptr) {
/* TODO: expheap, heap generation. */
return ams::Free(ptr);
}
Errno GetLastError() {
/* TODO: check that client library is initialized. */
return static_cast<Errno>(errno);
}
void SetLastError(Errno err) {
/* TODO: check that client library is initialized. */
errno = static_cast<int>(err);
}
u32 InetHtonl(u32 host) {
if constexpr (util::IsBigEndian()) {
return host;
} else {
return util::SwapBytes(host);
}
}
u16 InetHtons(u16 host) {
if constexpr (util::IsBigEndian()) {
return host;
} else {
return util::SwapBytes(host);
}
}
u32 InetNtohl(u32 net) {
if constexpr (util::IsBigEndian()) {
return net;
} else {
return util::SwapBytes(net);
}
}
u16 InetNtohs(u16 net) {
if constexpr (util::IsBigEndian()) {
return net;
} else {
return util::SwapBytes(net);
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "impl/socket_api.hpp"
namespace ams::socket {
Errno GetLastError() {
return impl::GetLastError();
}
void SetLastError(Errno err) {
return impl::SetLastError(err);
}
u32 InetHtonl(u32 host) {
return impl::InetHtonl(host);
}
u16 InetHtons(u16 host) {
return impl::InetHtons(host);
}
u32 InetNtohl(u32 net) {
return impl::InetNtohl(net);
}
u16 InetNtohs(u16 net) {
return impl::InetNtohs(net);
}
}

View File

@@ -38,5 +38,4 @@
#include <vapours/ams/ams_fatal_error_context.hpp>
#include <vapours/dd.hpp>
#include <vapours/sdmmc.hpp>
#include <vapours/prfile2.hpp>
#include <vapours/sdmmc.hpp>

View File

@@ -16,8 +16,8 @@
#pragma once
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 18
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 17
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
#include <vapours/results.hpp>
#include <vapours/util.hpp>
#include <vapours/svc.hpp>
#include <vapours/prfile2/prfile2_common.hpp>
#include <vapours/prfile2/prfile2_str.hpp>
#include <vapours/prfile2/prfile2_system.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_api.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_disk_management.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_upper_layer_api.hpp>
#include <vapours/prfile2/prfile2_fatfs.hpp>
#include <vapours/prfile2/prfile2_volume.hpp>

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/pdm/prfile2_pdm_types.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_disk_management.hpp>
namespace ams::prfile2::pdm {
pdm::Error Initialize(u32 config, void *param);
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out);
pdm::Error CloseDisk(HandleType handle);
pdm::Error OpenPartition(HandleType disk_handle, u16 part_id, HandleType *out);
pdm::Error ClosePartition(HandleType handle);
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_build_config.hpp>
#include <vapours/prfile2/prfile2_handle.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_types.hpp>
namespace ams::prfile2::pdm {
constexpr inline const auto MaxDisks = 5;
constexpr inline const auto MaxPartitions = 5;
struct Disk;
struct Partition;
using PartitionEventCallback = void (*)(u32 event, void *param);
using EraseFunction = pdm::Error (*)(u32, u32);
struct DiskInfo {
u32 total_sectors;
u16 cylinders;
u8 heads;
u8 sectors_per_track;
u16 bytes_per_sector;
u32 media_attr;
void *format_param;
/* ... */
};
struct FunctionTable {
pdm::Error (*initialize)(HandleType disk_handle);
pdm::Error (*finalize)(HandleType disk_handle);
pdm::Error (*mount)(HandleType disk_handle);
pdm::Error (*unmount)(HandleType disk_handle);
pdm::Error (*format)(HandleType disk_handle, const u8 *);
pdm::Error (*physical_read)(HandleType disk_handle, u8 *dst, u32 block, u32 count, u32 *num_read);
pdm::Error (*physical_write)(HandleType disk_handle, const u8 *src, u32 block, u32 count, u32 *num_read);
pdm::Error (*get_disk_info)(HandleType disk_handle, DiskInfo *out);
};
struct DiskTable {
FunctionTable *function_table;
u64 ui_ext;
};
struct InitDisk {
pdm::Error (*function)(DiskTable *disk_table, u64 ui_ext);
u64 ui_ext;
};
/* ... */
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_handle.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
namespace ams::prfile2::pdm {
struct Disk {
u32 status;
DiskTable disk_table;
u32 signature;
u16 open_count;
u16 lock_count;
Disk *lock_handle;
DiskInfo disk_info;
InitDisk *init_disk_table;
HandleType current_partition_handle;
DiskCallback erase_callback;
bool is_inserted;
volatile NonBlockingProtocolType nbc;
volatile NonBlockingProtocolType nbc_detect;
volatile NonBlockingProtocolType nbc_req;
template<size_t Ix>
constexpr ALWAYS_INLINE bool GetStatusBit() const {
constexpr u32 Mask = (1u << Ix);
return (this->status & Mask) != 0;
}
template<size_t Ix>
constexpr ALWAYS_INLINE void SetStatusBit(bool en) {
constexpr u32 Mask = (1u << Ix);
if (en) {
this->status |= Mask;
} else {
this->status &= ~Mask;
}
}
constexpr bool IsOpen() const { return this->GetStatusBit<0>(); }
constexpr void SetOpen(bool en) { this->SetStatusBit<0>(en); }
constexpr bool IsLocked() const { return this->GetStatusBit<1>(); }
constexpr void SetLocked(bool en) { this->SetStatusBit<1>(en); }
};
namespace disk {
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out);
pdm::Error CloseDisk(HandleType handle);
/* ... */
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_handle.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_disk.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_partition.hpp>
namespace ams::prfile2::pdm {
struct PartitionHolder {
u32 signature;
Partition *partition;
};
struct DiskHolder {
u32 signature;
Disk *disk;
};
struct DiskSet {
u16 num_partitions;
u16 num_allocated_disks;
DiskHolder disk_holders[MaxDisks];
PartitionHolder partition_holders[MaxPartitions];
Disk disks[MaxDisks];
Partition partitions[MaxPartitions];
};
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_handle.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
namespace ams::prfile2::pdm {
struct Partition {
u32 status;
HandleType disk_handle;
u32 signature;
u16 partition_id;
u16 open_count;
Partition *lock_handle;
u32 start_sector;
u32 total_sector;
u32 mbr_sector;
u8 partition_type;
pdm::Error last_driver_error;
void *volume;
volatile NonBlockingProtocolType nbc_detect;
PartitionEventCallback event_callback;
void *event_callback_param;
template<size_t Ix>
constexpr ALWAYS_INLINE bool GetStatusBit() const {
constexpr u32 Mask = (1u << Ix);
return (this->status & Mask) != 0;
}
template<size_t Ix>
constexpr ALWAYS_INLINE void SetStatusBit(bool en) {
constexpr u32 Mask = (1u << Ix);
if (en) {
this->status |= Mask;
} else {
this->status &= ~Mask;
}
}
constexpr bool IsOpen() const { return this->GetStatusBit<0>(); }
constexpr void SetOpen(bool en) { this->SetStatusBit<0>(en); }
constexpr bool IsLocked() const { return this->GetStatusBit<1>(); }
constexpr void SetLocked(bool en) { this->SetStatusBit<1>(en); }
};
namespace part {
pdm::Error OpenPartition(HandleType disk_handle, u16 partition_id, HandleType *out);
pdm::Error ClosePartition(HandleType part_handle);
void SetDriverErrorCode(HandleType part_handle, pdm::Error err);
void CheckPartitionOpen(HandleType disk_handle, bool *out);
void NotifyMediaEvent(HandleType disk_handle, u32 event);
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_build_config.hpp>
#include <vapours/prfile2/prfile2_handle.hpp>
namespace ams::prfile2::pdm {
enum Error {
Error_NoError = 0,
Error_Ok = Error_NoError,
Error_InvalidParameter = 0x0001,
Error_InvalidMasterBoot = 0x0002,
Error_InvalidBootSector = 0x0003,
Error_InvalidBpb = 0x0004,
Error_NotExistMbr = 0x0005,
Error_NotExistEpbr = 0x0006,
Error_NotExistPartition = 0x0007,
Error_NotExistFreeDiskStruct = 0x0008,
Error_NotExistPartitionStruct = 0x0009,
Error_NotExistFreePartitionStruct = 0x000A,
Error_StateOpened = 0x000B,
Error_StateClosed = 0x000C,
Error_StateLocked = 0x000D,
Error_StateUnlocked = 0x000E,
Error_AccessPermission = 0x000F,
Error_WriteProtected = 0x0010,
Error_MediaEjected = 0x0011,
Error_OutOfRange = 0x0012,
Error_SystemCallError = 0x0013,
Error_LockError = 0x0014,
Error_DriverError = 0x0015,
Error_UnsupportDiskFormat = 0x0016,
};
using NonBlockingProtocolType = int;
using DiskCallback = void (*)();
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/pdm/prfile2_pdm_types.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
#include <vapours/prfile2/pdm/prfile2_pdm_disk_management.hpp>
namespace ams::prfile2::pdm {
namespace part {
pdm::Error CheckDataEraseRequest(HandleType part_handle, bool *out);
pdm::Error CheckMediaDetect(HandleType part_handle, bool *out);
pdm::Error CheckMediaInsert(HandleType part_handle, bool *out);
}
namespace disk {
pdm::Error CheckDataEraseRequest(HandleType disk_handle, bool *out);
pdm::Error CheckMediaDetect(HandleType disk_handle, bool *out);
pdm::Error CheckMediaInsert(HandleType disk_handle, bool *out);
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/pf/prfile2_pf_config.hpp>
#include <vapours/prfile2/pf/prfile2_pf_types.hpp>
#include <vapours/prfile2/prfile2_critical_section.hpp>
namespace ams::prfile2::pf {
int Initialize(u32 config, void *param);
int Attach(DriveTable **drive_table);
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_build_config.hpp>
namespace ams::prfile2::pf {
constexpr inline const auto MaximumFileCount = 256;
constexpr inline const auto MaximumDirectoryCount = 32;
}

View File

@@ -1,152 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_build_config.hpp>
#include <vapours/prfile2/prfile2_handle.hpp>
namespace ams::prfile2::pf {
using DriveCharacter = char;
enum Error {
Error_NoError = 0,
Error_Ok = Error_NoError,
Error_Generic = -1,
Error_InvalidFileName = 1,
Error_InvalidPathName = 2,
Error_FileNotFound = 3,
Error_TooManyVolumesAttached = 4,
Error_DirectoryFull = 5,
Error_VolumeFull = 6,
Error_InvalidDiskFormat = 7,
Error_FileAlreadyExists = 8,
Error_VolumeNotMounted = 9,
Error_InvalidParameter = 10,
Error_WriteProtected = 11,
Error_UnsupportedFormat = 12,
Error_BrokenClusterChain = 13,
Error_InvalidClusterNum = 14,
Error_InvalidBpb = 15,
Error_AccessOutOfVolume = 16,
Error_DriverError = 17,
Error_InvalidVolumeLabel = 18,
Error_FileOpened = 19,
Error_NotADirectory = 20,
Error_TooManyFilesOpenedS = 21,
Error_TooManyFilesOpenedU = 22,
Error_NotAFile = 23,
Error_ReadOnly = 24,
Error_LockError = 25,
Error_InternalError = 26,
Error_EndOfFile = 27,
Error_AccessNotAllowed = 28,
Error_DirectoryNotEmpty = 29,
Error_NotEnoughCachePages = 30,
Error_DifferentDrive = 31,
Error_DifferentEntry = 32,
Error_InvalidEntry = 33,
Error_InvalidSector = 34,
Error_BrokenVolume = 35,
Error_NotEffective = 36,
Error_FileSizeOver = 37,
Error_InvalidFileDiscriptor = 38,
Error_InvalidLockFile = 39,
Error_ExtensionNotRegistered = 40,
Error_ExtensionError = 41,
};
constexpr inline const int ReturnValueNoError = 0;
constexpr inline const int ReturnValueError = -1;
constexpr inline int ConvertReturnValue(Error err) {
if (AMS_LIKELY(err == Error_NoError)) {
return ReturnValueNoError;
} else {
return ReturnValueError;
}
}
struct CachePage {
u16 status;
u16 option;
u8 *buffer_head;
u8 *buffer_cur;
u8 *buffer_dirty_start;
u8 *buffer_dirty_end;
u32 size;
u32 sector;
void *signature;
CachePage *next;
CachePage *prev;
};
static_assert(util::is_pod<CachePage>::value);
constexpr inline auto SectorBufferSize = 0x200;
constexpr inline auto Log2SectorBufferSize = 9;
static_assert((1u << Log2SectorBufferSize) == SectorBufferSize);
using SectorBuffer = u8[SectorBufferSize];
static_assert(sizeof(SectorBuffer) == SectorBufferSize);
struct CacheSetting {
CachePage *pages;
SectorBuffer *buffers;
u16 num_fat_pages;
u16 num_data_pages;
u32 fat_buf_size;
u32 data_buf_size;
};
struct DriveTable {
CacheSetting *cache;
HandleType partition_handle;
DriveCharacter drive_char;
u8 status;
template<size_t Ix>
constexpr ALWAYS_INLINE bool GetStatusBit() const {
constexpr u32 Mask = (1u << Ix);
return (this->status & Mask) != 0;
}
template<size_t Ix>
constexpr ALWAYS_INLINE void SetStatusBit(bool en) {
constexpr u32 Mask = (1u << Ix);
if (en) {
this->status |= Mask;
} else {
this->status &= ~Mask;
}
}
constexpr bool IsAttached() const { return this->GetStatusBit<0>(); }
constexpr void SetAttached(bool en) { this->SetStatusBit<0>(en); }
constexpr bool IsMounted() const { return this->GetStatusBit<1>(); }
constexpr void SetMounted(bool en) { this->SetStatusBit<1>(en); }
constexpr bool IsDiskInserted() const { return this->GetStatusBit<2>(); }
constexpr void SetDiskInserted(bool en) { this->SetStatusBit<2>(en); }
constexpr bool IsFlag12() const { return this->GetStatusBit<12>(); }
constexpr void SetFlag12(bool en) { this->SetStatusBit<12>(en); }
};
using TailBuf = u32;
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
#include <vapours/results.hpp>
#include <vapours/util.hpp>
#include <vapours/svc.hpp>
#include <vapours/dd.hpp>
#if defined(ATMOSPHERE_IS_EXOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
//#define AMS_PRFILE2_THREAD_SAFE
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
//#define AMS_PRFILE2_THREAD_SAFE
#elif defined(ATMOSPHERE_IS_STRATOSPHERE)
#define AMS_PRFILE2_THREAD_SAFE
#else
#error "Unknown execution context for ams::prfile2!"
#endif

View File

@@ -1,52 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2 {
constexpr inline const auto MinimumFatBufferSize = 1;
constexpr inline const auto MaximumFatBufferSize = (1 << 16) - 1;
constexpr inline const auto MinimumDataBufferSize = 1;
constexpr inline const auto MaximumDataBufferSize = (1 << 15) - 1;
constexpr inline const auto MinimumFatPages = 1;
constexpr inline const auto MinimumDataPages = 4;
struct SectorCache {
u32 mode;
u16 num_fat_pages;
u16 num_data_pages;
pf::CachePage *pages;
pf::CachePage *current_fat;
pf::CachePage *current_data;
pf::SectorBuffer *buffers;
u32 fat_buf_size;
u32 data_buf_size;
void *signature;
};
struct Volume;
}
namespace ams::prfile2::cache {
void SetCache(Volume *vol, pf::CachePage *cache_page, pf::SectorBuffer *cache_buf, u16 num_fat_pages, u16 num_data_pages);
void SetFatBufferSize(Volume *vol, u32 size);
void SetDataBufferSize(Volume *vol, u32 size);
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_build_config.hpp>
#include <vapours/prfile2/pf/prfile2_pf_config.hpp>
#include <vapours/prfile2/pf/prfile2_pf_api_common.hpp>
#include <vapours/prfile2/prfile2_wide_string.hpp>
namespace ams::prfile2 {
constexpr inline const auto MaximumOpenFileCountSystem = pf::MaximumFileCount;
constexpr inline const auto MaximumOpenFileCountUser = pf::MaximumFileCount;
constexpr inline const auto MaximumOpenDirectoryCountSystem = pf::MaximumDirectoryCount;
constexpr inline const auto MaximumOpenDirectoryCountUser = pf::MaximumDirectoryCount;
enum Error {
Error_NoError = 0,
Error_Ok = Error_NoError,
Error_EPERM = 1,
Error_ENOENT = 2,
Error_ESRCH = 3,
Error_EIO = 5,
Error_ENOEXEC = 8,
Error_EBADF = 9,
Error_ENOMEM = 12,
Error_EACCES = 13,
Error_EBUSY = 16,
Error_EEXIST = 17,
Error_ENODEV = 19,
Error_EISDIR = 21,
Error_EINVAL = 22,
Error_ENFILE = 23,
Error_EMFILE = 24,
Error_EFBIG = 27,
Error_ENOSPC = 28,
Error_ENOLCK = 46,
Error_ENOSYS = 88,
Error_ENOTEMPTY = 90,
Error_EMOD_NOTREG = 100,
Error_EMOD_NOTSPRT = 101,
Error_EMOD_FCS = 102,
Error_EMOD_SAFE = 103,
Error_ENOMEDIUM = 123,
Error_EEXFAT_NOTSPRT = 200,
Error_DFNC = 0x1000,
Error_SYSTEM = -1,
};
constexpr inline const u32 InvalidSector = std::numeric_limits<u32>::max();
constexpr inline const u32 InvalidCluster = std::numeric_limits<u32>::max();
enum OpenMode {
OpenMode_None = 0,
OpenMode_Write = (1u << 0),
OpenMode_Read = (1u << 1),
OpenMode_Append = (1u << 2),
OpenMode_Plus = (1u << 3),
OpenMode_NoOverwrite = (1u << 4),
OpenMode_V = (1u << 5),
OpenMode_ContCluster = (1u << 6),
};
enum FatFormat {
FatFormat_Fat12 = 0,
FatFormat_Fat16 = 1,
FatFormat_Fat32 = 2,
FatFormat_ExFat = 3,
FatFormat_Invalid = -1,
};
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/pf/prfile2_pf_config.hpp>
namespace ams::prfile2 {
struct CriticalSection {
enum State {
State_NotInitialized = 0,
State_Initialized = 1,
};
struct Resource;
u8 state;
int lock_count;
Resource *resource;
u64 owner;
};
void InitializeCriticalSection(CriticalSection *cs);
void FinalizeCriticalSection(CriticalSection *cs);
void EnterCriticalSection(CriticalSection *cs);
void ExitCriticalSection(CriticalSection *cs);
class ScopedCriticalSection {
private:
CriticalSection *cs;
public:
ALWAYS_INLINE ScopedCriticalSection(CriticalSection *c) : cs(c) { EnterCriticalSection(this->cs); }
ALWAYS_INLINE ScopedCriticalSection(CriticalSection &c) : ScopedCriticalSection(std::addressof(c)) { /* ... */ }
ALWAYS_INLINE ~ScopedCriticalSection() { ExitCriticalSection(this->cs); }
};
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2 {
struct Volume;
}
namespace ams::prfile2::drv {
pf::Error Initialize(Volume *volume);
bool IsDetected(Volume *volume);
bool IsInserted(Volume *volume);
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2 {
constexpr inline const auto LongNamePathCharacters = 260;
struct Volume;
struct DirectoryEntry {
u16 long_name[LongNamePathCharacters];
u32 attr;
u64 file_size;
u8 create_time_ms;
u16 create_time;
u16 create_date;
u8 create_flags;
u8 access_time_ms;
u16 access_time;
u16 access_date;
u8 access_flags;
u8 modify_time_ms;
u16 modify_time;
u16 modify_date;
u8 modify_flags;
Volume *volume;
u32 path_len;
u32 start_cluster;
u32 entry_sector;
u16 entry_offset;
/* ... */
u8 num_entry_lfns;
u8 ordinal;
u8 check_sum;
char short_name[13];
u8 small_letter_flag;
/* ... */
u16 full_path[LongNamePathCharacters];
};
struct DirectoryTail {
u32 tracker_size;
pf::TailBuf tracker_buf[1];
u32 *tracker_bits;
};
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2 {
struct FatHint {
u32 chain_index;
u32 cluster;
};
using LastAccess = FatHint;
struct LastCluster {
u32 num_last_cluster;
u32 max_chain_index;
};
struct ClusterLinkForVolume {
u16 flag;
u16 interval;
u32 *buffer;
u32 link_max;
};
using ClusterBuf = u32;
struct ClusterLink {
u64 position;
ClusterBuf *buffer;
u16 interval;
u16 interval_offset;
u32 save_index;
u32 max_count;
};
struct Volume;
struct FatFileDescriptor {
u32 start_cluster;
u32 *p_start_cluster;
LastCluster last_cluster;
LastAccess last_access;
ClusterLink cluster_link;
FatHint *hint;
Volume *volume;
/* ... */
};
}

View File

@@ -1,23 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2::fatfs {
pf::Error Initialize(u32 config, void *param);
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_build_config.hpp>
namespace ams::prfile2 {
using HandleType = util::BitPack32;
struct HandleField {
using Id = util::BitPack32::Field< 0, 8>;
using Kind = util::BitPack32::Field< 8, 8>;
using Signature = util::BitPack32::Field<16, 16>;
};
enum HandleKind {
HandleKind_Disk = 3,
HandleKind_Partition = 4,
};
constexpr ALWAYS_INLINE HandleType ConstructHandle(u8 id, HandleKind kind, u16 signature) {
/* Construct the handle. */
HandleType val = {};
val.Set<HandleField::Id>(id);
val.Set<HandleField::Kind>(kind);
val.Set<HandleField::Signature>(signature);
return val;
};
constexpr ALWAYS_INLINE u8 GetHandleId(HandleType handle) {
return handle.Get<HandleField::Id>();
}
constexpr ALWAYS_INLINE u16 GetHandleSignature(HandleType handle) {
return handle.Get<HandleField::Signature>();
}
constexpr inline const HandleType InvalidHandle = {};
constexpr ALWAYS_INLINE bool IsInvalidHandle(HandleType handle) {
return handle.value == 0;
}
static_assert(IsInvalidHandle(InvalidHandle));
constexpr ALWAYS_INLINE HandleType ConstructDiskHandle(u8 id, u16 signature) { return ConstructHandle(id, HandleKind_Disk, signature); }
constexpr ALWAYS_INLINE HandleType ConstructPartitionHandle(u8 id, u16 signature) { return ConstructHandle(id, HandleKind_Partition, signature); }
constexpr ALWAYS_INLINE bool IsDiskHandle(HandleType handle) { return handle.Get<HandleField::Kind>() == HandleKind_Disk; }
constexpr ALWAYS_INLINE bool IsPartitionHandle(HandleType handle) { return handle.Get<HandleField::Kind>() == HandleKind_Partition; }
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2::str {
enum CodeMode {
CodeMode_Invalid = 0,
CodeMode_Local = 1,
CodeMode_Unicode = 2,
};
enum TargetString {
TargetString_Head = 1,
TargetString_Tail = 2,
};
struct String {
const char *head;
const char *tail;
CodeMode code_mode;
};
pf::Error Initialize(String *str, const char *s, CodeMode code_mode);
void SetCodeMode(String *str, CodeMode code_mode);
CodeMode GetCodeMode(const String *str);
char *GetPos(String *str, TargetString target);
void MovePos(String *str, s16 num_char);
u16 GetLength(String *str);
u16 GetNumChar(String *str, TargetString target);
int Compare(const String *str, const char *rhs);
int Compare(const String *str, const WideChar *rhs);
/* TODO: StrNCmp */
/* TODO: ToUpperNStr */
constexpr bool IsNull(const String *str) {
return str->head == nullptr;
}
}
namespace ams::prfile2 {
using String = str::String;
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2::system {
void Initialize();
int GetCurrentContextId(u64 *out);
}

View File

@@ -1,238 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
#include <vapours/prfile2/prfile2_cache.hpp>
#include <vapours/prfile2/prfile2_critical_section.hpp>
#include <vapours/prfile2/prfile2_drv.hpp>
#include <vapours/prfile2/prfile2_entry.hpp>
#include <vapours/prfile2/prfile2_fat.hpp>
namespace ams::prfile2 {
constexpr inline const auto MaxVolumes = 5;
struct Cursor {
u64 position;
u32 sector;
u32 file_sector_index;
u16 offset_in_sector;
};
struct DirectoryCursor {
u32 physical_entry_index;
u32 logical_entry_index;
u32 logical_seek_index;
};
struct File;
struct FileLock {
u16 mode;
u16 count;
u16 waiting_count;
File *owner;
u32 resource;
};
struct SystemFileDescriptor {
u32 status;
FatFileDescriptor ffd;
DirectoryEntry dir_entry;
FileLock lock;
u16 num_handlers;
SystemFileDescriptor *next_sfd;
};
struct SystemDirectoryDescriptor {
u32 status;
u16 num_handlers;
FatFileDescriptor ffd;
DirectoryEntry dir_entry;
/* ... */
u64 context_id;
/* ... */
};
struct File {
u32 status;
/* TODO OpenMode */ u32 open_mode;
SystemFileDescriptor *sfd;
FatHint hint;
LastAccess last_access;
pf::Error last_error;
Cursor cursor;
u16 lock_count;
};
struct Directory {
u32 stat;
SystemDirectoryDescriptor *sdd;
FatHint hint;
DirectoryCursor cursor;
/* ... */
};
struct BiosParameterBlock {
u16 bytes_per_sector;
u32 num_reserved_sectors;
u16 num_root_dir_entries;
u32 sectors_per_cluster;
u8 num_fats;
u32 total_sectors;
u32 sectors_per_fat;
u32 root_dir_cluster;
u16 fs_info_sector;
u16 backup_boot_sector;
u16 ext_flags;
u16 ext_flags_;
u8 media;
FatFormat fat_fmt;
u8 log2_bytes_per_sector;
u8 log2_sectors_per_cluster;
u8 num_active_fats;
u8 num_active_fats_;
u16 num_root_dir_sectors;
u32 active_fat_sector;
u32 active_fat_sector_;
u32 first_root_dir_sector;
u32 first_data_sector;
u32 num_clusters;
/* ... */
};
using VolumeCallback = void (*)();
struct VolumeContext {
u64 context_id;
u32 volume_id;
DirectoryEntry dir_entries[MaxVolumes];
pf::Error last_error;
pf::Error last_driver_error[MaxVolumes];
pf::Error last_unk_error[MaxVolumes];
/* ... */
VolumeContext *next_used_context;
union {
VolumeContext *prev_used_context;
VolumeContext *next_free_context;
};
};
namespace pdm {
struct Partition;
}
struct Volume {
BiosParameterBlock bpb;
u32 num_free_clusters;
u32 num_free_clusters_;
u32 last_free_cluster;
u32 last_free_cluster_;
SystemFileDescriptor sfds[MaximumOpenFileCountSystem];
File ufds[MaximumOpenFileCountUser];
SystemDirectoryDescriptor sdds[MaximumOpenDirectoryCountSystem];
Directory udds[MaximumOpenDirectoryCountUser];
u32 num_open_files;
u32 num_open_directories;
/* ... */
SectorCache cache;
VolumeContext *context;
u64 context_id;
DirectoryTail tail_entry;
u32 volume_config;
u32 file_config;
u32 flags;
pf::DriveCharacter drive_char;
CriticalSection critical_section;
u16 fsi_flag;
ClusterLinkForVolume cluster_link;
pf::Error last_error;
pf::Error last_driver_error;
/* ... */
HandleType partition_handle;
VolumeCallback callback;
const u8 *format_param;
/* ... */
/* TODO: ExtensionTable extension_table; */
/* TODO: ExtensionData ext; */
/* ... */
template<size_t Ix>
constexpr ALWAYS_INLINE bool GetFlagsBit() const {
constexpr u32 Mask = (1u << Ix);
return (this->flags & Mask) != 0;
}
template<size_t Ix>
constexpr ALWAYS_INLINE void SetFlagsBit(bool en) {
constexpr u32 Mask = (1u << Ix);
if (en) {
this->flags |= Mask;
} else {
this->flags &= ~Mask;
}
}
constexpr bool IsAttached() const { return this->GetFlagsBit<0>(); }
constexpr void SetAttached(bool en) { this->SetFlagsBit<0>(en); }
constexpr bool IsMounted() const { return this->GetFlagsBit<1>(); }
constexpr void SetMounted(bool en) { this->SetFlagsBit<1>(en); }
constexpr bool IsFormatAfterMountRequested() const { return this->GetFlagsBit<4>(); }
constexpr void SetFormatAfterMountRequested(bool en) { this->SetFlagsBit<4>(en); }
constexpr bool IsNoFormattingByFatFsLayer() const { return this->GetFlagsBit<5>(); }
constexpr void SetNoFormattingByFatFsLayer(bool en) { this->SetFlagsBit<5>(en); }
constexpr bool IsDataEraseRequested() const { return this->GetFlagsBit<6>(); }
constexpr void SetDataEraseRequested(bool en) { this->SetFlagsBit<6>(en); }
constexpr bool IsFlag12() const { return this->GetFlagsBit<12>(); }
constexpr void SetFlag12(bool en) { this->SetFlagsBit<12>(en); }
};
struct VolumeSet {
bool initialized;
u32 num_attached_drives;
u32 num_mounted_volumes;
u32 config;
void *param;
/* TODO: CodeSet codeset; */
u32 setting;
CriticalSection critical_section;
VolumeContext default_context;
VolumeContext contexts[MaxVolumes];
VolumeContext *used_context_head;
VolumeContext *used_context_tail;
VolumeContext *free_context_head;
Volume volumes[MaxVolumes];
};
}
namespace ams::prfile2::vol {
pf::Error Initialize(u32 config, void *param);
pf::Error Attach(pf::DriveTable *drive_table);
VolumeContext *RegisterContext(u64 *out_context_id);
pf::Error UnregisterContext();
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/prfile2/prfile2_common.hpp>
namespace ams::prfile2 {
using WideChar = u16;
size_t w_strlen(const WideChar *s);
size_t w_strnlen(const WideChar *s, size_t length);
WideChar *w_strcpy(WideChar *dst, const WideChar *src);
WideChar *w_strncpy(WideChar *dst, const WideChar *src, size_t length);
int w_strcmp(const WideChar *lhs, const WideChar *rhs);
int w_strncmp(const WideChar *lhs, const WideChar *rhs, size_t length);
}

View File

@@ -17,7 +17,6 @@
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
#include <vapours/util/util_type_traits.hpp>
#include <chrono>
namespace ams {
@@ -55,7 +54,6 @@ namespace ams {
constexpr ALWAYS_INLINE friend TimeSpanType operator+(const TimeSpanType &lhs, const TimeSpanType &rhs) { TimeSpanType r(lhs); return r += rhs; }
constexpr ALWAYS_INLINE friend TimeSpanType operator-(const TimeSpanType &lhs, const TimeSpanType &rhs) { TimeSpanType r(lhs); return r -= rhs; }
};
static_assert(util::is_pod<TimeSpanType>::value);
class TimeSpan {
private:

View File

@@ -75,14 +75,6 @@ namespace ams::util {
this->value &= ~FieldMask;
this->value |= (static_cast<IntegralStorageType>(field_value) << FieldType::Index) & FieldMask;
}
constexpr ALWAYS_INLINE bool operator==(const BitPack &rhs) {
return this->value == rhs.value;
}
constexpr ALWAYS_INLINE bool operator!=(const BitPack &rhs) {
return !(*this == rhs);
}
};
}

View File

@@ -31,7 +31,7 @@ namespace ams::util {
}
template<typename T>
constexpr int Strncmp(const T *lhs, const T *rhs, int count) {
int Strncmp(const T *lhs, const T *rhs, int count) {
AMS_ASSERT(lhs != nullptr);
AMS_ASSERT(rhs != nullptr);
AMS_ABORT_UNLESS(count >= 0);
@@ -50,7 +50,7 @@ namespace ams::util {
}
template<typename T>
constexpr int Strnicmp(const T *lhs, const T *rhs, int count) {
int Strnicmp(const T *lhs, const T *rhs, int count) {
AMS_ASSERT(lhs != nullptr);
AMS_ASSERT(rhs != nullptr);
AMS_ABORT_UNLESS(count >= 0);

View File

@@ -1,90 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_pdm_disk_set.hpp"
namespace ams::prfile2::pdm {
namespace impl {
constinit DiskSet g_disk_set;
}
pdm::Error Initialize(u32 config, void *param) {
AMS_UNUSED(config, param);
/* Clear the disk set. */
std::memset(std::addressof(impl::g_disk_set), 0, sizeof(impl::g_disk_set));
return pdm::Error_Ok;
}
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out) {
/* Check the arguments. */
if (out == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Set the output as invalid. */
*out = InvalidHandle;
/* Open the disk. */
return disk::OpenDisk(init_disk_table, out);
}
pdm::Error CloseDisk(HandleType handle) {
/* Check the input. */
if (IsInvalidHandle(handle)) {
return pdm::Error_InvalidParameter;
}
/* Close the disk. */
return disk::CloseDisk(handle);
}
pdm::Error OpenPartition(HandleType disk_handle, u16 part_id, HandleType *out) {
/* Check the arguments. */
if (out == nullptr || IsInvalidHandle(disk_handle)) {
return pdm::Error_InvalidParameter;
}
/* Set the output as invalid. */
*out = InvalidHandle;
/* Open the partition. */
return part::OpenPartition(disk_handle, part_id, out);
}
pdm::Error ClosePartition(HandleType handle) {
/* Check the input. */
if (IsInvalidHandle(handle)) {
return pdm::Error_InvalidParameter;
}
/* Close the partition. */
return part::ClosePartition(handle);
}
}

View File

@@ -1,148 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_pdm_disk_set.hpp"
namespace ams::prfile2::pdm::disk {
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out) {
/* Check the arguments. */
if (out == nullptr || init_disk_table == nullptr || init_disk_table->function == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Find a free disk holder. */
DiskHolder *holder = nullptr;
for (auto &h : impl::g_disk_set.disk_holders) {
if (h.disk == nullptr) {
holder = std::addressof(h);
break;
}
}
if (holder == nullptr) {
return pdm::Error_NotExistFreeDiskStruct;
}
/* Find a free disk. */
Disk *disk = nullptr;
for (auto &d : impl::g_disk_set.disks) {
if (!d.IsOpen()) {
disk = std::addressof(d);
break;
}
}
if (disk == nullptr) {
return pdm::Error_NotExistFreeDiskStruct;
}
const auto disk_id = disk - impl::g_disk_set.disks;
/* Call the disk initialze function. */
init_disk_table->function(std::addressof(disk->disk_table), init_disk_table->ui_ext);
/* Set the disk as open .*/
disk->SetOpen(true);
/* Set the init disk table. */
disk->init_disk_table = init_disk_table;
/* Note the opened disk. */
++impl::g_disk_set.num_allocated_disks;
/* Increment the disk's signature. */
disk->signature = static_cast<u16>(disk->signature + 1);
/* Increment the disk's open count. */
++disk->open_count;
/* Set the disk in the holder. */
holder->signature = disk->signature;
holder->disk = disk;
/* Set the output handle. */
*out = ConstructDiskHandle(disk_id, disk->signature);
/* If this was the first opening for the disk, initialize it. */
if (disk->open_count == 1) {
if (auto err = disk->disk_table.function_table->initialize(*out); err != pdm::Error_Ok) {
/* Close the disk. */
--disk->open_count;
disk->SetOpen(false);
--impl::g_disk_set.num_allocated_disks;
/* Reset the holder. */
holder->disk = nullptr;
return pdm::Error_DriverError;
}
}
return pdm::Error_Ok;
}
pdm::Error CloseDisk(HandleType handle) {
/* Get the disk. */
Disk *disk = GetDisk(handle);
if (disk == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Check that the disk is open and unlocked. */
if (!disk->IsOpen()) {
return pdm::Error_StateClosed;
}
if (disk->IsLocked()) {
return pdm::Error_StateLocked;
}
/* Get the disk holder. */
DiskHolder *holder = GetDiskHolder(handle);
if (holder == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Close the disk. */
if (disk->open_count == 1) {
/* Finalize the disk. */
if (auto err = disk->disk_table.function_table->finalize(handle); err != pdm::Error_Ok) {
if (auto part = disk->current_partition_handle; part != InvalidHandle) {
part::SetDriverErrorCode(part, err);
}
return pdm::Error_DriverError;
}
/* Set the disk as closed. */
disk->SetOpen(false);
--impl::g_disk_set.num_allocated_disks;
/* Clear the disk holder. */
holder->disk = nullptr;
}
/* Decrement the disk's open count. */
--disk->open_count;
return pdm::Error_Ok;
}
}

View File

@@ -1,103 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::prfile2::pdm {
namespace impl {
extern DiskSet g_disk_set;
}
ALWAYS_INLINE Disk *GetDisk(HandleType handle) {
if (AMS_LIKELY(IsDiskHandle(handle))) {
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxDisks)) {
const auto signature = GetHandleSignature(handle);
Disk *disk = std::addressof(impl::g_disk_set.disks[id]);
for (const auto &holder : impl::g_disk_set.disk_holders) {
if (holder.disk == disk && holder.signature == signature) {
return disk;
}
}
}
}
return nullptr;
}
ALWAYS_INLINE Disk *GetDiskUnsafe(HandleType handle) {
return std::addressof(impl::g_disk_set.disks[GetHandleId(handle)]);
}
ALWAYS_INLINE DiskHolder *GetDiskHolder(HandleType handle) {
if (AMS_LIKELY(IsDiskHandle(handle))) {
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxDisks)) {
const auto signature = GetHandleSignature(handle);
Disk *disk = std::addressof(impl::g_disk_set.disks[id]);
for (auto &holder : impl::g_disk_set.disk_holders) {
if (holder.disk == disk && holder.signature == signature) {
return std::addressof(holder);
}
}
}
}
return nullptr;
}
ALWAYS_INLINE Partition *GetPartition(HandleType handle) {
if (AMS_LIKELY(IsPartitionHandle(handle))) {
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) {
const auto signature = GetHandleSignature(handle);
Partition *part = std::addressof(impl::g_disk_set.partitions[id]);
for (const auto &holder : impl::g_disk_set.partition_holders) {
if (holder.partition == part && holder.signature == signature) {
return part;
}
}
}
}
return nullptr;
}
ALWAYS_INLINE Partition *GetPartitionUnsafe(HandleType handle) {
return std::addressof(impl::g_disk_set.partitions[GetHandleId(handle)]);
}
ALWAYS_INLINE PartitionHolder *GetPartitionHolder(HandleType handle) {
if (AMS_LIKELY(IsPartitionHandle(handle))) {
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) {
const auto signature = GetHandleSignature(handle);
Partition *part = std::addressof(impl::g_disk_set.partitions[id]);
for (auto &holder : impl::g_disk_set.partition_holders) {
if (holder.partition == part && holder.signature == signature) {
return std::addressof(holder);
}
}
}
}
return nullptr;
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_pdm_disk_set.hpp"
namespace ams::prfile2::pdm::part {
pdm::Error OpenPartition(HandleType disk_handle, u16 partition_id, HandleType *out) {
/* Check the arguments. */
if (out == nullptr || disk_handle == InvalidHandle) {
return pdm::Error_InvalidParameter;
}
/* Find a free partition holder. */
PartitionHolder *holder = nullptr;
for (auto &h : impl::g_disk_set.partition_holders) {
if (h.partition == nullptr) {
holder = std::addressof(h);
break;
}
}
if (holder == nullptr) {
return pdm::Error_NotExistFreePartitionStruct;
}
/* Locate a free (or matching) partition. */
Partition *part = nullptr;
bool found_matching = false;
for (auto &p : impl::g_disk_set.partitions) {
if (p.IsOpen()) {
if (p.disk_handle == disk_handle && p.partition_id == partition_id) {
part = std::addressof(p);
found_matching = true;
break;
}
} else {
if (part == nullptr) {
part = std::addressof(p);
}
}
}
if (part == nullptr) {
return pdm::Error_NotExistFreePartitionStruct;
}
const auto part_id = part - impl::g_disk_set.partitions;
/* If we're not working with a match, open the new partition. */
if (!found_matching) {
/* Set the partition as open. */
part->SetOpen(true);
/* Increment the number of open partitions. */
++impl::g_disk_set.num_partitions;
/* Set the partition's disk/id. */
part->disk_handle = disk_handle;
part->partition_id = partition_id;
}
/* Increment the partition's signature. */
part->signature = static_cast<u16>(part->signature + 1);
/* Increment the partition's open count. */
++part->open_count;
/* Set the holder. */
holder->signature = part->signature;
holder->partition = part;
/* Set the output handle. */
*out = ConstructPartitionHandle(part_id, part->signature);
return pdm::Error_Ok;
}
pdm::Error ClosePartition(HandleType part_handle) {
/* Get the partition. */
Partition *part = GetPartition(part_handle);
if (part == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Check that the partition is open and unlocked. */
if (!part->IsOpen()) {
return pdm::Error_StateClosed;
}
if (part->IsLocked()) {
return pdm::Error_StateLocked;
}
/* Get the partition holder. */
PartitionHolder *holder = GetPartitionHolder(part_handle);
if (holder == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Close the partition. */
if (part->open_count == 1) {
/* Set the partition as closed. */
part->SetOpen(false);
--impl::g_disk_set.num_partitions;
/* Clear the partition holder. */
holder->partition = nullptr;
}
/* Decrement the partition's open count. */
--part->open_count;
return pdm::Error_Ok;
}
void SetDriverErrorCode(HandleType part_handle, pdm::Error err) {
GetPartitionUnsafe(part_handle)->last_driver_error = err;
}
void CheckPartitionOpen(HandleType disk_handle, bool *out) {
/* TODO */
AMS_UNUSED(disk_handle, out);
AMS_ABORT("CheckPartitionOpen");
}
void NotifyMediaEvent(HandleType disk_handle, u32 event) {
/* TODO */
AMS_UNUSED(disk_handle, event);
AMS_ABORT("NotifyMediaEvent");
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_pdm_disk_set.hpp"
namespace ams::prfile2::pdm::disk {
pdm::Error CheckDataEraseRequest(HandleType disk_handle, bool *out) {
/* Check parameters. */
Disk *disk = GetDisk(disk_handle);
if (out == nullptr || disk == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Check for data erase function. */
*out = disk->erase_callback != nullptr;
return pdm::Error_Ok;
}
pdm::Error CheckMediaDetect(HandleType disk_handle, bool *out) {
/* Check parameters. */
Disk *disk = GetDisk(disk_handle);
if (out == nullptr || disk == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Default to no status change detected. */
*out = false;
/* Detect status change via disk nbc detect. */
volatile NonBlockingProtocolType nbc;
do {
do {
nbc = disk->nbc;
} while ((nbc & 1) != 0);
if (nbc != disk->nbc_detect) {
*out = true;
}
} while (nbc != disk->nbc);
return pdm::Error_Ok;
}
pdm::Error CheckMediaInsert(HandleType disk_handle, bool *out) {
/* Check parameters. */
Disk *disk = GetDisk(disk_handle);
if (out == nullptr || disk == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Get whether the disk is inserted. */
*out = disk->is_inserted;
return pdm::Error_Ok;
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_pdm_disk_set.hpp"
namespace ams::prfile2::pdm::part {
pdm::Error CheckDataEraseRequest(HandleType part_handle, bool *out) {
/* Check parameters. */
Partition *part = GetPartition(part_handle);
if (out == nullptr || part == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Check the disk. */
return pdm::disk::CheckDataEraseRequest(part->disk_handle, out);
}
pdm::Error CheckMediaDetect(HandleType part_handle, bool *out) {
/* Check parameters. */
Partition *part = GetPartition(part_handle);
if (out == nullptr || part == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Get the disk (unsafe/not checked). */
Disk *disk = GetDiskUnsafe(part->disk_handle);
/* Default to no status change detected. */
*out = false;
/* Detect status change via partition nbc detect. */
volatile NonBlockingProtocolType nbc;
do {
do {
nbc = disk->nbc;
} while ((nbc & 1) != 0);
if (nbc != part->nbc_detect) {
*out = true;
}
} while (nbc != disk->nbc);
return pdm::Error_Ok;
}
pdm::Error CheckMediaInsert(HandleType part_handle, bool *out) {
/* Check parameters. */
Partition *part = GetPartition(part_handle);
if (out == nullptr || part == nullptr) {
return pdm::Error_InvalidParameter;
}
/* Check if the disk is inserted. */
return pdm::disk::CheckMediaInsert(part->disk_handle, out);
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_pf_errnum.hpp"
namespace ams::prfile2::pf {
int Initialize(u32 config, void *param) {
/* Initialize the fatfs api. */
if (auto err = fatfs::Initialize(config, param)) {
return ConvertReturnValue(err);
}
/* Initialize the system api. */
system::Initialize();
return ConvertReturnValue(pf::Error_Ok);
}
int Attach(DriveTable **drive_tables) {
/* Check parameters. */
if (drive_tables == nullptr || *drive_tables == nullptr) {
return ConvertReturnValue(SetInternalErrorAndReturn(pf::Error_InvalidParameter));
}
/* Attach each volume in the list. */
for (auto *table = *drive_tables; table != nullptr; table = *(++drive_tables)) {
if (auto err = vol::Attach(table); err != pf::Error_Ok) {
/* Clear each unattached drive character. */
for (table = *drive_tables; table != nullptr; table = *(++drive_tables)) {
table->drive_char = 0;
}
return ConvertReturnValue(err);
}
}
return ConvertReturnValue(pf::Error_Ok);
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::prfile2::pf {
void SetInternalError(pf::Error err);
ALWAYS_INLINE pf::Error SetInternalErrorAndReturn(pf::Error err) {
SetInternalError(err);
return err;
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2::cache {
void SetCache(Volume *vol, pf::CachePage *cache_page, pf::SectorBuffer *cache_buf, u16 num_fat_pages, u16 num_data_pages) {
/* Set the cache fields. */
vol->cache.pages = cache_page;
vol->cache.buffers = cache_buf;
vol->cache.num_fat_pages = num_fat_pages;
vol->cache.num_data_pages = num_data_pages;
std::memset(vol->cache.pages, 0, sizeof(*vol->cache.pages) * (num_fat_pages + num_data_pages));
}
void SetFatBufferSize(Volume *vol, u32 size) {
if (size > 0) {
vol->cache.fat_buf_size = size;
}
}
void SetDataBufferSize(Volume *vol, u32 size) {
if (size > 0) {
vol->cache.data_buf_size = size;
}
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2 {
#if defined(AMS_PRFILE2_THREAD_SAFE)
struct CriticalSection::Resource {
os::MutexType mutex;
bool in_use;
};
namespace {
constexpr inline const auto NumCriticalSectionResources = MaxVolumes + 1;
constinit os::SdkMutex g_crit_resource_mutex;
constinit CriticalSection::Resource g_crit_resources[NumCriticalSectionResources];
CriticalSection::Resource *AllocateCriticalSectionResource() {
std::scoped_lock lk(g_crit_resource_mutex);
for (auto &resource : g_crit_resources) {
if (!resource.in_use) {
resource.in_use = true;
return std::addressof(resource);
}
}
AMS_ABORT("Failed to allocate critical section resource");
}
void AcquireCriticalSectionResource(CriticalSection::Resource *resource) {
return os::LockMutex(std::addressof(resource->mutex));
}
void ReleaseCriticalSectionResource(CriticalSection::Resource *resource) {
return os::UnlockMutex(std::addressof(resource->mutex));
}
}
void InitializeCriticalSection(CriticalSection *cs) {
/* Check pre-condition. */
AMS_ASSERT(cs->state == CriticalSection::State_NotInitialized);
/* Perform initialization. */
if (cs->state == CriticalSection::State_NotInitialized) {
cs->resource = AllocateCriticalSectionResource();
cs->owner = 0;
cs->state = CriticalSection::State_Initialized;
}
}
void FinalizeCriticalSection(CriticalSection *cs) {
/* Check pre-condition. */
AMS_ASSERT(cs->state == CriticalSection::State_Initialized);
/* TODO */
AMS_UNUSED(cs);
AMS_ABORT("prfile2::FinalizeCriticalSection");
}
void EnterCriticalSection(CriticalSection *cs) {
/* Check pre-condition. */
AMS_ASSERT(cs->state == CriticalSection::State_Initialized);
if (AMS_LIKELY(cs->lock_count == 0)) {
/* Acquire the lock .*/
AcquireCriticalSectionResource(cs->resource);
system::GetCurrentContextId(std::addressof(cs->owner));
} else {
/* Get the current context id. */
u64 current_context_id;
system::GetCurrentContextId(std::addressof(current_context_id));
/* If the lock isn't already held, acquire it. */
if (cs->owner != current_context_id) {
AcquireCriticalSectionResource(cs->resource);
cs->owner = current_context_id;
}
}
/* Increment the lock count. */
++cs->lock_count;
}
void ExitCriticalSection(CriticalSection *cs) {
/* Check pre-condition. */
AMS_ASSERT(cs->state == CriticalSection::State_Initialized);
/* Unlock. */
if ((--cs->lock_count) == 0) {
cs->owner = 0;
ReleaseCriticalSectionResource(cs->resource);
}
}
#else
void InitializeCriticalSection(CriticalSection *cs) {
AMS_UNUSED(cs);
}
void FinalizeCriticalSection(CriticalSection *cs) {
AMS_UNUSED(cs);
}
void EnterCriticalSection(CriticalSection *cs) {
AMS_UNUSED(cs);
}
void ExitCriticalSection(CriticalSection *cs) {
AMS_UNUSED(cs);
}
#endif
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2::drv {
pf::Error Initialize(Volume *volume) {
/* Check the volume. */
if (volume == nullptr) {
return pf::Error_InvalidParameter;
}
/* Check the data erase request. */
bool data_erase;
if (auto pdm_err = pdm::part::CheckDataEraseRequest(volume->partition_handle, std::addressof(data_erase)); pdm_err != pdm::Error_Ok) {
return pf::Error_Generic;
}
/* Set the data erase request flag. */
volume->SetDataEraseRequested(data_erase);
return pf::Error_Ok;
}
bool IsDetected(Volume *volume) {
/* Check detect status changed. */
/* NOTE: Error is not checked here. */
bool detected = false;
pdm::part::CheckMediaDetect(volume->partition_handle, std::addressof(detected));
return detected;
}
bool IsInserted(Volume *volume) {
/* Check inserted. */
/* NOTE: Error is not checked here. */
bool inserted = false;
pdm::part::CheckMediaInsert(volume->partition_handle, std::addressof(inserted));
return inserted;
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2::fatfs {
pf::Error Initialize(u32 config, void *param) {
return vol::Initialize(config, param);
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2::str {
namespace {
/* TODO: Where does this come from? */
/* It's maximum path length * 2, but where should the definition live? */
constexpr inline size_t StringLengthMax = 520;
}
pf::Error Initialize(String *str, const char *s, CodeMode code_mode) {
/* Check parameters. */
if (str == nullptr || s == nullptr) {
return pf::Error_InvalidParameter;
}
/* Initialize the string. */
switch (code_mode) {
case CodeMode_Local:
{
str->head = s;
str->tail = s + sizeof(char) * strnlen(s, StringLengthMax);
}
break;
case CodeMode_Unicode:
{
str->head = s;
str->tail = s + sizeof(WideChar) * w_strnlen(reinterpret_cast<const WideChar *>(s), StringLengthMax);
}
break;
default:
return pf::Error_InvalidParameter;
}
/* Set the code mode. */
str->code_mode = code_mode;
return pf::Error_Ok;
}
void SetCodeMode(String *str, CodeMode code_mode) {
str->code_mode = code_mode;
}
CodeMode GetCodeMode(const String *str) {
return str->code_mode;
}
char *GetPos(String *str, TargetString target) {
if (target == TargetString_Head) {
return const_cast<char *>(str->head);
} else {
return const_cast<char *>(str->tail);
}
}
void MovePos(String *str, s16 num_char) {
AMS_UNUSED(str, num_char);
AMS_ABORT("TODO: oem charset");
}
u16 GetLength(String *str) {
if (str->code_mode == CodeMode_Unicode) {
return (str->tail - str->head) / sizeof(WideChar);
} else {
return (str->tail - str->head) / sizeof(char);
}
}
u16 GetNumChar(String *str, TargetString target) {
AMS_UNUSED(str, target);
AMS_ABORT("TODO: oem charset");
}
int Compare(const String *str, const char *rhs) {
AMS_UNUSED(str, rhs);
AMS_ABORT("TODO: oem charset");
}
int Compare(const String *str, const WideChar *rhs) {
AMS_UNUSED(str, rhs);
AMS_ABORT("TODO: oem charset");
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2::system {
void Initialize() {
/* ... */
}
int GetCurrentContextId(u64 *out) {
/* Check that out isn't null. */
if (out == nullptr) {
return -2;
}
/* Set the output. */
#if defined(AMS_PRFILE2_THREAD_SAFE)
*out = reinterpret_cast<u64>(os::GetCurrentThread());
#else
*out = 0;
#endif
return 0;
}
}

View File

@@ -1,433 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
#include "prfile2_volume_set.hpp"
namespace ams::prfile2::vol {
/* Global volume context object. */
constinit VolumeContext g_vol_set;
namespace {
constexpr inline u32 CharacterCheckDisable = 0x10000;
constexpr inline u32 CharacterCheckEnable = 0x20000;
constexpr inline u32 CharacterCheckMask = CharacterCheckDisable | CharacterCheckEnable;
constexpr inline u32 VolumeSetConfigMask = 0x5FFFFFFF;
VolumeContext *GetVolumeContextById(u64 context_id) {
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Acquire exclusive access to the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
/* Find a matching context. */
for (auto *ctx = vol_set.used_context_head; ctx != nullptr; ctx = ctx->next_used_context) {
if (ctx->context_id == context_id) {
return ctx;
}
}
return nullptr;
}
VolumeContext *GetCurrentVolumeContext(u64 *out_context_id) {
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Acquire exclusive access to the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
/* Get the current context id. */
u64 context_id = 0;
system::GetCurrentContextId(std::addressof(context_id));
if (out_context_id != nullptr) {
*out_context_id = context_id;
}
if (auto *ctx = GetVolumeContextById(context_id); ctx != nullptr) {
return ctx;
} else {
return std::addressof(vol_set.default_context);
}
}
bool IsValidDriveCharacter(pf::DriveCharacter drive_char) {
return static_cast<u8>((drive_char & 0xDF) - 'A') < 26;
}
Volume *GetVolumeByDriveCharacter(pf::DriveCharacter drive_char) {
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Calculate the volume index. */
const auto index = std::toupper(static_cast<unsigned char>(drive_char)) - 'A';
/* Acquire exclusive access to the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
if (index < MaxVolumes) {
return std::addressof(vol_set.volumes[index]);
} else {
return nullptr;
}
}
}
pf::Error Initialize(u32 config, void *param) {
/* Check the input config. */
if ((config & ~CharacterCheckMask) != 0) {
return pf::Error_InvalidParameter;
}
if ((config & CharacterCheckMask) == CharacterCheckMask) {
return pf::Error_InvalidParameter;
}
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Clear the default volume context. */
std::memset(std::addressof(vol_set.default_context), 0, sizeof(VolumeContext));
vol_set.default_context.volume_id = 0;
/* Setup the context lists. */
vol_set.used_context_head = nullptr;
vol_set.used_context_tail = nullptr;
vol_set.free_context_head = vol_set.contexts;
for (auto i = 0; i < MaxVolumes - 1; ++i) {
vol_set.contexts[i].next_free_context = std::addressof(vol_set.contexts[i + 1]);
}
vol_set.contexts[MaxVolumes - 1].next_free_context = nullptr;
/* Set the setting. */
vol_set.setting = 1;
/* Set the config. */
if ((config & CharacterCheckEnable) != 0) {
vol_set.config |= CharacterCheckDisable;
} else {
vol_set.config &= ~CharacterCheckDisable;
}
vol_set.config &= VolumeSetConfigMask;
/* Clear number of attached drives/volumes. */
vol_set.num_attached_drives = 0;
vol_set.num_mounted_volumes = 0;
/* Set the parameter. */
vol_set.param = param;
/* Set the codeset. */
/* TODO */
/* Clear the volumes. */
for (auto &volume : vol_set.volumes) {
std::memset(std::addressof(volume), 0, sizeof(volume));
}
/* Initialize the volume set critical section. */
InitializeCriticalSection(std::addressof(vol_set.critical_section));
/* NOTE: Here "InitLockFile()" is called, but this doesn't seem used so far. TODO: Add if used? */
/* Mark initialized. */
vol_set.initialized = true;
return pf::Error_Ok;
}
pf::Error Attach(pf::DriveTable *drive_table) {
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Get the volume context for error tracking. */
u64 context_id = 0;
auto *vol_ctx = GetCurrentVolumeContext(std::addressof(context_id));
auto SetLastErrorAndReturn = [&] ALWAYS_INLINE_LAMBDA (pf::Error err) -> pf::Error { vol_ctx->last_error = err; return err; };
/* Check the drive table. */
if (drive_table == nullptr) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
/* Clear the drive table's character/status. */
const auto drive_char = drive_table->drive_char;
drive_table->drive_char = 0;
drive_table->status = 0;
/* Check that we can attach. */
if (vol_set.num_attached_drives >= MaxVolumes) {
return SetLastErrorAndReturn(pf::Error_TooManyVolumesAttached);
}
/* Check the cache setting. */
auto *cache_setting = drive_table->cache;
if (cache_setting == nullptr) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (cache_setting->fat_buf_size > MaximumFatBufferSize) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (cache_setting->data_buf_size > MaximumDataBufferSize) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (cache_setting->num_fat_pages < MinimumFatPages) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (cache_setting->num_data_pages < MinimumDataPages) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (cache_setting->pages == nullptr) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (cache_setting->buffers == nullptr) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (!util::IsAligned(reinterpret_cast<uintptr_t>(cache_setting->pages), alignof(u32))) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (!util::IsAligned(reinterpret_cast<uintptr_t>(cache_setting->buffers), alignof(u32))) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
/* Adjust the cache setting. */
cache_setting->fat_buf_size = std::max<u32>(cache_setting->fat_buf_size, MinimumFatBufferSize);
cache_setting->data_buf_size = std::max<u32>(cache_setting->data_buf_size, MinimumDataBufferSize);
/* Check the adjusted setting. */
if (cache_setting->fat_buf_size > cache_setting->num_fat_pages) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if ((cache_setting->num_data_pages / cache_setting->data_buf_size) < MinimumDataPages) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
/* Validate the drive character. */
if (drive_char != 0) {
if (!IsValidDriveCharacter(drive_char)) {
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
}
if (auto *vol = GetVolumeByDriveCharacter(drive_char); vol == nullptr || vol->IsAttached()) {
return SetLastErrorAndReturn(pf::Error_InvalidVolumeLabel);
}
}
/* Perform the bulk of the attach. */
Volume *vol = nullptr;
{
/* Lock the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
/* Find a free volume. */
for (auto &v : vol_set.volumes) {
if (!v.IsAttached()) {
vol = std::addressof(v);
break;
}
}
if (vol == nullptr) {
return SetLastErrorAndReturn(pf::Error_TooManyVolumesAttached);
}
const auto vol_id = vol - vol_set.volumes;
/* Clear the volume. */
std::memset(vol, 0, sizeof(*vol));
/* Initialize the volume. */
vol->num_free_clusters = InvalidCluster;
vol->num_free_clusters_ = InvalidCluster;
vol->last_free_cluster = InvalidCluster;
vol->partition_handle = drive_table->partition_handle;
InitializeCriticalSection(std::addressof(vol->critical_section));
vol->drive_char = 'A' + vol_id;
/* Setup directory tail. */
vol->tail_entry.tracker_size = util::size(vol->tail_entry.tracker_buf);
vol->tail_entry.tracker_bits = vol->tail_entry.tracker_buf;
/* NOTE: Cluster link is cleared here, but we already memset vol to zero, so it's unnecessary. */
/* Initialize driver for volume. */
if (auto err = drv::Initialize(vol); err != pf::Error_Ok) {
return SetLastErrorAndReturn(err);
}
/* Setup the cache. */
cache::SetCache(vol, drive_table->cache->pages, drive_table->cache->buffers, drive_table->cache->num_fat_pages, drive_table->cache->num_data_pages);
cache::SetFatBufferSize(vol, drive_table->cache->fat_buf_size);
cache::SetDataBufferSize(vol, drive_table->cache->data_buf_size);
/* Set flags. */
vol->SetAttached(true);
vol->SetFlag12(true);
/* Update the drive table. */
drive_table->SetAttached(true);
drive_table->drive_char = vol->drive_char;
/* Update the number of attached drives. */
if ((vol_set.num_attached_drives++) == 0) {
vol_set.default_context.volume_id = vol_id;
}
}
/* Acquire exclusive access to the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
/* Associate the volume to our context while we operate on it. */
vol->context = vol_ctx;
vol->context_id = context_id;
ON_SCOPE_EXIT { vol->context_id = 0; };
/* TODO: Copy volume root dir entry to all contexts. */
/* TODO: Clear tracking fields at the end of the volume. */
/* Perform mount as appropriate. */
const auto check_mount_err = /* TODO vol::CheckMediaInsertForAttachMount(vol) */ pf::Error_Ok;
const bool inserted = drv::IsInserted(vol);
if (check_mount_err != pf::Error_Ok) {
if (inserted) {
drive_table->SetDiskInserted(true);
}
vol_ctx->last_error = check_mount_err;
} else if (inserted) {
drive_table->SetDiskInserted(true);
if (auto mount_err = /* TODO vol::MountImpl(vol, 0x1B, false) */pf::Error_InternalError; mount_err != pf::Error_Ok) {
vol_ctx->last_error = mount_err;
} else {
drive_table->SetMounted(true);
}
}
return pf::Error_Ok;
}
VolumeContext *RegisterContext(u64 *out_context_id) {
/* Get the current context id. */
u64 context_id = 0;
system::GetCurrentContextId(std::addressof(context_id));
if (out_context_id != nullptr) {
*out_context_id = context_id;
}
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Acquire exclusive access to the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
/* Get the volume context by ID. If we already have a context, return it. */
if (VolumeContext *match = GetVolumeContextById(context_id); match != nullptr) {
return match;
}
/* Try to find a free context in the list. */
VolumeContext *ctx = vol_set.free_context_head;
if (ctx == nullptr) {
vol_set.default_context.last_error = pf::Error_InternalError;
return nullptr;
}
/* Update the free lists. */
vol_set.free_context_head = ctx->next_free_context;
if (VolumeContext *next = vol_set.used_context_head; next != nullptr) {
next->prev_used_context = ctx;
ctx->next_used_context = next;
ctx->prev_used_context = nullptr;
vol_set.used_context_head = ctx;
} else {
ctx->next_used_context = nullptr;
ctx->prev_used_context = nullptr;
vol_set.used_context_head = ctx;
vol_set.used_context_tail = ctx;
}
/* Set the context's fields. */
ctx->context_id = context_id;
ctx->last_error = pf::Error_Ok;
for (auto i = 0; i < MaxVolumes; ++i) {
ctx->last_driver_error[i] = pf::Error_Ok;
ctx->last_unk_error[i] = pf::Error_Ok;
}
/* Copy from the default context. */
const auto volume_id = vol_set.default_context.volume_id;
ctx->volume_id = volume_id;
ctx->dir_entries[volume_id] = vol_set.default_context.dir_entries[volume_id];
return ctx;
}
pf::Error UnregisterContext() {
/* Get the current context id. */
u64 context_id = 0;
system::GetCurrentContextId(std::addressof(context_id));
/* Get the volume set. */
auto &vol_set = GetVolumeSet();
/* Acquire exclusive access to the volume set. */
ScopedCriticalSection lk(vol_set.critical_section);
/* Get the volume context by ID. */
VolumeContext *ctx = GetVolumeContextById(context_id);
if (ctx == nullptr) {
vol_set.default_context.last_error = pf::Error_InternalError;
return pf::Error_InternalError;
}
/* Update the lists. */
auto *prev_used = ctx->prev_used_context;
auto *next_used = ctx->next_used_context;
if (prev_used != nullptr) {
if (next_used != nullptr) {
prev_used->next_used_context = next_used;
next_used->prev_used_context = prev_used;
} else {
prev_used->next_used_context = nullptr;
vol_set.used_context_tail = prev_used;
}
} else if (next_used != nullptr) {
next_used->prev_used_context = nullptr;
vol_set.used_context_head = next_used;
} else {
vol_set.used_context_head = nullptr;
vol_set.used_context_tail = nullptr;
}
ctx->next_used_context = nullptr;
ctx->next_free_context = vol_set.free_context_head;
vol_set.free_context_head = ctx;
return pf::Error_Ok;
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::prfile2 {
namespace impl {
extern VolumeSet g_vol_set;
}
ALWAYS_INLINE VolumeSet &GetVolumeSet() {
return impl::g_vol_set;
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
#include <stratosphere.hpp>
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
#include <mesosphere.hpp>
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
#include <exosphere.hpp>
#else
#include <vapours.hpp>
#endif
namespace ams::prfile2 {
size_t w_strlen(const WideChar *s) {
const WideChar *cur;
for (cur = s; *cur != 0; ++cur) {
/* ... */
}
return cur - s;
}
size_t w_strnlen(const WideChar *s, size_t length) {
const WideChar *cur;
for (cur = s; *cur != 0 && length != 0; ++cur, --length) {
/* ... */
}
return cur - s;
}
WideChar *w_strcpy(WideChar *dst, const WideChar *src) {
WideChar * const ret = dst;
while (true) {
const auto c = *(src++);
*(dst++) = c;
if (c == 0) {
break;
}
}
return ret;
}
WideChar *w_strncpy(WideChar *dst, const WideChar *src, size_t length) {
WideChar * const ret = dst;
while (length > 1) {
const auto c = *(src++);
*(dst++) = c;
if (c == 0) {
return ret;
}
}
if (length == 1) {
*(dst++) = 0;
}
return ret;
}
int w_strcmp(const WideChar *lhs, const WideChar *rhs) {
WideChar l, r;
while (true) {
l = *(lhs++);
r = *(rhs++);
if (l == 0 || r == 0 || l != r) {
break;
}
}
return l - r;
}
int w_strncmp(const WideChar *lhs, const WideChar *rhs, size_t length) {
if (length == 0) {
return 0;
}
WideChar l, r;
while (true) {
l = *(lhs++);
r = *(rhs++);
if (l == 0 || r == 0 || l != r) {
break;
}
if ((--length) == 0) {
return 0;
}
}
return l - r;
}
}

View File

@@ -47,36 +47,6 @@ namespace ams::mitm::fs {
return fsFsCreateFile(&g_sd_filesystem, path, size, option);
}
Result DeleteSdFile(const char *path) {
R_TRY(EnsureSdInitialized());
return fsFsDeleteFile(&g_sd_filesystem, path);
}
bool HasSdFile(const char *path) {
if (R_FAILED(EnsureSdInitialized())) {
return false;
}
FsDirEntryType type;
if (R_FAILED(fsFsGetEntryType(&g_sd_filesystem, path, &type))) {
return false;
}
return type == FsDirEntryType_File;
}
bool HasAtmosphereSdFile(const char *path) {
char fixed_path[ams::fs::EntryNameLengthMax + 1];
FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path);
return HasSdFile(fixed_path);
}
Result DeleteAtmosphereSdFile(const char *path) {
char fixed_path[ams::fs::EntryNameLengthMax + 1];
FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path);
return DeleteSdFile(fixed_path);
}
Result CreateAtmosphereSdFile(const char *path, s64 size, s32 option) {
char fixed_path[ams::fs::EntryNameLengthMax + 1];
FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path);

View File

@@ -22,7 +22,6 @@ namespace ams::mitm::fs {
void OpenGlobalSdCardFileSystem();
/* Utilities. */
Result DeleteAtmosphereSdFile(const char *path);
Result CreateSdFile(const char *path, s64 size, s32 option);
Result CreateAtmosphereSdFile(const char *path, s64 size, s32 option);
Result OpenSdFile(FsFile *out, const char *path, u32 mode);
@@ -31,9 +30,6 @@ namespace ams::mitm::fs {
Result OpenAtmosphereSdRomfsFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode);
Result OpenAtmosphereRomfsFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode, FsFileSystem *fs);
bool HasSdFile(const char *path);
bool HasAtmosphereSdFile(const char *path);
Result CreateSdDirectory(const char *path);
Result CreateAtmosphereSdDirectory(const char *path);
Result OpenSdDirectory(FsDir *out, const char *path, u32 mode);

View File

@@ -38,15 +38,20 @@ extern "C" {
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
void __libnx_exception_handler(ThreadExceptionDump *ctx);
void *__libnx_alloc(size_t size);
void *__libnx_aligned_alloc(size_t alignment, size_t size);
void __libnx_free(void *mem);
void *__libnx_thread_alloc(size_t size);
void __libnx_thread_free(void *mem);
}
namespace ams {
ncm::ProgramId CurrentProgramId = ncm::AtmosphereProgramId::Mitm;
namespace result {
bool CallFatalOnResultAssertion = false;
}
/* Override. */
void ExceptionHandler(FatalErrorContext *ctx) {
/* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */
@@ -105,28 +110,15 @@ void __appExit(void) {
fsExit();
}
void *__libnx_alloc(size_t size) {
AMS_ABORT("__libnx_alloc was called");
void *__libnx_thread_alloc(size_t size) {
AMS_ABORT("__libnx_thread_alloc was called");
}
void *__libnx_aligned_alloc(size_t alignment, size_t size) {
AMS_ABORT("__libnx_aligned_alloc was called");
}
void __libnx_free(void *mem) {
AMS_ABORT("__libnx_free was called");
void __libnx_thread_free(void *mem) {
AMS_ABORT("__libnx_thread_free was called");
}
int main(int argc, char **argv) {
/* Register "ams" port, use up its session. */
{
svc::Handle ams_port;
R_ABORT_UNLESS(svc::ManageNamedPort(std::addressof(ams_port), "ams", 1));
svc::Handle ams_session;
R_ABORT_UNLESS(svc::ConnectToNamedPort(std::addressof(ams_session), "ams"));
}
/* Launch all mitm modules in sequence. */
mitm::LaunchAllModules();

View File

@@ -22,7 +22,6 @@
#include "bpc_mitm/bpcmitm_module.hpp"
#include "bpc_mitm/bpc_ams_module.hpp"
#include "ns_mitm/nsmitm_module.hpp"
#include "dns_mitm/dnsmitm_module.hpp"
#include "sysupdater/sysupdater_module.hpp"
namespace ams::mitm {
@@ -35,7 +34,6 @@ namespace ams::mitm {
ModuleId_BpcMitm,
ModuleId_BpcAms,
ModuleId_NsMitm,
ModuleId_DnsMitm,
ModuleId_Sysupdater,
ModuleId_Count,
@@ -68,7 +66,6 @@ namespace ams::mitm {
GetModuleDefinition<bpc::MitmModule>(),
GetModuleDefinition<bpc_ams::MitmModule>(),
GetModuleDefinition<ns::MitmModule>(),
GetModuleDefinition<socket::resolver::MitmModule>(),
GetModuleDefinition<sysupdater::MitmModule>(),
};

View File

@@ -1,77 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../amsmitm_fs_utils.hpp"
#include "dnsmitm_debug.hpp"
namespace ams::mitm::socket::resolver {
namespace {
constinit os::SdkMutex g_log_mutex;
constinit bool g_log_enabled;
constinit ::FsFile g_log_file;
constinit s64 g_log_ofs;
constinit char g_log_buf[0x400];
}
void InitializeDebug(bool enable_log) {
{
std::scoped_lock lk(g_log_mutex);
g_log_enabled = enable_log;
if (g_log_enabled) {
/* Create the logs directory. */
mitm::fs::CreateAtmosphereSdDirectory("/logs");
/* Create the log file. */
mitm::fs::CreateAtmosphereSdFile("/logs/dns_mitm_debug.log", 0, ams::fs::CreateOption_None);
/* Open the log file. */
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(g_log_file), "/logs/dns_mitm_debug.log", ams::fs::OpenMode_ReadWrite | ams::fs::OpenMode_AllowAppend));
/* Get the current log offset. */
R_ABORT_UNLESS(::fsFileGetSize(std::addressof(g_log_file), std::addressof(g_log_ofs)));
}
}
/* Start a new log. */
LogDebug("\n---\n");
}
void LogDebug(const char *fmt, ...) {
std::scoped_lock lk(g_log_mutex);
if (g_log_enabled) {
int len = 0;
{
std::va_list vl;
va_start(vl, fmt);
len = util::VSNPrintf(g_log_buf, sizeof(g_log_buf), fmt, vl);
va_end(vl);
}
R_ABORT_UNLESS(::fsFileWrite(std::addressof(g_log_file), g_log_ofs, g_log_buf, len, FsWriteOption_Flush));
g_log_ofs += len;
}
}
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::mitm::socket::resolver {
void InitializeDebug(bool enable_log);
void LogDebug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
}

View File

@@ -1,399 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../amsmitm_fs_utils.hpp"
#include "dnsmitm_debug.hpp"
#include "dnsmitm_host_redirection.hpp"
#include "socket_allocator.hpp"
namespace ams::mitm::socket::resolver {
namespace {
/* https://github.com/clibs/wildcardcmp */
constexpr int wildcardcmp(const char *pattern, const char *string) {
const char *w = nullptr; /* last `*` */
const char *s = nullptr; /* last checked char */
/* malformed */
if (!pattern || !string) return 0;
/* loop 1 char at a time */
while (1) {
if (!*string) {
if (!*pattern) return 1;
if ('*' == *pattern) return 1;
if (!*s) return 0;
string = s++;
pattern = w;
continue;
} else {
if (*pattern != *string) {
if ('*' == *pattern) {
w = ++pattern;
s = string;
/* "*" -> "foobar" */
if (*pattern) continue;
return 1;
} else if (w) {
string++;
/* "*ooba*" -> "foobar" */
continue;
}
return 0;
}
}
string++;
pattern++;
}
return 1;
}
constexpr const char DefaultHostsFile[] =
"# Nintendo telemetry servers\n"
"127.0.0.1 receive-%.dg.srv.nintendo.net receive-%.er.srv.nintendo.net\n";
constinit os::SdkMutex g_redirection_lock;
std::vector<std::pair<std::string, ams::socket::InAddrT>> g_redirection_list;
void RemoveRedirection(const char *hostname) {
for (auto it = g_redirection_list.begin(); it != g_redirection_list.end(); ++it) {
if (std::strcmp(it->first.c_str(), hostname) == 0) {
g_redirection_list.erase(it);
break;
}
}
}
void AddRedirection(const char *hostname, ams::socket::InAddrT addr) {
RemoveRedirection(hostname);
g_redirection_list.emplace(g_redirection_list.begin(), std::string(hostname), addr);
}
constinit char g_specific_emummc_hosts_path[0x40] = {};
void ParseHostsFile(const char *file_data) {
/* Get the environment identifier from settings. */
const auto env = ams::nsd::impl::device::GetEnvironmentIdentifierFromSettings();
const auto env_len = std::strlen(env.value);
/* Parse the file. */
enum class State {
IgnoredLine,
BeginLine,
Ip1,
IpDot1,
Ip2,
IpDot2,
Ip3,
IpDot3,
Ip4,
WhiteSpace,
HostName,
};
ams::socket::InAddrT current_address;
char current_hostname[0x200];
u32 work;
State state = State::BeginLine;
for (const char *cur = file_data; *cur != '\x00'; ++cur) {
const char c = *cur;
switch (state) {
case State::IgnoredLine:
if (c == '\n') {
state = State::BeginLine;
}
break;
case State::BeginLine:
if (std::isdigit(static_cast<unsigned char>(c))) {
current_address = 0;
work = static_cast<u32>(c - '0');
state = State::Ip1;
} else if (c == '\n') {
state = State::BeginLine;
} else {
state = State::IgnoredLine;
}
break;
case State::Ip1:
if (std::isdigit(static_cast<unsigned char>(c))) {
work *= 10;
work += static_cast<u32>(c - '0');
} else if (c == '.') {
current_address |= (work & 0xFF) << 0;
work = 0;
state = State::IpDot1;
} else {
state = State::IgnoredLine;
}
break;
case State::IpDot1:
if (std::isdigit(static_cast<unsigned char>(c))) {
work = static_cast<u32>(c - '0');
state = State::Ip2;
} else {
state = State::IgnoredLine;
}
break;
case State::Ip2:
if (std::isdigit(static_cast<unsigned char>(c))) {
work *= 10;
work += static_cast<u32>(c - '0');
} else if (c == '.') {
current_address |= (work & 0xFF) << 8;
work = 0;
state = State::IpDot2;
} else {
state = State::IgnoredLine;
}
break;
case State::IpDot2:
if (std::isdigit(static_cast<unsigned char>(c))) {
work = static_cast<u32>(c - '0');
state = State::Ip3;
} else {
state = State::IgnoredLine;
}
break;
case State::Ip3:
if (std::isdigit(static_cast<unsigned char>(c))) {
work *= 10;
work += static_cast<u32>(c - '0');
} else if (c == '.') {
current_address |= (work & 0xFF) << 16;
work = 0;
state = State::IpDot3;
} else {
state = State::IgnoredLine;
}
break;
case State::IpDot3:
if (std::isdigit(static_cast<unsigned char>(c))) {
work = static_cast<u32>(c - '0');
state = State::Ip4;
} else {
state = State::IgnoredLine;
}
break;
case State::Ip4:
if (std::isdigit(static_cast<unsigned char>(c))) {
work *= 10;
work += static_cast<u32>(c - '0');
} else if (c == ' ' || c == '\t') {
current_address |= (work & 0xFF) << 24;
work = 0;
state = State::WhiteSpace;
} else {
state = State::IgnoredLine;
}
break;
case State::WhiteSpace:
if (c == '\n') {
state = State::BeginLine;
} else if (c != ' ' && c != '\r' && c != '\t') {
if (c == '%') {
std::memcpy(current_hostname, env.value, env_len);
work = env_len;
} else {
current_hostname[0] = c;
work = 1;
}
state = State::HostName;
}
break;
case State::HostName:
if (c == ' ' || c == '\r' || c == '\n' || c == '\t') {
AMS_ABORT_UNLESS(work < sizeof(current_hostname));
current_hostname[work] = '\x00';
AddRedirection(current_hostname, current_address);
work = 0;
if (c == '\n') {
state = State::BeginLine;
} else {
state = State::WhiteSpace;
}
} else if (c == '%') {
AMS_ABORT_UNLESS(work < sizeof(current_hostname) - env_len);
std::memcpy(current_hostname + work, env.value, env_len);
work += env_len;
} else {
AMS_ABORT_UNLESS(work < sizeof(current_hostname) - 1);
current_hostname[work++] = c;
}
}
}
if (state == State::HostName) {
AMS_ABORT_UNLESS(work < sizeof(current_hostname));
current_hostname[work] = '\x00';
AddRedirection(current_hostname, current_address);
}
}
void Log(::FsFile &f, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
void Log(::FsFile &f, const char *fmt, ...) {
char log_buf[0x100];
int len = 0;
{
std::va_list vl;
va_start(vl, fmt);
len = util::VSNPrintf(log_buf, sizeof(log_buf), fmt, vl);
va_end(vl);
}
s64 ofs;
R_ABORT_UNLESS(::fsFileGetSize(std::addressof(f), std::addressof(ofs)));
R_ABORT_UNLESS(::fsFileWrite(std::addressof(f), ofs, log_buf, len, FsWriteOption_Flush));
}
const char *SelectHostsFile(::FsFile &log_file) {
Log(log_file, "Selecting hosts file...\n");
const bool is_emummc = emummc::IsActive();
const u32 emummc_id = emummc::GetActiveId();
util::SNPrintf(g_specific_emummc_hosts_path, sizeof(g_specific_emummc_hosts_path), "/hosts/emummc_%04x.txt", emummc_id);
if (is_emummc) {
if (mitm::fs::HasAtmosphereSdFile(g_specific_emummc_hosts_path)) {
return g_specific_emummc_hosts_path;
}
Log(log_file, "Skipping %s because it does not exist...\n", g_specific_emummc_hosts_path);
if (mitm::fs::HasAtmosphereSdFile("/hosts/emummc.txt")) {
return "/hosts/emummc.txt";
}
Log(log_file, "Skipping %s because it does not exist...\n", "/hosts/emummc.txt");
} else {
if (mitm::fs::HasAtmosphereSdFile("/hosts/sysmmc.txt")) {
return "/hosts/sysmmc.txt";
}
Log(log_file, "Skipping %s because it does not exist...\n", "/hosts/sysmmc.txt");
}
return "/hosts/default.txt";
}
bool ShouldAddDefaultResolverRedirections() {
u8 en = 0;
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "add_defaults_to_dns_hosts") == sizeof(en)) {
return (en != 0);
}
return false;
}
}
void InitializeResolverRedirections() {
/* Get whether we should add defaults. */
const bool add_defaults = ShouldAddDefaultResolverRedirections();
/* Acquire exclusive access to the map. */
std::scoped_lock lk(g_redirection_lock);
/* Clear the redirections map. */
g_redirection_list.clear();
/* Open log file. */
::FsFile log_file;
mitm::fs::DeleteAtmosphereSdFile("/logs/dns_mitm_startup.log");
mitm::fs::CreateAtmosphereSdDirectory("/logs");
R_ABORT_UNLESS(mitm::fs::CreateAtmosphereSdFile("/logs/dns_mitm_startup.log", 0, ams::fs::CreateOption_None));
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(log_file), "/logs/dns_mitm_startup.log", ams::fs::OpenMode_ReadWrite | ams::fs::OpenMode_AllowAppend));
ON_SCOPE_EXIT { ::fsFileClose(std::addressof(log_file)); };
Log(log_file, "DNS Mitm:\n");
/* If a default hosts file doesn't exist on the sd card, create one. */
if (!mitm::fs::HasAtmosphereSdFile("/hosts/default.txt")) {
Log(log_file, "Creating /hosts/default.txt because it does not exist.\n");
mitm::fs::CreateAtmosphereSdDirectory("/hosts");
R_ABORT_UNLESS(mitm::fs::CreateAtmosphereSdFile("/hosts/default.txt", sizeof(DefaultHostsFile) - 1, ams::fs::CreateOption_None));
::FsFile default_file;
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(default_file), "/hosts/default.txt", ams::fs::OpenMode_ReadWrite));
R_ABORT_UNLESS(::fsFileWrite(std::addressof(default_file), 0, DefaultHostsFile, sizeof(DefaultHostsFile) - 1, ::FsWriteOption_Flush));
::fsFileClose(std::addressof(default_file));
}
/* If we should, add the defaults. */
if (add_defaults) {
Log(log_file, "Adding defaults to redirection list.\n");
ParseHostsFile(DefaultHostsFile);
}
/* Select the hosts file. */
const char *hosts_path = SelectHostsFile(log_file);
Log(log_file, "Selected %s\n", hosts_path);
/* Load the hosts file. */
{
char *hosts_file_data = nullptr;
ON_SCOPE_EXIT { if (hosts_file_data != nullptr) { ams::Free(hosts_file_data); } };
{
::FsFile hosts_file;
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(hosts_file), hosts_path, ams::fs::OpenMode_Read));
ON_SCOPE_EXIT { ::fsFileClose(std::addressof(hosts_file)); };
/* Get the hosts file size. */
s64 hosts_size;
R_ABORT_UNLESS(::fsFileGetSize(std::addressof(hosts_file), std::addressof(hosts_size)));
/* Validate we can read the file. */
AMS_ABORT_UNLESS(0 <= hosts_size && hosts_size < 0x8000);
/* Read the data. */
hosts_file_data = static_cast<char *>(ams::Malloc(0x8000));
AMS_ABORT_UNLESS(hosts_file_data != nullptr);
u64 br;
R_ABORT_UNLESS(::fsFileRead(std::addressof(hosts_file), 0, hosts_file_data, hosts_size, ::FsReadOption_None, std::addressof(br)));
AMS_ABORT_UNLESS(br == static_cast<u64>(hosts_size));
/* Null-terminate. */
hosts_file_data[hosts_size] = '\x00';
}
/* Parse the hosts file. */
ParseHostsFile(hosts_file_data);
}
/* Print the redirections. */
Log(log_file, "Redirections:\n");
for (const auto &[host, address] : g_redirection_list) {
Log(log_file, " `%s` -> %u.%u.%u.%u\n", host.c_str(), (address >> 0) & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF, (address >> 24) & 0xFF);
}
}
bool GetRedirectedHostByName(ams::socket::InAddrT *out, const char *hostname) {
std::scoped_lock lk(g_redirection_lock);
for (const auto &[host, address] : g_redirection_list) {
if (wildcardcmp(host.c_str(), hostname)) {
*out = address;
return true;
}
}
return false;
}
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::mitm::socket::resolver {
void InitializeResolverRedirections();
bool GetRedirectedHostByName(ams::socket::InAddrT *out, const char *hostname);
}

View File

@@ -1,137 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../amsmitm_initialization.hpp"
#include "dnsmitm_module.hpp"
#include "dnsmitm_debug.hpp"
#include "dnsmitm_resolver_impl.hpp"
#include "dnsmitm_host_redirection.hpp"
namespace ams::mitm::socket::resolver {
namespace {
enum PortIndex {
PortIndex_Mitm,
PortIndex_Count,
};
constexpr sm::ServiceName DnsMitmServiceName = sm::ServiceName::Encode("sfdnsres");
constexpr size_t MaxSessions = 30;
using ServerOptions = sf::hipc::DefaultServerManagerOptions;
class ServerManager final : public sf::hipc::ServerManager<PortIndex_Count, ServerOptions, MaxSessions> {
private:
virtual Result OnNeedsToAccept(int port_index, Server *server) override;
};
ServerManager g_server_manager;
Result ServerManager::OnNeedsToAccept(int port_index, Server *server) {
/* Acknowledge the mitm session. */
std::shared_ptr<::Service> fsrv;
sm::MitmProcessInfo client_info;
server->AcknowledgeMitmSession(std::addressof(fsrv), std::addressof(client_info));
switch (port_index) {
case PortIndex_Mitm:
return this->AcceptMitmImpl(server, sf::CreateSharedObjectEmplaced<IResolver, ResolverImpl>(decltype(fsrv)(fsrv), client_info), fsrv);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
constexpr size_t TotalThreads = 8;
static_assert(TotalThreads >= 1, "TotalThreads");
constexpr size_t NumExtraThreads = TotalThreads - 1;
constexpr size_t ThreadStackSize = mitm::ModuleTraits<socket::resolver::MitmModule>::StackSize;
alignas(os::MemoryPageSize) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize];
os::ThreadType g_extra_threads[NumExtraThreads];
void LoopServerThread(void *arg) {
/* Loop forever, servicing our services. */
g_server_manager.LoopProcess();
}
void ProcessForServerOnAllThreads() {
/* Initialize threads. */
if constexpr (NumExtraThreads > 0) {
const s32 priority = os::GetThreadCurrentPriority(os::GetCurrentThread());
for (size_t i = 0; i < NumExtraThreads; i++) {
R_ABORT_UNLESS(os::CreateThread(g_extra_threads + i, LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, priority));
}
}
/* Start extra threads. */
if constexpr (NumExtraThreads > 0) {
for (size_t i = 0; i < NumExtraThreads; i++) {
os::StartThread(g_extra_threads + i);
}
}
/* Loop this thread. */
LoopServerThread(nullptr);
/* Wait for extra threads to finish. */
if constexpr (NumExtraThreads > 0) {
for (size_t i = 0; i < NumExtraThreads; i++) {
os::WaitThread(g_extra_threads + i);
}
}
}
bool ShouldMitmDns() {
u8 en = 0;
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "enable_dns_mitm") == sizeof(en)) {
return (en != 0);
}
return false;
}
bool ShouldEnableDebugLog() {
u8 en = 0;
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "enable_dns_mitm_debug_log") == sizeof(en)) {
return (en != 0);
}
return false;
}
}
void MitmModule::ThreadFunction(void *arg) {
/* Wait until initialization is complete. */
mitm::WaitInitialized();
/* If we shouldn't mitm dns, don't do anything at all. */
if (!ShouldMitmDns()) {
return;
}
/* Initialize debug. */
resolver::InitializeDebug(ShouldEnableDebugLog());
/* Initialize redirection map. */
resolver::InitializeResolverRedirections();
/* Create mitm servers. */
R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<ResolverImpl>(PortIndex_Mitm, DnsMitmServiceName)));
/* Loop forever, servicing our services. */
ProcessForServerOnAllThreads();
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
#include "../amsmitm_module.hpp"
namespace ams::mitm::socket::resolver {
DEFINE_MITM_MODULE_CLASS(0x2000, AMS_GET_SYSTEM_THREAD_PRIORITY(socket, ResolverIpcServer) - 1);
}

View File

@@ -1,200 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "dnsmitm_resolver_impl.hpp"
#include "dnsmitm_debug.hpp"
#include "dnsmitm_host_redirection.hpp"
#include "serializer/serializer.hpp"
#include "sfdnsres_shim.h"
namespace ams::mitm::socket::resolver {
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 };
struct in_addr *addr_list[2] = { &addr, nullptr };
struct hostent ent = {
.h_name = const_cast<char *>(hostname),
.h_aliases = nullptr,
.h_addrtype = AF_INET,
.h_length = sizeof(u32),
.h_addr_list = (char **)addr_list,
};
const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ent);
AMS_ABORT_UNLESS(result >= 0);
return result;
}
ssize_t SerializeRedirectedAddrInfo(u8 * const dst, size_t dst_size, const char *hostname, ams::socket::InAddrT redirect_addr, u16 redirect_port, const struct addrinfo *hint) {
struct addrinfo ai = {
.ai_flags = 0,
.ai_family = AF_UNSPEC,
.ai_socktype = 0,
.ai_protocol = 0,
.ai_addrlen = 0,
.ai_canonname = nullptr,
.ai_next = nullptr,
};
if (hint != nullptr) {
ai = *hint;
}
switch (ai.ai_family) {
case AF_UNSPEC: ai.ai_family = AF_INET; break;
case AF_INET: ai.ai_family = AF_INET; break;
case AF_INET6: AMS_ABORT("Redirected INET6 not supported"); break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
if (ai.ai_socktype == 0) {
ai.ai_socktype = SOCK_STREAM;
}
if (ai.ai_protocol == 0) {
ai.ai_protocol = IPPROTO_TCP;
}
const struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_port = ams::socket::InetHtons(redirect_port),
.sin_addr = { .s_addr = redirect_addr },
.sin_zero = {},
};
ai.ai_addrlen = sizeof(sin);
ai.ai_addr = (struct sockaddr *)(std::addressof(sin));
const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ai);
AMS_ABORT_UNLESS(result >= 0);
return result;
}
Result ResolverImpl::GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size) {
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
LogDebug("[%016lx]: GetHostByNameRequest(%s)\n", this->client_info.program_id.value, hostname);
ams::socket::InAddrT redirect_addr = {};
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
const auto size = SerializeRedirectedHostEnt(out_hostent.GetPointer(), out_hostent.GetSize(), hostname, redirect_addr);
*out_host_error = 0;
*out_errno = 0;
*out_size = size;
return ResultSuccess();
}
Result ResolverImpl::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<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size) {
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
LogDebug("[%016lx]: GetAddrInfoRequest(%s, %s)\n", this->client_info.program_id.value, reinterpret_cast<const char *>(node.GetPointer()), reinterpret_cast<const char *>(srv.GetPointer()));
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<const char *>(srv.GetPointer()); *cur != 0; ++cur) {
AMS_ABORT_UNLESS(std::isdigit(static_cast<unsigned char>(*cur)));
port *= 10;
port += *cur - '0';
}
}
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", this->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 addrinfo hint = {};
if (use_hint) {
AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0);
}
ON_SCOPE_EXIT { if (use_hint) { serializer::FreeAddrInfo(hint); } };
const auto size = SerializeRedirectedAddrInfo(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
*out_retval = 0;
*out_errno = 0;
*out_size = size;
return ResultSuccess();
}
Result ResolverImpl::GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno) {
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
LogDebug("[%016lx]: GetHostByNameRequestWithOptions(%s)\n", this->client_info.program_id.value, hostname);
ams::socket::InAddrT redirect_addr = {};
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
const auto size = SerializeRedirectedHostEnt(out_hostent.GetPointer(), out_hostent.GetSize(), hostname, redirect_addr);
*out_host_error = 0;
*out_errno = 0;
*out_size = size;
return ResultSuccess();
}
Result ResolverImpl::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<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno) {
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
LogDebug("[%016lx]: GetAddrInfoRequestWithOptions(%s, %s)\n", this->client_info.program_id.value, hostname, reinterpret_cast<const char *>(srv.GetPointer()));
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<const char *>(srv.GetPointer()); *cur != 0; ++cur) {
AMS_ABORT_UNLESS(std::isdigit(static_cast<unsigned char>(*cur)));
port *= 10;
port += *cur - '0';
}
}
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", this->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 addrinfo hint = {};
if (use_hint) {
AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0);
}
ON_SCOPE_EXIT { if (use_hint) { serializer::FreeAddrInfo(hint); } };
const auto size = SerializeRedirectedAddrInfo(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
*out_retval = 0;
*out_host_error = 0;
*out_errno = 0;
*out_size = size;
return ResultSuccess();
}
Result ResolverImpl::AtmosphereReloadHostsFile() {
/* Perform a hosts file reload. */
InitializeResolverRedirections();
return ResultSuccess();
}
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
#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<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> 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<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> 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<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> 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<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> 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, 65000, Result, AtmosphereReloadHostsFile, (), ())
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::socket::resolver, IResolver, AMS_DNS_MITM_INTERFACE_INFO)
namespace ams::mitm::socket::resolver {
class ResolverImpl : public sf::MitmServiceImplBase {
public:
using MitmServiceImplBase::MitmServiceImplBase;
public:
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
/* We will mitm:
* - everything.
*/
return true;
}
public:
/* Overridden commands. */
Result GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size);
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<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size);
Result GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> 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<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
/* Extension commands. */
Result AtmosphereReloadHostsFile();
};
static_assert(IsIResolver<ResolverImpl>);
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
ssize_t DNSSerializer::CheckToBufferArguments(const u8 *dst, size_t dst_size, size_t required, int error_id) {
if (dst == nullptr) {
return -1;
} else if (dst_size < required) {
return -1;
}
return 0;
}
u32 DNSSerializer::InternalHton(const u32 &v) {
return ams::socket::InetHtonl(v);
}
u16 DNSSerializer::InternalHton(const u16 &v) {
return ams::socket::InetHtons(v);
}
u32 DNSSerializer::InternalNtoh(const u32 &v) {
return ams::socket::InetNtohl(v);
}
u16 DNSSerializer::InternalNtoh(const u16 &v) {
return ams::socket::InetNtohs(v);
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::mitm::socket::resolver::serializer {
class DNSSerializer {
public:
static ssize_t CheckToBufferArguments(const u8 *dst, size_t dst_size, size_t required, int error_id);
static u32 InternalHton(const u32 &v);
static u16 InternalHton(const u16 &v);
static u32 InternalNtoh(const u32 &v);
static u16 InternalNtoh(const u16 &v);
public:
template<typename T>
static size_t SizeOf(const T &in);
template<typename T>
static size_t SizeOf(const T *in);
template<typename T>
static size_t SizeOf(const T *in, size_t count);
template<typename T>
static size_t SizeOf(const T **arr, u32 &out_count);
template<typename T>
static ssize_t ToBuffer(u8 * const dst, size_t dst_size, const T &in);
template<typename T>
static ssize_t FromBuffer(T &out, const u8 *src, size_t src_size);
template<typename T>
static ssize_t ToBuffer(u8 * const dst, size_t dst_Size, T *in);
template<typename T>
static ssize_t ToBuffer(u8 * const dst, size_t dst_size, T **arr);
template<typename T>
static ssize_t FromBuffer(T *&out, const u8 *src, size_t src_size);
template<typename T>
static ssize_t FromBuffer(T **&out_arr, const u8 *src, size_t src_size);
template<typename T>
static ssize_t ToBuffer(u8 * const dst, size_t dst_size, const T * const arr, size_t count);
template<typename T>
static ssize_t FromBuffer(T * const arr, size_t arr_size, const u8 *src, size_t src_size, size_t count);
};
void FreeHostent(ams::socket::HostEnt &ent);
void FreeHostent(struct hostent &ent);
void FreeAddrInfo(ams::socket::AddrInfo &addr_info);
void FreeAddrInfo(struct addrinfo &addr_info);
}

View File

@@ -1,444 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "../socket_allocator.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
namespace {
constexpr inline u32 AddrInfoMagic = 0xBEEFCAFE;
template<typename T>
concept IsAddrInfo = std::same_as<T, ams::socket::AddrInfo> || std::same_as<T, struct addrinfo>;
template<typename T> requires IsAddrInfo<T>
using SockAddrType = typename std::conditional<std::same_as<T, ams::socket::AddrInfo>, ams::socket::SockAddr, struct sockaddr>::type;
template<typename T> requires IsAddrInfo<T>
using SockAddrInType = typename std::conditional<std::same_as<T, ams::socket::AddrInfo>, ams::socket::SockAddrIn, struct sockaddr_in>::type;
template<typename T> requires IsAddrInfo<T>
using SockAddrIn6Type = typename std::conditional<std::same_as<T, ams::socket::AddrInfo>, struct sockaddr_in6, struct sockaddr_in6>::type;
template<typename T> requires IsAddrInfo<T>
constexpr bool IsAfInet(const auto ai_family) {
if constexpr (std::same_as<T, ams::socket::AddrInfo>) {
return ai_family == ams::socket::Family::Af_Inet;
} else {
return ai_family == AF_INET;
}
}
template<typename T> requires IsAddrInfo<T>
constexpr bool IsAfInet6(const auto ai_family) {
if constexpr (std::same_as<T, ams::socket::AddrInfo>) {
return ai_family == ams::socket::Family::Af_Inet6;
} else {
return ai_family == AF_INET;
}
}
template<typename T> requires IsAddrInfo<T>
void FreeAddrInfoImpl(T &addr_info) {
T *next = nullptr;
for (T *cur = std::addressof(addr_info); cur != nullptr; cur = next) {
next = cur->ai_next;
if (cur->ai_addr != nullptr) {
if (IsAfInet<T>(cur->ai_family)) {
ams::socket::impl::Free(reinterpret_cast<SockAddrInType<T> *>(cur->ai_addr));
} else if (IsAfInet6<T>(cur->ai_family)) {
ams::socket::impl::Free(reinterpret_cast<SockAddrIn6Type<T> *>(cur->ai_addr));
} else {
ams::socket::impl::Free(cur->ai_addr);
}
cur->ai_addr = nullptr;
}
if (cur->ai_canonname != nullptr) {
ams::socket::impl::Free(cur->ai_canonname);
cur->ai_canonname = nullptr;
}
if (cur != std::addressof(addr_info)) {
ams::socket::impl::Free(cur);
}
}
}
template<typename T> requires IsAddrInfo<T>
size_t AddrInfoSingleSizeOf(const T *addr_info) {
size_t rc = 6 * sizeof(u32);
if (addr_info->ai_addr == nullptr) {
rc += sizeof(u32);
} else if (IsAfInet<T>(addr_info->ai_family)) {
rc += DNSSerializer::SizeOf(*reinterpret_cast<SockAddrInType<T> *>(addr_info->ai_addr));
} else if (IsAfInet6<T>(addr_info->ai_family)) {
rc += DNSSerializer::SizeOf(*reinterpret_cast<SockAddrIn6Type<T> *>(addr_info->ai_addr));
} else if (addr_info->ai_addrlen == 0) {
rc += sizeof(u32);
} else {
rc += addr_info->ai_addrlen;
}
if (addr_info->ai_canonname != nullptr) {
rc += DNSSerializer::SizeOf(static_cast<const char *>(addr_info->ai_canonname));
} else {
rc += sizeof(u8);
}
if (addr_info->ai_next == nullptr) {
rc += sizeof(u32);
}
return rc;
}
template<typename T> requires IsAddrInfo<T>
size_t SizeOfImpl(const T &in) {
size_t rc = 0;
for (const T *addr_info = std::addressof(in); addr_info != nullptr; addr_info = addr_info->ai_next) {
rc += AddrInfoSingleSizeOf(addr_info);
}
return rc;
}
template<typename T> requires IsAddrInfo<T>
ssize_t ToBufferInternalImpl(u8 * const dst, size_t dst_size, const T &addr_info) {
ssize_t rc = -1;
u8 *cur = dst;
{
const u32 value = AddrInfoMagic;
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
cur += rc;
}
{
const u32 value = static_cast<u32>(addr_info.ai_flags);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
cur += rc;
}
{
const u32 value = static_cast<u32>(addr_info.ai_family);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
cur += rc;
}
{
const u32 value = static_cast<u32>(addr_info.ai_socktype);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
cur += rc;
}
{
const u32 value = static_cast<u32>(addr_info.ai_protocol);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
cur += rc;
}
{
const u32 value = static_cast<u32>(addr_info.ai_addrlen);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
cur += rc;
}
{
if (addr_info.ai_addr == nullptr || addr_info.ai_addrlen == 0) {
const u32 value = 0;
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
return rc;
}
} else if (IsAfInet<T>(addr_info.ai_family)) {
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast<SockAddrInType<T> *>(addr_info.ai_addr))) == -1) {
return rc;
}
} else if (IsAfInet6<T>(addr_info.ai_family)) {
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast<SockAddrIn6Type<T> *>(addr_info.ai_addr))) == -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;
}
cur += rc;
}
{
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), addr_info.ai_canonname)) == -1) {
return rc;
}
cur += rc;
}
if (addr_info.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<typename T> requires IsAddrInfo<T>
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;
}
for (const T *addr_info = std::addressof(in); addr_info != nullptr; addr_info = addr_info->ai_next) {
if ((rc = ToBufferInternalImpl(cur, dst_size, *addr_info)) == -1) {
return rc;
}
cur += rc;
}
rc = cur - dst;
return rc;
}
template<typename T> requires IsAddrInfo<T>
ssize_t FromBufferInternalImpl(T &out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
const u8 *cur = src;
std::memset(std::addressof(out), 0, sizeof(out));
ON_SCOPE_EXIT { if (rc < 0) { FreeAddrInfo(out); } };
u32 tmp_value;
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
} else if (tmp_value != AddrInfoMagic) {
return rc;
}
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.ai_flags = static_cast<decltype(out.ai_flags)>(tmp_value);
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.ai_family = static_cast<decltype(out.ai_family)>(tmp_value);
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.ai_socktype = static_cast<decltype(out.ai_socktype)>(tmp_value);
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.ai_protocol = static_cast<decltype(out.ai_protocol)>(tmp_value);
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.ai_addrlen = static_cast<decltype(out.ai_addrlen)>(tmp_value);
cur += rc;
}
{
if (out.ai_addrlen == 0) {
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
}
if (tmp_value != 0) {
rc = -1;
return rc;
}
out.ai_addr = nullptr;
} else if (IsAfInet<T>(out.ai_family)) {
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrInType<T>)));
if (out.ai_addr == nullptr) {
rc = -1;
return rc;
}
std::memset(out.ai_addr, 0, sizeof(SockAddrInType<T>));
if ((rc = DNSSerializer::FromBuffer(*reinterpret_cast<SockAddrInType<T> *>(out.ai_addr), cur, src_size - (cur - src))) == -1) {
return rc;
}
} else if (IsAfInet6<T>(out.ai_family)) {
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrIn6Type<T>)));
if (out.ai_addr == nullptr) {
rc = -1;
return rc;
}
std::memset(out.ai_addr, 0, sizeof(SockAddrIn6Type<T>));
if ((rc = DNSSerializer::FromBuffer(*reinterpret_cast<SockAddrIn6Type<T> *>(out.ai_addr), cur, src_size - (cur - src))) == -1) {
return rc;
}
} else {
out.ai_addr = static_cast<decltype(out.ai_addr)>(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;
}
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(out.ai_canonname, cur, src_size - (cur - src))) == -1) {
return rc;
}
cur += rc;
}
{
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
return rc;
} else if (tmp_value == 0) {
out.ai_next = nullptr;
cur += rc;
} else if (tmp_value == AddrInfoMagic) {
out.ai_next = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
if (out.ai_next == nullptr) {
rc = -1;
return rc;
}
std::memset(out.ai_next, 0, sizeof(T));
} else {
rc = -1;
return rc;
}
}
rc = cur - src;
return rc;
}
template<typename T> requires IsAddrInfo<T>
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;
}
for (T *addr_info = std::addressof(out); addr_info != nullptr; addr_info = addr_info->ai_next) {
if ((rc = FromBufferInternalImpl(*addr_info, cur, src_size - (cur - src))) == -1) {
rc = -1;
return rc;
}
cur += rc;
}
rc = cur - src;
return rc;
}
}
template<> size_t DNSSerializer::SizeOf(const struct addrinfo &in) {
return SizeOfImpl(in);
}
template<> size_t DNSSerializer::SizeOf(const ams::socket::AddrInfo &in) {
return SizeOfImpl(in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::AddrInfo &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct addrinfo &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::FromBuffer(ams::socket::AddrInfo &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
template<> ssize_t DNSSerializer::FromBuffer(struct addrinfo &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
void FreeAddrInfo(ams::socket::AddrInfo &addr_info) {
return FreeAddrInfoImpl(addr_info);
}
void FreeAddrInfo(struct addrinfo &addr_info) {
return FreeAddrInfoImpl(addr_info);
}
}

View File

@@ -1,234 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "../socket_allocator.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
namespace {
template<typename T>
concept IsHostEnt = std::same_as<T, ams::socket::HostEnt> || std::same_as<T, struct hostent>;
template<typename T> requires IsHostEnt<T>
using InAddrType = typename std::conditional<std::same_as<T, ams::socket::HostEnt>, ams::socket::InAddr, struct in_addr>::type;
template<typename T> requires IsHostEnt<T>
constexpr bool IsAfInet(const auto h_addrtype) {
if constexpr (std::same_as<T, ams::socket::HostEnt>) {
return h_addrtype == ams::socket::Family::Af_Inet;
} else {
return h_addrtype == AF_INET;
}
}
template<typename T> requires IsHostEnt<T>
constexpr bool IsAfInet6(const auto h_addrtype) {
if constexpr (std::same_as<T, ams::socket::HostEnt>) {
return h_addrtype == ams::socket::Family::Af_Inet6;
} else {
return h_addrtype == AF_INET;
}
}
template<typename T> requires IsHostEnt<T>
size_t SizeOfImpl(const T &in) {
size_t rc = 0;
u32 dummy = 0;
rc += DNSSerializer::SizeOf((const char *)(in.h_name));
rc += DNSSerializer::SizeOf((const char **)(in.h_aliases), dummy);
rc += sizeof(u32);
rc += sizeof(u32);
rc += DNSSerializer::SizeOf((const InAddrType<T> **)(in.h_addr_list), dummy);
return rc;
}
template<typename T> requires IsHostEnt<T>
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 ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, required, __LINE__)) == -1) {
return rc;
}
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), in.h_name)) == -1) {
return rc;
}
cur += rc;
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), in.h_aliases)) == -1) {
return rc;
}
cur += rc;
const u16 h_addrtype = static_cast<u16>(in.h_addrtype);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), h_addrtype)) == -1) {
return rc;
}
cur += rc;
const u16 h_length = in.h_length;
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), h_length)) == -1) {
return rc;
}
cur += rc;
if (IsAfInet<T>(in.h_addrtype)) {
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), (InAddrType<T> **)(in.h_addr_list))) == -1) {
return rc;
}
} else if (IsAfInet6<T>(in.h_addrtype)) {
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), (InAddrType<T> **)(in.h_addr_list))) == -1) {
return rc;
}
} else {
const u32 null = 0;
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), null)) == -1) {
return rc;
}
}
cur += rc;
rc = cur - dst;
return rc;
}
template<typename T> requires IsHostEnt<T>
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
const u8 *cur = src;
std::memset(std::addressof(out), 0, sizeof(out));
ON_SCOPE_EXIT {
if (rc < 0) {
FreeHostent(out);
}
};
if ((rc = DNSSerializer::FromBuffer(out.h_name, cur, src_size - (cur - src))) == -1) {
return rc;
}
cur += rc;
if ((rc = DNSSerializer::FromBuffer(out.h_aliases, cur, src_size - (cur - src))) == -1) {
return rc;
}
cur += rc;
u16 h_addrtype = 0;
if ((rc = DNSSerializer::FromBuffer(h_addrtype, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.h_addrtype = static_cast<decltype(out.h_addrtype)>(h_addrtype);
cur += rc;
u16 h_length = 0;
if ((rc = DNSSerializer::FromBuffer(h_length, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.h_length = h_length;
cur += rc;
InAddrType<T> **addrs = nullptr;
if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.h_addr_list = (char **)addrs;
cur += rc;
rc = cur - src;
return rc;
}
template<typename T> requires IsHostEnt<T>
void FreeHostentImpl(T &ent) {
if (ent.h_name != nullptr) {
ams::socket::impl::Free(ent.h_name);
ent.h_name = nullptr;
}
if (ent.h_aliases != nullptr) {
u32 i = 0;
for (char *str = ent.h_aliases[i]; str != nullptr; str = ent.h_aliases[++i]) {
ams::socket::impl::Free(str);
ent.h_aliases[i] = nullptr;
}
ams::socket::impl::Free(ent.h_aliases);
ent.h_aliases = nullptr;
}
if (ent.h_addr_list != nullptr) {
AMS_ASSERT(ent.h_length == sizeof(u32));
if (ent.h_length == sizeof(u32)) {
auto **addr_list = reinterpret_cast<InAddrType<T> **>(ent.h_addr_list);
u32 i = 0;
for (auto *addr = addr_list[i]; addr != nullptr; addr = addr_list[++i]) {
ams::socket::impl::Free(addr);
addr_list[i] = nullptr;
}
ams::socket::impl::Free(ent.h_addr_list);
ent.h_addr_list = nullptr;
}
}
std::memset(std::addressof(ent), 0, sizeof(ent));
}
}
template<> size_t DNSSerializer::SizeOf(const struct hostent &in) {
return SizeOfImpl(in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct hostent &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::FromBuffer(struct hostent &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
template<> size_t DNSSerializer::SizeOf(const ams::socket::HostEnt &in) {
return SizeOfImpl(in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::HostEnt &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::FromBuffer(ams::socket::HostEnt &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
void FreeHostent(ams::socket::HostEnt &ent) {
return FreeHostentImpl(ent);
}
void FreeHostent(struct hostent &ent) {
return FreeHostentImpl(ent);
}
}

View File

@@ -1,237 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "../socket_allocator.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
namespace {
template<typename T>
concept IsInAddr = std::same_as<T, ams::socket::InAddr> || std::same_as<T, struct in_addr>;
template<typename T> requires IsInAddr<T>
size_t SizeOfImpl(const T &in) {
return sizeof(u32);
}
template<typename T> requires IsInAddr<T>
size_t SizeOfImpl(const T **in, u32 &out_count) {
size_t rc = sizeof(u32);
out_count = 0;
if (in != nullptr) {
for (const T ** cur_addr = in; *cur_addr != nullptr; ++cur_addr) {
++out_count;
rc += sizeof(u32);
}
}
return rc;
}
template<typename T> requires IsInAddr<T>
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
ssize_t rc = -1;
u8 *cur = dst;
const u32 val = DNSSerializer::InternalHton(in.s_addr);
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, sizeof(in), __LINE__)) == -1) {
return rc;
}
std::memcpy(cur, std::addressof(val), sizeof(val));
rc += sizeof(val);
return rc;
}
template<typename T> requires IsInAddr<T>
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
if (src_size < sizeof(out)) {
return rc;
}
std::memset(std::addressof(out), 0, sizeof(out));
out.s_addr = DNSSerializer::InternalNtoh(*reinterpret_cast<const u32 *>(src));
rc = sizeof(u32);
return rc;
}
template<typename T> requires IsInAddr<T>
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, T **arr) {
ssize_t rc = -1;
u8 *cur = dst;
if (arr == nullptr && dst_size < sizeof(u32)) {
return rc;
} else if (arr == nullptr) {
const u32 null = 0;
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), null)) == -1) {
return rc;
}
cur += rc;
} else {
u32 count = 0;
for (auto *tmp = arr; *tmp != nullptr; ++tmp) {
++count;
}
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, (count + 1) * sizeof(**arr), __LINE__)) == -1) {
return rc;
}
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), count)) == -1) {
return rc;
}
cur += rc;
rc = 0;
for (auto i = 0; arr[i] != nullptr; ++i) {
const T addr = *arr[i];
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), addr)) == -1) {
return rc;
}
cur += rc;
}
rc = cur - dst;
}
return rc;
}
template<typename T> requires IsInAddr<T>
ssize_t FromBufferImpl(T **&out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
const u8 *cur = src;
out = nullptr;
ON_SCOPE_EXIT {
if (rc == -1 && out != nullptr) {
for (auto i = 0; out[i] != nullptr; ++i) {
ams::socket::impl::Free(out[i]);
out[i] = nullptr;
}
ams::socket::impl::Free(out);
out = nullptr;
}
};
if (src == nullptr) {
rc = 0;
return rc;
} else if (src_size == 0) {
rc = 0;
return rc;
}
u32 count = 0;
if ((rc = DNSSerializer::FromBuffer(count, cur, src_size)) == -1) {
return rc;
}
cur += rc;
if (count == 0) {
return rc;
}
out = static_cast<T **>(ams::socket::impl::Alloc((count + 1) * sizeof(T *)));
if (out == nullptr) {
rc = -1;
return rc;
}
std::memset(out, 0, (count + 1) * sizeof(T *));
for (u32 i = 0; i < count; ++i) {
out[i] = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
if (out[i] == nullptr) {
rc = -1;
return rc;
}
u32 s_addr = 0;
if ((rc = DNSSerializer::FromBuffer(s_addr, cur, src_size - (cur - src))) == -1) {
return rc;
}
out[i]->s_addr = s_addr;
cur += rc;
}
out[count] = nullptr;
rc = cur - src;
return rc;
}
}
template<> size_t DNSSerializer::SizeOf(const struct in_addr &in) {
return SizeOfImpl(in);
}
template<> size_t DNSSerializer::SizeOf(const ams::socket::InAddr &in) {
return SizeOfImpl(in);
}
template<> size_t DNSSerializer::SizeOf(const struct in_addr **in, u32 &out_count) {
return SizeOfImpl(in, out_count);
}
template<> size_t DNSSerializer::SizeOf(const ams::socket::InAddr **in, u32 &out_count) {
return SizeOfImpl(in, out_count);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct in_addr &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::InAddr &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::FromBuffer(struct in_addr &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::InAddr &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, struct in_addr **arr) {
return ToBufferImpl(dst, dst_size, arr);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, ams::socket::InAddr **arr) {
return ToBufferImpl(dst, dst_size, arr);
}
template<> ssize_t DNSSerializer::FromBuffer(struct in_addr **&out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::InAddr **&out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const u16 &in) {
/* Convert the value. */
u8 *cur = dst;
const u16 val = InternalHton(in);
/* Check arguments. */
ssize_t rc = -1;
if ((rc = CheckToBufferArguments(cur, dst_size, sizeof(u16), __LINE__)) == -1) {
return rc;
}
std::memcpy(cur, std::addressof(val), sizeof(u16));
rc += sizeof(u16);
return rc;
}
template<> ssize_t DNSSerializer::FromBuffer(u16 &out, const u8 *src, size_t src_size) {
if (src_size < sizeof(u16)) {
return -1;
}
out = InternalNtoh(*reinterpret_cast<const u16 *>(src));
return sizeof(u16);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const u32 &in) {
/* Convert the value. */
u8 *cur = dst;
const u32 val = InternalHton(in);
/* Check arguments. */
ssize_t rc = -1;
if ((rc = CheckToBufferArguments(cur, dst_size, sizeof(u32), __LINE__)) == -1) {
return rc;
}
std::memcpy(cur, std::addressof(val), sizeof(u32));
rc += sizeof(u32);
return rc;
}
template<> ssize_t DNSSerializer::FromBuffer(u32 &out, const u8 *src, size_t src_size) {
if (src_size < sizeof(u32)) {
return -1;
}
out = InternalNtoh(*reinterpret_cast<const u32 *>(src));
return sizeof(u32);
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "../socket_allocator.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
namespace {
template<typename T>
concept IsSockAddrIn = std::same_as<T, ams::socket::SockAddrIn> || std::same_as<T, struct sockaddr_in>;
template<typename T> requires IsSockAddrIn<T>
size_t SizeOfImpl(const T &in) {
size_t rc = 0;
rc += sizeof(u16);
rc += sizeof(u16);
rc += DNSSerializer::SizeOf(in.sin_addr);
rc += sizeof(in.sin_zero);
return rc;
}
template<typename T> requires IsSockAddrIn<T>
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
ssize_t rc = -1;
u8 *cur = dst;
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, sizeof(in), __LINE__)) == -1) {
return rc;
}
const u16 sin_family = static_cast<u16>(in.sin_family);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin_family)) == -1) {
return rc;
}
cur += rc;
const u16 sin_port = static_cast<u16>(in.sin_port);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin_port)) == -1) {
return rc;
}
cur += rc;
const u32 s_addr = static_cast<u32>(in.sin_addr.s_addr);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), s_addr)) == -1) {
return rc;
}
cur += rc;
if (dst_size - (cur - dst) < sizeof(in.sin_zero)) {
rc = -1;
return rc;
}
std::memcpy(cur, in.sin_zero, sizeof(in.sin_zero));
cur += sizeof(in.sin_zero);
rc = cur - dst;
return rc;
}
template<typename T> requires IsSockAddrIn<T>
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
const u8 *cur = src;
u16 sin_family;
if ((rc = DNSSerializer::FromBuffer(sin_family, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin_family = static_cast<decltype(out.sin_family)>(sin_family);
cur += rc;
u16 sin_port;
if ((rc = DNSSerializer::FromBuffer(sin_port, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin_port = static_cast<decltype(out.sin_port)>(sin_port);
cur += rc;
u32 s_addr;
if ((rc = DNSSerializer::FromBuffer(s_addr, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin_addr.s_addr = static_cast<decltype(out.sin_addr.s_addr)>(s_addr);
cur += rc;
if (src_size - (cur - src) < sizeof(out.sin_zero)) {
rc = -1;
return rc;
}
std::memcpy(out.sin_zero, cur, sizeof(out.sin_zero));
cur += sizeof(out.sin_zero);
rc = cur - src;
return rc;
}
}
template<> size_t DNSSerializer::SizeOf(const struct sockaddr_in &in) {
return SizeOfImpl(in);
}
template<> size_t DNSSerializer::SizeOf(const ams::socket::SockAddrIn &in) {
return SizeOfImpl(in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct sockaddr_in &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::SockAddrIn &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::FromBuffer(struct sockaddr_in &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::SockAddrIn &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
}

View File

@@ -1,133 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "../socket_allocator.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
namespace {
template<typename T>
concept IsSockAddrIn6 = std::same_as<T, struct sockaddr_in6>;
template<typename T> requires IsSockAddrIn6<T>
size_t SizeOfImpl(const T &in) {
size_t rc = 0;
rc += sizeof(u16);
rc += sizeof(u16);
rc += sizeof(u32);
rc += DNSSerializer::SizeOf(in.sin6_addr);
rc += sizeof(u32);
return rc;
}
template<typename T> requires IsSockAddrIn6<T>
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
ssize_t rc = -1;
u8 *cur = dst;
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, sizeof(in), __LINE__)) == -1) {
return rc;
}
const u16 sin6_family = static_cast<u16>(in.sin6_family);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_family)) == -1) {
return rc;
}
cur += rc;
const u16 sin6_port = static_cast<u16>(in.sin6_port);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_port)) == -1) {
return rc;
}
cur += rc;
const u32 sin6_flowinfo = static_cast<u32>(in.sin6_flowinfo);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_flowinfo)) == -1) {
return rc;
}
cur += rc;
std::memcpy(cur, std::addressof(in.sin6_addr), sizeof(in.sin6_addr));
cur += sizeof(in.sin6_addr);
const u32 sin6_scope_id = static_cast<u32>(in.sin6_scope_id);
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_scope_id)) == -1) {
return rc;
}
cur += rc;
rc = cur - dst;
return rc;
}
template<typename T> requires IsSockAddrIn6<T>
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
const u8 *cur = src;
u16 sin6_family;
if ((rc = DNSSerializer::FromBuffer(sin6_family, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin6_family = static_cast<decltype(out.sin6_family)>(sin6_family);
cur += rc;
u16 sin6_port;
if ((rc = DNSSerializer::FromBuffer(sin6_port, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin6_port = static_cast<decltype(out.sin6_port)>(sin6_port);
cur += rc;
u32 sin6_flowinfo;
if ((rc = DNSSerializer::FromBuffer(sin6_flowinfo, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin6_flowinfo = static_cast<decltype(out.sin6_flowinfo)>(sin6_flowinfo);
cur += rc;
std::memcpy(std::addressof(out.sin6_addr), cur, sizeof(out.sin6_addr));
cur += sizeof(out.sin6_addr);
u32 sin6_scope_id;
if ((rc = DNSSerializer::FromBuffer(sin6_scope_id, cur, src_size - (cur - src))) == -1) {
return rc;
}
out.sin6_scope_id = static_cast<decltype(out.sin6_scope_id)>(sin6_scope_id);
cur += rc;
rc = cur - src;
return rc;
}
}
template<> size_t DNSSerializer::SizeOf(const struct sockaddr_in6 &in) {
return SizeOfImpl(in);
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct sockaddr_in6 &in) {
return ToBufferImpl(dst, dst_size, in);
}
template<> ssize_t DNSSerializer::FromBuffer(struct sockaddr_in6 &out, const u8 *src, size_t src_size) {
return FromBufferImpl(out, src, src_size);
}
}

View File

@@ -1,180 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "../dnsmitm_debug.hpp"
#include "../socket_allocator.hpp"
#include "serializer.hpp"
namespace ams::mitm::socket::resolver::serializer {
template<> size_t DNSSerializer::SizeOf(const char *str) {
if (str == nullptr) {
return sizeof(char);
}
return std::strlen(str) + 1;
}
template<> size_t DNSSerializer::SizeOf(const char **str, u32 &out_count) {
size_t rc = sizeof(u32);
out_count = 0;
if (str != nullptr) {
for (const char **cur = str; *cur != nullptr; ++cur) {
++out_count;
rc += SizeOf(*cur);
}
}
return rc;
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, char *str) {
ssize_t rc = -1;
u8 *cur = dst;
if (str == nullptr && dst_size == 0) {
return -1;
} else if (str == nullptr) {
*cur = '\x00';
return 1;
} else if ((rc = SizeOf(static_cast<const char *>(str))) == 0) {
*cur = '\x00';
return 1;
} else if (CheckToBufferArguments(cur, dst_size, rc + 1, __LINE__) == -1) {
return -1;
}
std::memmove(cur, str, rc);
return rc;
}
template<> ssize_t DNSSerializer::FromBuffer(char *&out, const u8 *src, size_t src_size) {
size_t len = 0;
if (src == nullptr) {
return 0;
} else if (src_size == 0) {
return 0;
} else if (src_size < (len = SizeOf(reinterpret_cast<const char *>(src)))) {
return 1;
} else if (src[0] == '\x00') {
return 1;
}
out = static_cast<char *>(ams::socket::impl::Alloc(len));
if (out == nullptr) {
return -1;
}
std::memmove(out, src, len);
return len;
}
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, char **str) {
ssize_t rc = -1;
u8 *cur = dst;
u32 count = 0;
if (dst_size == 0) {
return -1;
}
const size_t total_size = SizeOf(const_cast<const char **>(str), count);
AMS_UNUSED(total_size);
if ((rc = CheckToBufferArguments(cur, dst_size, sizeof(u32), __LINE__)) == -1) {
return rc;
} else if ((rc = ToBuffer(cur, dst_size, count)) == -1) {
return rc;
}
cur += rc;
dst_size -= rc;
if (str != nullptr) {
for (char **cur_str = str; *cur_str != nullptr; ++cur_str) {
const auto tmp = ToBuffer(cur, dst_size, *cur_str);
if (tmp == -1) {
return rc;
}
cur += tmp;
dst_size -= tmp;
rc += tmp;
}
}
rc = cur - dst;
return rc;
}
template<> ssize_t DNSSerializer::FromBuffer(char **&out, const u8 *src, size_t src_size) {
ssize_t rc = -1;
const u8 *cur = src;
u32 count = 0;
out = nullptr;
ON_SCOPE_EXIT {
if (rc < 0 && out != nullptr) {
u32 i = 0;
for (char *str = *out; str != nullptr; str = out[++i]) {
ams::socket::impl::Free(str);
}
ams::socket::impl::Free(out);
out = nullptr;
}
};
if (src == nullptr) {
rc = 0;
return rc;
} else if (src_size == 0) {
rc = 0;
return rc;
} else if ((rc = FromBuffer(count, cur, src_size)) == -1) {
rc = -1;
return rc;
}
cur += rc;
out = static_cast<char **>(ams::socket::impl::Alloc((count + 1) * sizeof(char *)));
if (out == nullptr) {
rc = -1;
return rc;
}
std::memset(out, 0, (count + 1) * sizeof(char *));
u32 i;
for (i = 0; i < count; ++i) {
const size_t len = std::strlen(reinterpret_cast<const char *>(cur));
out[i] = static_cast<char *>(ams::socket::impl::Alloc(len + 1));
if (out[i] == nullptr) {
rc = -1;
return rc;
}
std::memmove(out[i], cur, len + 1);
cur += len + 1;
}
out[i] = nullptr;
rc = cur - src;
return rc;
}
}

View File

@@ -1,97 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include "sfdnsres_shim.h"
#include <stratosphere/sf/sf_mitm_dispatch.h>
/* Command forwarders. */
Result sfdnsresGetHostByNameRequestWithOptionsFwd(Service *s, u64 process_id, const void *name, size_t name_size, void *out_hostent, size_t out_hostent_size, u32 *out_size, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno) {
const struct {
u32 options_version;
u32 num_options;
u64 process_id;
} in = { options_version, num_options, process_id };
struct {
u32 size;
s32 host_error;
s32 errno;
} out;
Result rc = serviceMitmDispatchInOut(s, 10, in, out,
.buffer_attrs = {
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In
},
.buffers = {
{ name, name_size },
{ out_hostent, out_hostent_size },
{ option, option_size }
},
.in_send_pid = true,
.override_pid = process_id,
);
if (R_SUCCEEDED(rc)) {
if (out_size) *out_size = out.size;
if (out_host_error) *out_host_error = out.host_error;
if (out_errno) *out_errno = out.errno;
}
return rc;
}
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) {
const struct {
u32 options_version;
u32 num_options;
u64 process_id;
} in = { options_version, num_options, process_id };
struct {
u32 size;
s32 rv;
s32 host_error;
s32 errno;
} out;
Result rc = serviceMitmDispatchInOut(s, 12, in, out,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In
},
.buffers = {
{ node, node_size },
{ srv, srv_size },
{ hint, hint_size },
{ out_ai, out_ai_size },
{ option, option_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_host_error) *out_host_error = out.host_error;
if (out_errno) *out_errno = out.errno;
}
return rc;
}

Some files were not shown because too many files have changed in this diff Show More