mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
settings: implement KeyValueStore (#1659)
* settings: implement KeyValueStore and dependencies * settings: update KeyValueStore for recent refactoring * settings: address feedback
This commit is contained in:
parent
14c8801259
commit
303c6eb5f9
23 changed files with 2767 additions and 81 deletions
|
@ -213,8 +213,8 @@ namespace ams::secmon::smc {
|
||||||
case ConfigItem::IsChargerHiZModeEnabled:
|
case ConfigItem::IsChargerHiZModeEnabled:
|
||||||
args.r[1] = IsChargerHiZModeEnabled();
|
args.r[1] = IsChargerHiZModeEnabled();
|
||||||
break;
|
break;
|
||||||
case ConfigItem::QuestState:
|
case ConfigItem::RetailInteractiveDisplayState:
|
||||||
args.r[1] = fuse::GetQuestState();
|
args.r[1] = fuse::GetRetailInteractiveDisplayState();
|
||||||
break;
|
break;
|
||||||
case ConfigItem::RegulatorType:
|
case ConfigItem::RegulatorType:
|
||||||
args.r[1] = fuse::GetRegulator();
|
args.r[1] = fuse::GetRegulator();
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace ams::secmon::smc {
|
||||||
IsDevelopmentFunctionEnabled = 11,
|
IsDevelopmentFunctionEnabled = 11,
|
||||||
KernelConfiguration = 12,
|
KernelConfiguration = 12,
|
||||||
IsChargerHiZModeEnabled = 13,
|
IsChargerHiZModeEnabled = 13,
|
||||||
QuestState = 14,
|
RetailInteractiveDisplayState = 14,
|
||||||
RegulatorType = 15,
|
RegulatorType = 15,
|
||||||
DeviceUniqueKeyGeneration = 16,
|
DeviceUniqueKeyGeneration = 16,
|
||||||
Package2Hash = 17,
|
Package2Hash = 17,
|
||||||
|
|
|
@ -81,9 +81,9 @@ namespace ams::fuse {
|
||||||
DramId_Count,
|
DramId_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum QuestState {
|
enum RetailInteractiveDisplayState {
|
||||||
QuestState_Disabled = 0,
|
RetailInteractiveDisplayState_Disabled = 0,
|
||||||
QuestState_Enabled = 1,
|
RetailInteractiveDisplayState_Enabled = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetRegisterAddress(uintptr_t address);
|
void SetRegisterAddress(uintptr_t address);
|
||||||
|
@ -107,7 +107,7 @@ namespace ams::fuse {
|
||||||
HardwareState GetHardwareState();
|
HardwareState GetHardwareState();
|
||||||
u64 GetDeviceId();
|
u64 GetDeviceId();
|
||||||
PatchVersion GetPatchVersion();
|
PatchVersion GetPatchVersion();
|
||||||
QuestState GetQuestState();
|
RetailInteractiveDisplayState GetRetailInteractiveDisplayState();
|
||||||
pmic::Regulator GetRegulator();
|
pmic::Regulator GetRegulator();
|
||||||
int GetDeviceUniqueKeyGeneration();
|
int GetDeviceUniqueKeyGeneration();
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,8 @@ namespace ams::fuse {
|
||||||
using DramId = util::BitPack32::Field<HardwareType1::Next, 5, int>;
|
using DramId = util::BitPack32::Field<HardwareType1::Next, 5, int>;
|
||||||
using HardwareType2 = util::BitPack32::Field<DramId::Next, 1, int>;
|
using HardwareType2 = util::BitPack32::Field<DramId::Next, 1, int>;
|
||||||
using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>;
|
using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>;
|
||||||
using QuestState = util::BitPack32::Field<HardwareState2::Next, 1, int>;
|
using RetailInteractiveDisplayState = util::BitPack32::Field<HardwareState2::Next, 1, int>;
|
||||||
using FormatVersion = util::BitPack32::Field<QuestState::Next, 1, int>;
|
using FormatVersion = util::BitPack32::Field<RetailInteractiveDisplayState::Next, 1, int>;
|
||||||
using Reserved = util::BitPack32::Field<FormatVersion::Next, 4, int>;
|
using Reserved = util::BitPack32::Field<FormatVersion::Next, 4, int>;
|
||||||
using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>;
|
using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>;
|
||||||
};
|
};
|
||||||
|
@ -343,8 +343,8 @@ namespace ams::fuse {
|
||||||
return static_cast<PatchVersion>(static_cast<int>(GetSocType() << 12) | patch_version);
|
return static_cast<PatchVersion>(static_cast<int>(GetSocType() << 12) | patch_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
QuestState GetQuestState() {
|
RetailInteractiveDisplayState GetRetailInteractiveDisplayState() {
|
||||||
return static_cast<QuestState>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::QuestState>());
|
return static_cast<RetailInteractiveDisplayState>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::RetailInteractiveDisplayState>());
|
||||||
}
|
}
|
||||||
|
|
||||||
pmic::Regulator GetRegulator() {
|
pmic::Regulator GetRegulator() {
|
||||||
|
|
|
@ -114,6 +114,7 @@ namespace ams::impl {
|
||||||
/* settings. */
|
/* settings. */
|
||||||
AMS_DEFINE_SYSTEM_THREAD(21, settings, Main);
|
AMS_DEFINE_SYSTEM_THREAD(21, settings, Main);
|
||||||
AMS_DEFINE_SYSTEM_THREAD(21, settings, IpcServer);
|
AMS_DEFINE_SYSTEM_THREAD(21, settings, IpcServer);
|
||||||
|
AMS_DEFINE_SYSTEM_THREAD(21, settings, LazyWriter);
|
||||||
|
|
||||||
/* erpt. */
|
/* erpt. */
|
||||||
AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main);
|
AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main);
|
||||||
|
|
|
@ -267,6 +267,10 @@ namespace ams::ncm {
|
||||||
static const SystemDataId RebootlessSystemUpdateVersion;
|
static const SystemDataId RebootlessSystemUpdateVersion;
|
||||||
static const SystemDataId ContentActionTable;
|
static const SystemDataId ContentActionTable;
|
||||||
|
|
||||||
|
static const SystemDataId PlatformConfigCalcio;
|
||||||
|
|
||||||
|
static const SystemDataId PlatformConfigAula;
|
||||||
|
|
||||||
static const SystemDataId End;
|
static const SystemDataId End;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -312,6 +316,10 @@ namespace ams::ncm {
|
||||||
inline constexpr const SystemDataId SystemDataId::RebootlessSystemUpdateVersion = { 0x0100000000000826ul };
|
inline constexpr const SystemDataId SystemDataId::RebootlessSystemUpdateVersion = { 0x0100000000000826ul };
|
||||||
inline constexpr const SystemDataId SystemDataId::ContentActionTable = { 0x0100000000000827ul };
|
inline constexpr const SystemDataId SystemDataId::ContentActionTable = { 0x0100000000000827ul };
|
||||||
|
|
||||||
|
inline constexpr const SystemDataId SystemDataId::PlatformConfigCalcio = { 0x0100000000000829ul };
|
||||||
|
|
||||||
|
inline constexpr const SystemDataId SystemDataId::PlatformConfigAula = { 0x0100000000000831ul };
|
||||||
|
|
||||||
inline constexpr const SystemDataId SystemDataId::End = { 0x0100000000000FFFul };
|
inline constexpr const SystemDataId SystemDataId::End = { 0x0100000000000FFFul };
|
||||||
|
|
||||||
inline constexpr bool IsSystemDataId(const DataId &data_id) {
|
inline constexpr bool IsSystemDataId(const DataId &data_id) {
|
||||||
|
|
|
@ -20,19 +20,4 @@
|
||||||
|
|
||||||
namespace ams::settings::fwdbg {
|
namespace ams::settings::fwdbg {
|
||||||
|
|
||||||
constexpr size_t SettingsNameLengthMax = 0x40;
|
|
||||||
constexpr size_t SettingsItemKeyLengthMax = 0x40;
|
|
||||||
|
|
||||||
struct SettingsName : sf::LargeData {
|
|
||||||
char value[util::AlignUp(SettingsNameLengthMax + 1, alignof(u64))];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(util::is_pod<SettingsName>::value && sizeof(SettingsName) > SettingsNameLengthMax);
|
|
||||||
|
|
||||||
struct SettingsItemKey : sf::LargeData {
|
|
||||||
char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))];
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(util::is_pod<SettingsItemKey>::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,21 @@
|
||||||
|
|
||||||
namespace ams::settings {
|
namespace ams::settings {
|
||||||
|
|
||||||
|
constexpr size_t SettingsNameLengthMax = 0x40;
|
||||||
|
constexpr size_t SettingsItemKeyLengthMax = 0x40;
|
||||||
|
|
||||||
|
struct SettingsName : public sf::LargeData {
|
||||||
|
char value[util::AlignUp(SettingsNameLengthMax + 1, alignof(u64))];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(util::is_pod<SettingsName>::value && sizeof(SettingsName) > SettingsNameLengthMax);
|
||||||
|
|
||||||
|
struct SettingsItemKey : public sf::LargeData {
|
||||||
|
char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(util::is_pod<SettingsItemKey>::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax);
|
||||||
|
|
||||||
enum Language {
|
enum Language {
|
||||||
Language_Japanese,
|
Language_Japanese,
|
||||||
Language_AmericanEnglish,
|
Language_AmericanEnglish,
|
||||||
|
|
|
@ -60,6 +60,12 @@ namespace ams::spl {
|
||||||
return static_cast<HardwareState>(v);
|
return static_cast<HardwareState>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline RetailInteractiveDisplayState GetRetailInteractiveDisplayState() {
|
||||||
|
u64 v;
|
||||||
|
R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::RetailInteractiveDisplayState));
|
||||||
|
return static_cast<RetailInteractiveDisplayState>(v);
|
||||||
|
}
|
||||||
|
|
||||||
inline u64 GetDeviceIdLow() {
|
inline u64 GetDeviceIdLow() {
|
||||||
u64 v;
|
u64 v;
|
||||||
R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::DeviceId));
|
R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::DeviceId));
|
||||||
|
|
|
@ -138,6 +138,11 @@ namespace ams::spl {
|
||||||
MemoryArrangement_Count,
|
MemoryArrangement_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RetailInteractiveDisplayState {
|
||||||
|
RetailInteractiveDisplayState_Disabled = 0,
|
||||||
|
RetailInteractiveDisplayState_Enabled = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct BootReasonValue {
|
struct BootReasonValue {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
|
@ -217,7 +222,7 @@ namespace ams::spl {
|
||||||
IsDevelopmentFunctionEnabled = 11,
|
IsDevelopmentFunctionEnabled = 11,
|
||||||
KernelConfiguration = 12,
|
KernelConfiguration = 12,
|
||||||
IsChargerHiZModeEnabled = 13,
|
IsChargerHiZModeEnabled = 13,
|
||||||
QuestState = 14,
|
RetailInteractiveDisplayState = 14,
|
||||||
RegulatorType = 15,
|
RegulatorType = 15,
|
||||||
DeviceUniqueKeyGeneration = 16,
|
DeviceUniqueKeyGeneration = 16,
|
||||||
Package2Hash = 17,
|
Package2Hash = 17,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_system_save_data.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
struct KeyValueStoreItemForDebug {
|
||||||
|
const char *key;
|
||||||
|
u8 type;
|
||||||
|
size_t current_value_size;
|
||||||
|
size_t default_value_size;
|
||||||
|
void *current_value;
|
||||||
|
void *default_value;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(KeyValueStoreItemForDebug) == 0x30);
|
||||||
|
|
||||||
|
struct KeyValueStoreKeyIterator {
|
||||||
|
size_t header_size;
|
||||||
|
size_t entire_size;
|
||||||
|
char *map_key;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(KeyValueStoreKeyIterator) == 0x18);
|
||||||
|
|
||||||
|
class KeyValueStore {
|
||||||
|
private:
|
||||||
|
const SettingsName &m_name;
|
||||||
|
public:
|
||||||
|
explicit KeyValueStore(const SettingsName &name) : m_name(name) { /* ... */ }
|
||||||
|
|
||||||
|
Result CreateKeyIterator(KeyValueStoreKeyIterator *out);
|
||||||
|
Result GetValue(u64 *out_count, char *out_buffer, size_t out_buffer_size, const SettingsItemKey &item_key);
|
||||||
|
Result GetValueSize(u64 *out_value_size, const SettingsItemKey &item_key);
|
||||||
|
Result ResetValue(const SettingsItemKey &item_key);
|
||||||
|
Result SetValue(const SettingsItemKey &item_key, const void *buffer, size_t buffer_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
Result AddKeyValueStoreItemForDebug(const KeyValueStoreItemForDebug * const items, size_t items_count);
|
||||||
|
Result AdvanceKeyValueStoreKeyIterator(KeyValueStoreKeyIterator *out);
|
||||||
|
Result DestroyKeyValueStoreKeyIterator(KeyValueStoreKeyIterator *out);
|
||||||
|
Result GetKeyValueStoreItemCountForDebug(u64 *out_count);
|
||||||
|
Result GetKeyValueStoreItemForDebug(u64 *out_count, KeyValueStoreItemForDebug * const out_items, size_t out_items_count);
|
||||||
|
Result GetKeyValueStoreKeyIteratorKey(u64 *out_count, char *out_buffer, size_t out_buffer_size, const KeyValueStoreKeyIterator &iterator);
|
||||||
|
Result GetKeyValueStoreKeyIteratorKeySize(u64 *out_count, const KeyValueStoreKeyIterator &iterator);
|
||||||
|
Result ReadKeyValueStoreFirmwareDebug(u64 *out_count, char * const out_buffer, size_t out_buffer_size);
|
||||||
|
Result ReadKeyValueStorePlatformConfiguration(u64 *out_count, char * const out_buffer, size_t out_buffer_size);
|
||||||
|
Result ReadKeyValueStoreSaveData(u64 *out_count, char * const out_buffer, size_t out_buffer_size);
|
||||||
|
Result ReloadKeyValueStoreForDebug(SystemSaveData *system_save_data, SystemSaveData *fwdbg_system_data, SystemSaveData *pfcfg_system_data);
|
||||||
|
Result ReloadKeyValueStoreForDebug();
|
||||||
|
Result ResetKeyValueStoreSaveData();
|
||||||
|
Result SaveKeyValueStoreAllForDebug(SystemSaveData *data);
|
||||||
|
|
||||||
|
}
|
100
libraries/libstratosphere/source/settings/impl/settings_spl.cpp
Normal file
100
libraries/libstratosphere/source/settings/impl/settings_spl.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_spl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct SplConfig {
|
||||||
|
bool is_development;
|
||||||
|
SplHardwareType hardware_type;
|
||||||
|
bool is_quest;
|
||||||
|
u64 device_id_low;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr SplHardwareType ConvertToSplHardwareType(spl::HardwareType type) {
|
||||||
|
switch (type) {
|
||||||
|
case spl::HardwareType::Icosa:
|
||||||
|
return SplHardwareType_Icosa;
|
||||||
|
case spl::HardwareType::Copper:
|
||||||
|
return SplHardwareType_Copper;
|
||||||
|
case spl::HardwareType::Hoag:
|
||||||
|
return SplHardwareType_Hoag;
|
||||||
|
case spl::HardwareType::Iowa:
|
||||||
|
return SplHardwareType_IcosaMariko;
|
||||||
|
case spl::HardwareType::Calcio:
|
||||||
|
return SplHardwareType_Calcio;
|
||||||
|
case spl::HardwareType::Aula:
|
||||||
|
return SplHardwareType_Aula;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsSplRetailInteractiveDisplayStateEnabled(spl::RetailInteractiveDisplayState quest_state) {
|
||||||
|
switch (quest_state) {
|
||||||
|
case spl::RetailInteractiveDisplayState_Disabled:
|
||||||
|
return false;
|
||||||
|
case spl::RetailInteractiveDisplayState_Enabled:
|
||||||
|
return true;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SplConfig GetSplConfig() {
|
||||||
|
static constinit bool s_is_initialized = false;
|
||||||
|
static constinit SplConfig s_config;
|
||||||
|
|
||||||
|
if (!s_is_initialized) {
|
||||||
|
/* Initialize spl. */
|
||||||
|
spl::Initialize();
|
||||||
|
ON_SCOPE_EXIT { spl::Finalize(); };
|
||||||
|
|
||||||
|
/* Create the config. */
|
||||||
|
s_config = {
|
||||||
|
.is_development = spl::IsDevelopment(),
|
||||||
|
.hardware_type = ConvertToSplHardwareType(spl::GetHardwareType()),
|
||||||
|
.is_quest = IsSplRetailInteractiveDisplayStateEnabled(spl::GetRetailInteractiveDisplayState()),
|
||||||
|
.device_id_low = spl::GetDeviceIdLow(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Mark as initialized. */
|
||||||
|
s_is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSplDevelopment() {
|
||||||
|
return GetSplConfig().is_development;
|
||||||
|
}
|
||||||
|
|
||||||
|
SplHardwareType GetSplHardwareType() {
|
||||||
|
return GetSplConfig().hardware_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSplRetailInteractiveDisplayStateEnabled() {
|
||||||
|
return GetSplConfig().is_quest;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 GetSplDeviceIdLow() {
|
||||||
|
return GetSplConfig().device_id_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
enum SplHardwareType : u8 {
|
||||||
|
SplHardwareType_None = 0x0,
|
||||||
|
SplHardwareType_Icosa = 0x1,
|
||||||
|
SplHardwareType_IcosaMariko = 0x2,
|
||||||
|
SplHardwareType_Copper = 0x3,
|
||||||
|
SplHardwareType_Hoag = 0x4,
|
||||||
|
SplHardwareType_Calcio = 0x5,
|
||||||
|
SplHardwareType_Aula = 0x6,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool IsSplDevelopment();
|
||||||
|
SplHardwareType GetSplHardwareType();
|
||||||
|
bool IsSplRetailInteractiveDisplayStateEnabled();
|
||||||
|
u64 GetSplDeviceIdLow();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
template<typename T, typename Tag>
|
||||||
|
class StaticObject final {
|
||||||
|
NON_COPYABLE(StaticObject);
|
||||||
|
NON_MOVEABLE(StaticObject);
|
||||||
|
private:
|
||||||
|
StaticObject();
|
||||||
|
public:
|
||||||
|
static T &Get() {
|
||||||
|
/* Declare static instance variables. */
|
||||||
|
static constinit util::TypedStorage<T> s_storage = {};
|
||||||
|
static constinit bool s_initialized = false;
|
||||||
|
static constinit os::SdkMutex s_mutex;
|
||||||
|
|
||||||
|
/* If we haven't already done so, construct the instance. */
|
||||||
|
if (AMS_UNLIKELY(!s_initialized)) {
|
||||||
|
std::scoped_lock lk(s_mutex);
|
||||||
|
|
||||||
|
/* Check that we didn't concurrently construct the instance. */
|
||||||
|
if (AMS_LIKELY(!s_initialized)) {
|
||||||
|
/* Construct the instance. */
|
||||||
|
util::ConstructAt(s_storage);
|
||||||
|
|
||||||
|
/* Note that we constructed. */
|
||||||
|
s_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the constructed instance. */
|
||||||
|
return util::GetReference(s_storage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_static_object.hpp"
|
||||||
|
#include "settings_system_data.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const char MountNameSeparator[] = ":";
|
||||||
|
constexpr inline const char DirectoryNameSeparator[] = "/";
|
||||||
|
constexpr inline const char SystemDataFileName[] = "file";
|
||||||
|
|
||||||
|
class LazyFileAccessor final {
|
||||||
|
NON_COPYABLE(LazyFileAccessor);
|
||||||
|
NON_MOVEABLE(LazyFileAccessor);
|
||||||
|
private:
|
||||||
|
bool m_is_cached;
|
||||||
|
fs::FileHandle m_file;
|
||||||
|
s64 m_offset;
|
||||||
|
size_t m_size;
|
||||||
|
u8 m_buffer[16_KB];
|
||||||
|
public:
|
||||||
|
LazyFileAccessor() : m_is_cached(false), m_file(), m_offset(), m_size(), m_buffer() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Open(const char *path, int mode);
|
||||||
|
void Close();
|
||||||
|
Result Read(s64 offset, void *dst, size_t size);
|
||||||
|
private:
|
||||||
|
bool GetCache(s64 offset, void *dst, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Open(const char *path, int mode) {
|
||||||
|
/* Open our file. */
|
||||||
|
return fs::OpenFile(std::addressof(m_file), path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LazyFileAccessor::Close() {
|
||||||
|
/* Close our file. */
|
||||||
|
fs::CloseFile(m_file);
|
||||||
|
|
||||||
|
/* Reset our state. */
|
||||||
|
m_is_cached = false;
|
||||||
|
m_file = {};
|
||||||
|
m_size = 0;
|
||||||
|
m_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LazyFileAccessor::GetCache(s64 offset, void *dst, size_t size) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(offset >= 0);
|
||||||
|
AMS_ASSERT(dst != nullptr);
|
||||||
|
|
||||||
|
/* Check that we're cached. */
|
||||||
|
if (!m_is_cached) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that offset is within cache. */
|
||||||
|
if (offset < m_offset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the read remains within range. */
|
||||||
|
const size_t offset_in_cache = offset - m_offset;
|
||||||
|
if (m_size < offset_in_cache + size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the cached data. */
|
||||||
|
std::memcpy(dst, m_buffer + offset_in_cache, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Read(s64 offset, void *dst, size_t size) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(offset >= 0);
|
||||||
|
AMS_ASSERT(dst != nullptr);
|
||||||
|
|
||||||
|
/* Try to read from cache. */
|
||||||
|
R_SUCCEED_IF(this->GetCache(offset, dst, size));
|
||||||
|
|
||||||
|
/* If the read is too big for the cache, read the data directly. */
|
||||||
|
if (size > sizeof(m_buffer)) {
|
||||||
|
return fs::ReadFile(m_file, offset, dst, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the file size. */
|
||||||
|
s64 file_size;
|
||||||
|
R_TRY(fs::GetFileSize(std::addressof(file_size), m_file));
|
||||||
|
|
||||||
|
/* If the file is too small, read the data directly. */
|
||||||
|
if (file_size < offset + static_cast<s64>(size)) {
|
||||||
|
return fs::ReadFile(m_file, offset, dst, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the read size. */
|
||||||
|
const size_t read_size = std::min<size_t>(file_size - offset, sizeof(m_buffer));
|
||||||
|
|
||||||
|
/* Read into the cache. */
|
||||||
|
if (read_size > 0) {
|
||||||
|
R_TRY(fs::ReadFile(m_file, offset, m_buffer, read_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update cache statement. */
|
||||||
|
m_offset = offset;
|
||||||
|
m_size = read_size;
|
||||||
|
m_is_cached = true;
|
||||||
|
|
||||||
|
/* Get the data from the cache. */
|
||||||
|
const bool succeeded = this->GetCache(offset, dst, size);
|
||||||
|
AMS_ASSERT(succeeded);
|
||||||
|
AMS_UNUSED(succeeded);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyFileAccessor &GetLazyFileAccessor() {
|
||||||
|
return StaticObject<LazyFileAccessor, void>::Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemData::SetSystemDataId(ncm::SystemDataId id) {
|
||||||
|
m_system_data_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemData::SetMountName(const char *name) {
|
||||||
|
util::Strlcpy(m_mount_name, name, sizeof(m_mount_name));
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
pos += util::Strlcpy(m_file_path + pos, name, sizeof(m_mount_name));
|
||||||
|
pos += util::Strlcpy(m_file_path + pos, MountNameSeparator, sizeof(MountNameSeparator));
|
||||||
|
pos += util::Strlcpy(m_file_path + pos, DirectoryNameSeparator, sizeof(DirectoryNameSeparator));
|
||||||
|
pos += util::Strlcpy(m_file_path + pos, SystemDataFileName, sizeof(SystemDataFileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemData::Mount() {
|
||||||
|
return fs::MountSystemData(m_mount_name, m_system_data_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemData::OpenToRead() {
|
||||||
|
return GetLazyFileAccessor().Open(m_file_path, fs::OpenMode_Read);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemData::Close() {
|
||||||
|
return GetLazyFileAccessor().Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemData::Read(s64 offset, void *dst, size_t size) {
|
||||||
|
return GetLazyFileAccessor().Read(offset, dst, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
class SystemData {
|
||||||
|
NON_COPYABLE(SystemData);
|
||||||
|
NON_MOVEABLE(SystemData);
|
||||||
|
private:
|
||||||
|
static constexpr size_t FileNameLengthMax = 31;
|
||||||
|
private:
|
||||||
|
ncm::SystemDataId m_system_data_id;
|
||||||
|
char m_mount_name[fs::MountNameLengthMax + 1];
|
||||||
|
char m_file_path[fs::MountNameLengthMax + 1 + 1 + FileNameLengthMax + 1];
|
||||||
|
public:
|
||||||
|
SystemData() : m_system_data_id(), m_mount_name(), m_file_path() { /* ... */ }
|
||||||
|
|
||||||
|
void SetSystemDataId(ncm::SystemDataId id);
|
||||||
|
void SetMountName(const char *name);
|
||||||
|
Result Mount();
|
||||||
|
Result OpenToRead();
|
||||||
|
void Close();
|
||||||
|
Result Read(s64 offset, void *dst, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,503 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_static_object.hpp"
|
||||||
|
#include "settings_system_save_data.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr s64 LazyWriterDelayMilliSeconds = 500;
|
||||||
|
|
||||||
|
constexpr inline const char *MountNameSeparator = ":";
|
||||||
|
constexpr inline const char *DirectoryNameSeparator = "/";
|
||||||
|
constexpr inline const char *SystemSaveDataFileName = "file";
|
||||||
|
|
||||||
|
class LazyFileAccessor final {
|
||||||
|
NON_COPYABLE(LazyFileAccessor);
|
||||||
|
NON_MOVEABLE(LazyFileAccessor);
|
||||||
|
private:
|
||||||
|
static constexpr size_t FileNameLengthMax = 31;
|
||||||
|
private:
|
||||||
|
bool m_is_activated;
|
||||||
|
bool m_is_busy;
|
||||||
|
bool m_is_cached;
|
||||||
|
bool m_is_modified;
|
||||||
|
bool m_is_file_size_changed;
|
||||||
|
char m_mount_name[fs::MountNameLengthMax + 1];
|
||||||
|
char m_file_path[fs::MountNameLengthMax + 1 + 1 + FileNameLengthMax + 1];
|
||||||
|
int m_open_mode;
|
||||||
|
s64 m_file_size;
|
||||||
|
s64 m_offset;
|
||||||
|
size_t m_size;
|
||||||
|
u8 m_buffer[512_KB];
|
||||||
|
os::Mutex m_mutex;
|
||||||
|
os::TimerEvent m_timer_event;
|
||||||
|
os::ThreadType m_thread;
|
||||||
|
alignas(os::ThreadStackAlignment) u8 m_thread_stack[4_KB];
|
||||||
|
public:
|
||||||
|
LazyFileAccessor() : m_is_activated(false), m_is_busy(false), m_is_cached(false), m_is_modified(false), m_is_file_size_changed(false), m_mount_name{}, m_file_path{}, m_open_mode(0), m_file_size(0), m_offset(0), m_size(0), m_mutex(false), m_timer_event(os::EventClearMode_AutoClear), m_thread{} {
|
||||||
|
std::memset(m_buffer, 0, sizeof(m_buffer));
|
||||||
|
std::memset(m_thread_stack, 0, sizeof(m_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Activate();
|
||||||
|
Result Commit(const char *name, bool synchronous);
|
||||||
|
Result Create(const char *name, s64 size);
|
||||||
|
Result Open(const char *name, int mode);
|
||||||
|
void Close();
|
||||||
|
Result Read(s64 offset, void *dst, size_t size);
|
||||||
|
Result Write(s64 offset, const void *src, size_t size);
|
||||||
|
Result SetFileSize(s64 size);
|
||||||
|
private:
|
||||||
|
static void ThreadFunc(void *arg);
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
static int CreateFilePath(char (&path)[N], const char *name);
|
||||||
|
|
||||||
|
static bool AreEqual(const void *lhs, const void *rhs, size_t size);
|
||||||
|
|
||||||
|
void SetMountName(const char *name);
|
||||||
|
bool CompareMountName(const char *name) const;
|
||||||
|
void InvokeWriteBackLoop();
|
||||||
|
Result CommitSynchronously();
|
||||||
|
};
|
||||||
|
|
||||||
|
LazyFileAccessor &GetLazyFileAccessor() {
|
||||||
|
return StaticObject<LazyFileAccessor, void>::Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Activate() {
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
if (!m_is_activated) {
|
||||||
|
/* Create and start the lazy writer thread. */
|
||||||
|
R_TRY(os::CreateThread(std::addressof(m_thread), LazyFileAccessor::ThreadFunc, this, m_thread_stack, sizeof(m_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(settings, LazyWriter)));
|
||||||
|
os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(settings, LazyWriter));
|
||||||
|
os::StartThread(std::addressof(m_thread));
|
||||||
|
m_is_activated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Commit(const char *name, bool synchronous) {
|
||||||
|
AMS_ASSERT(name != nullptr);
|
||||||
|
AMS_UNUSED(name);
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
AMS_ASSERT(m_is_activated);
|
||||||
|
AMS_ASSERT(!m_is_busy);
|
||||||
|
AMS_ASSERT(this->CompareMountName(name));
|
||||||
|
|
||||||
|
if (synchronous) {
|
||||||
|
/* Stop the timer and commit synchronously. */
|
||||||
|
m_timer_event.Stop();
|
||||||
|
R_TRY(this->CommitSynchronously());
|
||||||
|
} else {
|
||||||
|
/* Start the timer to write. */
|
||||||
|
m_timer_event.StartOneShot(TimeSpan::FromMilliSeconds(LazyWriterDelayMilliSeconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Create(const char *name, s64 size) {
|
||||||
|
AMS_ASSERT(name != nullptr);
|
||||||
|
AMS_ASSERT(size >= 0);
|
||||||
|
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
AMS_ASSERT(m_is_activated);
|
||||||
|
AMS_ASSERT(!m_is_busy);
|
||||||
|
|
||||||
|
if (m_is_cached) {
|
||||||
|
/* Stop the timer and commit synchronously. */
|
||||||
|
m_timer_event.Stop();
|
||||||
|
R_TRY(this->CommitSynchronously());
|
||||||
|
|
||||||
|
/* Reset the current state. */
|
||||||
|
m_is_cached = false;
|
||||||
|
this->SetMountName("");
|
||||||
|
m_open_mode = 0;
|
||||||
|
m_file_size = 0;
|
||||||
|
|
||||||
|
/* Clear the buffer. */
|
||||||
|
std::memset(m_buffer, 0, sizeof(m_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the save file. */
|
||||||
|
this->CreateFilePath(m_file_path, name);
|
||||||
|
R_TRY(fs::CreateFile(m_file_path, size));
|
||||||
|
|
||||||
|
/* Initialize the accessor. */
|
||||||
|
m_is_cached = true;
|
||||||
|
m_is_modified = true;
|
||||||
|
|
||||||
|
this->SetMountName(name);
|
||||||
|
|
||||||
|
m_open_mode = fs::OpenMode_Write;
|
||||||
|
m_file_size = size;
|
||||||
|
m_offset = 0;
|
||||||
|
m_size = size;
|
||||||
|
|
||||||
|
/* Start the timer to write. */
|
||||||
|
m_timer_event.StartOneShot(TimeSpan::FromMilliSeconds(LazyWriterDelayMilliSeconds));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Open(const char *name, int mode) {
|
||||||
|
AMS_ASSERT(name != nullptr);
|
||||||
|
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
AMS_ASSERT(m_is_activated);
|
||||||
|
AMS_ASSERT(!m_is_busy);
|
||||||
|
|
||||||
|
bool caches = true;
|
||||||
|
|
||||||
|
if (m_is_cached) {
|
||||||
|
/* Check if the current mount matches the requested mount. */
|
||||||
|
if (this->CompareMountName(name)) {
|
||||||
|
/* Check if the mode matches, or the existing mode is read-only. */
|
||||||
|
if (m_open_mode == mode || m_open_mode == fs::OpenMode_Read) {
|
||||||
|
m_is_busy = true;
|
||||||
|
m_open_mode = mode;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
caches = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop the timer and commit synchronously. */
|
||||||
|
m_timer_event.Stop();
|
||||||
|
R_TRY(this->CommitSynchronously());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caches) {
|
||||||
|
/* Create the save file if needed. */
|
||||||
|
this->CreateFilePath(m_file_path, name);
|
||||||
|
|
||||||
|
/* Open the save file. */
|
||||||
|
fs::FileHandle file = {};
|
||||||
|
R_TRY(fs::OpenFile(std::addressof(file), m_file_path, fs::OpenMode_Read));
|
||||||
|
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||||
|
|
||||||
|
/* Get the save size. */
|
||||||
|
s64 file_size = 0;
|
||||||
|
R_TRY(fs::GetFileSize(std::addressof(file_size), file));
|
||||||
|
AMS_ASSERT(0 <= file_size && file_size <= static_cast<s64>(sizeof(m_buffer)));
|
||||||
|
R_UNLESS(file_size <= static_cast<s64>(sizeof(m_buffer)), ResultTooLargeSystemSaveData());
|
||||||
|
|
||||||
|
/* Read the save file. */
|
||||||
|
R_TRY(fs::ReadFile(file, 0, m_buffer, static_cast<size_t>(file_size)));
|
||||||
|
|
||||||
|
m_is_cached = true;
|
||||||
|
this->SetMountName(name);
|
||||||
|
m_file_size = file_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_is_busy = true;
|
||||||
|
m_open_mode = mode;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LazyFileAccessor::Close() {
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
AMS_ASSERT(m_is_activated);
|
||||||
|
AMS_ASSERT(m_is_busy);
|
||||||
|
|
||||||
|
m_is_busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Read(s64 offset, void *dst, size_t size) {
|
||||||
|
AMS_ASSERT(offset >= 0);
|
||||||
|
AMS_ASSERT(dst != nullptr);
|
||||||
|
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
AMS_ASSERT(m_is_activated);
|
||||||
|
AMS_ASSERT(m_is_busy);
|
||||||
|
AMS_ASSERT(m_is_cached);
|
||||||
|
AMS_ASSERT((m_open_mode & fs::OpenMode_Read) != 0);
|
||||||
|
AMS_ASSERT(offset + static_cast<s64>(size) <= m_file_size);
|
||||||
|
|
||||||
|
std::memcpy(dst, m_buffer + offset, size);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::Write(s64 offset, const void *src, size_t size) {
|
||||||
|
AMS_ASSERT(offset >= 0);
|
||||||
|
AMS_ASSERT(src != nullptr);
|
||||||
|
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
AMS_ASSERT(m_is_activated);
|
||||||
|
AMS_ASSERT(m_is_busy);
|
||||||
|
AMS_ASSERT(m_is_cached);
|
||||||
|
AMS_ASSERT((m_open_mode & ::ams::fs::OpenMode_Write) != 0);
|
||||||
|
|
||||||
|
s64 end = offset + static_cast<s64>(size);
|
||||||
|
AMS_ASSERT(end <= static_cast<s64>(m_size));
|
||||||
|
|
||||||
|
/* Succeed if there's nothing to write. */
|
||||||
|
R_SUCCEED_IF(this->AreEqual(m_buffer + offset, src, size));
|
||||||
|
|
||||||
|
/* Copy to dst. */
|
||||||
|
std::memcpy(m_buffer + offset, src, size);
|
||||||
|
|
||||||
|
/* Update offset and size. */
|
||||||
|
if (m_is_modified) {
|
||||||
|
end = std::max(end, m_offset + static_cast<s64>(m_size));
|
||||||
|
m_offset = std::min(m_offset, offset);
|
||||||
|
m_size = static_cast<size_t>(end - m_offset);
|
||||||
|
} else {
|
||||||
|
m_is_modified = true;
|
||||||
|
m_offset = offset;
|
||||||
|
m_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::SetFileSize(s64 size) {
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
const s64 prev_file_size = m_file_size;
|
||||||
|
|
||||||
|
/* If the existing file size exceeds the new file size, reset the state or truncate. */
|
||||||
|
if (m_file_size >= size) {
|
||||||
|
if (m_is_modified) {
|
||||||
|
/* If the current offset exceeds the new file size, reset the state. */
|
||||||
|
if (m_offset >= size) {
|
||||||
|
m_is_modified = false;
|
||||||
|
m_offset = 0;
|
||||||
|
m_size = 0;
|
||||||
|
} else if (m_offset + static_cast<s64>(m_size) > size) {
|
||||||
|
/* Truncate the buffer for the new file size. */
|
||||||
|
m_size = size - m_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* If unmodified, mark as modified and move the offset to the current end of the file. */
|
||||||
|
if (!m_is_modified) {
|
||||||
|
m_is_modified = true;
|
||||||
|
m_offset = m_file_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zero-initialize the expanded file segment. */
|
||||||
|
std::memset(m_buffer + m_file_size, 0, size - m_file_size);
|
||||||
|
|
||||||
|
/* Update the current buffer size. */
|
||||||
|
m_size = size - m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update state. */
|
||||||
|
m_is_file_size_changed = prev_file_size != size;
|
||||||
|
m_file_size = size;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LazyFileAccessor::ThreadFunc(void *arg) {
|
||||||
|
AMS_ASSERT(arg != nullptr);
|
||||||
|
reinterpret_cast<LazyFileAccessor *>(arg)->InvokeWriteBackLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
int LazyFileAccessor::CreateFilePath(char (&path)[N], const char *name) {
|
||||||
|
AMS_ASSERT(name != nullptr);
|
||||||
|
|
||||||
|
const auto len = static_cast<int>(N);
|
||||||
|
|
||||||
|
s32 pos = util::Strlcpy(path, name, len);
|
||||||
|
pos += util::Strlcpy(path + pos, MountNameSeparator, len - pos);
|
||||||
|
pos += util::Strlcpy(path + pos, DirectoryNameSeparator, len - pos);
|
||||||
|
pos += util::Strlcpy(path + pos, SystemSaveDataFileName, len - pos);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LazyFileAccessor::AreEqual(const void *lhs, const void *rhs, size_t size) {
|
||||||
|
AMS_ASSERT(lhs != nullptr);
|
||||||
|
AMS_ASSERT(rhs != nullptr);
|
||||||
|
|
||||||
|
auto lhs8 = static_cast<const u8 *>(lhs);
|
||||||
|
auto rhs8 = static_cast<const u8 *>(rhs);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (*(lhs8++) != *(rhs8++)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LazyFileAccessor::SetMountName(const char *name) {
|
||||||
|
AMS_ASSERT(name != nullptr);
|
||||||
|
|
||||||
|
util::Strlcpy(m_mount_name, name, sizeof(m_mount_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LazyFileAccessor::CompareMountName(const char *name) const {
|
||||||
|
return util::Strncmp(m_mount_name, name, sizeof(m_mount_name)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LazyFileAccessor::InvokeWriteBackLoop() {
|
||||||
|
while (true) {
|
||||||
|
m_timer_event.Wait();
|
||||||
|
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
if (!m_is_busy) {
|
||||||
|
R_ABORT_UNLESS(this->CommitSynchronously());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LazyFileAccessor::CommitSynchronously() {
|
||||||
|
/* If we have data cached/modified, we need to commit. */
|
||||||
|
if (m_is_cached && (m_is_file_size_changed || m_is_modified)) {
|
||||||
|
/* Get the save file path. */
|
||||||
|
this->CreateFilePath(m_file_path, m_mount_name);
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Open the save file. */
|
||||||
|
fs::FileHandle file;
|
||||||
|
R_TRY(fs::OpenFile(std::addressof(file), m_file_path, fs::OpenMode_Write));
|
||||||
|
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||||
|
|
||||||
|
/* If we need to, update the file size. */
|
||||||
|
if (m_is_file_size_changed) {
|
||||||
|
R_TRY(fs::SetFileSize(file, m_file_size));
|
||||||
|
m_is_file_size_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we need to, write the file data. */
|
||||||
|
if (m_is_modified) {
|
||||||
|
/* Write to the file. */
|
||||||
|
R_TRY(fs::WriteFile(file, m_offset, m_buffer + m_offset, m_size, fs::WriteOption::None));
|
||||||
|
R_TRY(fs::FlushFile(file));
|
||||||
|
|
||||||
|
/* Reset state. */
|
||||||
|
m_is_modified = false;
|
||||||
|
m_offset = 0;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Commit the savedata. */
|
||||||
|
R_TRY(fs::CommitSaveData(m_mount_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemSaveData::SetSystemSaveDataId(u64 id) {
|
||||||
|
m_system_save_data_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemSaveData::SetTotalSize(s64 size) {
|
||||||
|
m_total_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemSaveData::SetJournalSize(s64 size) {
|
||||||
|
m_journal_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemSaveData::SetFlags(u32 flags) {
|
||||||
|
m_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemSaveData::SetMountName(const char *name) {
|
||||||
|
AMS_ASSERT(name != nullptr);
|
||||||
|
|
||||||
|
util::Strlcpy(m_mount_name, name, sizeof(m_mount_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::Mount(bool create_save) {
|
||||||
|
/* Activate the file accessor. */
|
||||||
|
R_TRY(GetLazyFileAccessor().Activate());
|
||||||
|
|
||||||
|
/* Don't allow automatic save data creation. */
|
||||||
|
fs::DisableAutoSaveDataCreation();
|
||||||
|
|
||||||
|
/* Attempt to get the flags of existing save data. */
|
||||||
|
u32 cur_flags = 0;
|
||||||
|
const auto flags_result = fs::GetSaveDataFlags(std::addressof(cur_flags), m_save_data_space_id, m_system_save_data_id);
|
||||||
|
|
||||||
|
/* If the save data exists, ensure flags are correct. */
|
||||||
|
if (R_SUCCEEDED(flags_result)) {
|
||||||
|
if (cur_flags != m_flags) {
|
||||||
|
R_TRY(fs::SetSaveDataFlags(m_system_save_data_id, m_save_data_space_id, m_flags));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Unless we can create save data, return the error we got when retrieving flags. */
|
||||||
|
R_UNLESS(create_save, flags_result);
|
||||||
|
|
||||||
|
/* Create the save data. */
|
||||||
|
R_TRY(fs::CreateSystemSaveData(m_save_data_space_id, m_system_save_data_id, ncm::SystemProgramId::Settings.value, m_total_size, m_journal_size, m_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mount the save data. */
|
||||||
|
return fs::MountSystemSaveData(m_mount_name, m_save_data_space_id, m_system_save_data_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::Commit(bool synchronous) {
|
||||||
|
return GetLazyFileAccessor().Commit(m_mount_name, synchronous);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::Create(s64 size) {
|
||||||
|
return GetLazyFileAccessor().Create(m_mount_name, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::OpenToRead() {
|
||||||
|
return GetLazyFileAccessor().Open(m_mount_name, fs::OpenMode_Read);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::OpenToWrite() {
|
||||||
|
return GetLazyFileAccessor().Open(m_mount_name, fs::OpenMode_Write);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemSaveData::Close() {
|
||||||
|
GetLazyFileAccessor().Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::Read(s64 offset, void *buf, size_t size) {
|
||||||
|
AMS_ASSERT(offset >= 0);
|
||||||
|
AMS_ASSERT(buf != nullptr);
|
||||||
|
|
||||||
|
return GetLazyFileAccessor().Read(offset, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::Write(s64 offset, const void *buf, size_t size) {
|
||||||
|
AMS_ASSERT(offset >= 0);
|
||||||
|
AMS_ASSERT(buf != nullptr);
|
||||||
|
|
||||||
|
return GetLazyFileAccessor().Write(offset, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::Flush() {
|
||||||
|
/* N doesn't do anything here. */
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SystemSaveData::SetFileSize(s64 size) {
|
||||||
|
return GetLazyFileAccessor().SetFileSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
class SystemSaveData {
|
||||||
|
NON_COPYABLE(SystemSaveData);
|
||||||
|
private:
|
||||||
|
fs::SystemSaveDataId m_system_save_data_id;
|
||||||
|
fs::SaveDataSpaceId m_save_data_space_id;
|
||||||
|
s64 m_total_size;
|
||||||
|
s64 m_journal_size;
|
||||||
|
u32 m_flags;
|
||||||
|
char m_mount_name[fs::MountNameLengthMax + 1];
|
||||||
|
public:
|
||||||
|
SystemSaveData() : m_system_save_data_id(0), m_save_data_space_id(fs::SaveDataSpaceId::System), m_total_size(0), m_journal_size(0), m_flags(0) { /* ... */ }
|
||||||
|
|
||||||
|
void SetSystemSaveDataId(u64 id);
|
||||||
|
void SetTotalSize(s64 size);
|
||||||
|
void SetJournalSize(s64 size);
|
||||||
|
void SetFlags(u32 flags);
|
||||||
|
void SetMountName(const char *name);
|
||||||
|
|
||||||
|
Result Mount(bool create_save);
|
||||||
|
Result Commit(bool synchronous);
|
||||||
|
Result Create(s64 size);
|
||||||
|
Result OpenToRead();
|
||||||
|
Result OpenToWrite();
|
||||||
|
void Close();
|
||||||
|
Result Read(s64 offset, void *buf, size_t size);
|
||||||
|
Result Write(s64 offset, const void *buf, size_t size);
|
||||||
|
Result Flush();
|
||||||
|
Result SetFileSize(s64 size);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -22,27 +22,32 @@ namespace ams::settings {
|
||||||
R_DEFINE_NAMESPACE_RESULT_MODULE(105);
|
R_DEFINE_NAMESPACE_RESULT_MODULE(105);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemNotFound, 11);
|
R_DEFINE_ERROR_RESULT(SettingsItemNotFound, 11);
|
||||||
|
R_DEFINE_ERROR_RESULT(StopIteration, 21);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RANGE(InternalError, 100, 149);
|
R_DEFINE_ERROR_RANGE(InternalError, 100, 149);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyAllocationFailed, 101);
|
R_DEFINE_ERROR_RESULT(SettingsItemKeyAllocationFailed, 101);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemValueAllocationFailed, 102);
|
R_DEFINE_ERROR_RESULT(SettingsItemValueAllocationFailed, 102);
|
||||||
|
R_DEFINE_ERROR_RESULT(SettingsItemKeyIteratorAllocationFailed, 111);
|
||||||
|
R_DEFINE_ERROR_RESULT(TooLargeSystemSaveData, 141);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RANGE(InvalidArgument, 200, 399);
|
R_DEFINE_ERROR_RANGE(InvalidArgument, 200, 399);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsNameNull, 201);
|
R_DEFINE_ERROR_RESULT(NullSettingsName, 201);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyNull, 202);
|
R_DEFINE_ERROR_RESULT(NullSettingsItemKey, 202);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemValueNull, 203);
|
R_DEFINE_ERROR_RESULT(NullSettingsItemValue, 203);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyBufferNull, 204);
|
R_DEFINE_ERROR_RESULT(NullSettingsItemKeyBuffer, 204);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemValueBufferNull, 205);
|
R_DEFINE_ERROR_RESULT(NullSettingsItemValueBuffer, 205);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(SettingsNameEmpty, 221);
|
R_DEFINE_ERROR_RESULT(EmptySettingsName, 221);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyEmpty, 222);
|
R_DEFINE_ERROR_RESULT(EmptySettingsItemKey, 222);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(SettingsNameTooLong, 241);
|
R_DEFINE_ERROR_RESULT(TooLongSettingsName, 241);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyTooLong, 242);
|
R_DEFINE_ERROR_RESULT(TooLongSettingsItemKey, 242);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(SettingsNameInvalidFormat, 261);
|
R_DEFINE_ERROR_RESULT(InvalidFormatSettingsName, 261);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemKeyInvalidFormat, 262);
|
R_DEFINE_ERROR_RESULT(InvalidFormatSettingsItemKey, 262);
|
||||||
R_DEFINE_ERROR_RESULT(SettingsItemValueInvalidFormat, 263);
|
R_DEFINE_ERROR_RESULT(InvalidFormatSettingsItemValue, 263);
|
||||||
|
|
||||||
|
R_DEFINE_ERROR_RESULT(NotFoundSettingsItemKeyIterator, 281);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RANGE(CalibrationDataError, 580, 599);
|
R_DEFINE_ERROR_RANGE(CalibrationDataError, 580, 599);
|
||||||
R_DEFINE_ERROR_RESULT(CalibrationDataFileSystemCorrupted, 581);
|
R_DEFINE_ERROR_RESULT(CalibrationDataFileSystemCorrupted, 581);
|
||||||
|
|
|
@ -102,7 +102,7 @@ namespace ams::mitm::settings {
|
||||||
return GetFirmwareVersionImpl(out.GetPointer(), this->client_info);
|
return GetFirmwareVersionImpl(out.GetPointer(), this->client_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> out_size, const settings::fwdbg::SettingsName &name, const settings::fwdbg::SettingsItemKey &key) {
|
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> out_size, const settings::SettingsName &name, const settings::SettingsItemKey &key) {
|
||||||
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValueSize(out_size.GetPointer(), name.value, key.value)) {
|
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValueSize(out_size.GetPointer(), name.value, key.value)) {
|
||||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
||||||
R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession());
|
R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession());
|
||||||
|
@ -111,7 +111,7 @@ namespace ams::mitm::settings {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetSysMitmService::GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const settings::fwdbg::SettingsName &name, const settings::fwdbg::SettingsItemKey &key) {
|
Result SetSysMitmService::GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const settings::SettingsName &name, const settings::SettingsItemKey &key) {
|
||||||
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValue(out_size.GetPointer(), out.GetPointer(), out.GetSize(), name.value, key.value)) {
|
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValue(out_size.GetPointer(), out.GetPointer(), out.GetSize(), name.value, key.value)) {
|
||||||
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)
|
||||||
R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession());
|
R_CONVERT_ALL(sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#define AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO(C, H) \
|
#define AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO(C, H) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 3, Result, GetFirmwareVersion, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 3, Result, GetFirmwareVersion, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetFirmwareVersion2, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 4, Result, GetFirmwareVersion2, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 37, Result, GetSettingsItemValueSize, (sf::Out<u64> out_size, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key), (out_size, name, key)) \
|
AMS_SF_METHOD_INFO(C, H, 37, Result, GetSettingsItemValueSize, (sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, name, key)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 38, Result, GetSettingsItemValue, (sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key), (out_size, out, name, key)) \
|
AMS_SF_METHOD_INFO(C, H, 38, Result, GetSettingsItemValue, (sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, out, name, key)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 62, Result, GetDebugModeFlag, (sf::Out<bool> out), (out))
|
AMS_SF_METHOD_INFO(C, H, 62, Result, GetDebugModeFlag, (sf::Out<bool> out), (out))
|
||||||
|
|
||||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::settings, ISetSysMitmInterface, AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO)
|
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::settings, ISetSysMitmInterface, AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO)
|
||||||
|
@ -41,8 +41,8 @@ namespace ams::mitm::settings {
|
||||||
public:
|
public:
|
||||||
Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out);
|
Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out);
|
||||||
Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out);
|
Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out);
|
||||||
Result GetSettingsItemValueSize(sf::Out<u64> out_size, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key);
|
Result GetSettingsItemValueSize(sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key);
|
||||||
Result GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::fwdbg::SettingsName &name, const ams::settings::fwdbg::SettingsItemKey &key);
|
Result GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key);
|
||||||
Result GetDebugModeFlag(sf::Out<bool> out);
|
Result GetDebugModeFlag(sf::Out<bool> out);
|
||||||
};
|
};
|
||||||
static_assert(IsISetSysMitmInterface<SetSysMitmService>);
|
static_assert(IsISetSysMitmInterface<SetSysMitmService>);
|
||||||
|
|
|
@ -122,20 +122,20 @@ namespace ams::settings::fwdbg {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ValidateSettingsName(const char *name) {
|
Result ValidateSettingsName(const char *name) {
|
||||||
R_UNLESS(name != nullptr, ResultSettingsNameNull());
|
R_UNLESS(name != nullptr, ResultNullSettingsName());
|
||||||
const size_t len = strnlen(name, SettingsNameLengthMax + 1);
|
const size_t len = strnlen(name, SettingsNameLengthMax + 1);
|
||||||
R_UNLESS(len > 0, ResultSettingsNameEmpty());
|
R_UNLESS(len > 0, ResultEmptySettingsName());
|
||||||
R_UNLESS(len <= SettingsNameLengthMax, ResultSettingsNameTooLong());
|
R_UNLESS(len <= SettingsNameLengthMax, ResultTooLongSettingsName());
|
||||||
R_UNLESS(IsValidSettingsFormat(name, len), ResultSettingsNameInvalidFormat());
|
R_UNLESS(IsValidSettingsFormat(name, len), ResultInvalidFormatSettingsName());
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ValidateSettingsItemKey(const char *key) {
|
Result ValidateSettingsItemKey(const char *key) {
|
||||||
R_UNLESS(key != nullptr, ResultSettingsNameNull());
|
R_UNLESS(key != nullptr, ResultNullSettingsName());
|
||||||
const size_t len = strnlen(key, SettingsItemKeyLengthMax + 1);
|
const size_t len = strnlen(key, SettingsItemKeyLengthMax + 1);
|
||||||
R_UNLESS(len > 0, ResultSettingsItemKeyEmpty());
|
R_UNLESS(len > 0, ResultEmptySettingsItemKey());
|
||||||
R_UNLESS(len <= SettingsNameLengthMax, ResultSettingsItemKeyTooLong());
|
R_UNLESS(len <= SettingsNameLengthMax, ResultTooLongSettingsItemKey());
|
||||||
R_UNLESS(IsValidSettingsFormat(key, len), ResultSettingsItemKeyInvalidFormat());
|
R_UNLESS(IsValidSettingsFormat(key, len), ResultInvalidFormatSettingsItemKey());
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ namespace ams::settings::fwdbg {
|
||||||
const char *value_str = delimiter + 1;
|
const char *value_str = delimiter + 1;
|
||||||
const char *type = val_tup;
|
const char *type = val_tup;
|
||||||
|
|
||||||
R_UNLESS(delimiter != nullptr, ResultSettingsItemValueInvalidFormat());
|
R_UNLESS(delimiter != nullptr, ResultInvalidFormatSettingsItemValue());
|
||||||
|
|
||||||
while (std::isspace(static_cast<unsigned char>(*type)) && type != delimiter) {
|
while (std::isspace(static_cast<unsigned char>(*type)) && type != delimiter) {
|
||||||
type++;
|
type++;
|
||||||
|
@ -216,8 +216,8 @@ namespace ams::settings::fwdbg {
|
||||||
|
|
||||||
const size_t type_len = delimiter - type;
|
const size_t type_len = delimiter - type;
|
||||||
const size_t value_len = strlen(value_str);
|
const size_t value_len = strlen(value_str);
|
||||||
R_UNLESS(type_len > 0, ResultSettingsItemValueInvalidFormat());
|
R_UNLESS(type_len > 0, ResultInvalidFormatSettingsItemValue());
|
||||||
R_UNLESS(value_len > 0, ResultSettingsItemValueInvalidFormat());
|
R_UNLESS(value_len > 0, ResultInvalidFormatSettingsItemValue());
|
||||||
|
|
||||||
/* Create new value. */
|
/* Create new value. */
|
||||||
SdKeyValueStoreEntry new_value = {};
|
SdKeyValueStoreEntry new_value = {};
|
||||||
|
@ -232,9 +232,9 @@ namespace ams::settings::fwdbg {
|
||||||
std::memcpy(new_value.value, value_str, size);
|
std::memcpy(new_value.value, value_str, size);
|
||||||
new_value.value_size = size;
|
new_value.value_size = size;
|
||||||
} else if (strncasecmp(type, "hex", type_len) == 0 || strncasecmp(type, "bytes", type_len) == 0) {
|
} else if (strncasecmp(type, "hex", type_len) == 0 || strncasecmp(type, "bytes", type_len) == 0) {
|
||||||
R_UNLESS(value_len > 0, ResultSettingsItemValueInvalidFormat());
|
R_UNLESS(value_len > 0, ResultInvalidFormatSettingsItemValue());
|
||||||
R_UNLESS(value_len % 2 == 0, ResultSettingsItemValueInvalidFormat());
|
R_UNLESS(value_len % 2 == 0, ResultInvalidFormatSettingsItemValue());
|
||||||
R_UNLESS(IsHexadecimal(value_str), ResultSettingsItemValueInvalidFormat());
|
R_UNLESS(IsHexadecimal(value_str), ResultInvalidFormatSettingsItemValue());
|
||||||
|
|
||||||
const size_t size = value_len / 2;
|
const size_t size = value_len / 2;
|
||||||
R_TRY(AllocateValue(&new_value.value, size));
|
R_TRY(AllocateValue(&new_value.value, size));
|
||||||
|
@ -253,7 +253,7 @@ namespace ams::settings::fwdbg {
|
||||||
} else if (strncasecmp(type, "u64", type_len) == 0) {
|
} else if (strncasecmp(type, "u64", type_len) == 0) {
|
||||||
R_TRY((ParseSettingsItemIntegralValue<u64>(new_value, value_str)));
|
R_TRY((ParseSettingsItemIntegralValue<u64>(new_value, value_str)));
|
||||||
} else {
|
} else {
|
||||||
return ResultSettingsItemValueInvalidFormat();
|
return ResultInvalidFormatSettingsItemValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the entry. */
|
/* Insert the entry. */
|
||||||
|
@ -429,7 +429,7 @@ namespace ams::settings::fwdbg {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key) {
|
Result GetSdCardKeyValueStoreSettingsItemValue(size_t *out_size, void *dst, size_t dst_size, const char *name, const char *key) {
|
||||||
R_UNLESS(dst != nullptr, ResultSettingsItemValueBufferNull());
|
R_UNLESS(dst != nullptr, ResultNullSettingsItemValueBuffer());
|
||||||
|
|
||||||
SdKeyValueStoreEntry *entry = nullptr;
|
SdKeyValueStoreEntry *entry = nullptr;
|
||||||
R_TRY(GetEntry(&entry, name, key));
|
R_TRY(GetEntry(&entry, name, key));
|
||||||
|
|
Loading…
Reference in a new issue