subrepo:
  subdir:   "libraries"
  merged:   "07af583b"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "07af583b"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
This commit is contained in:
Michael Scire
2019-12-09 03:57:37 -08:00
committed by SciresM
parent 28717bfd27
commit 0105455086
294 changed files with 29915 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2018-2019 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
/* libvapours (pulls in util, svc, results). */
#include <vapours.hpp>
/* Libstratosphere-only utility. */
#include "stratosphere/util.hpp"
/* Critical modules with no dependencies. */
#include "stratosphere/ams.hpp"
#include "stratosphere/os.hpp"
#include "stratosphere/dd.hpp"
/* Lots of things depend on NCM, for Program IDs. */
#include "stratosphere/ncm.hpp"
/* At this point, just include the rest alphabetically. */
/* TODO: Figure out optimal order. */
#include "stratosphere/boot2.hpp"
#include "stratosphere/cfg.hpp"
#include "stratosphere/dmnt.hpp"
#include "stratosphere/fatal.hpp"
#include "stratosphere/hid.hpp"
#include "stratosphere/hos.hpp"
#include "stratosphere/kvdb.hpp"
#include "stratosphere/ldr.hpp"
#include "stratosphere/map.hpp"
#include "stratosphere/patcher.hpp"
#include "stratosphere/pm.hpp"
#include "stratosphere/reg.hpp"
#include "stratosphere/rnd.hpp"
#include "stratosphere/ro.hpp"
#include "stratosphere/settings.hpp"
#include "stratosphere/sf.hpp"
#include "stratosphere/sm.hpp"
#include "stratosphere/spl.hpp"
#include "stratosphere/updater.hpp"
/* Include FS last. */
#include "stratosphere/fs.hpp"
#include "stratosphere/fssrv.hpp"
#include "stratosphere/fssystem.hpp"

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2019 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 "ams/ams_types.hpp"
#include "ams/ams_exosphere_api.hpp"
#include "ams/ams_emummc_api.hpp"
#include "ams/ams_environment.hpp"

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2019 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 "ams_types.hpp"
namespace ams::emummc {
/* Get whether emummc is active. */
bool IsActive();
/* Get Nintendo redirection path. */
const char *GetNintendoDirPath();
/* Get Emummc folderpath, NULL if not file-based. */
const char *GetFilePath();
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 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 "ams_types.hpp"
namespace ams {
/* Will be called by libstratosphere on crash. */
void CrashHandler(ThreadExceptionDump *ctx);
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2019 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 "ams_types.hpp"
namespace ams::exosphere {
ApiInfo GetApiInfo();
void ForceRebootToRcm();
void ForceRebootToIramPayload();
void ForceShutdown();
bool IsRcmBugPatched();
void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size);
void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size);
}
namespace ams {
/* Version checking utility. */
inline void CheckApiVersion() {
const u32 runtime_version = exosphere::GetApiInfo().GetVersion();
const u32 build_version = exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION);
if (runtime_version < build_version) {
R_ASSERT(exosphere::ResultVersionMismatch());
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2018-2019 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 "../sf/sf_buffer_tags.hpp"
#include "../hos.hpp"
namespace ams::exosphere {
#define AMS_DEFINE_TARGET_FIRMWARE_ENUM(n) TargetFirmware_##n = ATMOSPHERE_TARGET_FIRMWARE_##n
enum TargetFirmware : u32 {
AMS_DEFINE_TARGET_FIRMWARE_ENUM(100),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(200),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(300),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(400),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(500),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(600),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(620),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(700),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(800),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(810),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(900),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(910),
};
#undef AMS_DEFINE_TARGET_FIRMWARE_ENUM
constexpr inline u32 GetVersion(u32 major, u32 minor, u32 micro) {
return (major << 16) | (minor << 8) | (micro);
}
struct ApiInfo {
u32 major_version;
u32 minor_version;
u32 micro_version;
TargetFirmware target_firmware;
u32 master_key_revision;
constexpr u32 GetVersion() const {
return ::ams::exosphere::GetVersion(this->major_version, this->minor_version, this->micro_version);
}
constexpr TargetFirmware GetTargetFirmware() const {
return this->target_firmware;
}
constexpr u32 GetMasterKeyRevision() const {
return this->master_key_revision;
}
};
}
namespace ams {
struct FatalErrorContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
static constexpr size_t MaxStackTrace = 0x20;
static constexpr size_t MaxStackDumpSize = 0x100;
static constexpr size_t NumGprs = 29;
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
static constexpr u32 StdAbortErrorDesc = 0xFFE;
static constexpr u32 DataAbortErrorDesc = 0x101;
static constexpr u32 Magic = 0x31454641;
u32 magic;
u32 error_desc;
u64 program_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[MaxStackTrace];
u8 stack_dump[MaxStackDumpSize];
};
static_assert(sizeof(FatalErrorContext) == 0x350, "sizeof(FatalErrorContext)");
static_assert(std::is_pod<FatalErrorContext>::value, "FatalErrorContext");
#ifdef ATMOSPHERE_GIT_BRANCH
NX_CONSTEXPR const char *GetGitBranch() {
return ATMOSPHERE_GIT_BRANCH;
}
#endif
#ifdef ATMOSPHERE_GIT_REVISION
NX_CONSTEXPR const char *GetGitRevision() {
return ATMOSPHERE_GIT_REVISION;
}
#endif
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "boot2/boot2_api.hpp"

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2018-2019 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::boot2 {
/* Boot2 API. */
/* Normally invoked by PM. */
void LaunchPreSdCardBootProgramsAndBoot2();
/* Normally invoked by boot2. */
void LaunchPostSdCardBootPrograms();
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "cfg/cfg_api.hpp"

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2018-2019 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 "cfg_types.hpp"
#include "cfg_locale_types.hpp"
#include "../sm/sm_types.hpp"
namespace ams::cfg {
/* Privileged Process configuration. */
bool IsInitialProcess();
void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max);
/* SD card configuration. */
bool IsSdCardRequiredServicesReady();
void WaitSdCardRequiredServicesReady();
bool IsSdCardInitialized();
void WaitSdCardInitialized();
/* Override key utilities. */
OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id);
/* Locale utilities. */
OverrideLocale GetOverrideLocale(ncm::ProgramId program_id);
/* Flag utilities. */
bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag);
bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag);
bool HasGlobalFlag(const char *flag);
/* HBL Configuration utilities. */
bool IsHblProgramId(ncm::ProgramId program_id);
bool HasHblFlag(const char *flag);
const char *GetHblPath();
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 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 "cfg_types.hpp"
#include "../settings/settings_types.hpp"
namespace ams::cfg {
struct OverrideLocale {
settings::LanguageCode language_code;
settings::RegionCode region_code;
};
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2018-2019 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 "../os/os_common_types.hpp"
#include "../ncm/ncm_types.hpp"
namespace ams::cfg {
namespace impl {
enum OverrideStatusFlag : u64 {
OverrideStatusFlag_Hbl = BIT(0),
OverrideStatusFlag_ProgramSpecific = BIT(1),
OverrideStatusFlag_CheatEnabled = BIT(2),
};
}
struct OverrideStatus {
u64 keys_held;
u64 flags;
constexpr inline u64 GetKeysHeld() const { return this->keys_held; }
#define DEFINE_FLAG_ACCESSORS(flag) \
constexpr inline bool Is##flag() const { return this->flags & impl::OverrideStatusFlag_##flag; } \
constexpr inline void Set##flag() { this->flags |= impl::OverrideStatusFlag_##flag; } \
constexpr inline void Clear##flag() { this->flags &= ~u64(impl::OverrideStatusFlag_##flag); }
DEFINE_FLAG_ACCESSORS(Hbl)
DEFINE_FLAG_ACCESSORS(ProgramSpecific)
DEFINE_FLAG_ACCESSORS(CheatEnabled)
#undef DEFINE_FLAG_ACCESSORS
};
static_assert(sizeof(OverrideStatus) == 0x10, "sizeof(OverrideStatus)");
static_assert(std::is_pod<OverrideStatus>::value, "std::is_pod<OverrideStatus>::value");
constexpr inline bool operator==(const OverrideStatus &lhs, const OverrideStatus &rhs) {
return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
constexpr inline bool operator!=(const OverrideStatus &lhs, const OverrideStatus &rhs) {
return !(lhs == rhs);
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 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 "dd/dd_io_mappings.hpp"
#include "dd/dd_process_handle.hpp"

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2018-2019 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::dd {
uintptr_t QueryIoMapping(uintptr_t phys_addr, size_t size);
u32 ReadRegister(uintptr_t phys_addr);
void WriteRegister(uintptr_t phys_addr, u32 value);
u32 ReadWriteRegister(uintptr_t phys_addr, u32 value, u32 mask);
/* Convenience Helper. */
inline uintptr_t GetIoMapping(uintptr_t phys_addr, size_t size) {
const uintptr_t io_mapping = QueryIoMapping(phys_addr, size);
AMS_ASSERT(io_mapping);
return io_mapping;
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 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::dd {
::Handle GetCurrentProcessHandle();
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "dmnt/dmnt_cheat_types.hpp"

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2019 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 "../os/os_common_types.hpp"
#include "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::dmnt::cheat {
struct CheatProcessMetadata {
struct MemoryRegionExtents {
u64 base;
u64 size;
};
os::ProcessId process_id;
ncm::ProgramId program_id;
MemoryRegionExtents main_nso_extents;
MemoryRegionExtents heap_extents;
MemoryRegionExtents alias_extents;
MemoryRegionExtents aslr_extents;
u8 main_nso_build_id[0x20];
};
static_assert(std::is_pod<CheatProcessMetadata>::value && sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata definition!");
struct CheatDefinition : sf::LargeData, sf::PrefersMapAliasTransferMode {
char readable_name[0x40];
uint32_t num_opcodes;
uint32_t opcodes[0x100];
};
struct CheatEntry : sf::LargeData, sf::PrefersMapAliasTransferMode {
bool enabled;
uint32_t cheat_id;
CheatDefinition definition;
};
static_assert(std::is_pod<CheatDefinition>::value, "CheatDefinition");
static_assert(std::is_pod<CheatEntry>::value, "CheatEntry");
struct FrozenAddressValue {
u64 value;
u8 width;
};
struct FrozenAddressEntry {
u64 address;
FrozenAddressValue value;
};
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "fatal/fatal_types.hpp"

View File

@@ -0,0 +1,348 @@
/*
* Copyright (c) 2018-2019 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 "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::fatal {
namespace aarch64 {
enum RegisterName {
RegisterName_X0 = 0,
RegisterName_X1 = 1,
RegisterName_X2 = 2,
RegisterName_X3 = 3,
RegisterName_X4 = 4,
RegisterName_X5 = 5,
RegisterName_X6 = 6,
RegisterName_X7 = 7,
RegisterName_X8 = 8,
RegisterName_X9 = 9,
RegisterName_X10 = 10,
RegisterName_X11 = 11,
RegisterName_X12 = 12,
RegisterName_X13 = 13,
RegisterName_X14 = 14,
RegisterName_X15 = 15,
RegisterName_X16 = 16,
RegisterName_X17 = 17,
RegisterName_X18 = 18,
RegisterName_X19 = 19,
RegisterName_X20 = 20,
RegisterName_X21 = 21,
RegisterName_X22 = 22,
RegisterName_X23 = 23,
RegisterName_X24 = 24,
RegisterName_X25 = 25,
RegisterName_X26 = 26,
RegisterName_X27 = 27,
RegisterName_X28 = 28,
RegisterName_FP = 29,
RegisterName_LR = 30,
RegisterName_SP = 31,
RegisterName_PC = 32,
RegisterName_GeneralPurposeCount,
RegisterName_PState = 33,
RegisterName_Afsr0 = 34,
RegisterName_Afsr1 = 35,
RegisterName_Esr = 36,
RegisterName_Far = 37,
RegisterName_Count,
};
struct CpuContext {
using RegisterType = u64;
static constexpr size_t MaxStackTraceDepth = 0x20;
static constexpr const char *RegisterNameStrings[RegisterName_Count] = {
u8"X0",
u8"X1",
u8"X2",
u8"X3",
u8"X4",
u8"X5",
u8"X6",
u8"X7",
u8"X8",
u8"X9",
u8"X10",
u8"X11",
u8"X12",
u8"X13",
u8"X14",
u8"X15",
u8"X16",
u8"X17",
u8"X18",
u8"X19",
u8"X20",
u8"X21",
u8"X22",
u8"X23",
u8"X24",
u8"X25",
u8"X26",
u8"X27",
u8"X28",
u8"FP",
u8"LR",
u8"SP",
u8"PC",
u8"PState",
u8"Afsr0",
u8"Afsr1",
u8"Esr",
u8"Far",
};
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
struct {
union {
RegisterType x[RegisterName_GeneralPurposeCount];
struct {
RegisterType _x[RegisterName_FP];
RegisterType fp;
RegisterType lr;
RegisterType sp;
RegisterType pc;
};
};
RegisterType pstate;
RegisterType afsr0;
RegisterType afsr1;
RegisterType esr;
RegisterType far;
};
RegisterType registers[RegisterName_Count];
};
/* Misc. */
RegisterType stack_trace[MaxStackTraceDepth];
RegisterType base_address;
RegisterType register_set_flags;
u32 stack_trace_size;
void ClearState() {
std::memset(this, 0, sizeof(*this));
}
void SetProgramIdForAtmosphere(ncm::ProgramId program_id) {
/* Right now, we mux program ID in through afsr when creport. */
/* TODO: Better way to do this? */
this->afsr0 = static_cast<RegisterType>(program_id);
}
ncm::ProgramId GetProgramIdForAtmosphere() const {
return ncm::ProgramId{this->afsr0};
}
void SetRegisterValue(RegisterName name, RegisterType value) {
this->registers[name] = value;
this->register_set_flags |= (RegisterType(1) << name);
}
bool HasRegisterValue(RegisterName name) const {
return this->register_set_flags & (RegisterType(1) << name);
}
void SetBaseAddress(RegisterType base_addr) {
this->base_address = base_addr;
}
};
}
namespace aarch32 {
enum RegisterName {
RegisterName_R0 = 0,
RegisterName_R1 = 1,
RegisterName_R2 = 2,
RegisterName_R3 = 3,
RegisterName_R4 = 4,
RegisterName_R5 = 5,
RegisterName_R6 = 6,
RegisterName_R7 = 7,
RegisterName_R8 = 8,
RegisterName_R9 = 9,
RegisterName_R10 = 10,
RegisterName_FP = 11,
RegisterName_IP = 12,
RegisterName_LR = 13,
RegisterName_SP = 14,
RegisterName_PC = 15,
RegisterName_GeneralPurposeCount,
RegisterName_PState = 16,
RegisterName_Afsr0 = 17,
RegisterName_Afsr1 = 18,
RegisterName_Esr = 29,
RegisterName_Far = 20,
RegisterName_Count,
};
struct CpuContext {
using RegisterType = u32;
static constexpr size_t MaxStackTraceDepth = 0x20;
static constexpr const char *RegisterNameStrings[RegisterName_Count] = {
u8"R0",
u8"R1",
u8"R2",
u8"R3",
u8"R4",
u8"R5",
u8"R6",
u8"R7",
u8"R8",
u8"R9",
u8"R10",
u8"FP",
u8"IP",
u8"LR",
u8"SP",
u8"PC",
u8"PState",
u8"Afsr0",
u8"Afsr1",
u8"Esr",
u8"Far",
};
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
struct {
union {
RegisterType r[RegisterName_GeneralPurposeCount];
struct {
RegisterType _x[RegisterName_FP];
RegisterType fp;
RegisterType ip;
RegisterType lr;
RegisterType sp;
RegisterType pc;
};
};
RegisterType pstate;
RegisterType afsr0;
RegisterType afsr1;
RegisterType esr;
RegisterType far;
};
RegisterType registers[RegisterName_Count];
};
/* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */
RegisterType stack_trace[MaxStackTraceDepth];
u32 stack_trace_size;
RegisterType base_address;
RegisterType register_set_flags;
void ClearState() {
std::memset(this, 0, sizeof(*this));
}
void SetProgramIdForAtmosphere(ncm::ProgramId program_id) {
/* Right now, we mux program ID in through afsr when creport. */
/* TODO: Better way to do this? */
this->afsr0 = static_cast<RegisterType>(static_cast<u64>(program_id) >> 0);
this->afsr1 = static_cast<RegisterType>(static_cast<u64>(program_id) >> 32);
}
ncm::ProgramId GetProgramIdForAtmosphere() const {
return ncm::ProgramId{(static_cast<u64>(this->afsr1) << 32ul) | (static_cast<u64>(this->afsr0) << 0ul)};
}
void SetRegisterValue(RegisterName name, RegisterType value) {
this->registers[name] = value;
this->register_set_flags |= (RegisterType(1) << name);
}
bool HasRegisterValue(RegisterName name) const {
return this->register_set_flags & (RegisterType(1) << name);
}
void SetBaseAddress(RegisterType base_addr) {
this->base_address = base_addr;
}
};
}
struct CpuContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
enum Architecture {
Architecture_Aarch64 = 0,
Architecture_Aarch32 = 1,
};
union {
aarch64::CpuContext aarch64_ctx;
aarch32::CpuContext aarch32_ctx;
};
Architecture architecture;
u32 type;
void ClearState() {
std::memset(this, 0, sizeof(*this));
}
};
static_assert(std::is_pod<aarch64::CpuContext>::value && sizeof(aarch64::CpuContext) == 0x248, "aarch64::CpuContext definition!");
static_assert(std::is_pod<aarch32::CpuContext>::value && sizeof(aarch32::CpuContext) == 0xE0, "aarch32::CpuContext definition!");
static_assert(std::is_pod<CpuContext>::value && sizeof(CpuContext) == 0x250, "CpuContext definition!");
namespace srv {
struct ThrowContext {
Result result;
ncm::ProgramId program_id;
char proc_name[0xD];
bool is_creport;
CpuContext cpu_ctx;
bool generate_error_report;
Event erpt_event;
Event battery_event;
size_t stack_dump_size;
u8 stack_dump[0x100];
void ClearState() {
this->result = ResultSuccess();
this->program_id = ncm::ProgramId::Invalid;
std::memset(this->proc_name, 0, sizeof(this->proc_name));
this->is_creport = false;
std::memset(&this->cpu_ctx, 0, sizeof(this->cpu_ctx));
this->generate_error_report = false;
std::memset(&this->erpt_event, 0, sizeof(this->erpt_event));
std::memset(&this->battery_event, 0, sizeof(this->battery_event));
this->stack_dump_size = 0;
std::memset(this->stack_dump, 0, sizeof(this->stack_dump));
}
};
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 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 "fs/fs_common.hpp"
#include "fs/fsa/fs_ifile.hpp"
#include "fs/fsa/fs_idirectory.hpp"
#include "fs/fsa/fs_ifilesystem.hpp"
#include "fs/fs_remote_filesystem.hpp"
#include "fs/fs_istorage.hpp"
#include "fs/fs_remote_storage.hpp"
#include "fs/fs_file_storage.hpp"
#include "fs/fs_query_range.hpp"
#include "fs/fs_path_tool.hpp"
#include "fs/fs_path_utils.hpp"

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 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 "../os.hpp"
#include "../ncm.hpp"
#include "../sf.hpp"
namespace ams::fs {
/* TODO: Better place for this? */
constexpr inline size_t MountNameLengthMax = 15;
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
namespace ams::fs {
constexpr inline size_t EntryNameLengthMax = 0x300;
using DirectoryEntry = ::FsDirectoryEntry;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
namespace ams::fs {
struct ReadOption {
u32 value;
static const ReadOption None;
};
inline constexpr const ReadOption ReadOption::None = {FsReadOption_None};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
return !(lhs == rhs);
}
static_assert(std::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
struct WriteOption {
u32 value;
constexpr inline bool HasFlushFlag() const {
return this->value & FsWriteOption_Flush;
}
static const WriteOption None;
static const WriteOption Flush;
};
inline constexpr const WriteOption WriteOption::None = {FsWriteOption_None};
inline constexpr const WriteOption WriteOption::Flush = {FsWriteOption_Flush};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
return !(lhs == rhs);
}
static_assert(std::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32));
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
#include "fs_istorage.hpp"
#include "fsa/fs_ifile.hpp"
namespace ams::fs {
class FileStorage : public IStorage {
private:
static constexpr s64 InvalidSize = -1;
private:
std::unique_ptr<fsa::IFile> unique_file;
std::shared_ptr<fsa::IFile> shared_file;
fsa::IFile *base_file;
s64 size;
public:
FileStorage(fsa::IFile *f) : unique_file(f), size(InvalidSize) {
this->base_file = this->unique_file.get();
}
FileStorage(std::unique_ptr<fsa::IFile> f) : unique_file(std::move(f)), size(InvalidSize) {
this->base_file = this->unique_file.get();
}
FileStorage(std::shared_ptr<fsa::IFile> f) : shared_file(f), size(InvalidSize) {
this->base_file = this->shared_file.get();
}
virtual ~FileStorage() { /* ... */ }
protected:
Result UpdateSize();
public:
virtual Result Read(s64 offset, void *buffer, size_t size) override;
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
virtual Result Flush() override;
virtual Result GetSize(s64 *out_size) override;
virtual Result SetSize(s64 size) override;
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
};
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
namespace ams::fs {
enum OpenMode {
OpenMode_Read = ::FsOpenMode_Read,
OpenMode_Write = ::FsOpenMode_Write,
OpenMode_Append = ::FsOpenMode_Append,
OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write),
OpenMode_All = (OpenMode_ReadWrite | OpenMode_Append),
};
enum OpenDirectoryMode {
OpenDirectoryMode_Directory = ::FsDirOpenMode_ReadDirs,
OpenDirectoryMode_File = ::FsDirOpenMode_ReadFiles,
OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File),
/* TODO: Separate enum, like N? */
OpenDirectoryMode_NotRequireFileSize = ::FsDirOpenMode_NoFileSize,
};
enum DirectoryEntryType {
DirectoryEntryType_Directory = ::FsDirEntryType_Dir,
DirectoryEntryType_File = ::FsDirEntryType_File,
};
enum CreateOption {
CreateOption_None = 0,
CreateOption_BigFile = ::FsCreateOption_BigFile,
};
using FileTimeStampRaw = ::FsTimeStampRaw;
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
#include "fs_file.hpp"
#include "fs_operate_range.hpp"
namespace ams::fs {
class IStorage {
public:
virtual ~IStorage() { /* ... */ }
virtual Result Read(s64 offset, void *buffer, size_t size) = 0;
virtual Result Write(s64 offset, const void *buffer, size_t size) {
return fs::ResultUnsupportedOperation();
}
virtual Result Flush() = 0;
virtual Result SetSize(s64 size) {
return fs::ResultUnsupportedOperation();
}
virtual Result GetSize(s64 *out) = 0;
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
return fs::ResultUnsupportedOperation();
}
virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) {
return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0);
}
public:
static inline bool IsRangeValid(s64 offset, s64 size, s64 total_size) {
return offset >= 0 &&
size >= 0 &&
size <= total_size &&
offset <= (total_size - size);
}
static inline bool IsRangeValid(s64 offset, size_t size, s64 total_size) {
return IsRangeValid(offset, static_cast<s64>(size), total_size);
}
static inline bool IsOffsetAndSizeValid(s64 offset, s64 size) {
return offset >= 0 &&
size >= 0 &&
offset <= (offset + size);
}
static inline bool IsOffsetAndSizeValid(s64 offset, size_t size) {
return IsOffsetAndSizeValid(offset, static_cast<s64>(size));
}
};
class ReadOnlyStorageAdapter : public IStorage {
private:
std::shared_ptr<IStorage> shared_storage;
std::unique_ptr<IStorage> unique_storage;
IStorage *storage;
public:
ReadOnlyStorageAdapter(IStorage *s) : unique_storage(s) {
this->storage = this->unique_storage.get();
}
ReadOnlyStorageAdapter(std::shared_ptr<IStorage> s) : shared_storage(s) {
this->storage = this->shared_storage.get();
}
ReadOnlyStorageAdapter(std::unique_ptr<IStorage> s) : unique_storage(std::move(s)) {
this->storage = this->unique_storage.get();
}
virtual ~ReadOnlyStorageAdapter() { /* ... */ }
public:
virtual Result Read(s64 offset, void *buffer, size_t size) {
return this->storage->Read(offset, buffer, size);
}
virtual Result Flush() {
return this->storage->Flush();
}
virtual Result GetSize(s64 *out) {
return this->storage->GetSize(out);
}
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
return this->storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
}
};
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
namespace ams::fs {
enum class OperationId : u64 {
Clear = ::FsOperationId_Clear,
ClearSignature = ::FsOperationId_ClearSignature,
InvalidateCache = ::FsOperationId_InvalidateCache,
QueryRange = ::FsOperationId_QueryRange,
};
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
#include "../fssrv/fssrv_sf_path.hpp"
namespace ams::fs {
namespace StringTraits {
constexpr inline char DirectorySeparator = '/';
constexpr inline char DriveSeparator = ':';
constexpr inline char Dot = '.';
constexpr inline char NullTerminator = '\x00';
}
class PathTool {
public:
static constexpr const char RootPath[] = "/";
public:
static constexpr inline bool IsSeparator(char c) {
return c == StringTraits::DirectorySeparator;
}
static constexpr inline bool IsNullTerminator(char c) {
return c == StringTraits::NullTerminator;
}
static constexpr inline bool IsDot(char c) {
return c == StringTraits::Dot;
}
static constexpr inline bool IsWindowsDriveCharacter(char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
static constexpr inline bool IsDriveSeparator(char c) {
return c == StringTraits::DriveSeparator;
}
static constexpr inline bool IsWindowsAbsolutePath(const char *p) {
return IsWindowsDriveCharacter(p[0]) && IsDriveSeparator(p[1]);
}
static constexpr inline bool IsCurrentDirectory(const char *p) {
return IsDot(p[0]) && (IsSeparator(p[1]) || IsNullTerminator(p[1]));
}
static constexpr inline bool IsParentDirectory(const char *p) {
return IsDot(p[0]) && IsDot(p[1]) && (IsSeparator(p[2]) || IsNullTerminator(p[2]));
}
static Result Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved = false);
static Result IsNormalized(bool *out, const char *path);
static bool IsSubPath(const char *lhs, const char *rhs);
};
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
#include "../fssrv/fssrv_sf_path.hpp"
namespace ams::fs {
inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) {
for (char *cur = dst; cur < dst + dst_size && *cur != '\x00'; cur++) {
if (*cur == old_char) {
*cur = new_char;
}
}
}
inline Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) {
/* Format the path. */
std::va_list va_list;
va_start(va_list, format);
const size_t len = std::vsnprintf(dst->str, sizeof(dst->str), format, va_list);
va_end(va_list);
/* Validate length. */
R_UNLESS(len < sizeof(dst->str), fs::ResultTooLongPath());
/* Fix slashes. */
Replace(dst->str, sizeof(dst->str) - 1, '\\', '/');
return ResultSuccess();
}
Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
namespace ams::fs {
struct QueryRangeInfo {
u32 aes_ctr_key_type;
u32 speed_emulation_type;
u32 reserved[0x38 / sizeof(u32)];
void Clear() {
this->aes_ctr_key_type = 0;
this->speed_emulation_type = 0;
std::memset(this->reserved, 0, sizeof(this->reserved));
}
void Merge(const QueryRangeInfo &rhs) {
this->aes_ctr_key_type |= rhs.aes_ctr_key_type;
this->speed_emulation_type |= rhs.speed_emulation_type;
}
};
static_assert(std::is_pod<QueryRangeInfo>::value);
static_assert(sizeof(QueryRangeInfo) == 0x40);
static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo));
using FileQueryRangeInfo = QueryRangeInfo;
using StorageQueryRangeInfo = QueryRangeInfo;
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
#include "fsa/fs_ifile.hpp"
#include "fsa/fs_idirectory.hpp"
#include "fsa/fs_ifilesystem.hpp"
namespace ams::fs {
class RemoteFile : public fsa::IFile {
private:
std::unique_ptr<::FsFile> base_file;
public:
RemoteFile(::FsFile *f) : base_file(f) { /* ... */ }
RemoteFile(std::unique_ptr<::FsFile> f) : base_file(std::move(f)) { /* ... */ }
RemoteFile(::FsFile f) {
this->base_file = std::make_unique<::FsFile>(f);
}
virtual ~RemoteFile() { fsFileClose(this->base_file.get()); }
public:
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final {
return fsFileRead(this->base_file.get(), offset, buffer, size, option.value, out);
}
virtual Result GetSizeImpl(s64 *out) override final {
return fsFileGetSize(this->base_file.get(), out);
}
virtual Result FlushImpl() override final {
return fsFileFlush(this->base_file.get());
}
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
return fsFileWrite(this->base_file.get(), offset, buffer, size, option.value);
}
virtual Result SetSizeImpl(s64 size) override final {
return fsFileSetSize(this->base_file.get(), size);
}
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
/* TODO: How should this be handled? */
return fs::ResultNotImplemented();
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_file->s)};
}
};
class RemoteDirectory : public fsa::IDirectory {
private:
std::unique_ptr<::FsDir> base_dir;
public:
RemoteDirectory(::FsDir *d) : base_dir(d) { /* ... */ }
RemoteDirectory(std::unique_ptr<::FsDir> d) : base_dir(std::move(d)) { /* ... */ }
RemoteDirectory(::FsDir d) {
this->base_dir = std::make_unique<::FsDir>(d);
}
virtual ~RemoteDirectory() { fsDirClose(this->base_dir.get()); }
public:
virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final {
return fsDirRead(this->base_dir.get(), out_count, max_entries, out_entries);
}
virtual Result GetEntryCountImpl(s64 *out) override final {
return fsDirGetEntryCount(this->base_dir.get(), out);
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_dir->s)};
}
};
class RemoteFileSystem : public fsa::IFileSystem {
private:
std::unique_ptr<::FsFileSystem> base_fs;
public:
RemoteFileSystem(::FsFileSystem *fs) : base_fs(fs) { /* ... */ }
RemoteFileSystem(std::unique_ptr<::FsFileSystem> fs) : base_fs(std::move(fs)) { /* ... */ }
RemoteFileSystem(::FsFileSystem fs) {
this->base_fs = std::make_unique<::FsFileSystem>(fs);
}
virtual ~RemoteFileSystem() { fsFsClose(this->base_fs.get()); }
public:
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final {
return fsFsCreateFile(this->base_fs.get(), path, size, flags);
}
virtual Result DeleteFileImpl(const char *path) override final {
return fsFsDeleteFile(this->base_fs.get(), path);
}
virtual Result CreateDirectoryImpl(const char *path) override final {
return fsFsCreateDirectory(this->base_fs.get(), path);
}
virtual Result DeleteDirectoryImpl(const char *path) override final {
return fsFsDeleteDirectory(this->base_fs.get(), path);
}
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final {
return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path);
}
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final {
return fsFsRenameFile(this->base_fs.get(), old_path, new_path);
}
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final {
return fsFsRenameDirectory(this->base_fs.get(), old_path, new_path);
}
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final {
static_assert(sizeof(::FsDirEntryType) == sizeof(DirectoryEntryType));
return fsFsGetEntryType(this->base_fs.get(), path, reinterpret_cast<::FsDirEntryType *>(out));
}
virtual Result OpenFileImpl(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
FsFile f;
R_TRY(fsFsOpenFile(this->base_fs.get(), path, mode, &f));
*out_file = std::make_unique<RemoteFile>(f);
return ResultSuccess();
}
virtual Result OpenDirectoryImpl(std::unique_ptr<fsa::IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) override final {
FsDir d;
R_TRY(fsFsOpenDirectory(this->base_fs.get(), path, mode, &d));
*out_dir = std::make_unique<RemoteDirectory>(d);
return ResultSuccess();
}
virtual Result CommitImpl() override final {
return fsFsCommit(this->base_fs.get());
}
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
return fsFsGetFreeSpace(this->base_fs.get(), path, out);
}
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
return fsFsGetTotalSpace(this->base_fs.get(), path, out);
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) {
return fsFsCleanDirectoryRecursively(this->base_fs.get(), path);
}
virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) {
static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw));
return fsFsGetFileTimeStampRaw(this->base_fs.get(), path, reinterpret_cast<::FsTimeStampRaw *>(out));
}
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) {
return fsFsQueryEntry(this->base_fs.get(), dst, dst_size, src, src_size, path, static_cast<FsFileSystemQueryId>(query));
}
};
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2018-2019 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 "fs_common.hpp"
#include "fs_istorage.hpp"
namespace ams::fs {
class RemoteStorage : public IStorage {
private:
std::unique_ptr<::FsStorage> base_storage;
public:
RemoteStorage(::FsStorage *s) : base_storage(s) { /* ... */ }
RemoteStorage(std::unique_ptr<::FsStorage> s) : base_storage(std::move(s)) { /* ... */ }
RemoteStorage(::FsStorage s) {
this->base_storage = std::make_unique<::FsStorage>(s);
}
virtual ~RemoteStorage() { fsStorageClose(this->base_storage.get()); }
public:
virtual Result Read(s64 offset, void *buffer, size_t size) override {
return fsStorageRead(this->base_storage.get(), offset, buffer, size);
};
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
return fsStorageWrite(this->base_storage.get(), offset, buffer, size);
};
virtual Result Flush() override {
return fsStorageFlush(this->base_storage.get());
};
virtual Result GetSize(s64 *out_size) override {
return fsStorageGetSize(this->base_storage.get(), out_size);
};
virtual Result SetSize(s64 size) override {
return fsStorageSetSize(this->base_storage.get(), size);
};
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
/* TODO: How to deal with this? */
return fs::ResultUnsupportedOperation();
};
};
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2019 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 "../fs_common.hpp"
#include "../fs_directory.hpp"
namespace ams::fs::fsa {
class IDirectory {
public:
virtual ~IDirectory() { /* ... */ }
Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) {
R_UNLESS(out_count != nullptr, fs::ResultNullptrArgument());
if (max_entries == 0) {
*out_count = 0;
return ResultSuccess();
}
R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument());
R_UNLESS(max_entries > 0, fs::ResultInvalidArgument());
return this->ReadImpl(out_count, out_entries, max_entries);
}
Result GetEntryCount(s64 *out) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetEntryCountImpl(out);
}
public:
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0;
protected:
/* ...? */
private:
virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0;
virtual Result GetEntryCountImpl(s64 *out) = 0;
};
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2018-2019 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 "../fs_common.hpp"
#include "../fs_file.hpp"
#include "../fs_operate_range.hpp"
namespace ams::fs::fsa {
class IFile {
public:
virtual ~IFile() { /* ... */ }
Result Read(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
if (size == 0) {
*out = 0;
return ResultSuccess();
}
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
const s64 signed_size = static_cast<s64>(size);
R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
R_UNLESS((std::numeric_limits<s64>::max() - offset) >= signed_size, fs::ResultOutOfRange());
return this->ReadImpl(out, offset, buffer, size, option);
}
Result Read(size_t *out, s64 offset, void *buffer, size_t size) {
return this->Read(out, offset, buffer, size, ReadOption::None);
}
Result GetSize(s64 *out) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetSizeImpl(out);
}
Result Flush() {
return this->FlushImpl();
}
Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
if (size == 0) {
if (option.HasFlushFlag()) {
R_TRY(this->Flush());
}
return ResultSuccess();
}
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
const s64 signed_size = static_cast<s64>(size);
R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
R_UNLESS((std::numeric_limits<s64>::max() - offset) >= signed_size, fs::ResultOutOfRange());
return this->WriteImpl(offset, buffer, size, option);
}
Result SetSize(s64 size) {
R_UNLESS(size >= 0, fs::ResultOutOfRange());
return this->SetSizeImpl(size);
}
Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
return this->OperateRangeImpl(dst, dst_size, op_id, offset, size, src, src_size);
}
Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) {
return this->OperateRangeImpl(nullptr, 0, op_id, offset, size, nullptr, 0);
}
public:
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0;
protected:
/* ...? */
private:
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0;
virtual Result GetSizeImpl(s64 *out) = 0;
virtual Result FlushImpl() = 0;
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) = 0;
virtual Result SetSizeImpl(s64 size) = 0;
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0;
};
}

