Compare commits
21 Commits
experiment
...
sf_shared
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b6df8c2f7 | ||
|
|
3b2c2ba5a2 | ||
|
|
88a99bc68e | ||
|
|
2d7a85d14f | ||
|
|
2801d00d98 | ||
|
|
57c197ec1c | ||
|
|
2696240566 | ||
|
|
ea9d360b14 | ||
|
|
a63b97fbbd | ||
|
|
6c6e698a3e | ||
|
|
15b225f919 | ||
|
|
ac2c713ee0 | ||
|
|
6a2f8e8344 | ||
|
|
54a1ba2a7e | ||
|
|
2c485f832c | ||
|
|
6467f6f07b | ||
|
|
4f001b4f4c | ||
|
|
a6e452ed9e | ||
|
|
fb6a4e28a5 | ||
|
|
bc9da91362 | ||
|
|
8956e3bd29 |
@@ -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.
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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"};
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 (*)();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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>(),
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)));
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user