View File

@@ -0,0 +1,191 @@
/*
* Copyright (c) 2018-2019 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 "../fs_common.hpp"
#include "../fs_filesystem.hpp"
namespace ams::fs::fsa {
class IFile;
class IDirectory;
enum class QueryId {
SetConcatenationFileAttribute = FsFileSystemQueryId_SetConcatenationFileAttribute
};
class IFileSystem {
public:
virtual ~IFileSystem() { /* ... */ }
Result CreateFile(const char *path, s64 size, int option) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(size >= 0, fs::ResultOutOfRange());
return this->CreateFileImpl(path, size, option);
}
Result CreateFile(const char *path, s64 size) {
return this->CreateFile(path, size, 0);
}
Result DeleteFile(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DeleteFileImpl(path);
}
Result CreateDirectory(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->CreateDirectoryImpl(path);
}
Result DeleteDirectory(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DeleteDirectoryImpl(path);
}
Result DeleteDirectoryRecursively(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DeleteDirectoryRecursivelyImpl(path);
}
Result RenameFile(const char *old_path, const char *new_path) {
R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
return this->RenameFileImpl(old_path, new_path);
}
Result RenameDirectory(const char *old_path, const char *new_path) {
R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
return this->RenameDirectoryImpl(old_path, new_path);
}
Result GetEntryType(DirectoryEntryType *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetEntryTypeImpl(out, path);
}
Result OpenFile(std::unique_ptr<IFile> *out_file, const char *path, OpenMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidArgument());
R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidArgument());
return this->OpenFileImpl(out_file, path, mode);
}
Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument());
R_UNLESS((mode & ~OpenDirectoryMode_All) == 0, fs::ResultInvalidArgument());
return this->OpenDirectoryImpl(out_dir, path, mode);
}
Result Commit() {
return this->CommitImpl();
}
Result GetFreeSpaceSize(s64 *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetFreeSpaceSizeImpl(out, path);
}
Result GetTotalSpaceSize(s64 *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetTotalSpaceSizeImpl(out, path);
}
Result CleanDirectoryRecursively(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->CleanDirectoryRecursivelyImpl(path);
}
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetFileTimeStampRawImpl(out, path);
}
Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->QueryEntryImpl(dst, dst_size, src, src_size, query, path);
}
/* These aren't accessible as commands. */
Result CommitProvisionally(s64 counter) {
return this->CommitProvisionallyImpl(counter);
}
Result Rollback() {
return this->RollbackImpl();
}
Result Flush() {
return this->FlushImpl();
}
protected:
/* ...? */
private:
virtual Result CreateFileImpl(const char *path, s64 size, int flags) = 0;
virtual Result DeleteFileImpl(const char *path) = 0;
virtual Result CreateDirectoryImpl(const char *path) = 0;
virtual Result DeleteDirectoryImpl(const char *path) = 0;
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) = 0;
virtual Result RenameFileImpl(const char *old_path, const char *new_path) = 0;
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) = 0;
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) = 0;
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) = 0;
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0;
virtual Result CommitImpl() = 0;
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
return fs::ResultNotImplemented();
}
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
return fs::ResultNotImplemented();
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) = 0;
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) {
return fs::ResultNotImplemented();
}
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) {
return fs::ResultNotImplemented();
}
/* These aren't accessible as commands. */
virtual Result CommitProvisionallyImpl(s64 counter) {
return fs::ResultNotImplemented();
}
virtual Result RollbackImpl() {
return fs::ResultNotImplemented();
}
virtual Result FlushImpl() {
return fs::ResultNotImplemented();
}
};
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "fssrv/fssrv_sf_path.hpp"
#include "fssrv/fssrv_path_normalizer.hpp"

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2018-2019 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 "interface_adapters/fssrv_storage_interface_adapter.hpp"
#include "interface_adapters/fssrv_filesystem_interface_adapter.hpp"

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2019 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 "../fs/fs_common.hpp"
namespace ams::fssrv {
/* This is in fssrv::detail in official code. */
/* TODO: Consider moving to ::impl? */
class PathNormalizer {
public:
enum Option : u32 {
Option_None = BIT(0),
Option_PreserveUnc = BIT(1),
Option_PreserveTailSeparator = BIT(2),
Option_HasMountName = BIT(3),
Option_AcceptEmpty = BIT(4),
};
private:
using Buffer = std::unique_ptr<char[]>;
private:
Buffer buffer;
const char *path;
Result result;
private:
static Result Normalize(const char **out_path, Buffer *out_buf, const char *path, bool preserve_unc, bool preserve_tail_sep, bool has_mount_name);
public:
explicit PathNormalizer(const char *p) : buffer(), path(nullptr), result(ResultSuccess()) {
this->result = Normalize(&this->path, &this->buffer, p, false, false, false);
}
PathNormalizer(const char *p, u32 option) : buffer(), path(nullptr), result(ResultSuccess()) {
if ((option & Option_AcceptEmpty) && p[0] == '\x00') {
this->path = path;
} else {
const bool preserve_unc = (option & Option_PreserveUnc);
const bool preserve_tail_sep = (option & Option_PreserveTailSeparator);
const bool has_mount_name = (option & Option_HasMountName);
this->result = Normalize(&this->path, &this->buffer, p, preserve_unc, preserve_tail_sep, has_mount_name);
}
}
inline Result GetResult() const {
return this->result;
}
inline const char * GetPath() const {
return this->path;
}
};
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2019 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 "../fs/fs_common.hpp"
#include "../fs/fs_directory.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::fssrv::sf {
struct Path : ams::sf::LargeData {
char str[fs::EntryNameLengthMax + 1];
static constexpr Path Encode(const char *p) {
Path path = {};
for (size_t i = 0; i < sizeof(path) - 1; i++) {
path.str[i] = p[i];
if (p[i] == '\x00') {
break;
}
}
return path;
}
static constexpr size_t GetPathLength(const Path &path) {
size_t len = 0;
for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
len++;
}
return len;
}
};
static_assert(std::is_pod<Path>::value && sizeof(Path) == FS_MAX_PATH);
using FspPath = Path;
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright (c) 2018-2019 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 "../../fs/fs_common.hpp"
#include "../../fs/fs_file.hpp"
#include "../../fs/fs_directory.hpp"
#include "../../fs/fs_filesystem.hpp"
#include "../../fs/fs_query_range.hpp"
#include "../../fssrv/fssrv_sf_path.hpp"
#include "../../fssystem/fssystem_utility.hpp"
namespace ams::fs::fsa {
class IFile;
class IDirectory;
class IFileSystem;
}
namespace ams::fssrv::impl {
class FileSystemInterfaceAdapter;
class FileInterfaceAdapter final : public ams::sf::IServiceObject {
NON_COPYABLE(FileInterfaceAdapter);
public:
enum class CommandId {
Read = 0,
Write = 1,
Flush = 2,
SetSize = 3,
GetSize = 4,
OperateRange = 5,
};
private:
std::shared_ptr<FileSystemInterfaceAdapter> parent_filesystem;
std::unique_ptr<fs::fsa::IFile> base_file;
std::unique_lock<fssystem::SemaphoreAdapter> open_count_semaphore;
public:
FileInterfaceAdapter(std::unique_ptr<fs::fsa::IFile> &&file, std::shared_ptr<FileSystemInterfaceAdapter> &&parent, std::unique_lock<fssystem::SemaphoreAdapter> &&sema);
~FileInterfaceAdapter();
private:
void InvalidateCache();
public:
/* Command API. */
Result Read(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option);
Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option);
Result Flush();
Result SetSize(s64 size);
Result GetSize(ams::sf::Out<s64> out);
Result OperateRange(ams::sf::Out<fs::FileQueryRangeInfo> out, s32 op_id, s64 offset, s64 size);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(Write),
MAKE_SERVICE_COMMAND_META(Flush),
MAKE_SERVICE_COMMAND_META(SetSize),
MAKE_SERVICE_COMMAND_META(GetSize),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
};
};
class DirectoryInterfaceAdapter final : public ams::sf::IServiceObject {
NON_COPYABLE(DirectoryInterfaceAdapter);
public:
enum class CommandId {
Read = 0,
GetEntryCount = 1,
};
private:
std::shared_ptr<FileSystemInterfaceAdapter> parent_filesystem;
std::unique_ptr<fs::fsa::IDirectory> base_dir;
std::unique_lock<fssystem::SemaphoreAdapter> open_count_semaphore;
public:
DirectoryInterfaceAdapter(std::unique_ptr<fs::fsa::IDirectory> &&dir, std::shared_ptr<FileSystemInterfaceAdapter> &&parent, std::unique_lock<fssystem::SemaphoreAdapter> &&sema);
~DirectoryInterfaceAdapter();
public:
/* Command API */
Result Read(ams::sf::Out<s64> out, const ams::sf::OutBuffer &out_entries);
Result GetEntryCount(ams::sf::Out<s64> out);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(GetEntryCount),
};
};
class FileSystemInterfaceAdapter final : public std::enable_shared_from_this<FileSystemInterfaceAdapter>, public ams::sf::IServiceObject {
NON_COPYABLE(FileSystemInterfaceAdapter);
public:
enum class CommandId {
/* 1.0.0+ */
CreateFile = 0,
DeleteFile = 1,
CreateDirectory = 2,
DeleteDirectory = 3,
DeleteDirectoryRecursively = 4,
RenameFile = 5,
RenameDirectory = 6,
GetEntryType = 7,
OpenFile = 8,
OpenDirectory = 9,
Commit = 10,
GetFreeSpaceSize = 11,
GetTotalSpaceSize = 12,
/* 3.0.0+ */
CleanDirectoryRecursively = 13,
GetFileTimeStampRaw = 14,
/* 4.0.0+ */
QueryEntry = 15,
};
private:
std::shared_ptr<fs::fsa::IFileSystem> base_fs;
std::unique_lock<fssystem::SemaphoreAdapter> mount_count_semaphore;
os::ReadWriteLock invalidation_lock;
bool open_count_limited;
bool deep_retry_enabled = false;
public:
FileSystemInterfaceAdapter(std::shared_ptr<fs::fsa::IFileSystem> &&fs, bool open_limited);
/* TODO: Other constructors. */
~FileSystemInterfaceAdapter();
public:
bool IsDeepRetryEnabled() const;
bool IsAccessFailureDetectionObserved() const;
std::optional<std::shared_lock<os::ReadWriteLock>> AcquireCacheInvalidationReadLock();
os::ReadWriteLock &GetReadWriteLockForCacheInvalidation();
public:
/* Command API. */
Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option);
Result DeleteFile(const fssrv::sf::Path &path);
Result CreateDirectory(const fssrv::sf::Path &path);
Result DeleteDirectory(const fssrv::sf::Path &path);
Result DeleteDirectoryRecursively(const fssrv::sf::Path &path);
Result RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path);
Result RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path);
Result GetEntryType(ams::sf::Out<u32> out, const fssrv::sf::Path &path);
Result OpenFile(ams::sf::Out<std::shared_ptr<FileInterfaceAdapter>> out, const fssrv::sf::Path &path, u32 mode);
Result OpenDirectory(ams::sf::Out<std::shared_ptr<DirectoryInterfaceAdapter>> out, const fssrv::sf::Path &path, u32 mode);
Result Commit();
Result GetFreeSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path);
Result GetTotalSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path);
Result CleanDirectoryRecursively(const fssrv::sf::Path &path);
Result GetFileTimeStampRaw(ams::sf::Out<fs::FileTimeStampRaw> out, const fssrv::sf::Path &path);
Result QueryEntry(const ams::sf::OutBuffer &out_buf, const ams::sf::InBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MAKE_SERVICE_COMMAND_META(CreateFile),
MAKE_SERVICE_COMMAND_META(DeleteFile),
MAKE_SERVICE_COMMAND_META(CreateDirectory),
MAKE_SERVICE_COMMAND_META(DeleteDirectory),
MAKE_SERVICE_COMMAND_META(DeleteDirectoryRecursively),
MAKE_SERVICE_COMMAND_META(RenameFile),
MAKE_SERVICE_COMMAND_META(RenameDirectory),
MAKE_SERVICE_COMMAND_META(GetEntryType),
MAKE_SERVICE_COMMAND_META(OpenFile),
MAKE_SERVICE_COMMAND_META(OpenDirectory),
MAKE_SERVICE_COMMAND_META(Commit),
MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize),
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize),
/* 3.0.0- */
MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_300),
MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_300),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_400),
};
};
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2018-2019 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 "../../fs/fs_common.hpp"
#include "../../fs/fs_query_range.hpp"
#include "../../fssystem/fssystem_utility.hpp"
namespace ams::fs {
class IStorage;
}
namespace ams::fssrv::impl {
class StorageInterfaceAdapter final : public ams::sf::IServiceObject {
NON_COPYABLE(StorageInterfaceAdapter);
public:
enum class CommandId {
Read = 0,
Write = 1,
Flush = 2,
SetSize = 3,
GetSize = 4,
OperateRange = 5,
};
private:
/* TODO: Nintendo uses fssystem::AsynchronousAccessStorage here. */
std::shared_ptr<fs::IStorage> base_storage;
std::unique_lock<fssystem::SemaphoreAdapter> open_count_semaphore;
os::ReadWriteLock invalidation_lock;
/* TODO: DataStorageContext. */
bool deep_retry_enabled = false;
public:
StorageInterfaceAdapter(fs::IStorage *storage);
StorageInterfaceAdapter(std::unique_ptr<fs::IStorage> storage);
explicit StorageInterfaceAdapter(std::shared_ptr<fs::IStorage> &&storage);
/* TODO: Other constructors. */
~StorageInterfaceAdapter();
private:
std::optional<std::shared_lock<os::ReadWriteLock>> AcquireCacheInvalidationReadLock();
private:
/* Command API. */
Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size);
Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size);
Result Flush();
Result SetSize(s64 size);
Result GetSize(ams::sf::Out<s64> out);
Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(Write),
MAKE_SERVICE_COMMAND_META(Flush),
MAKE_SERVICE_COMMAND_META(SetSize),
MAKE_SERVICE_COMMAND_META(GetSize),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
};
};
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2019 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 "fssystem/fssystem_utility.hpp"
#include "fssystem/fssystem_path_tool.hpp"
#include "fssystem/fssystem_subdirectory_filesystem.hpp"
#include "fssystem/fssystem_directory_redirection_filesystem.hpp"
#include "fssystem/fssystem_directory_savedata_filesystem.hpp"

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2019 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 "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class DirectoryRedirectionFileSystem : public impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem> {
NON_COPYABLE(DirectoryRedirectionFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
friend class impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
private:
char *before_dir;
size_t before_dir_len;
char *after_dir;
size_t after_dir_len;
public:
DirectoryRedirectionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc = false);
DirectoryRedirectionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc = false);
virtual ~DirectoryRedirectionFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() const {
/* No accessor lock is needed. */
return std::nullopt;
}
private:
Result GetNormalizedDirectoryPath(char **out, size_t *out_size, const char *dir);
Result Initialize(const char *before, const char *after);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
};
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2019 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 "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class DirectorySaveDataFileSystem : public impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem> {
NON_COPYABLE(DirectorySaveDataFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
friend class impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
private:
os::Mutex accessor_mutex;
s32 open_writable_files;
public:
DirectorySaveDataFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs);
DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs);
Result Initialize();
virtual ~DirectorySaveDataFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() {
/* We have a real accessor lock that we want to use. */
return std::make_optional<std::scoped_lock<os::Mutex>>(this->accessor_mutex);
}
private:
Result AllocateWorkBuffer(std::unique_ptr<u8[]> *out, size_t *out_size, size_t ideal_size);
Result SynchronizeDirectory(const char *dst, const char *src);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
public:
void OnWritableFileClose();
Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs);
public:
/* Overridden from IPathResolutionFileSystem */
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
virtual Result CommitImpl() override;
/* Overridden from IPathResolutionFileSystem but not commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override;
virtual Result RollbackImpl() override;
/* Explicitly overridden to be not implemented. */
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override;
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override;
virtual Result FlushImpl() override;
};
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2019 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 "../fs/fs_common.hpp"
#include "../fs/fs_path_tool.hpp"
namespace ams::fssystem {
namespace StringTraits = ::ams::fs::StringTraits;
using PathTool = ::ams::fs::PathTool;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2019 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 "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class SubDirectoryFileSystem : public impl::IPathResolutionFileSystem<SubDirectoryFileSystem> {
NON_COPYABLE(SubDirectoryFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
friend class impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
private:
char *base_path;
size_t base_path_len;
public:
SubDirectoryFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc = false);
SubDirectoryFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc = false);
virtual ~SubDirectoryFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() const {
/* No accessor lock is needed. */
return std::nullopt;
}
private:
Result Initialize(const char *bp);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
};
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2018-2019 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 "../fs/fs_common.hpp"
#include "../fs/fs_file.hpp"
#include "../fs/fs_directory.hpp"
#include "../fs/fs_filesystem.hpp"
#include "fssystem_path_tool.hpp"
namespace ams::fssystem {
namespace impl {
/* Iteration. */
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
/* Open the directory. */
std::unique_ptr<fs::fsa::IDirectory> dir;
R_TRY(fs->OpenDirectory(&dir, work_path, fs::OpenDirectoryMode_All));
const size_t parent_len = strnlen(work_path, work_path_size - 1);
/* Read and handle entries. */
while (true) {
/* Read a single entry. */
s64 read_count = 0;
R_TRY(dir->Read(&read_count, dir_ent, 1));
/* If we're out of entries, we're done. */
if (read_count == 0) {
break;
}
/* Validate child path size. */
const size_t child_name_len = strnlen(dir_ent->name, sizeof(dir_ent->name) - 1);
const bool is_dir = dir_ent->type == fs::DirectoryEntryType_Directory;
const size_t separator_size = is_dir ? 1 : 0;
R_UNLESS(parent_len + child_name_len + separator_size < work_path_size, fs::ResultTooLongPath());
/* Set child path. */
std::strncat(work_path, dir_ent->name, work_path_size - parent_len - 1);
{
if (is_dir) {
/* Enter directory. */
R_TRY(on_enter_dir(work_path, *dir_ent));
/* Append separator, recurse. */
std::strncat(work_path, "/", work_path_size - (parent_len + child_name_len) - 1);
R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent, on_enter_dir, on_exit_dir, on_file));
/* Exit directory. */
R_TRY(on_exit_dir(work_path, *dir_ent));
} else {
/* Call file handler. */
R_TRY(on_file(work_path, *dir_ent));
}
}
/* Restore parent path. */
work_path[parent_len] = StringTraits::NullTerminator;
}
return ResultSuccess();
}
/* TODO: Cleanup. */
}
/* Iteration API */
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
AMS_ASSERT(work_path_size >= fs::EntryNameLengthMax + 1);
/* Get size of the root path. */
size_t root_path_len = strnlen(root_path, fs::EntryNameLengthMax + 1);
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
/* Copy root path in, add a / if necessary. */
std::memcpy(work_path, root_path, root_path_len);
if (!PathTool::IsSeparator(work_path[root_path_len - 1])) {
work_path[root_path_len++] = StringTraits::DirectorySeparator;
}
/* Make sure the result path is still valid. */
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
work_path[root_path_len] = StringTraits::NullTerminator;
return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent_buf, on_enter_dir, on_exit_dir, on_file);
}
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
fs::DirectoryEntry dir_entry = {};
char work_path[fs::EntryNameLengthMax + 1] = {};
return IterateDirectoryRecursively(fs, root_path, work_path, sizeof(work_path), &dir_entry, on_enter_dir, on_exit_dir, on_file);
}
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
return IterateDirectoryRecursively(fs, PathTool::RootPath, on_enter_dir, on_exit_dir, on_file);
}
/* TODO: Cleanup API */
/* Copy API. */
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
}
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
}
/* Semaphore adapter class. */
class SemaphoreAdapter : public os::Semaphore {
public:
SemaphoreAdapter(int c, int mc) : os::Semaphore(c, mc) { /* ... */ }
bool try_lock() {
return this->TryAcquire();
}
void unlock() {
this->Release();
}
};
/* Other utility. */
Result EnsureDirectoryExistsRecursively(fs::fsa::IFileSystem *fs, const char *path);
template<typename F>
NX_INLINE Result RetryFinitelyForTargetLocked(F f) {
/* Retry up to 10 times, 100ms between retries. */
constexpr s32 MaxRetryCount = 10;
constexpr u64 RetryWaitTime = 100'000'000ul;
s32 remaining_retries = MaxRetryCount;
while (true) {
R_TRY_CATCH(f()) {
R_CATCH(fs::ResultTargetLocked) {
R_UNLESS(remaining_retries > 0, fs::ResultTargetLocked());
remaining_retries--;
svcSleepThread(RetryWaitTime);
continue;
}
} R_END_TRY_CATCH;
return ResultSuccess();
}
}
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2018-2019 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 "../../fs/fs_common.hpp"
#include "../../fs/fsa/fs_ifile.hpp"
#include "../../fs/fsa/fs_idirectory.hpp"
#include "../../fs/fsa/fs_ifilesystem.hpp"
namespace ams::fssystem::impl {
template<typename Impl>
class IPathResolutionFileSystem : public fs::fsa::IFileSystem {
NON_COPYABLE(IPathResolutionFileSystem);
private:
std::shared_ptr<fs::fsa::IFileSystem> shared_fs;
std::unique_ptr<fs::fsa::IFileSystem> unique_fs;
bool unc_preserved;
protected:
fs::fsa::IFileSystem * const base_fs;
public:
IPathResolutionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : shared_fs(std::move(fs)), unc_preserved(unc), base_fs(shared_fs.get()) {
/* ... */
}
IPathResolutionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : unique_fs(std::move(fs)), unc_preserved(unc), base_fs(unique_fs.get()) {
/* ... */
}
virtual ~IPathResolutionFileSystem() { /* ... */ }
protected:
constexpr inline bool IsUncPreserved() const {
return this->unc_preserved;
}
public:
virtual Result CreateFileImpl(const char *path, s64 size, int option) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CreateFile(full_path, size, option);
}
virtual Result DeleteFileImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteFile(full_path);
}
virtual Result CreateDirectoryImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CreateDirectory(full_path);
}
virtual Result DeleteDirectoryImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteDirectory(full_path);
}
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteDirectoryRecursively(full_path);
}
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override {
char old_full_path[fs::EntryNameLengthMax + 1];
char new_full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path));
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->RenameFile(old_full_path, new_full_path);
}
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override {
char old_full_path[fs::EntryNameLengthMax + 1];
char new_full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path));
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->RenameDirectory(old_full_path, new_full_path);
}
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetEntryType(out, full_path);
}
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->OpenFile(out_file, full_path, mode);
}
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
}
virtual Result CommitImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Commit();
}
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetFreeSpaceSize(out, full_path);
}
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetTotalSpaceSize(out, full_path);
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CleanDirectoryRecursively(full_path);
}
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetFileTimeStampRaw(out, full_path);
}
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path);
}
/* These aren't accessible as commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CommitProvisionally(counter);
}
virtual Result RollbackImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Rollback();
}
virtual Result FlushImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Flush();
}
};
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "hid/hid_api.hpp"

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 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
namespace ams::hid {
/* Key API. */
Result GetKeysHeld(u64 *out);
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 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 "hos/hos_types.hpp"
#include "hos/hos_version_api.hpp"

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2019 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::hos {
enum Version : u16 {
Version_Min = 0,
Version_100 = Version_Min,
Version_200 = 1,
Version_300 = 2,
Version_400 = 3,
Version_500 = 4,
Version_600 = 5,
Version_700 = 6,
Version_800 = 7,
Version_810 = 8,
Version_900 = 9,
Version_910 = 10,
Version_Current = Version_910,
Version_Max = 32,
};
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 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 "hos_types.hpp"
namespace ams::hos {
::ams::hos::Version GetVersion();
void SetVersionForLibnx();
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 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 "kvdb/kvdb_auto_buffer.hpp"
#include "kvdb/kvdb_bounded_string.hpp"
#include "kvdb/kvdb_archive.hpp"
#include "kvdb/kvdb_memory_key_value_store.hpp"
#include "kvdb/kvdb_file_key_value_store.hpp"
#include "kvdb/kvdb_file_key_value_cache.hpp"

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2019 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 "kvdb_auto_buffer.hpp"
namespace ams::kvdb {
/* Functionality for parsing/generating a key value archive. */
class ArchiveReader {
private:
AutoBuffer &buffer;
size_t offset;
public:
ArchiveReader(AutoBuffer &b) : buffer(b), offset(0) { /* ... */ }
private:
Result Peek(void *dst, size_t size);
Result Read(void *dst, size_t size);
public:
Result ReadEntryCount(size_t *out);
Result GetEntrySize(size_t *out_key_size, size_t *out_value_size);
Result ReadEntry(void *out_key, size_t key_size, void *out_value, size_t value_size);
};
class ArchiveWriter {
private:
AutoBuffer &buffer;
size_t offset;
public:
ArchiveWriter(AutoBuffer &b) : buffer(b), offset(0) { /* ... */ }
private:
Result Write(const void *src, size_t size);
public:
void WriteHeader(size_t entry_count);
void WriteEntry(const void *key, size_t key_size, const void *value, size_t value_size);
};
class ArchiveSizeHelper {
private:
size_t size;
public:
ArchiveSizeHelper();
void AddEntry(size_t key_size, size_t value_size);
size_t GetSize() const {
return this->size;
}
};
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2018-2019 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::kvdb {
class AutoBuffer {
NON_COPYABLE(AutoBuffer);
private:
u8 *buffer;
size_t size;
public:
AutoBuffer() : buffer(nullptr), size(0) { /* ... */ }
~AutoBuffer() {
this->Reset();
}
AutoBuffer(AutoBuffer &&rhs) {
this->buffer = rhs.buffer;
this->size = rhs.size;
rhs.buffer = nullptr;
rhs.size = 0;
}
AutoBuffer& operator=(AutoBuffer &&rhs) {
rhs.Swap(*this);
return *this;
}
void Swap(AutoBuffer &rhs) {
std::swap(this->buffer, rhs.buffer);
std::swap(this->size, rhs.size);
}
void Reset() {
if (this->buffer != nullptr) {
std::free(this->buffer);
this->buffer = nullptr;
this->size = 0;
}
}
u8 *Get() const {
return this->buffer;
}
size_t GetSize() const {
return this->size;
}
Result Initialize(size_t size) {
/* Check that we're not already initialized. */
AMS_ASSERT(this->buffer == nullptr);
/* Allocate a buffer. */
this->buffer = static_cast<u8 *>(std::malloc(size));
if (this->buffer == nullptr) {
return ResultAllocationFailed();
}
this->size = size;
return ResultSuccess();
}
Result Initialize(const void *buf, size_t size) {
/* Create a new buffer of the right size. */
R_TRY(this->Initialize(size));
/* Copy the input data in. */
std::memcpy(this->buffer, buf, size);
return ResultSuccess();
}
};
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2018-2019 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::kvdb {
/* Represents a string with a backing buffer of N bytes. */
template<size_t N>
class BoundedString {
static_assert(N > 0, "BoundedString requires non-zero backing buffer!");
private:
char buffer[N];
private:
/* Utility. */
static inline void CheckLength(size_t len) {
AMS_ASSERT(len < N);
}
public:
/* Constructors. */
constexpr BoundedString() {
buffer[0] = 0;
}
explicit constexpr BoundedString(const char *s) {
this->Set(s);
}
/* Static constructors. */
static constexpr BoundedString<N> Make(const char *s) {
return BoundedString<N>(s);
}
static constexpr BoundedString<N> MakeFormat(const char *format, ...) __attribute__((format (printf, 1, 2))) {
BoundedString<N> string;
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(string.buffer, N, format, args));
va_end(args);
return string;
}
/* Getters. */
size_t GetLength() const {
return strnlen(this->buffer, N);
}
const char *Get() const {
return this->buffer;
}
operator const char *() const {
return this->buffer;
}
/* Setters. */
void Set(const char *s) {
/* Ensure string can fit in our buffer. */
CheckLength(strnlen(s, N));
std::strncpy(this->buffer, s, N);
}
void SetFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) {
/* Format into the buffer, abort if too large. */
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(this->buffer, N, format, args));
va_end(args);
}
/* Append to existing. */
void Append(const char *s) {
const size_t length = GetLength();
CheckLength(length + strnlen(s, N));
std::strncat(this->buffer, s, N - length - 1);
}
void Append(char c) {
const size_t length = GetLength();
CheckLength(length + 1);
this->buffer[length] = c;
this->buffer[length + 1] = 0;
}
void AppendFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) {
const size_t length = GetLength();
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(this->buffer + length, N - length, format, args) + length);
va_end(args);
}
/* Substring utilities. */
void GetSubstring(char *dst, size_t dst_size, size_t offset, size_t length) const {
/* Make sure output buffer can hold the substring. */
AMS_ASSERT(offset + length <= GetLength());
AMS_ASSERT(dst_size > length);
/* Copy substring to dst. */
std::strncpy(dst, this->buffer + offset, length);
dst[length] = 0;
}
BoundedString<N> GetSubstring(size_t offset, size_t length) const {
BoundedString<N> string;
GetSubstring(string.buffer, N, offset, length);
return string;
}
/* Comparison. */
constexpr bool operator==(const BoundedString<N> &rhs) const {
return std::strncmp(this->buffer, rhs.buffer, N) == 0;
}
constexpr bool operator!=(const BoundedString<N> &rhs) const {
return !(*this == rhs);
}
bool EndsWith(const char *s, size_t offset) const {
return std::strncmp(this->buffer + offset, s, N - offset) == 0;
}
bool EndsWith(const char *s) const {
const size_t suffix_length = strnlen(s, N);
const size_t length = GetLength();
return suffix_length <= length && EndsWith(s, length - suffix_length);
}
};
}

View File

@@ -0,0 +1,391 @@
/*
* Copyright (c) 2018-2019 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 <sys/stat.h>
#include "kvdb_bounded_string.hpp"
#include "kvdb_file_key_value_store.hpp"
namespace ams::kvdb {
namespace impl {
template<class Key, size_t Capacity>
class LruList {
private:
/* Subtypes. */
struct LruHeader {
u32 entry_count;
};
public:
static constexpr size_t BufferSize = sizeof(Key) * Capacity;
static constexpr size_t FileSize = sizeof(LruHeader) + BufferSize;
using Path = FileKeyValueStore::Path;
private:
Path file_path;
Key *keys;
LruHeader header;
public:
static Result CreateNewList(const char *path) {
/* Create new lru_list.dat. */
R_TRY(fsdevCreateFile(path, FileSize, 0));
/* Open the file. */
FILE *fp = fopen(path, "r+b");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
/* Write new header with zero entries to the file. */
LruHeader new_header = { .entry_count = 0, };
R_UNLESS(fwrite(&new_header, sizeof(new_header), 1, fp) == 1, fsdevGetLastResult());
return ResultSuccess();
}
private:
void RemoveIndex(size_t i) {
AMS_ASSERT(i < this->GetCount());
std::memmove(this->keys + i, this->keys + i + 1, sizeof(*this->keys) * (this->GetCount() - (i + 1)));
this->DecrementCount();
}
void IncrementCount() {
this->header.entry_count++;
}
void DecrementCount() {
this->header.entry_count--;
}
public:
LruList() : keys(nullptr), header({}) { /* ... */ }
Result Initialize(const char *path, void *buf, size_t size) {
/* Only initialize once, and ensure we have sufficient memory. */
AMS_ASSERT(this->keys == nullptr);
AMS_ASSERT(size >= BufferSize);
/* Setup member variables. */
this->keys = static_cast<Key *>(buf);
this->file_path.Set(path);
std::memset(this->keys, 0, BufferSize);
/* Open file. */
FILE *fp = fopen(this->file_path, "rb");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
/* Read header. */
R_UNLESS(fread(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult());
/* Read entries. */
const size_t count = this->GetCount();
if (count > 0) {
R_UNLESS(fread(this->keys, std::min(BufferSize, sizeof(Key) * count), 1, fp) == 1, fsdevGetLastResult());
}
return ResultSuccess();
}
Result Save() {
/* Open file. */
FILE *fp = fopen(this->file_path, "r+b");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
/* Write header. */
R_UNLESS(fwrite(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult());
/* Write entries. */
R_UNLESS(fwrite(this->keys, BufferSize, 1, fp) == 1, fsdevGetLastResult());
/* Flush. */
fflush(fp);
return ResultSuccess();
}
size_t GetCount() const {
return this->header.entry_count;
}
bool IsEmpty() const {
return this->GetCount() == 0;
}
bool IsFull() const {
return this->GetCount() >= Capacity;
}
Key Get(size_t i) const {
AMS_ASSERT(i < this->GetCount());
return this->keys[i];
}
Key Peek() const {
AMS_ASSERT(!this->IsEmpty());
return this->Get(0);
}
void Push(const Key &key) {
AMS_ASSERT(!this->IsFull());
this->keys[this->GetCount()] = key;
this->IncrementCount();
}
Key Pop() {
AMS_ASSERT(!this->IsEmpty());
this->RemoveIndex(0);
}
bool Remove(const Key &key) {
const size_t count = this->GetCount();
/* Iterate over the list, removing the last entry that matches the key. */
for (size_t i = 0; i < count; i++) {
if (this->keys[count - 1 - i] == key) {
this->RemoveIndex(count - 1 - i);
return true;
}
}
return false;
}
bool Contains(const Key &key) const {
const size_t count = this->GetCount();
/* Iterate over the list, checking to see if we have the key. */
for (size_t i = 0; i < count; i++) {
if (this->keys[count - 1 - i] == key) {
return true;
}
}
return false;
}
bool Update(const Key &key) {
if (this->Remove(key)) {
this->Push(key);
return true;
}
return false;
}
};
}
template<class Key, size_t Capacity>
class FileKeyValueCache {
static_assert(std::is_pod<Key>::value, "FileKeyValueCache Key must be pod!");
static_assert(sizeof(Key) <= FileKeyValueStore::MaxKeySize, "FileKeyValueCache Key is too big!");
public:
using LeastRecentlyUsedList = impl::LruList<Key, Capacity>;
/* Note: Nintendo code in NS uses Path = BoundedString<0x180> here. */
/* It's unclear why, since they use 0x300 everywhere else. */
/* We'll just use 0x300, since it shouldn't make a difference, */
/* as FileKeyValueStore paths are limited to 0x100 anyway. */
using Path = typename LeastRecentlyUsedList::Path;
private:
FileKeyValueStore kvs;
LeastRecentlyUsedList lru_list;
private:
static constexpr Path GetLeastRecentlyUsedListPath(const char *dir) {
return Path::MakeFormat("%s/%s", dir, "lru_list.dat");
}
static constexpr Path GetFileKeyValueStorePath(const char *dir) {
return Path::MakeFormat("%s/%s", dir, "kvs");
}
static Result Exists(bool *out, const char *path, bool is_dir) {
/* Set out to false initially. */
*out = false;
/* Check that the path exists, and that our entry type is correct. */
{
struct stat st;
if (stat(path, &st) != 0) {
R_TRY_CATCH(fsdevGetLastResult()) {
/* If the path doesn't exist, nothing has gone wrong. */
R_CONVERT(fs::ResultPathNotFound, ResultSuccess());
} R_END_TRY_CATCH;
}
if (is_dir) {
R_UNLESS((S_ISDIR(st.st_mode)), ResultInvalidFilesystemState());
} else {
R_UNLESS((S_ISREG(st.st_mode)), ResultInvalidFilesystemState());
}
}
*out = true;
return ResultSuccess();
}
static Result DirectoryExists(bool *out, const char *path) {
return Exists(out, path, true);
}
static Result FileExists(bool *out, const char *path) {
return Exists(out, path, false);
}
public:
static Result CreateNewCache(const char *dir) {
/* Make a new key value store filesystem, and a new lru_list.dat. */
R_TRY(LeastRecentlyUsedList::CreateNewList(GetLeastRecentlyUsedListPath(dir)));
R_UNLESS(mkdir(GetFileKeyValueStorePath(dir), 0) == 0, fsdevGetLastResult());
return ResultSuccess();
}
static Result ValidateExistingCache(const char *dir) {
/* Check for existence. */
bool has_lru = false, has_kvs = false;
R_TRY(FileExists(&has_lru, GetLeastRecentlyUsedListPath(dir)));
R_TRY(DirectoryExists(&has_kvs, GetFileKeyValueStorePath(dir)));
/* If neither exists, CreateNewCache was never called. */
R_UNLESS(has_lru || has_kvs, ResultNotCreated());
/* If one exists but not the other, we have an invalid state. */
R_UNLESS(has_lru && has_kvs, ResultInvalidFilesystemState());
return ResultSuccess();
}
private:
void RemoveOldestKey() {
const Key &oldest_key = this->lru_list.Peek();
this->lru_list.Pop();
this->kvs.Remove(oldest_key);
}
public:
Result Initialize(const char *dir, void *buf, size_t size) {
/* Initialize list. */
R_TRY(this->lru_list.Initialize(GetLeastRecentlyUsedListPath(dir), buf, size));
/* Initialize kvs. */
/* NOTE: Despite creating the kvs folder and returning an error if it does not exist, */
/* Nintendo does not use the kvs folder, and instead uses the passed dir. */
/* This causes lru_list.dat to be in the same directory as the store's .val files */
/* instead of in the same directory as a folder containing the store's .val files. */
/* This is probably a Nintendo bug, but because system saves contain data in the wrong */
/* layout it can't really be fixed without breaking existing devices... */
R_TRY(this->kvs.Initialize(dir));
return ResultSuccess();
}
size_t GetCount() const {
return this->lru_list.GetCount();
}
size_t GetCapacity() const {
return Capacity;
}
Key GetKey(size_t i) const {
return this->lru_list.Get(i);
}
bool Contains(const Key &key) const {
return this->lru_list.Contains(key);
}
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) {
/* Note that we accessed the key. */
this->lru_list.Update(key);
return this->kvs.Get(out_size, out_value, max_out_size, key);
}
template<typename Value>
Result Get(Value *out_value, const Key &key) {
/* Note that we accessed the key. */
this->lru_list.Update(key);
return this->kvs.Get(out_value, key);
}
Result GetSize(size_t *out_size, const Key &key) {
return this->kvs.GetSize(out_size, key);
}
Result Set(const Key &key, const void *value, size_t value_size) {
if (this->lru_list.Update(key)) {
/* If an entry for the key exists, delete the existing value file. */
this->kvs.Remove(key);
} else {
/* If the list is full, we need to remove the oldest key. */
if (this->lru_list.IsFull()) {
this->RemoveOldestKey();
}
/* Add the key to the list. */
this->lru_list.Push(key);
}
/* Loop, trying to save the new value to disk. */
while (true) {
/* Try to set the key. */
R_TRY_CATCH(this->kvs.Set(key, value, value_size)) {
R_CATCH(fs::ResultNotEnoughFreeSpace) {
/* If our entry is the only thing in the Lru list, remove it. */
if (this->lru_list.GetCount() == 1) {
this->lru_list.Pop();
R_TRY(this->lru_list.Save());
return fs::ResultNotEnoughFreeSpace();
}
/* Otherwise, remove the oldest element from the cache and try again. */
this->RemoveOldestKey();
continue;
}
} R_END_TRY_CATCH;
/* If we got here, we succeeded. */
break;
}
/* Save the list. */
R_TRY(this->lru_list.Save());
return ResultSuccess();
}
template<typename Value>
Result Set(const Key &key, const Value &value) {
return this->Set(key, &value, sizeof(Value));
}
Result Remove(const Key &key) {
/* Remove the key. */
this->lru_list.Remove(key);
R_TRY(this->kvs.Remove(key));
R_TRY(this->lru_list.Save());
return ResultSuccess();
}
Result RemoveAll() {
/* TODO: Nintendo doesn't check errors here. Should we? */
while (!this->lru_list.IsEmpty()) {
this->RemoveOldestKey();
}
R_TRY(this->lru_list.Save());
return ResultSuccess();
}
};
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2018-2019 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 "../os.hpp"
#include "kvdb_bounded_string.hpp"
namespace ams::kvdb {
class FileKeyValueStore {
NON_COPYABLE(FileKeyValueStore);
NON_MOVEABLE(FileKeyValueStore);
public:
static constexpr size_t MaxPathLength = 0x300; /* TODO: FS_MAX_PATH - 1? */
static constexpr size_t MaxFileLength = 0xFF;
static constexpr char FileExtension[5] = ".val";
static constexpr size_t FileExtensionLength = sizeof(FileExtension) - 1;
static constexpr size_t MaxKeySize = (MaxFileLength - FileExtensionLength) / 2;
using Path = kvdb::BoundedString<MaxPathLength>;
using FileName = kvdb::BoundedString<MaxFileLength>;
private:
/* Subtypes. */
struct Entry {
u8 key[MaxKeySize];
void *value;
size_t key_size;
size_t value_size;
};
static_assert(std::is_pod<Entry>::value, "FileKeyValueStore::Entry definition!");
class Cache {
private:
u8 *backing_buffer = nullptr;
size_t backing_buffer_size = 0;
size_t backing_buffer_free_offset = 0;
Entry *entries = nullptr;
size_t count = 0;
size_t capacity = 0;
private:
void *Allocate(size_t size);
bool HasEntries() const {
return this->entries != nullptr && this->capacity != 0;
}
public:
Result Initialize(void *buffer, size_t buffer_size, size_t capacity);
void Invalidate();
std::optional<size_t> TryGet(void *out_value, size_t max_out_size, const void *key, size_t key_size);
std::optional<size_t> TryGetSize(const void *key, size_t key_size);
void Set(const void *key, size_t key_size, const void *value, size_t value_size);
bool Contains(const void *key, size_t key_size);
};
private:
os::Mutex lock;
Path dir_path;
Cache cache;
private:
Path GetPath(const void *key, size_t key_size);
Result GetKey(size_t *out_size, void *out_key, size_t max_out_size, const FileName &file_name);
public:
FileKeyValueStore() { /* ... */ }
/* Basic accessors. */
Result Initialize(const char *dir);
Result InitializeWithCache(const char *dir, void *cache_buffer, size_t cache_buffer_size, size_t cache_capacity);
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const void *key, size_t key_size);
Result GetSize(size_t *out_size, const void *key, size_t key_size);
Result Set(const void *key, size_t key_size, const void *value, size_t value_size);
Result Remove(const void *key, size_t key_size);
/* Niceties. */
template<typename Key>
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) {
static_assert(std::is_pod<Key>::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!");
return this->Get(out_size, out_value, max_out_size, &key, sizeof(Key));
}
template<typename Key, typename Value>
Result Get(Value *out_value, const Key &key) {
static_assert(std::is_pod<Value>::value && !std::is_pointer<Value>::value, "Invalid FileKeyValueStore Value!");
size_t size = 0;
R_TRY(this->Get(&size, out_value, sizeof(Value), key));
AMS_ASSERT(size >= sizeof(Value));
return ResultSuccess();
}
template<typename Key>
Result GetSize(size_t *out_size, const Key &key) {
return this->GetSize(out_size, &key, sizeof(Key));
}
template<typename Key>
Result Set(const Key &key, const void *value, size_t value_size) {
static_assert(std::is_pod<Key>::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!");
return this->Set(&key, sizeof(Key), value, value_size);
}
template<typename Key, typename Value>
Result Set(const Key &key, const Value &value) {
static_assert(std::is_pod<Value>::value && !std::is_pointer<Value>::value, "Invalid FileKeyValueStore Value!");
return this->Set(key, &value, sizeof(Value));
}
template<typename Key>
Result Remove(const Key &key) {
return this->Remove(&key, sizeof(Key));
}
};
}

View File

@@ -0,0 +1,525 @@
/*
* Copyright (c) 2018-2019 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/stat.h>
#include "kvdb_auto_buffer.hpp"
#include "kvdb_archive.hpp"
#include "kvdb_bounded_string.hpp"
namespace ams::kvdb {
template<class Key>
class MemoryKeyValueStore {
static_assert(std::is_pod<Key>::value, "KeyValueStore Keys must be pod!");
NON_COPYABLE(MemoryKeyValueStore);
NON_MOVEABLE(MemoryKeyValueStore);
public:
/* Subtypes. */
class Entry {
private:
Key key;
void *value;
size_t value_size;
public:
constexpr Entry(const Key &k, void *v, size_t s) : key(k), value(v), value_size(s) { /* ... */ }
const Key &GetKey() const {
return this->key;
}
template<typename Value = void>
Value *GetValuePointer() {
/* Size check. Note: Nintendo does not size check. */
if constexpr (!std::is_same<Value, void>::value) {
AMS_ASSERT(sizeof(Value) <= this->value_size);
/* Ensure we only get pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
}
return reinterpret_cast<Value *>(this->value);
}
template<typename Value = void>
const Value *GetValuePointer() const {
/* Size check. Note: Nintendo does not size check. */
if constexpr (!std::is_same<Value, void>::value) {
AMS_ASSERT(sizeof(Value) <= this->value_size);
/* Ensure we only get pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
}
return reinterpret_cast<Value *>(this->value);
}
template<typename Value>
Value &GetValue() {
return *(this->GetValuePointer<Value>());
}
template<typename Value>
const Value &GetValue() const {
return *(this->GetValuePointer<Value>());
}
size_t GetValueSize() const {
return this->value_size;
}
constexpr inline bool operator<(const Key &rhs) const {
return key < rhs;
}
constexpr inline bool operator==(const Key &rhs) const {
return key == rhs;
}
};
class Index {
private:
size_t count;
size_t capacity;
Entry *entries;
public:
Index() : count(0), capacity(0), entries(nullptr) { /* ... */ }
~Index() {
if (this->entries != nullptr) {
this->ResetEntries();
std::free(this->entries);
this->entries = nullptr;
}
}
size_t GetCount() const {
return this->count;
}
size_t GetCapacity() const {
return this->capacity;
}
void ResetEntries() {
for (size_t i = 0; i < this->count; i++) {
std::free(this->entries[i].GetValuePointer());
}
this->count = 0;
}
Result Initialize(size_t capacity) {
this->entries = reinterpret_cast<Entry *>(std::malloc(sizeof(Entry) * capacity));
R_UNLESS(this->entries != nullptr, ResultAllocationFailed());
this->capacity = capacity;
return ResultSuccess();
}
Result Set(const Key &key, const void *value, size_t value_size) {
/* Allocate new value. */
void *new_value = std::malloc(value_size);
R_UNLESS(new_value != nullptr, ResultAllocationFailed());
auto value_guard = SCOPE_GUARD { std::free(new_value); };
std::memcpy(new_value, value, value_size);
/* Find entry for key. */
Entry *it = this->lower_bound(key);
if (it != this->end() && it->GetKey() == key) {
/* Entry already exists. Free old value. */
std::free(it->GetValuePointer());
} else {
/* We need to add a new entry. Check we have room, move future keys forward. */
R_UNLESS(this->count < this->capacity, ResultOutOfKeyResource());
std::memmove(it + 1, it, sizeof(*it) * (this->end() - it));
this->count++;
}
/* Save the new Entry in the map. */
value_guard.Cancel();
*it = Entry(key, new_value, value_size);
return ResultSuccess();
}
Result AddUnsafe(const Key &key, void *value, size_t value_size) {
R_UNLESS(this->count < this->capacity, ResultOutOfKeyResource());
this->entries[this->count++] = Entry(key, value, value_size);
return ResultSuccess();
}
Result Remove(const Key &key) {
/* Find entry for key. */
Entry *it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
/* Free the value, move entries back. */
std::free(it->GetValuePointer());
std::memmove(it, it + 1, sizeof(*it) * (this->end() - (it + 1)));
this->count--;
return ResultSuccess();
}
Entry *begin() {
return this->GetBegin();
}
const Entry *begin() const {
return this->GetBegin();
}
Entry *end() {
return this->GetEnd();
}
const Entry *end() const {
return this->GetEnd();
}
const Entry *cbegin() const {
return this->begin();
}
const Entry *cend() const {
return this->end();
}
Entry *lower_bound(const Key &key) {
return this->GetLowerBound(key);
}
const Entry *lower_bound(const Key &key) const {
return this->GetLowerBound(key);
}
Entry *find(const Key &key) {
return this->Find(key);
}
const Entry *find(const Key &key) const {
return this->Find(key);
}
private:
Entry *GetBegin() {
return this->entries;
}
const Entry *GetBegin() const {
return this->entries;
}
Entry *GetEnd() {
return this->GetBegin() + this->count;
}
const Entry *GetEnd() const {
return this->GetBegin() + this->count;
}
Entry *GetLowerBound(const Key &key) {
return std::lower_bound(this->GetBegin(), this->GetEnd(), key);
}
const Entry *GetLowerBound(const Key &key) const {
return std::lower_bound(this->GetBegin(), this->GetEnd(), key);
}
Entry *Find(const Key &key) {
auto it = this->GetLowerBound(key);
auto end = this->GetEnd();
if (it != end && it->GetKey() == key) {
return it;
}
return end;
}
const Entry *Find(const Key &key) const {
auto it = this->GetLowerBound(key);
auto end = this->GetEnd();
if (it != end && it->GetKey() == key) {
return it;
}
return end;
}
};
private:
static constexpr size_t MaxPathLen = 0x300; /* TODO: FS_MAX_PATH - 1? */
using Path = kvdb::BoundedString<MaxPathLen>;
private:
Index index;
Path path;
Path temp_path;
public:
MemoryKeyValueStore() { /* ... */ }
Result Initialize(const char *dir, size_t capacity) {
/* Ensure that the passed path is a directory. */
{
struct stat st;
R_UNLESS(stat(dir, &st) == 0, fs::ResultPathNotFound());
R_UNLESS((S_ISDIR(st.st_mode)), fs::ResultPathNotFound());
}
/* Set paths. */
this->path.SetFormat("%s%s", dir, "/imkvdb.arc");
this->temp_path.SetFormat("%s%s", dir, "/imkvdb.tmp");
/* Initialize our index. */
R_TRY(this->index.Initialize(capacity));
return ResultSuccess();
}
Result Initialize(size_t capacity) {
/* This initializes without an archive file. */
/* A store initialized this way cannot have its contents loaded from or flushed to disk. */
this->path.Set("");
this->temp_path.Set("");
/* Initialize our index. */
R_TRY(this->index.Initialize(capacity));
return ResultSuccess();
}
size_t GetCount() const {
return this->index.GetCount();
}
size_t GetCapacity() const {
return this->index.GetCapacity();
}
Result Load() {
/* Reset any existing entries. */
this->index.ResetEntries();
/* Try to read the archive -- note, path not found is a success condition. */
/* This is because no archive file = no entries, so we're in the right state. */
AutoBuffer buffer;
R_TRY_CATCH(this->ReadArchiveFile(&buffer)) {
R_CONVERT(fs::ResultPathNotFound, ResultSuccess());
} R_END_TRY_CATCH;
/* Parse entries from the buffer. */
{
ArchiveReader reader(buffer);
size_t entry_count = 0;
R_TRY(reader.ReadEntryCount(&entry_count));
for (size_t i = 0; i < entry_count; i++) {
/* Get size of key/value. */
size_t key_size = 0, value_size = 0;
R_TRY(reader.GetEntrySize(&key_size, &value_size));
/* Allocate memory for value. */
void *new_value = std::malloc(value_size);
R_UNLESS(new_value != nullptr, ResultAllocationFailed());
auto value_guard = SCOPE_GUARD { std::free(new_value); };
/* Read key and value. */
Key key;
R_TRY(reader.ReadEntry(&key, sizeof(key), new_value, value_size));
R_TRY(this->index.AddUnsafe(key, new_value, value_size));
/* We succeeded, so cancel the value guard to prevent deallocation. */
value_guard.Cancel();
}
}
return ResultSuccess();
}
Result Save() {
/* Create a buffer to hold the archive. */
AutoBuffer buffer;
R_TRY(buffer.Initialize(this->GetArchiveSize()));
/* Write the archive to the buffer. */
{
ArchiveWriter writer(buffer);
writer.WriteHeader(this->GetCount());
for (const auto &it : this->index) {
const auto &key = it.GetKey();
writer.WriteEntry(&key, sizeof(Key), it.GetValuePointer(), it.GetValueSize());
}
}
/* Save the buffer to disk. */
return this->Commit(buffer);
}
Result Set(const Key &key, const void *value, size_t value_size) {
return this->index.Set(key, value, value_size);
}
template<typename Value>
Result Set(const Key &key, const Value &value) {
/* Only allow setting pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
return this->Set(key, &value, sizeof(Value));
}
template<typename Value>
Result Set(const Key &key, const Value *value) {
/* Only allow setting pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
return this->Set(key, value, sizeof(Value));
}
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
size_t size = std::min(max_out_size, it->GetValueSize());
std::memcpy(out_value, it->GetValuePointer(), size);
*out_size = size;
return ResultSuccess();
}
template<typename Value = void>
Result GetValuePointer(Value **out_value, const Key &key) {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_value = it->template GetValuePointer<Value>();
return ResultSuccess();
}
template<typename Value = void>
Result GetValuePointer(const Value **out_value, const Key &key) const {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_value = it->template GetValuePointer<Value>();
return ResultSuccess();
}
template<typename Value>
Result GetValue(Value *out_value, const Key &key) const {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_value = it->template GetValue<Value>();
return ResultSuccess();
}
Result GetValueSize(size_t *out_size, const Key &key) const {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_size = it->GetValueSize();
return ResultSuccess();
}
Result Remove(const Key &key) {
return this->index.Remove(key);
}
Entry *begin() {
return this->index.begin();
}
const Entry *begin() const {
return this->index.begin();
}
Entry *end() {
return this->index.end();
}
const Entry *end() const {
return this->index.end();
}
const Entry *cbegin() const {
return this->index.cbegin();
}
const Entry *cend() const {
return this->index.cend();
}
Entry *lower_bound(const Key &key) {
return this->index.lower_bound(key);
}
const Entry *lower_bound(const Key &key) const {
return this->index.lower_bound(key);
}
Entry *find(const Key &key) {
return this->index.find(key);
}
const Entry *find(const Key &key) const {
return this->index.find(key);
}
private:
Result Commit(const AutoBuffer &buffer) {
/* Try to delete temporary archive, but allow deletion failure (it may not exist). */
std::remove(this->temp_path.Get());
/* Create new temporary archive. */
R_TRY(fsdevCreateFile(this->temp_path.Get(), buffer.GetSize(), 0));
/* Write data to the temporary archive. */
{
FILE *f = fopen(this->temp_path, "r+b");
R_UNLESS(f != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(f); };
R_UNLESS(fwrite(buffer.Get(), buffer.GetSize(), 1, f) == 1, fsdevGetLastResult());
}
/* Try to delete the saved archive, but allow deletion failure. */
std::remove(this->path.Get());
/* Rename the path. */
R_UNLESS(std::rename(this->temp_path.Get(), this->path.Get()) == 0, fsdevGetLastResult());
return ResultSuccess();
}
size_t GetArchiveSize() const {
ArchiveSizeHelper size_helper;
for (const auto &it : this->index) {
size_helper.AddEntry(sizeof(Key), it.GetValueSize());
}
return size_helper.GetSize();
}
Result ReadArchiveFile(AutoBuffer *dst) const {
/* Open the file. */
FILE *f = fopen(this->path, "rb");
R_UNLESS(f != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(f); };
/* Get the archive file size. */
fseek(f, 0, SEEK_END);
const size_t archive_size = ftell(f);
fseek(f, 0, SEEK_SET);
/* Make a new buffer, read the file. */
R_TRY(dst->Initialize(archive_size));
R_UNLESS(fread(dst->Get(), archive_size, 1, f) == 1, fsdevGetLastResult());
return ResultSuccess();
}
};
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 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 "ldr/ldr_types.hpp"
#include "ldr/ldr_pm_api.hpp"

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2019 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 "ldr_types.hpp"
namespace ams::ldr::pm {
/* Process Manager API. */
Result CreateProcess(Handle *out, PinId pin_id, u32 flags, Handle reslimit);
Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc);
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc);
Result UnpinProgram(PinId pin_id);
Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id);
/* Atmosphere extension API. */
Result AtmosphereGetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc);
Result AtmospherePinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status);
}

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2018-2019 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 "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::ldr {
/* General types. */
struct ProgramInfo : sf::LargeData {
u8 main_thread_priority;
u8 default_cpu_id;
u16 flags;
u32 main_thread_stack_size;
ncm::ProgramId program_id;
u32 acid_sac_size;
u32 aci_sac_size;
u32 acid_fac_size;
u32 aci_fah_size;
u8 ac_buffer[0x3E0];
};
static_assert(std::is_pod<ProgramInfo>::value && sizeof(ProgramInfo) == 0x400, "ProgramInfo definition!");
enum ProgramInfoFlag {
ProgramInfoFlag_SystemModule = (0 << 0),
ProgramInfoFlag_Application = (1 << 0),
ProgramInfoFlag_Applet = (2 << 0),
ProgramInfoFlag_InvalidType = (3 << 0),
ProgramInfoFlag_ApplicationTypeMask = (3 << 0),
ProgramInfoFlag_AllowDebug = (1 << 2),
};
enum CreateProcessFlag {
CreateProcessFlag_EnableDebug = (1 << 0),
CreateProcessFlag_DisableAslr = (1 << 1),
};
struct ProgramArguments {
u32 allocated_size;
u32 arguments_size;
u8 reserved[0x18];
u8 arguments[];
};
static_assert(sizeof(ProgramArguments) == 0x20, "ProgramArguments definition!");
struct PinId {
u64 value;
};
inline bool operator==(const PinId &lhs, const PinId &rhs) {
return lhs.value == rhs.value;
}
inline bool operator!=(const PinId &lhs, const PinId &rhs) {
return lhs.value != rhs.value;
}
static_assert(sizeof(PinId) == sizeof(u64) && std::is_pod<PinId>::value, "PinId definition!");
/* Import ModuleInfo from libnx. */
using ModuleInfo = ::LoaderModuleInfo;
/* NSO types. */
struct NsoHeader {
static constexpr u32 Magic = 0x304F534E;
enum Segment : size_t {
Segment_Text = 0,
Segment_Ro = 1,
Segment_Rw = 2,
Segment_Count,
};
enum Flag : u32 {
Flag_CompressedText = (1 << 0),
Flag_CompressedRo = (1 << 1),
Flag_CompressedRw = (1 << 2),
Flag_CheckHashText = (1 << 3),
Flag_CheckHashRo = (1 << 4),
Flag_CheckHashRw = (1 << 5),
};
struct SegmentInfo {
u32 file_offset;
u32 dst_offset;
u32 size;
u32 reserved;
};
u32 magic;
u32 version;
u32 reserved_08;
u32 flags;
union {
struct {
u32 text_file_offset;
u32 text_dst_offset;
u32 text_size;
u32 unk_file_offset;
u32 ro_file_offset;
u32 ro_dst_offset;
u32 ro_size;
u32 unk_size;
u32 rw_file_offset;
u32 rw_dst_offset;
u32 rw_size;
u32 bss_size;
};
SegmentInfo segments[Segment_Count];
};
u8 build_id[sizeof(ModuleInfo::build_id)];
union {
u32 compressed_sizes[Segment_Count];
struct {
u32 text_compressed_size;
u32 ro_compressed_size;
u32 rw_compressed_size;
};
};
u8 reserved_6C[0x34];
union {
u8 segment_hashes[Segment_Count][SHA256_HASH_SIZE];
struct {
u8 text_hash[SHA256_HASH_SIZE];
u8 ro_hash[SHA256_HASH_SIZE];
u8 rw_hash[SHA256_HASH_SIZE];
};
};
};
static_assert(sizeof(NsoHeader) == 0x100 && std::is_pod<NsoHeader>::value, "NsoHeader definition!");
/* NPDM types. */
struct Aci {
static constexpr u32 Magic = 0x30494341;
u32 magic;
u8 reserved_04[0xC];
ncm::ProgramId program_id;
u8 reserved_18[0x8];
u32 fah_offset;
u32 fah_size;
u32 sac_offset;
u32 sac_size;
u32 kac_offset;
u32 kac_size;
u8 reserved_38[0x8];
};
static_assert(sizeof(Aci) == 0x40 && std::is_pod<Aci>::value, "Aci definition!");
struct Acid {
static constexpr u32 Magic = 0x44494341;
enum AcidFlag {
AcidFlag_Production = (1 << 0),
AcidFlag_UnqualifiedApproval = (1 << 1),
AcidFlag_DeprecatedUseSecureMemory = (1 << 2),
AcidFlag_PoolPartitionShift = 2,
AcidFlag_PoolPartitionMask = (3 << AcidFlag_PoolPartitionShift),
};
enum PoolPartition {
PoolPartition_Application = (svc::CreateProcessFlag_PoolPartitionApplication >> svc::CreateProcessFlag_PoolPartitionShift),
PoolPartition_Applet = (svc::CreateProcessFlag_PoolPartitionApplet >> svc::CreateProcessFlag_PoolPartitionShift),
PoolPartition_System = (svc::CreateProcessFlag_PoolPartitionSystem >> svc::CreateProcessFlag_PoolPartitionShift),
PoolPartition_SystemNonSecure = (svc::CreateProcessFlag_PoolPartitionSystemNonSecure >> svc::CreateProcessFlag_PoolPartitionShift),
};
u8 signature[0x100];
u8 modulus[0x100];
u32 magic;
u32 size;
u8 version;
u8 reserved_209[3];
u32 flags;
ncm::ProgramId program_id_min;
ncm::ProgramId program_id_max;
u32 fac_offset;
u32 fac_size;
u32 sac_offset;
u32 sac_size;
u32 kac_offset;
u32 kac_size;
u8 reserved_238[0x8];
};
static_assert(sizeof(Acid) == 0x240 && std::is_pod<Acid>::value, "Acid definition!");
struct Npdm {
static constexpr u32 Magic = 0x4154454D;
enum MetaFlag {
MetaFlag_Is64Bit = (1 << 0),
MetaFlag_AddressSpaceTypeShift = 1,
MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift),
MetaFlag_OptimizeMemoryAllocation = (1 << 4),
};
enum AddressSpaceType {
AddressSpaceType_32Bit = (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift),
AddressSpaceType_64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift),
AddressSpaceType_32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift),
AddressSpaceType_64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift),
};
u32 magic;
u8 reserved_04[8];
u8 flags;
u8 reserved_0D;
u8 main_thread_priority;
u8 default_cpu_id;
u8 reserved_10[4];
u32 system_resource_size;
u32 version;
u32 main_thread_stack_size;
char program_name[0x10];
char product_code[0x10];
u8 reserved_40[0x30];
u32 aci_offset;
u32 aci_size;
u32 acid_offset;
u32 acid_size;
};
static_assert(sizeof(Npdm) == 0x80 && std::is_pod<Npdm>::value, "Npdm definition!");
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 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 "map/map_types.hpp"
#include "map/map_api.hpp"

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 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 "map_types.hpp"
namespace ams::map {
/* Public API. */
Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h);
Result LocateMappableSpace(uintptr_t *out_address, size_t size);
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, Handle process_handle, uintptr_t base_address, size_t size);
bool CanAddGuardRegionsInProcess(Handle process_handle, uintptr_t address, size_t size);
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2018-2019 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::map {
/* Types. */
struct AddressSpaceInfo {
uintptr_t heap_base;
size_t heap_size;
uintptr_t heap_end;
uintptr_t alias_base;
size_t alias_size;
uintptr_t alias_end;
uintptr_t aslr_base;
size_t aslr_size;
uintptr_t aslr_end;
};
static constexpr uintptr_t AslrBase32Bit = 0x0000200000ul;
static constexpr size_t AslrSize32Bit = 0x003FE00000ul;
static constexpr uintptr_t AslrBase64BitDeprecated = 0x0008000000ul;
static constexpr size_t AslrSize64BitDeprecated = 0x0078000000ul;
static constexpr uintptr_t AslrBase64Bit = 0x0008000000ul;
static constexpr size_t AslrSize64Bit = 0x7FF8000000ul;
class AutoCloseMap {
private:
Handle process_handle;
Result result;
void *mapped_address;
uintptr_t base_address;
size_t size;
public:
AutoCloseMap(uintptr_t mp, Handle p_h, uintptr_t ba, size_t sz) : process_handle(p_h), mapped_address(reinterpret_cast<void *>(mp)), base_address(ba), size(sz) {
this->result = svcMapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size);
}
~AutoCloseMap() {
if (this->process_handle != INVALID_HANDLE && R_SUCCEEDED(this->result)) {
R_ASSERT(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size));
}
}
Result GetResult() const {
return this->result;
}
bool IsSuccess() const {
return R_SUCCEEDED(this->result);
}
void Invalidate() {
this->process_handle = INVALID_HANDLE;
}
};
class MappedCodeMemory {
private:
Handle process_handle;
Result result;
uintptr_t dst_address;
uintptr_t src_address;
size_t size;
public:
MappedCodeMemory(Result init_res) : process_handle(INVALID_HANDLE), result(init_res), dst_address(0), src_address(0), size(0) {
/* ... */
}
MappedCodeMemory(Handle p_h, uintptr_t dst, uintptr_t src, size_t sz) : process_handle(p_h), dst_address(dst), src_address(src), size(sz) {
this->result = svcMapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size);
}
~MappedCodeMemory() {
if (this->process_handle != INVALID_HANDLE && R_SUCCEEDED(this->result) && this->size > 0) {
R_ASSERT(svcUnmapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size));
}
}
uintptr_t GetDstAddress() const {
return this->dst_address;
}
Result GetResult() const {
return this->result;
}
bool IsSuccess() const {
return R_SUCCEEDED(this->result);
}
void Invalidate() {
this->process_handle = INVALID_HANDLE;
}
MappedCodeMemory &operator=(MappedCodeMemory &&o) {
this->process_handle = o.process_handle;
this->result = o.result;
this->dst_address = o.dst_address;
this->src_address = o.src_address;
this->size = o.size;
o.Invalidate();
return *this;
}
};
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "ncm/ncm_types.hpp"

View File

@@ -0,0 +1,447 @@
/*
* Copyright (c) 2018-2019 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::ncm {
/* Storage IDs. */
enum class StorageId : u8 {
#define DEFINE_ENUM_MEMBER(nm) nm = NcmStorageId_##nm
DEFINE_ENUM_MEMBER(None),
DEFINE_ENUM_MEMBER(Host),
DEFINE_ENUM_MEMBER(GameCard),
DEFINE_ENUM_MEMBER(BuiltInSystem),
DEFINE_ENUM_MEMBER(BuiltInUser),
DEFINE_ENUM_MEMBER(SdCard),
DEFINE_ENUM_MEMBER(Any),
#undef DEFINE_ENUM_MEMBER
};
/* Program IDs (Formerly: Title IDs). */
struct ProgramId {
u64 value;
inline explicit operator u64() const {
return this->value;
}
/* Invalid Program ID. */
static const ProgramId Invalid;
/* System Modules. */
static const ProgramId SystemStart;
static const ProgramId Fs;
static const ProgramId Loader;
static const ProgramId Ncm;
static const ProgramId Pm;
static const ProgramId Sm;
static const ProgramId Boot;
static const ProgramId Usb;
static const ProgramId Tma;
static const ProgramId Boot2;
static const ProgramId Settings;
static const ProgramId Bus;
static const ProgramId Bluetooth;
static const ProgramId Bcat;
static const ProgramId Dmnt;
static const ProgramId Friends;
static const ProgramId Nifm;
static const ProgramId Ptm;
static const ProgramId Shell;
static const ProgramId BsdSockets;
static const ProgramId Hid;
static const ProgramId Audio;
static const ProgramId LogManager;
static const ProgramId Wlan;
static const ProgramId Cs;
static const ProgramId Ldn;
static const ProgramId NvServices;
static const ProgramId Pcv;
static const ProgramId Ppc;
static const ProgramId NvnFlinger;
static const ProgramId Pcie;
static const ProgramId Account;
static const ProgramId Ns;
static const ProgramId Nfc;
static const ProgramId Psc;
static const ProgramId CapSrv;
static const ProgramId Am;
static const ProgramId Ssl;
static const ProgramId Nim;
static const ProgramId Cec;
static const ProgramId Tspm;
static const ProgramId Spl;
static const ProgramId Lbl;
static const ProgramId Btm;
static const ProgramId Erpt;
static const ProgramId Time;
static const ProgramId Vi;
static const ProgramId Pctl;
static const ProgramId Npns;
static const ProgramId Eupld;
static const ProgramId Arp;
static const ProgramId Glue;
static const ProgramId Eclct;
static const ProgramId Es;
static const ProgramId Fatal;
static const ProgramId Grc;
static const ProgramId Creport;
static const ProgramId Ro;
static const ProgramId Profiler;
static const ProgramId Sdb;
static const ProgramId Migration;
static const ProgramId Jit;
static const ProgramId JpegDec;
static const ProgramId SafeMode;
static const ProgramId Olsc;
static const ProgramId Dt;
static const ProgramId Nd;
static const ProgramId Ngct;
static const ProgramId SystemEnd;
/* System Data Archives. */
static const ProgramId ArchiveStart;
static const ProgramId ArchiveCertStore;
static const ProgramId ArchiveErrorMessage;
static const ProgramId ArchiveMiiModel;
static const ProgramId ArchiveBrowserDll;
static const ProgramId ArchiveHelp;
static const ProgramId ArchiveSharedFont;
static const ProgramId ArchiveNgWord;
static const ProgramId ArchiveSsidList;
static const ProgramId ArchiveDictionary;
static const ProgramId ArchiveSystemVersion;
static const ProgramId ArchiveAvatarImage;
static const ProgramId ArchiveLocalNews;
static const ProgramId ArchiveEula;
static const ProgramId ArchiveUrlBlackList;
static const ProgramId ArchiveTimeZoneBinar;
static const ProgramId ArchiveCertStoreCruiser;
static const ProgramId ArchiveFontNintendoExtension;
static const ProgramId ArchiveFontStandard;
static const ProgramId ArchiveFontKorean;
static const ProgramId ArchiveFontChineseTraditional;
static const ProgramId ArchiveFontChineseSimple;
static const ProgramId ArchiveFontBfcpx;
static const ProgramId ArchiveSystemUpdate;
static const ProgramId ArchiveFirmwareDebugSettings;
static const ProgramId ArchiveBootImagePackage;
static const ProgramId ArchiveBootImagePackageSafe;
static const ProgramId ArchiveBootImagePackageExFat;
static const ProgramId ArchiveBootImagePackageExFatSafe;
static const ProgramId ArchiveFatalMessage;
static const ProgramId ArchiveControllerIcon;
static const ProgramId ArchivePlatformConfigIcosa;
static const ProgramId ArchivePlatformConfigCopper;
static const ProgramId ArchivePlatformConfigHoag;
static const ProgramId ArchiveControllerFirmware;
static const ProgramId ArchiveNgWord2;
static const ProgramId ArchivePlatformConfigIcosaMariko;
static const ProgramId ArchiveApplicationBlackList;
static const ProgramId ArchiveRebootlessSystemUpdateVersion;
static const ProgramId ArchiveContentActionTable;
static const ProgramId ArchiveEnd;
/* System Applets. */
static const ProgramId AppletStart;
static const ProgramId AppletQlaunch;
static const ProgramId AppletAuth;
static const ProgramId AppletCabinet;
static const ProgramId AppletController;
static const ProgramId AppletDataErase;
static const ProgramId AppletError;
static const ProgramId AppletNetConnect;
static const ProgramId AppletPlayerSelect;
static const ProgramId AppletSwkbd;
static const ProgramId AppletMiiEdit;
static const ProgramId AppletWeb;
static const ProgramId AppletShop;
static const ProgramId AppletOverlayDisp;
static const ProgramId AppletPhotoViewer;
static const ProgramId AppletSet;
static const ProgramId AppletOfflineWeb;
static const ProgramId AppletLoginShare;
static const ProgramId AppletWifiWebAuth;
static const ProgramId AppletStarter;
static const ProgramId AppletMyPage;
static const ProgramId AppletPlayReport;
static const ProgramId AppletMaintenanceMenu;
static const ProgramId AppletGift;
static const ProgramId AppletDummyShop;
static const ProgramId AppletUserMigration;
static const ProgramId AppletEncounter;
static const ProgramId AppletStory;
static const ProgramId AppletEnd;
/* Debug Applets. */
/* Debug Modules. */
/* Factory Setup. */
/* Applications. */
static const ProgramId ApplicationStart;
static const ProgramId ApplicationEnd;
/* Atmosphere Extensions. */
static const ProgramId AtmosphereMitm;
};
/* Invalid Program ID. */
inline constexpr const ProgramId ProgramId::Invalid = {};
inline constexpr const ProgramId InvalidProgramId = ProgramId::Invalid;
/* System Modules. */
inline constexpr const ProgramId ProgramId::SystemStart = { 0x0100000000000000ul };
inline constexpr const ProgramId ProgramId::Fs = { 0x0100000000000000ul };
inline constexpr const ProgramId ProgramId::Loader = { 0x0100000000000001ul };
inline constexpr const ProgramId ProgramId::Ncm = { 0x0100000000000002ul };
inline constexpr const ProgramId ProgramId::Pm = { 0x0100000000000003ul };
inline constexpr const ProgramId ProgramId::Sm = { 0x0100000000000004ul };
inline constexpr const ProgramId ProgramId::Boot = { 0x0100000000000005ul };
inline constexpr const ProgramId ProgramId::Usb = { 0x0100000000000006ul };
inline constexpr const ProgramId ProgramId::Tma = { 0x0100000000000007ul };
inline constexpr const ProgramId ProgramId::Boot2 = { 0x0100000000000008ul };
inline constexpr const ProgramId ProgramId::Settings = { 0x0100000000000009ul };
inline constexpr const ProgramId ProgramId::Bus = { 0x010000000000000Aul };
inline constexpr const ProgramId ProgramId::Bluetooth = { 0x010000000000000Bul };
inline constexpr const ProgramId ProgramId::Bcat = { 0x010000000000000Cul };
inline constexpr const ProgramId ProgramId::Dmnt = { 0x010000000000000Dul };
inline constexpr const ProgramId ProgramId::Friends = { 0x010000000000000Eul };
inline constexpr const ProgramId ProgramId::Nifm = { 0x010000000000000Ful };
inline constexpr const ProgramId ProgramId::Ptm = { 0x0100000000000010ul };
inline constexpr const ProgramId ProgramId::Shell = { 0x0100000000000011ul };
inline constexpr const ProgramId ProgramId::BsdSockets = { 0x0100000000000012ul };
inline constexpr const ProgramId ProgramId::Hid = { 0x0100000000000013ul };
inline constexpr const ProgramId ProgramId::Audio = { 0x0100000000000014ul };
inline constexpr const ProgramId ProgramId::LogManager = { 0x0100000000000015ul };
inline constexpr const ProgramId ProgramId::Wlan = { 0x0100000000000016ul };
inline constexpr const ProgramId ProgramId::Cs = { 0x0100000000000017ul };
inline constexpr const ProgramId ProgramId::Ldn = { 0x0100000000000018ul };
inline constexpr const ProgramId ProgramId::NvServices = { 0x0100000000000019ul };
inline constexpr const ProgramId ProgramId::Pcv = { 0x010000000000001Aul };
inline constexpr const ProgramId ProgramId::Ppc = { 0x010000000000001Bul };
inline constexpr const ProgramId ProgramId::NvnFlinger = { 0x010000000000001Cul };
inline constexpr const ProgramId ProgramId::Pcie = { 0x010000000000001Dul };
inline constexpr const ProgramId ProgramId::Account = { 0x010000000000001Eul };
inline constexpr const ProgramId ProgramId::Ns = { 0x010000000000001Ful };
inline constexpr const ProgramId ProgramId::Nfc = { 0x0100000000000020ul };
inline constexpr const ProgramId ProgramId::Psc = { 0x0100000000000021ul };
inline constexpr const ProgramId ProgramId::CapSrv = { 0x0100000000000022ul };
inline constexpr const ProgramId ProgramId::Am = { 0x0100000000000023ul };
inline constexpr const ProgramId ProgramId::Ssl = { 0x0100000000000024ul };
inline constexpr const ProgramId ProgramId::Nim = { 0x0100000000000025ul };
inline constexpr const ProgramId ProgramId::Cec = { 0x0100000000000026ul };
inline constexpr const ProgramId ProgramId::Tspm = { 0x0100000000000027ul };
inline constexpr const ProgramId ProgramId::Spl = { 0x0100000000000028ul };
inline constexpr const ProgramId ProgramId::Lbl = { 0x0100000000000029ul };
inline constexpr const ProgramId ProgramId::Btm = { 0x010000000000002Aul };
inline constexpr const ProgramId ProgramId::Erpt = { 0x010000000000002Bul };
inline constexpr const ProgramId ProgramId::Time = { 0x010000000000002Cul };
inline constexpr const ProgramId ProgramId::Vi = { 0x010000000000002Dul };
inline constexpr const ProgramId ProgramId::Pctl = { 0x010000000000002Eul };
inline constexpr const ProgramId ProgramId::Npns = { 0x010000000000002Ful };
inline constexpr const ProgramId ProgramId::Eupld = { 0x0100000000000030ul };
inline constexpr const ProgramId ProgramId::Arp = { 0x0100000000000031ul };
inline constexpr const ProgramId ProgramId::Glue = { 0x0100000000000031ul };
inline constexpr const ProgramId ProgramId::Eclct = { 0x0100000000000032ul };
inline constexpr const ProgramId ProgramId::Es = { 0x0100000000000033ul };
inline constexpr const ProgramId ProgramId::Fatal = { 0x0100000000000034ul };
inline constexpr const ProgramId ProgramId::Grc = { 0x0100000000000035ul };
inline constexpr const ProgramId ProgramId::Creport = { 0x0100000000000036ul };
inline constexpr const ProgramId ProgramId::Ro = { 0x0100000000000037ul };
inline constexpr const ProgramId ProgramId::Profiler = { 0x0100000000000038ul };
inline constexpr const ProgramId ProgramId::Sdb = { 0x0100000000000039ul };
inline constexpr const ProgramId ProgramId::Migration = { 0x010000000000003Aul };
inline constexpr const ProgramId ProgramId::Jit = { 0x010000000000003Bul };
inline constexpr const ProgramId ProgramId::JpegDec = { 0x010000000000003Cul };
inline constexpr const ProgramId ProgramId::SafeMode = { 0x010000000000003Dul };
inline constexpr const ProgramId ProgramId::Olsc = { 0x010000000000003Eul };
inline constexpr const ProgramId ProgramId::Dt = { 0x010000000000003Ful };
inline constexpr const ProgramId ProgramId::Nd = { 0x0100000000000040ul };
inline constexpr const ProgramId ProgramId::Ngct = { 0x0100000000000041ul };
inline constexpr const ProgramId ProgramId::SystemEnd = { 0x01000000000007FFul };
/* System Data Archives. */
inline constexpr const ProgramId ProgramId::ArchiveStart = { 0x0100000000000800ul };
inline constexpr const ProgramId ProgramId::ArchiveCertStore = { 0x0100000000000800ul };
inline constexpr const ProgramId ProgramId::ArchiveErrorMessage = { 0x0100000000000801ul };
inline constexpr const ProgramId ProgramId::ArchiveMiiModel = { 0x0100000000000802ul };
inline constexpr const ProgramId ProgramId::ArchiveBrowserDll = { 0x0100000000000803ul };
inline constexpr const ProgramId ProgramId::ArchiveHelp = { 0x0100000000000804ul };
inline constexpr const ProgramId ProgramId::ArchiveSharedFont = { 0x0100000000000805ul };
inline constexpr const ProgramId ProgramId::ArchiveNgWord = { 0x0100000000000806ul };
inline constexpr const ProgramId ProgramId::ArchiveSsidList = { 0x0100000000000807ul };
inline constexpr const ProgramId ProgramId::ArchiveDictionary = { 0x0100000000000808ul };
inline constexpr const ProgramId ProgramId::ArchiveSystemVersion = { 0x0100000000000809ul };
inline constexpr const ProgramId ProgramId::ArchiveAvatarImage = { 0x010000000000080Aul };
inline constexpr const ProgramId ProgramId::ArchiveLocalNews = { 0x010000000000080Bul };
inline constexpr const ProgramId ProgramId::ArchiveEula = { 0x010000000000080Cul };
inline constexpr const ProgramId ProgramId::ArchiveUrlBlackList = { 0x010000000000080Dul };
inline constexpr const ProgramId ProgramId::ArchiveTimeZoneBinar = { 0x010000000000080Eul };
inline constexpr const ProgramId ProgramId::ArchiveCertStoreCruiser = { 0x010000000000080Ful };
inline constexpr const ProgramId ProgramId::ArchiveFontNintendoExtension = { 0x0100000000000810ul };
inline constexpr const ProgramId ProgramId::ArchiveFontStandard = { 0x0100000000000811ul };
inline constexpr const ProgramId ProgramId::ArchiveFontKorean = { 0x0100000000000812ul };
inline constexpr const ProgramId ProgramId::ArchiveFontChineseTraditional = { 0x0100000000000813ul };
inline constexpr const ProgramId ProgramId::ArchiveFontChineseSimple = { 0x0100000000000814ul };
inline constexpr const ProgramId ProgramId::ArchiveFontBfcpx = { 0x0100000000000815ul };
inline constexpr const ProgramId ProgramId::ArchiveSystemUpdate = { 0x0100000000000816ul };
inline constexpr const ProgramId ProgramId::ArchiveFirmwareDebugSettings = { 0x0100000000000818ul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackage = { 0x0100000000000819ul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageSafe = { 0x010000000000081Aul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageExFat = { 0x010000000000081Bul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageExFatSafe = { 0x010000000000081Cul };
inline constexpr const ProgramId ProgramId::ArchiveFatalMessage = { 0x010000000000081Dul };
inline constexpr const ProgramId ProgramId::ArchiveControllerIcon = { 0x010000000000081Eul };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigIcosa = { 0x010000000000081Ful };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigCopper = { 0x0100000000000820ul };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigHoag = { 0x0100000000000821ul };
inline constexpr const ProgramId ProgramId::ArchiveControllerFirmware = { 0x0100000000000822ul };
inline constexpr const ProgramId ProgramId::ArchiveNgWord2 = { 0x0100000000000823ul };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigIcosaMariko = { 0x0100000000000824ul };
inline constexpr const ProgramId ProgramId::ArchiveApplicationBlackList = { 0x0100000000000825ul };
inline constexpr const ProgramId ProgramId::ArchiveRebootlessSystemUpdateVersion = { 0x0100000000000826ul };
inline constexpr const ProgramId ProgramId::ArchiveContentActionTable = { 0x0100000000000827ul };
inline constexpr const ProgramId ProgramId::ArchiveEnd = { 0x0100000000000FFFul };
/* System Applets. */
inline constexpr const ProgramId ProgramId::AppletStart = { 0x0100000000001000ul };
inline constexpr const ProgramId ProgramId::AppletQlaunch = { 0x0100000000001000ul };
inline constexpr const ProgramId ProgramId::AppletAuth = { 0x0100000000001001ul };
inline constexpr const ProgramId ProgramId::AppletCabinet = { 0x0100000000001002ul };
inline constexpr const ProgramId ProgramId::AppletController = { 0x0100000000001003ul };
inline constexpr const ProgramId ProgramId::AppletDataErase = { 0x0100000000001004ul };
inline constexpr const ProgramId ProgramId::AppletError = { 0x0100000000001005ul };
inline constexpr const ProgramId ProgramId::AppletNetConnect = { 0x0100000000001006ul };
inline constexpr const ProgramId ProgramId::AppletPlayerSelect = { 0x0100000000001007ul };
inline constexpr const ProgramId ProgramId::AppletSwkbd = { 0x0100000000001008ul };
inline constexpr const ProgramId ProgramId::AppletMiiEdit = { 0x0100000000001009ul };
inline constexpr const ProgramId ProgramId::AppletWeb = { 0x010000000000100Aul };
inline constexpr const ProgramId ProgramId::AppletShop = { 0x010000000000100Bul };
inline constexpr const ProgramId ProgramId::AppletOverlayDisp = { 0x010000000000100Cul };
inline constexpr const ProgramId ProgramId::AppletPhotoViewer = { 0x010000000000100Dul };
inline constexpr const ProgramId ProgramId::AppletSet = { 0x010000000000100Eul };
inline constexpr const ProgramId ProgramId::AppletOfflineWeb = { 0x010000000000100Ful };
inline constexpr const ProgramId ProgramId::AppletLoginShare = { 0x0100000000001010ul };
inline constexpr const ProgramId ProgramId::AppletWifiWebAuth = { 0x0100000000001011ul };
inline constexpr const ProgramId ProgramId::AppletStarter = { 0x0100000000001012ul };
inline constexpr const ProgramId ProgramId::AppletMyPage = { 0x0100000000001013ul };
inline constexpr const ProgramId ProgramId::AppletPlayReport = { 0x0100000000001014ul };
inline constexpr const ProgramId ProgramId::AppletMaintenanceMenu = { 0x0100000000001015ul };
inline constexpr const ProgramId ProgramId::AppletGift = { 0x010000000000101Aul };
inline constexpr const ProgramId ProgramId::AppletDummyShop = { 0x010000000000101Bul };
inline constexpr const ProgramId ProgramId::AppletUserMigration = { 0x010000000000101Cul };
inline constexpr const ProgramId ProgramId::AppletEncounter = { 0x010000000000101Dul };
inline constexpr const ProgramId ProgramId::AppletStory = { 0x0100000000001020ul };
inline constexpr const ProgramId ProgramId::AppletEnd = { 0x0100000000001FFFul };
/* Debug Applets. */
/* Debug Modules. */
/* Factory Setup. */
/* Applications. */
inline constexpr const ProgramId ProgramId::ApplicationStart = { 0x0100000000010000ul };
inline constexpr const ProgramId ProgramId::ApplicationEnd = { 0x01FFFFFFFFFFFFFFul };
/* Atmosphere Extensions. */
inline constexpr const ProgramId ProgramId::AtmosphereMitm = { 0x010041544D530000ul };
inline constexpr bool operator==(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value != rhs.value;
}
inline constexpr bool operator<(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value < rhs.value;
}
inline constexpr bool operator<=(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value <= rhs.value;
}
inline constexpr bool operator>(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value > rhs.value;
}
inline constexpr bool operator>=(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value >= rhs.value;
}
inline constexpr bool IsSystemProgramId(const ProgramId &program_id) {
return ProgramId::SystemStart <= program_id && program_id <= ProgramId::SystemEnd;
}
inline constexpr bool IsArchiveProgramId(const ProgramId &program_id) {
return ProgramId::ArchiveStart <= program_id && program_id <= ProgramId::ArchiveEnd;
}
inline constexpr bool IsAppletProgramId(const ProgramId &program_id) {
return ProgramId::AppletStart <= program_id && program_id <= ProgramId::AppletEnd;
}
inline constexpr bool IsApplicationProgramId(const ProgramId &program_id) {
return ProgramId::ApplicationStart <= program_id && program_id <= ProgramId::ApplicationEnd;
}
inline constexpr bool IsWebAppletProgramId(const ProgramId &program_id) {
return program_id == ProgramId::AppletWeb ||
program_id == ProgramId::AppletShop ||
program_id == ProgramId::AppletOfflineWeb ||
program_id == ProgramId::AppletLoginShare ||
program_id == ProgramId::AppletWifiWebAuth;
}
static_assert(sizeof(ProgramId) == sizeof(u64) && std::is_pod<ProgramId>::value, "ProgramId definition!");
/* Program Location. */
struct ProgramLocation {
ProgramId program_id;
u8 storage_id;
static constexpr ProgramLocation Make(ProgramId program_id, StorageId storage_id) {
return { .program_id = program_id, .storage_id = static_cast<u8>(storage_id), };
}
};
static_assert(sizeof(ProgramLocation) == 0x10 && std::is_pod<ProgramLocation>::value, "ProgramLocation definition!");
static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility");
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-2019 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 "os/os_common_types.hpp"
#include "os/os_memory_common.hpp"
#include "os/os_managed_handle.hpp"
#include "os/os_process_handle.hpp"
#include "os/os_mutex.hpp"
#include "os/os_condvar.hpp"
#include "os/os_rw_lock.hpp"
#include "os/os_semaphore.hpp"
#include "os/os_timeout_helper.hpp"
#include "os/os_event.hpp"
#include "os/os_system_event.hpp"
#include "os/os_interrupt_event.hpp"
#include "os/os_thread.hpp"
#include "os/os_message_queue.hpp"
#include "os/os_waitable_holder.hpp"
#include "os/os_waitable_manager.hpp"

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2018-2019 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::os {
enum class TriBool {
False = 0,
True = 1,
Undefined = 2,
};
enum class MessageQueueWaitKind {
ForNotEmpty,
ForNotFull,
};
struct ProcessId {
u64 value;
inline constexpr explicit operator u64() const {
return this->value;
}
/* Invalid Process ID. */
static const ProcessId Invalid;
};
inline constexpr const ProcessId ProcessId::Invalid = {static_cast<u64>(-1ull)};
inline constexpr const ProcessId InvalidProcessId = ProcessId::Invalid;
NX_INLINE Result TryGetProcessId(os::ProcessId *out, ::Handle process_handle) {
return svcGetProcessId(&out->value, process_handle);
}
NX_INLINE os::ProcessId GetProcessId(::Handle process_handle) {
os::ProcessId process_id;
R_ASSERT(TryGetProcessId(&process_id, process_handle));
return process_id;
}
inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value != rhs.value;
}
inline constexpr bool operator<(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value < rhs.value;
}
inline constexpr bool operator<=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value <= rhs.value;
}
inline constexpr bool operator>(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value > rhs.value;
}
inline constexpr bool operator>=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value >= rhs.value;
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018-2019 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 "os_mutex.hpp"
namespace ams::os {
enum class ConditionVariableStatus {
TimedOut = 0,
Success = 1,
};
class ConditionVariable {
NON_COPYABLE(ConditionVariable);
NON_MOVEABLE(ConditionVariable);
private:
CondVar cv;
public:
ConditionVariable() {
condvarInit(&cv);
}
ConditionVariableStatus TimedWait(::Mutex *m, u64 timeout) {
if (timeout > 0) {
/* Abort on any error other than timed out/success. */
R_TRY_CATCH(condvarWaitTimeout(&this->cv, m, timeout)) {
R_CATCH(svc::ResultTimedOut) { return ConditionVariableStatus::TimedOut; }
} R_END_TRY_CATCH_WITH_ASSERT;
return ConditionVariableStatus::Success;
}
return ConditionVariableStatus::TimedOut;
}
void Wait(::Mutex *m) {
R_ASSERT(condvarWait(&this->cv, m));
}
ConditionVariableStatus TimedWait(os::Mutex *m, u64 timeout) {
return this->TimedWait(m->GetMutex(), timeout);
}
void Wait(os::Mutex *m) {
return this->Wait(m->GetMutex());
}
void Signal() {
condvarWakeOne(&this->cv);
}
void Broadcast() {
condvarWakeAll(&this->cv);
}
};
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2019 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 "os_mutex.hpp"
#include "os_condvar.hpp"
#include "os_timeout_helper.hpp"
namespace ams::os {
namespace impl {
class WaitableObjectList;
class WaitableHolderOfEvent;
}
class Event {
friend class impl::WaitableHolderOfEvent;
NON_COPYABLE(Event);
NON_MOVEABLE(Event);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitable_object_list_storage;
Mutex lock;
ConditionVariable cv;
u64 counter = 0;
bool auto_clear;
bool signaled;
public:
Event(bool a = true, bool s = false);
~Event();
void Signal();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
};
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2018-2019 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 "os_managed_handle.hpp"
namespace ams::os {
namespace impl {
class WaitableHolderOfInterruptEvent;
}
class InterruptEvent {
friend class impl::WaitableHolderOfInterruptEvent;
NON_COPYABLE(InterruptEvent);
NON_MOVEABLE(InterruptEvent);
private:
ManagedHandle handle;
bool auto_clear;
bool is_initialized;
public:
InterruptEvent() : auto_clear(true), is_initialized(false) { }
InterruptEvent(u32 interrupt_id, bool autoclear = true);
Result Initialize(u32 interrupt_id, bool autoclear = true);
void Finalize();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
};
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2018-2019 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 "os_common_types.hpp"
namespace ams::os {
class ManagedHandle {
NON_COPYABLE(ManagedHandle);
private:
Handle hnd;
public:
ManagedHandle() : hnd(INVALID_HANDLE) { /* ... */ }
ManagedHandle(Handle h) : hnd(h) { /* ... */ }
~ManagedHandle() {
if (this->hnd != INVALID_HANDLE) {
R_ASSERT(svcCloseHandle(this->hnd));
this->hnd = INVALID_HANDLE;
}
}
ManagedHandle(ManagedHandle&& rhs) {
this->hnd = rhs.hnd;
rhs.hnd = INVALID_HANDLE;
}
ManagedHandle& operator=(ManagedHandle&& rhs) {
rhs.Swap(*this);
return *this;
}
explicit operator bool() const {
return this->hnd != INVALID_HANDLE;
}
void Swap(ManagedHandle& rhs) {
std::swap(this->hnd, rhs.hnd);
}
Handle Get() const {
return this->hnd;
}
Handle *GetPointer() {
return &this->hnd;
}
Handle *GetPointerAndClear() {
this->Clear();
return this->GetPointer();
}
Handle Move() {
const Handle h = this->hnd;
this->hnd = INVALID_HANDLE;
return h;
}
void Reset(Handle h) {
ManagedHandle(h).Swap(*this);
}
void Clear() {
this->Reset(INVALID_HANDLE);
}
};
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 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::os {
constexpr inline size_t MemoryPageSize = 0x1000;
constexpr inline size_t MemoryBlockUnitSize = 0x200000;
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2019 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 "os_mutex.hpp"
#include "os_condvar.hpp"
namespace ams::os {
namespace impl {
class WaitableObjectList;
template<MessageQueueWaitKind WaitKind>
class WaitableHolderOfMessageQueue;
}
class MessageQueue {
template<MessageQueueWaitKind WaitKind>
friend class impl::WaitableHolderOfMessageQueue;
NON_COPYABLE(MessageQueue);
NON_MOVEABLE(MessageQueue);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_empty;
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_full;
Mutex queue_lock;
ConditionVariable cv_not_full;
ConditionVariable cv_not_empty;
std::unique_ptr<uintptr_t[]> buffer;
size_t capacity;
size_t count;
size_t offset;
private:
constexpr inline bool IsFull() const {
return this->count >= this->capacity;
}
constexpr inline bool IsEmpty() const {
return this->count == 0;
}
void SendInternal(uintptr_t data);
void SendNextInternal(uintptr_t data);
uintptr_t ReceiveInternal();
uintptr_t PeekInternal();
public:
MessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c);
~MessageQueue();
/* For convenience. */
MessageQueue(size_t c) : MessageQueue(std::make_unique<uintptr_t[]>(c), c) { /* ... */ }
/* Sending (FIFO functionality) */
void Send(uintptr_t data);
bool TrySend(uintptr_t data);
bool TimedSend(uintptr_t data, u64 timeout);
/* Sending (LIFO functionality) */
void SendNext(uintptr_t data);
bool TrySendNext(uintptr_t data);
bool TimedSendNext(uintptr_t data, u64 timeout);
/* Receive functionality */
void Receive(uintptr_t *out);
bool TryReceive(uintptr_t *out);
bool TimedReceive(uintptr_t *out, u64 timeout);
/* Peek functionality */
void Peek(uintptr_t *out);
bool TryPeek(uintptr_t *out);
bool TimedPeek(uintptr_t *out, u64 timeout);
};
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2018-2019 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 "os_common_types.hpp"
namespace ams::os {
class ConditionVariable;
class Mutex {
NON_COPYABLE(Mutex);
NON_MOVEABLE(Mutex);
friend class ams::os::ConditionVariable;
private:
::Mutex m;
private:
::Mutex *GetMutex() {
return &this->m;
}
public:
Mutex() {
mutexInit(GetMutex());
}
void lock() {
mutexLock(GetMutex());
}
void unlock() {
mutexUnlock(GetMutex());
}
bool try_lock() {
return mutexTryLock(GetMutex());
}
void Lock() {
lock();
}
void Unlock() {
unlock();
}
bool TryLock() {
return try_lock();
}
};
class RecursiveMutex {
private:
::RMutex m;
private:
::RMutex *GetMutex() {
return &this->m;
}
public:
RecursiveMutex() {
rmutexInit(GetMutex());
}
void lock() {
rmutexLock(GetMutex());
}
void unlock() {
rmutexUnlock(GetMutex());
}
bool try_lock() {
return rmutexTryLock(GetMutex());
}
void Lock() {
lock();
}
void Unlock() {
unlock();
}
bool TryLock() {
return try_lock();
}
};
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 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 "os_managed_handle.hpp"
namespace ams::os {
::Handle GetCurrentProcessHandle();
NX_INLINE ProcessId GetCurrentProcessId() {
return GetProcessId(GetCurrentProcessHandle());
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2019 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 "os_common_types.hpp"
namespace ams::os {
class ReadWriteLock {
NON_COPYABLE(ReadWriteLock);
NON_MOVEABLE(ReadWriteLock);
private:
::RwLock r;
public:
ReadWriteLock() {
rwlockInit(&this->r);
}
bool IsWriteLockHeldByCurrentThread() const {
return rwlockIsWriteLockHeldByCurrentThread(const_cast<::RwLock *>(&this->r));
}
bool IsLockOwner() const {
return rwlockIsOwnedByCurrentThread(const_cast<::RwLock *>(&this->r));
}
void AcquireReadLock() {
rwlockReadLock(&this->r);
}
void ReleaseReadLock() {
rwlockReadUnlock(&this->r);
}
bool TryAcquireReadLock() {
return rwlockTryReadLock(&this->r);
}
void AcquireWriteLock() {
rwlockWriteLock(&this->r);
}
void ReleaseWriteLock() {
rwlockWriteUnlock(&this->r);
}
bool TryAcquireWriteLock() {
return rwlockTryWriteLock(&this->r);
}
void lock_shared() {
this->AcquireReadLock();
}
void unlock_shared() {
this->ReleaseReadLock();
}
bool try_lock_shared() {
return this->TryAcquireReadLock();
}
void lock() {
this->AcquireWriteLock();
}
void unlock() {
this->ReleaseWriteLock();
}
bool try_lock() {
return this->TryAcquireWriteLock();
}
};
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2018-2019 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 "os_mutex.hpp"
#include "os_condvar.hpp"
namespace ams::os {
namespace impl {
class WaitableObjectList;
class WaitableHolderOfSemaphore;
}
class Semaphore {
friend class impl::WaitableHolderOfSemaphore;
NON_COPYABLE(Semaphore);
NON_MOVEABLE(Semaphore);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist;
os::Mutex mutex;
os::ConditionVariable condvar;
int count;
int max_count;
public:
explicit Semaphore(int c, int mc);
~Semaphore();
void Acquire();
bool TryAcquire();
bool TimedAcquire(u64 timeout);
void Release();
void Release(int count);
constexpr inline int GetCurrentCount() const {
return this->count;
}
};
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2018-2019 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 "os_event.hpp"
namespace ams::os {
class WaitableHolder;
namespace impl {
class InterProcessEvent;
}
enum class SystemEventState {
Uninitialized,
Event,
InterProcessEvent,
};
class SystemEvent {
friend class WaitableHolder;
NON_COPYABLE(SystemEvent);
NON_MOVEABLE(SystemEvent);
private:
union {
util::TypedStorage<Event, sizeof(Event), alignof(Event)> storage_for_event;
util::TypedStorage<impl::InterProcessEvent, 3 * sizeof(Handle), alignof(Handle)> storage_for_inter_process_event;
};
SystemEventState state;
private:
Event &GetEvent();
const Event &GetEvent() const;
impl::InterProcessEvent &GetInterProcessEvent();
const impl::InterProcessEvent &GetInterProcessEvent() const;
public:
SystemEvent() : state(SystemEventState::Uninitialized) { /* ... */ }
SystemEvent(bool inter_process, bool autoclear = true);
SystemEvent(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true);
SystemEvent(Handle read_handle, bool manage_read_handle, bool autoclear = true) : SystemEvent(read_handle, manage_read_handle, INVALID_HANDLE, false, autoclear) { /* ... */ }
~SystemEvent();
Result InitializeAsEvent(bool autoclear = true);
Result InitializeAsInterProcessEvent(bool autoclear = true);
void AttachHandles(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true);
void AttachReadableHandle(Handle read_handle, bool manage_read_handle, bool autoclear = true);
void AttachWritableHandle(Handle write_handle, bool manage_write_handle, bool autoclear = true);
Handle DetachReadableHandle();
Handle DetachWritableHandle();
Handle GetReadableHandle() const;
Handle GetWritableHandle() const;
void Finalize();
SystemEventState GetState() const {
return this->state;
}
void Signal();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
};
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2018-2019 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 "os_common_types.hpp"
#include "os_memory_common.hpp"
namespace ams::os {
class Thread {
NON_COPYABLE(Thread);
NON_MOVEABLE(Thread);
private:
::Thread thr;
public:
constexpr Thread() : thr{} { /* ... */ }
Result Initialize(ThreadFunc entry, void *arg, void *stack_mem, size_t stack_sz, int prio, int cpuid = -2) {
return threadCreate(&this->thr, entry, arg, stack_mem, stack_sz, prio, cpuid);
}
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
return threadCreate(&this->thr, entry, arg, nullptr, stack_sz, prio, cpuid);
}
Handle GetHandle() const {
return this->thr.handle;
}
Result Start() {
return threadStart(&this->thr);
}
Result Wait() {
return threadWaitForExit(&this->thr);
}
Result Join() {
R_TRY(threadWaitForExit(&this->thr));
R_TRY(threadClose(&this->thr));
return ResultSuccess();
}
Result CancelSynchronization() {
return svcCancelSynchronization(this->thr.handle);
}
};
template<size_t StackSize>
class StaticThread {
NON_COPYABLE(StaticThread);
NON_MOVEABLE(StaticThread);
static_assert(util::IsAligned(StackSize, os::MemoryPageSize), "StaticThread must have aligned resource size");
private:
alignas(os::MemoryPageSize) u8 stack_mem[StackSize];
::Thread thr;
public:
constexpr StaticThread() : stack_mem{}, thr{} { /* ... */ }
constexpr StaticThread(ThreadFunc entry, void *arg, int prio, int cpuid = -2) : StaticThread() {
R_ASSERT(this->Initialize(entry, arg, prio, cpuid));
}
Result Initialize(ThreadFunc entry, void *arg, int prio, int cpuid = -2) {
return threadCreate(&this->thr, entry, arg, this->stack_mem, StackSize, prio, cpuid);
}
Handle GetHandle() const {
return this->thr.handle;
}
Result Start() {
return threadStart(&this->thr);
}
Result Wait() {
return threadWaitForExit(&this->thr);
}
Result Join() {
R_TRY(threadWaitForExit(&this->thr));
R_TRY(threadClose(&this->thr));
return ResultSuccess();
}
Result CancelSynchronization() {
return svcCancelSynchronization(this->thr.handle);
}
};
NX_INLINE u32 GetCurrentThreadPriority() {
u32 prio;
R_ASSERT(svcGetThreadPriority(&prio, CUR_THREAD_HANDLE));
return prio;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2018-2019 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 "os_common_types.hpp"
namespace ams::os {
class TimeoutHelper {
private:
u64 end_tick;
public:
TimeoutHelper(u64 ns) {
/* Special case zero-time timeouts. */
if (ns == 0) {
end_tick = 0;
return;
}
u64 cur_tick = armGetSystemTick();
this->end_tick = cur_tick + NsToTick(ns) + 1;
}
static constexpr inline u64 NsToTick(u64 ns) {
return (ns * 12) / 625;
}
static constexpr inline u64 TickToNs(u64 tick) {
return (tick * 625) / 12;
}
inline bool TimedOut() const {
if (this->end_tick == 0) {
return true;
}
return armGetSystemTick() >= this->end_tick;
}
inline u64 NsUntilTimeout() const {
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
if (this->TimedOut()) {
return 0;
}
return diff;
}
};
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2018-2019 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 "os_common_types.hpp"
namespace ams::os {
class WaitableManager;
class Event;
class SystemEvent;
class InterruptEvent;
class Thread;
class MessageQueue;
class Semaphore;
namespace impl {
class WaitableHolderImpl;
}
class WaitableHolder {
friend class WaitableManager;
NON_COPYABLE(WaitableHolder);
NON_MOVEABLE(WaitableHolder);
private:
util::TypedStorage<impl::WaitableHolderImpl, 2 * sizeof(util::IntrusiveListNode) + 3 * sizeof(void *), alignof(void *)> impl_storage;
uintptr_t user_data;
public:
static constexpr size_t ImplStorageSize = sizeof(impl_storage);
public:
WaitableHolder(Handle handle);
WaitableHolder(Event *event);
WaitableHolder(SystemEvent *event);
WaitableHolder(InterruptEvent *event);
WaitableHolder(Thread *thread);
WaitableHolder(Semaphore *semaphore);
WaitableHolder(MessageQueue *message_queue, MessageQueueWaitKind wait_kind);
~WaitableHolder();
void SetUserData(uintptr_t data) {
this->user_data = data;
}
uintptr_t GetUserData() const {
return this->user_data;
}
void UnlinkFromWaitableManager();
};
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2018-2019 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 "os_mutex.hpp"
namespace ams::os {
class WaitableHolder;
namespace impl {
class WaitableManagerImpl;
}
class WaitableManager {
NON_COPYABLE(WaitableManager);
NON_MOVEABLE(WaitableManager);
private:
util::TypedStorage<impl::WaitableManagerImpl, sizeof(util::IntrusiveListNode) + sizeof(Mutex) + 2 * sizeof(void *) + sizeof(Handle), alignof(void *)> impl_storage;
public:
static constexpr size_t ImplStorageSize = sizeof(impl_storage);
public:
WaitableManager();
~WaitableManager();
/* Wait. */
WaitableHolder *WaitAny();
WaitableHolder *TryWaitAny();
WaitableHolder *TimedWaitAny(u64 timeout);
/* Link. */
void LinkWaitableHolder(WaitableHolder *holder);
void UnlinkAll();
void MoveAllFrom(WaitableManager *other);
};
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "patcher/patcher_api.hpp"

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2019 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 "../ro/ro_types.hpp"
namespace ams::patcher {
/* Helper for applying to code binaries. */
void LocateAndApplyIpsPatchesToModule(const char *patch_dir, size_t protected_size, size_t offset, const ro::ModuleId *module_id, u8 *mapped_module, size_t mapped_size);
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2019 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 "pm/pm_types.hpp"
#include "pm/pm_boot_mode_api.hpp"
#include "pm/pm_info_api.hpp"
#include "pm/pm_shell_api.hpp"
#include "pm/pm_dmnt_api.hpp"

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 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 "pm_types.hpp"
namespace ams::pm::bm {
/* Boot Mode API. */
BootMode GetBootMode();
void SetMaintenanceBoot();
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2019 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 "../ldr.hpp"
#include "pm_types.hpp"
namespace ams::pm::dmnt {
/* Debug Monitor API. */
Result StartProcess(os::ProcessId process_id);
Result GetProcessId(os::ProcessId *out_process_id, const ncm::ProgramId program_id);
Result GetApplicationProcessId(os::ProcessId *out_process_id);
Result HookToCreateApplicationProcess(Handle *out_handle);
Result AtmosphereGetProcessInfo(Handle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id);
Result AtmosphereGetCurrentLimitInfo(u64 *out_current_value, u64 *out_limit_value, ResourceLimitGroup group, LimitableResource resource);
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018-2019 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 "pm_types.hpp"
#include "../ncm/ncm_types.hpp"
namespace ams::pm::info {
/* Information API. */
Result GetProgramId(ncm::ProgramId *out_program_id, os::ProcessId process_id);
Result GetProcessId(os::ProcessId *out_process_id, ncm::ProgramId program_id);
Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id);
Result GetProcessInfo(ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id);
/* Information convenience API. */
bool HasLaunchedProgram(ncm::ProgramId program_id);
Result IsHblProcessId(bool *out, os::ProcessId process_id);
Result IsHblProgramId(bool *out, ncm::ProgramId program_id);
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 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 "../ldr.hpp"
#include "pm_types.hpp"
namespace ams::pm::shell {
/* Shell API. */
Result LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-2019 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 "../os/os_common_types.hpp"
namespace ams::pm {
enum class BootMode {
Normal = 0,
Maintenance = 1,
SafeMode = 2,
};
enum ResourceLimitGroup {
ResourceLimitGroup_System = 0,
ResourceLimitGroup_Application = 1,
ResourceLimitGroup_Applet = 2,
ResourceLimitGroup_Count,
};
using LimitableResource = ::LimitableResource;
struct ProcessEventInfo {
u32 event;
os::ProcessId process_id;
};
static_assert(sizeof(ProcessEventInfo) == 0x10 && std::is_pod<ProcessEventInfo>::value, "ProcessEventInfo definition!");
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018-2019 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::reg {
inline void Write(volatile u32 *reg, u32 val) {
*reg = val;
}
inline void Write(uintptr_t reg, u32 val) {
Write(reinterpret_cast<volatile u32 *>(reg), val);
}
inline u32 Read(volatile u32 *reg) {
return *reg;
}
inline u32 Read(uintptr_t reg) {
return Read(reinterpret_cast<volatile u32 *>(reg));
}
inline void SetBits(volatile u32 *reg, u32 mask) {
*reg |= mask;
}
inline void SetBits(uintptr_t reg, u32 mask) {
SetBits(reinterpret_cast<volatile u32 *>(reg), mask);
}
inline void ClearBits(volatile u32 *reg, u32 mask) {
*reg &= ~mask;
}
inline void ClearBits(uintptr_t reg, u32 mask) {
ClearBits(reinterpret_cast<volatile u32 *>(reg), mask);
}
inline void MaskBits(volatile u32 *reg, u32 mask) {
*reg &= mask;
}
inline void MaskBits(uintptr_t reg, u32 mask) {
MaskBits(reinterpret_cast<volatile u32 *>(reg), mask);
}
inline void ReadWrite(volatile u32 *reg, u32 val, u32 mask) {
*reg = (*reg & (~mask)) | (val & mask);
}
inline void ReadWrite(uintptr_t reg, u32 val, u32 mask) {
ReadWrite(reinterpret_cast<volatile u32 *>(reg), val, mask);
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "rnd/rnd_api.hpp"

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 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::rnd {
/* Random utilities. */
void GenerateRandomBytes(void* out, size_t size);
u32 GenerateRandomU32(u32 max = std::numeric_limits<u32>::max());
u64 GenerateRandomU64(u64 max = std::numeric_limits<u64>::max());
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 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 "ro/ro_types.hpp"

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2018-2019 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 "../ncm/ncm_types.hpp"
namespace ams::ro {
enum class ModuleType : u8 {
ForSelf = 0,
ForOthers = 1,
Count
};
struct ModuleId {
u8 build_id[0x20];
};
static_assert(sizeof(ModuleId) == sizeof(LoaderModuleInfo::build_id), "ModuleId definition!");
class NrrHeader {
public:
static constexpr u32 Magic = 0x3052524E;
private:
u32 magic;
u8 reserved_04[0xC];
u64 program_id_mask;
u64 program_id_pattern;
u8 reserved_20[0x10];
u8 modulus[0x100];
u8 fixed_key_signature[0x100];
u8 nrr_signature[0x100];
ncm::ProgramId program_id;
u32 size;
u8 type; /* 7.0.0+ */
u8 reserved_33D[3];
u32 hashes_offset;
u32 num_hashes;
u8 reserved_348[8];
public:
bool IsMagicValid() const {
return this->magic == Magic;
}
bool IsProgramIdValid() const {
return (static_cast<u64>(this->program_id) & this->program_id_mask) == this->program_id_pattern;
}
ModuleType GetType() const {
const ModuleType type = static_cast<ModuleType>(this->type);
AMS_ASSERT(type < ModuleType::Count);
return type;
}
ncm::ProgramId GetProgramId() const {
return this->program_id;
}
u32 GetSize() const {
return this->size;
}
u32 GetNumHashes() const {
return this->num_hashes;
}
uintptr_t GetHashes() const {
return reinterpret_cast<uintptr_t>(this) + this->hashes_offset;
}
};
static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader definition!");
class NroHeader {
public:
static constexpr u32 Magic = 0x304F524E;
private:
u32 entrypoint_insn;
u32 mod_offset;
u8 reserved_08[0x8];
u32 magic;
u8 reserved_14[0x4];
u32 size;
u8 reserved_1C[0x4];
u32 text_offset;
u32 text_size;
u32 ro_offset;
u32 ro_size;
u32 rw_offset;
u32 rw_size;
u32 bss_size;
u8 reserved_3C[0x4];
ModuleId module_id;
u8 reserved_60[0x20];
public:
bool IsMagicValid() const {
return this->magic == Magic;
}
u32 GetSize() const {
return this->size;
}
u32 GetTextOffset() const {
return this->text_offset;
}
u32 GetTextSize() const {
return this->text_size;
}
u32 GetRoOffset() const {
return this->ro_offset;
}
u32 GetRoSize() const {
return this->ro_size;
}
u32 GetRwOffset() const {
return this->rw_offset;
}
u32 GetRwSize() const {
return this->rw_size;
}
u32 GetBssSize() const {
return this->bss_size;
}
const ModuleId *GetModuleId() const {
return &this->module_id;
}
};
static_assert(sizeof(NroHeader) == 0x80, "NroHeader definition!");
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2018-2019 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 "settings/settings_types.hpp"
#include "settings/settings_fwdbg_types.hpp"
#include "settings/settings_fwdbg_api.hpp"

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 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 "settings_fwdbg_types.hpp"
namespace ams::settings::fwdbg {
bool IsDebugModeEnabled();
size_t GetSettingsItemValueSize(const char *name, const char *key);
size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key);
}

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