mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
erpt: reimplement the sysmodule (#875)
* erpt: reimplement the sysmodule * fatal: update for latest bindings * erpt: amend logic for culling orphan attachments
This commit is contained in:
parent
eca5ac01b8
commit
79b9e07ee9
117 changed files with 6716 additions and 59 deletions
|
@ -20,47 +20,49 @@
|
||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
|
|
||||||
/* Libstratosphere-only utility. */
|
/* Libstratosphere-only utility. */
|
||||||
#include "stratosphere/util.hpp"
|
#include <stratosphere/util.hpp>
|
||||||
|
|
||||||
/* Sadly required shims. */
|
/* Sadly required shims. */
|
||||||
#include "stratosphere/svc/svc_stratosphere_shims.hpp"
|
#include <stratosphere/svc/svc_stratosphere_shims.hpp>
|
||||||
|
|
||||||
/* Critical modules with no dependencies. */
|
/* Critical modules with no dependencies. */
|
||||||
#include "stratosphere/ams.hpp"
|
#include <stratosphere/ams.hpp>
|
||||||
#include "stratosphere/os.hpp"
|
#include <stratosphere/os.hpp>
|
||||||
#include "stratosphere/dd.hpp"
|
#include <stratosphere/dd.hpp>
|
||||||
#include "stratosphere/lmem.hpp"
|
#include <stratosphere/lmem.hpp>
|
||||||
#include "stratosphere/mem.hpp"
|
#include <stratosphere/mem.hpp>
|
||||||
|
|
||||||
/* Pull in all ID definitions from NCM. */
|
/* Pull in all ID definitions from NCM. */
|
||||||
#include "stratosphere/ncm/ncm_ids.hpp"
|
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||||
|
|
||||||
/* At this point, just include the rest alphabetically. */
|
/* At this point, just include the rest alphabetically. */
|
||||||
/* TODO: Figure out optimal order. */
|
/* TODO: Figure out optimal order. */
|
||||||
#include "stratosphere/boot2.hpp"
|
#include <stratosphere/boot2.hpp>
|
||||||
#include "stratosphere/cfg.hpp"
|
#include <stratosphere/cfg.hpp>
|
||||||
#include "stratosphere/dmnt.hpp"
|
#include <stratosphere/dmnt.hpp>
|
||||||
#include "stratosphere/erpt.hpp"
|
#include <stratosphere/erpt.hpp>
|
||||||
#include "stratosphere/fatal.hpp"
|
#include <stratosphere/fatal.hpp>
|
||||||
#include "stratosphere/hid.hpp"
|
#include <stratosphere/hid.hpp>
|
||||||
#include "stratosphere/hos.hpp"
|
#include <stratosphere/hos.hpp>
|
||||||
#include "stratosphere/kvdb.hpp"
|
#include <stratosphere/kvdb.hpp>
|
||||||
#include "stratosphere/ldr.hpp"
|
#include <stratosphere/ldr.hpp>
|
||||||
#include "stratosphere/lr.hpp"
|
#include <stratosphere/lr.hpp>
|
||||||
#include "stratosphere/map.hpp"
|
#include <stratosphere/map.hpp>
|
||||||
#include "stratosphere/ncm.hpp"
|
#include <stratosphere/ncm.hpp>
|
||||||
#include "stratosphere/nim.hpp"
|
#include <stratosphere/nim.hpp>
|
||||||
#include "stratosphere/patcher.hpp"
|
#include <stratosphere/patcher.hpp>
|
||||||
#include "stratosphere/pm.hpp"
|
#include <stratosphere/psc.hpp>
|
||||||
#include "stratosphere/reg.hpp"
|
#include <stratosphere/pm.hpp>
|
||||||
#include "stratosphere/ro.hpp"
|
#include <stratosphere/reg.hpp>
|
||||||
#include "stratosphere/settings.hpp"
|
#include <stratosphere/ro.hpp>
|
||||||
#include "stratosphere/sf.hpp"
|
#include <stratosphere/settings.hpp>
|
||||||
#include "stratosphere/sm.hpp"
|
#include <stratosphere/sf.hpp>
|
||||||
#include "stratosphere/spl.hpp"
|
#include <stratosphere/sm.hpp>
|
||||||
#include "stratosphere/updater.hpp"
|
#include <stratosphere/spl.hpp>
|
||||||
|
#include <stratosphere/time.hpp>
|
||||||
|
#include <stratosphere/updater.hpp>
|
||||||
|
|
||||||
/* Include FS last. */
|
/* Include FS last. */
|
||||||
#include "stratosphere/fs.hpp"
|
#include <stratosphere/fs.hpp>
|
||||||
#include "stratosphere/fssrv.hpp"
|
#include <stratosphere/fssrv.hpp>
|
||||||
#include "stratosphere/fssystem.hpp"
|
#include <stratosphere/fssystem.hpp>
|
|
@ -17,3 +17,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
|
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_multiple_category_context.hpp>
|
||||||
|
#include <stratosphere/erpt/sf/erpt_sf_i_context.hpp>
|
||||||
|
#include <stratosphere/erpt/sf/erpt_sf_i_session.hpp>
|
||||||
|
#include <stratosphere/erpt/srv/erpt_srv_types.hpp>
|
||||||
|
#include <stratosphere/erpt/srv/erpt_srv_api.hpp>
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
#include <stratosphere/sf/sf_buffer_tags.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt {
|
||||||
|
|
||||||
|
constexpr inline u32 CategoriesPerMultipleCategoryContext = 0x10;
|
||||||
|
constexpr inline u32 FieldsPerMultipleCategoryContext = CategoriesPerMultipleCategoryContext * 4;
|
||||||
|
|
||||||
|
struct MultipleCategoryContextEntry : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||||
|
u32 version;
|
||||||
|
u32 category_count;
|
||||||
|
CategoryId categories[CategoriesPerMultipleCategoryContext];
|
||||||
|
u32 field_counts[CategoriesPerMultipleCategoryContext];
|
||||||
|
u32 array_buf_counts[CategoriesPerMultipleCategoryContext];
|
||||||
|
FieldEntry fields[FieldsPerMultipleCategoryContext];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os.hpp>
|
||||||
|
#include <stratosphere/time/time_posix_time.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt {
|
||||||
|
|
||||||
|
#define GENERATE_ENUM(NAME, ID, ...) NAME = ID,
|
||||||
|
|
||||||
|
enum FieldType {
|
||||||
|
AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM)
|
||||||
|
FieldType_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef GENERATE_ENUM
|
||||||
|
|
||||||
|
#define GENERATE_ENUM(NAME, ID, ...) CategoryId_##NAME = ID,
|
||||||
|
|
||||||
|
enum CategoryId {
|
||||||
|
AMS_ERPT_FOREACH_CATEGORY(GENERATE_ENUM)
|
||||||
|
CategoryId_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef GENERATE_ENUM
|
||||||
|
|
||||||
|
#define GENERATE_ENUM(NAME, ID, ...) FieldId_##NAME = ID,
|
||||||
|
|
||||||
|
enum FieldId {
|
||||||
|
AMS_ERPT_FOREACH_FIELD(GENERATE_ENUM)
|
||||||
|
FieldId_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef GENERATE_ENUM
|
||||||
|
|
||||||
|
constexpr inline u32 ArrayBufferSizeDefault = 0x100;
|
||||||
|
constexpr inline u32 ArrayBufferSizeMax = 96_KB;
|
||||||
|
constexpr inline u32 ArrayFieldSizeMax = 16_KB - 1;
|
||||||
|
|
||||||
|
enum ReportType {
|
||||||
|
ReportType_Start = 0,
|
||||||
|
|
||||||
|
ReportType_Visible = ReportType_Start,
|
||||||
|
ReportType_Invisible = 1,
|
||||||
|
|
||||||
|
ReportType_End = 2,
|
||||||
|
|
||||||
|
ReportType_Count = ReportType_End,
|
||||||
|
|
||||||
|
ReportType_Any = ReportType_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 ReportCountMax = 50;
|
||||||
|
constexpr inline u32 AttachmentsPerReportMax = 5;
|
||||||
|
constexpr inline u32 AttachmentCountMax = ReportCountMax * AttachmentsPerReportMax;
|
||||||
|
|
||||||
|
constexpr inline u32 ReportMetaDataSize = 0x20;
|
||||||
|
struct ReportMetaData {
|
||||||
|
u8 user_data[ReportMetaDataSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
constexpr inline u32 ReportIdSize = 20;
|
||||||
|
struct ReportId {
|
||||||
|
union {
|
||||||
|
u8 id[ReportIdSize];
|
||||||
|
util::Uuid uuid;
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct {
|
||||||
|
u32 time_low;
|
||||||
|
u16 time_mid;
|
||||||
|
u16 time_high_and_version;
|
||||||
|
u8 clock_high;
|
||||||
|
u8 clock_low;
|
||||||
|
u64 node;
|
||||||
|
} uuid_data;
|
||||||
|
#pragma pack(pop)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ReportId) == ReportIdSize);
|
||||||
|
|
||||||
|
inline bool operator==(const ReportId &lhs, const ReportId &rhs) {
|
||||||
|
return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const ReportId &lhs, const ReportId &rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReportFlag {
|
||||||
|
using Transmitted = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<0>;
|
||||||
|
using HasAttachment = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ReportFlagSet = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>;
|
||||||
|
static_assert(std::is_pod<ReportFlagSet>::value);
|
||||||
|
static_assert(sizeof(ReportFlagSet) == sizeof(u32));
|
||||||
|
|
||||||
|
struct ReportInfo {
|
||||||
|
ReportType type;
|
||||||
|
ReportId id;
|
||||||
|
ReportMetaData meta_data;
|
||||||
|
ReportFlagSet flags;
|
||||||
|
time::PosixTime timestamp_user;
|
||||||
|
time::PosixTime timestamp_network;
|
||||||
|
s64 report_size;
|
||||||
|
u64 reserved[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReportList {
|
||||||
|
u32 report_count;
|
||||||
|
ReportInfo reports[ReportCountMax];
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 AttachmentIdSize = 20;
|
||||||
|
struct AttachmentId {
|
||||||
|
union {
|
||||||
|
u8 id[AttachmentIdSize];
|
||||||
|
util::Uuid uuid;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(AttachmentId) == AttachmentIdSize);
|
||||||
|
|
||||||
|
inline bool operator==(const AttachmentId &lhs, const AttachmentId &rhs) {
|
||||||
|
return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const AttachmentId &lhs, const AttachmentId &rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AttachmentFlag {
|
||||||
|
using HasOwner = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>::Flag<1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using AttachmentFlagSet = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>;
|
||||||
|
static_assert(std::is_pod<AttachmentFlagSet>::value);
|
||||||
|
static_assert(sizeof(AttachmentFlagSet) == sizeof(u32));
|
||||||
|
|
||||||
|
constexpr inline u32 AttachmentNameSizeMax = 0x20;
|
||||||
|
struct AttachmentInfo {
|
||||||
|
ReportId owner_report_id;
|
||||||
|
AttachmentId attachment_id;
|
||||||
|
AttachmentFlagSet flags;
|
||||||
|
s64 attachment_size;
|
||||||
|
char attachment_name[AttachmentNameSizeMax];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AttachmentList {
|
||||||
|
u32 attachment_count;
|
||||||
|
AttachmentInfo attachments[AttachmentsPerReportMax];
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 AttachmentSizeMax = 512_KB;
|
||||||
|
|
||||||
|
struct FieldEntry {
|
||||||
|
FieldId id;
|
||||||
|
FieldType type;
|
||||||
|
union {
|
||||||
|
u64 value_u64;
|
||||||
|
u32 value_u32;
|
||||||
|
u16 value_u16;
|
||||||
|
u8 value_u8;
|
||||||
|
s64 value_i64;
|
||||||
|
s32 value_i32;
|
||||||
|
s16 value_i16;
|
||||||
|
s8 value_i8;
|
||||||
|
bool value_bool;
|
||||||
|
struct {
|
||||||
|
u32 start_idx;
|
||||||
|
u32 size;
|
||||||
|
} value_array;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 FieldsPerContext = 20;
|
||||||
|
struct ContextEntry {
|
||||||
|
u32 version;
|
||||||
|
u32 field_count;
|
||||||
|
CategoryId category;
|
||||||
|
FieldEntry fields[FieldsPerContext];
|
||||||
|
u8 *array_buffer;
|
||||||
|
u32 array_free_count;
|
||||||
|
u32 array_buffer_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageUsageStatistics {
|
||||||
|
util::Uuid journal_uuid;
|
||||||
|
u32 used_storage_size;
|
||||||
|
s64 max_report_size;
|
||||||
|
u32 report_count[ReportType_Count];
|
||||||
|
u32 transmitted_count[ReportType_Count];
|
||||||
|
u32 untransmitted_count[ReportType_Count];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* https://github.com/msgpack/msgpack/blob/master/spec.md#overview */
|
||||||
|
enum class ValueTypeTag {
|
||||||
|
FixMap = 0x80,
|
||||||
|
FixArray = 0x90,
|
||||||
|
FixStr = 0xA0,
|
||||||
|
False = 0xC2,
|
||||||
|
True = 0xC3,
|
||||||
|
Bin8 = 0xC4,
|
||||||
|
Bin16 = 0xC5,
|
||||||
|
U8 = 0xCC,
|
||||||
|
U16 = 0xCD,
|
||||||
|
U32 = 0xCE,
|
||||||
|
U64 = 0xCF,
|
||||||
|
I8 = 0xD0,
|
||||||
|
I16 = 0xD1,
|
||||||
|
I32 = 0xD2,
|
||||||
|
I64 = 0xD3,
|
||||||
|
Str8 = 0xD9,
|
||||||
|
Str16 = 0xDA,
|
||||||
|
Array16 = 0xDC,
|
||||||
|
Map16 = 0xDE,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::sf {
|
||||||
|
|
||||||
|
class IAttachment : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
Open = 0,
|
||||||
|
Read = 1,
|
||||||
|
SetFlags = 2,
|
||||||
|
GetFlags = 3,
|
||||||
|
Close = 4,
|
||||||
|
GetSize = 5,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result Open(const AttachmentId &attachment_id) = 0;
|
||||||
|
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) = 0;
|
||||||
|
virtual Result SetFlags(AttachmentFlagSet flags) = 0;
|
||||||
|
virtual Result GetFlags(ams::sf::Out<AttachmentFlagSet> out) = 0;
|
||||||
|
virtual Result Close() = 0;
|
||||||
|
virtual Result GetSize(ams::sf::Out<s64> out) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(Open),
|
||||||
|
MAKE_SERVICE_COMMAND_META(Read),
|
||||||
|
MAKE_SERVICE_COMMAND_META(SetFlags),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetFlags),
|
||||||
|
MAKE_SERVICE_COMMAND_META(Close),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetSize),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/sf.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_multiple_category_context.hpp>
|
||||||
|
#include <stratosphere/time/time_steady_clock_time_point.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::sf {
|
||||||
|
|
||||||
|
class IContext : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
SubmitContext = 0,
|
||||||
|
CreateReport = 1,
|
||||||
|
SetInitialLaunchSettingsCompletionTime = 2,
|
||||||
|
ClearInitialLaunchSettingsCompletionTime = 3,
|
||||||
|
UpdatePowerOnTime = 4,
|
||||||
|
UpdateAwakeTime = 5,
|
||||||
|
SubmitMultipleCategoryContext = 6,
|
||||||
|
UpdateApplicationLaunchTime = 7,
|
||||||
|
ClearApplicationLaunchTime = 8,
|
||||||
|
SubmitAttachment = 9,
|
||||||
|
CreateReportWithAttachments = 10,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result SubmitContext(const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer) = 0;
|
||||||
|
virtual Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer) = 0;
|
||||||
|
virtual Result SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) = 0;
|
||||||
|
virtual Result ClearInitialLaunchSettingsCompletionTime() = 0;
|
||||||
|
virtual Result UpdatePowerOnTime() = 0;
|
||||||
|
virtual Result UpdateAwakeTime() = 0;
|
||||||
|
virtual Result SubmitMultipleCategoryContext(const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer) = 0;
|
||||||
|
virtual Result UpdateApplicationLaunchTime() = 0;
|
||||||
|
virtual Result ClearApplicationLaunchTime() = 0;
|
||||||
|
virtual Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data) = 0;
|
||||||
|
virtual Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(SubmitContext),
|
||||||
|
MAKE_SERVICE_COMMAND_META(CreateReport),
|
||||||
|
MAKE_SERVICE_COMMAND_META(SetInitialLaunchSettingsCompletionTime, hos::Version_300),
|
||||||
|
MAKE_SERVICE_COMMAND_META(ClearInitialLaunchSettingsCompletionTime, hos::Version_300),
|
||||||
|
MAKE_SERVICE_COMMAND_META(UpdatePowerOnTime, hos::Version_300),
|
||||||
|
MAKE_SERVICE_COMMAND_META(UpdateAwakeTime, hos::Version_300),
|
||||||
|
MAKE_SERVICE_COMMAND_META(SubmitMultipleCategoryContext, hos::Version_500),
|
||||||
|
MAKE_SERVICE_COMMAND_META(UpdateApplicationLaunchTime, hos::Version_600),
|
||||||
|
MAKE_SERVICE_COMMAND_META(ClearApplicationLaunchTime, hos::Version_600),
|
||||||
|
MAKE_SERVICE_COMMAND_META(SubmitAttachment, hos::Version_800),
|
||||||
|
MAKE_SERVICE_COMMAND_META(CreateReportWithAttachments, hos::Version_800),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::sf {
|
||||||
|
|
||||||
|
class IManager : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
GetReportList = 0,
|
||||||
|
GetEvent = 1,
|
||||||
|
CleanupReports = 2,
|
||||||
|
DeleteReport = 3,
|
||||||
|
GetStorageUsageStatistics = 4,
|
||||||
|
GetAttachmentList = 5,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result GetReportList(const ams::sf::OutBuffer &out_list, ReportType type_filter) = 0;
|
||||||
|
virtual Result GetEvent(ams::sf::OutCopyHandle out) = 0;
|
||||||
|
virtual Result CleanupReports() = 0;
|
||||||
|
virtual Result DeleteReport(const ReportId &report_id) = 0;
|
||||||
|
virtual Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out) = 0;
|
||||||
|
virtual Result GetAttachmentList(const ams::sf::OutBuffer &out_buf, const ReportId &report_id) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetReportList),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetEvent),
|
||||||
|
MAKE_SERVICE_COMMAND_META(CleanupReports, hos::Version_400),
|
||||||
|
MAKE_SERVICE_COMMAND_META(DeleteReport, hos::Version_500),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetStorageUsageStatistics, hos::Version_500),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetAttachmentList, hos::Version_800),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::sf {
|
||||||
|
|
||||||
|
class IReport : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
Open = 0,
|
||||||
|
Read = 1,
|
||||||
|
SetFlags = 2,
|
||||||
|
GetFlags = 3,
|
||||||
|
Close = 4,
|
||||||
|
GetSize = 5,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result Open(const ReportId &report_id) = 0;
|
||||||
|
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) = 0;
|
||||||
|
virtual Result SetFlags(ReportFlagSet flags) = 0;
|
||||||
|
virtual Result GetFlags(ams::sf::Out<ReportFlagSet> out) = 0;
|
||||||
|
virtual Result Close() = 0;
|
||||||
|
virtual Result GetSize(ams::sf::Out<s64> out) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(Open),
|
||||||
|
MAKE_SERVICE_COMMAND_META(Read),
|
||||||
|
MAKE_SERVICE_COMMAND_META(SetFlags),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetFlags),
|
||||||
|
MAKE_SERVICE_COMMAND_META(Close),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetSize),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_types.hpp>
|
||||||
|
#include <stratosphere/erpt/sf/erpt_sf_i_report.hpp>
|
||||||
|
#include <stratosphere/erpt/sf/erpt_sf_i_manager.hpp>
|
||||||
|
#include <stratosphere/erpt/sf/erpt_sf_i_attachment.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::sf {
|
||||||
|
|
||||||
|
class ISession : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
OpenReport = 0,
|
||||||
|
OpenManager = 1,
|
||||||
|
OpenAttachment = 2,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result OpenReport(ams::sf::Out<std::shared_ptr<erpt::sf::IReport>> out) = 0;
|
||||||
|
virtual Result OpenManager(ams::sf::Out<std::shared_ptr<erpt::sf::IManager>> out) = 0;
|
||||||
|
virtual Result OpenAttachment(ams::sf::Out<std::shared_ptr<erpt::sf::IAttachment>> out) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(OpenReport),
|
||||||
|
MAKE_SERVICE_COMMAND_META(OpenManager),
|
||||||
|
MAKE_SERVICE_COMMAND_META(OpenAttachment, hos::Version_800),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
Result Initialize(u8 *mem, size_t mem_size);
|
||||||
|
Result InitializeAndStartService();
|
||||||
|
|
||||||
|
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len);
|
||||||
|
Result SetProductModel(const char *model, u32 model_len);
|
||||||
|
Result SetRegionSetting(const char *region, u32 region_len);
|
||||||
|
|
||||||
|
/* Atmosphere extension. */
|
||||||
|
Result SetRedirectNewReportsToSdCard(bool redirect);
|
||||||
|
|
||||||
|
void Wait();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os.hpp>
|
||||||
|
#include <stratosphere/erpt/erpt_ids.autogen.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
constexpr inline const char ReportOnSdStoragePath[] = "ersd";
|
||||||
|
|
||||||
|
constexpr inline const char ReportStoragePath[] = "save";
|
||||||
|
constexpr inline const char JournalFileName[] = "save:/journal";
|
||||||
|
|
||||||
|
constexpr size_t ReportFileNameLength = 64;
|
||||||
|
constexpr size_t AttachmentFileNameLength = 64;
|
||||||
|
constexpr size_t MaxFieldStringSize = 64;
|
||||||
|
|
||||||
|
struct ReportFileName {
|
||||||
|
char name[ReportFileNameLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AttachmentFileName {
|
||||||
|
char name[AttachmentFileNameLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FieldFlag : u8 {
|
||||||
|
FieldFlag_None = 0,
|
||||||
|
FieldFlag_Encrypt = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define STRINGIZE_HANDLER(NAME, ...) #NAME,
|
||||||
|
constexpr inline const char * const FieldString[] = {
|
||||||
|
AMS_ERPT_FOREACH_FIELD(STRINGIZE_HANDLER)
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const char * const CategoryString[] = {
|
||||||
|
AMS_ERPT_FOREACH_CATEGORY(STRINGIZE_HANDLER)
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline const char * const TypeString[] = {
|
||||||
|
AMS_ERPT_FOREACH_FIELD_TYPE(STRINGIZE_HANDLER)
|
||||||
|
};
|
||||||
|
#undef STRINGIZE_HANDLER
|
||||||
|
|
||||||
|
#define GET_FIELD_CATEGORY(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = CategoryId_##CATEGORY,
|
||||||
|
constexpr inline const CategoryId FieldToCategoryMap[] = {
|
||||||
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_CATEGORY)
|
||||||
|
};
|
||||||
|
#undef GET_FIELD_CATEGORY
|
||||||
|
|
||||||
|
#define GET_FIELD_TYPE(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = TYPE,
|
||||||
|
constexpr inline const FieldType FieldToTypeMap[] = {
|
||||||
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_TYPE)
|
||||||
|
};
|
||||||
|
#undef GET_FIELD_TYPE
|
||||||
|
|
||||||
|
#define GET_FIELD_FLAG(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = FLAG,
|
||||||
|
constexpr inline const FieldFlag FieldToFlagMap[] = {
|
||||||
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_FLAG)
|
||||||
|
};
|
||||||
|
#undef GET_FIELD_FLAG
|
||||||
|
|
||||||
|
constexpr inline ReportFlagSet MakeNoReportFlags() {
|
||||||
|
return util::MakeBitFlagSet<32, ReportFlag>();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline AttachmentFlagSet MakeNoAttachmentFlags() {
|
||||||
|
return util::MakeBitFlagSet<32, AttachmentFlag>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -26,4 +26,9 @@ namespace ams::fs {
|
||||||
Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id);
|
Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id);
|
||||||
Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags);
|
Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags);
|
||||||
|
|
||||||
|
Result GetSaveDataAvailableSize(s64 *out, SaveDataId id);
|
||||||
|
Result GetSaveDataJournalSize(s64 *out, SaveDataId id);
|
||||||
|
|
||||||
|
Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,4 +20,6 @@ namespace ams::fs {
|
||||||
|
|
||||||
Result MountSdCard(const char *name);
|
Result MountSdCard(const char *name);
|
||||||
|
|
||||||
|
Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,16 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../fs/fs_common.hpp"
|
#include <stratosphere/fs/fs_common.hpp>
|
||||||
#include "../../fs/fsa/fs_ifile.hpp"
|
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||||
#include "../../fs/fsa/fs_idirectory.hpp"
|
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||||
#include "../../fs/fsa/fs_ifilesystem.hpp"
|
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||||
|
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||||
|
|
||||||
namespace ams::fssystem::impl {
|
namespace ams::fssystem::impl {
|
||||||
|
|
||||||
template<typename Impl>
|
template<typename Impl>
|
||||||
class IPathResolutionFileSystem : public fs::fsa::IFileSystem {
|
class IPathResolutionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||||
NON_COPYABLE(IPathResolutionFileSystem);
|
NON_COPYABLE(IPathResolutionFileSystem);
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<fs::fsa::IFileSystem> shared_fs;
|
std::shared_ptr<fs::fsa::IFileSystem> shared_fs;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|
22
libraries/libstratosphere/include/stratosphere/psc.hpp
Normal file
22
libraries/libstratosphere/include/stratosphere/psc.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stratosphere/psc/psc_types.hpp>
|
||||||
|
#include <stratosphere/psc/psc_pm_module_id.hpp>
|
||||||
|
#include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp>
|
||||||
|
#include <stratosphere/psc/psc_pm_module.hpp>
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
|
#include <stratosphere/psc/psc_pm_module.os.horizon.hpp>
|
||||||
|
#else
|
||||||
|
#error "Unknown OS for psc::PmModule"
|
||||||
|
#endif
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/psc/psc_types.hpp>
|
||||||
|
#include <stratosphere/psc/psc_pm_module_id.hpp>
|
||||||
|
#include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp>
|
||||||
|
|
||||||
|
namespace ams::psc {
|
||||||
|
|
||||||
|
class PmModule {
|
||||||
|
NON_COPYABLE(PmModule);
|
||||||
|
NON_MOVEABLE(PmModule);
|
||||||
|
private:
|
||||||
|
std::shared_ptr<psc::sf::IPmModule> intf;
|
||||||
|
os::SystemEvent system_event;
|
||||||
|
bool initialized;
|
||||||
|
PmModuleId module_id;
|
||||||
|
uintptr_t reserved;
|
||||||
|
public:
|
||||||
|
PmModule();
|
||||||
|
~PmModule();
|
||||||
|
|
||||||
|
Result Initialize(const PmModuleId mid, const PmModuleId *dependencies, u32 dependency_count, os::EventClearMode clear_mode);
|
||||||
|
Result Finalize();
|
||||||
|
|
||||||
|
constexpr PmModuleId GetId() const { return this->module_id; }
|
||||||
|
|
||||||
|
Result GetRequest(PmState *out_state, PmFlagSet *out_flags);
|
||||||
|
Result Acknowledge(PmState state, Result res);
|
||||||
|
|
||||||
|
os::SystemEvent *GetEventPointer();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::psc {
|
||||||
|
|
||||||
|
enum PmModuleId : u16 {
|
||||||
|
PmModuleId_Usb = 4,
|
||||||
|
PmModuleId_Ethernet = 5,
|
||||||
|
PmModuleId_Fgm = 6,
|
||||||
|
PmModuleId_PcvClock = 7,
|
||||||
|
PmModuleId_PcvVoltage = 8,
|
||||||
|
PmModuleId_Gpio = 9,
|
||||||
|
PmModuleId_Pinmux = 10,
|
||||||
|
PmModuleId_Uart = 11,
|
||||||
|
PmModuleId_I2c = 12,
|
||||||
|
PmModuleId_I2cPcv = 13,
|
||||||
|
PmModuleId_Spi = 14,
|
||||||
|
PmModuleId_Pwm = 15,
|
||||||
|
PmModuleId_Psm = 16,
|
||||||
|
PmModuleId_Tc = 17,
|
||||||
|
PmModuleId_Omm = 18,
|
||||||
|
PmModuleId_Pcie = 19,
|
||||||
|
PmModuleId_Lbl = 20,
|
||||||
|
PmModuleId_Display = 21,
|
||||||
|
|
||||||
|
PmModuleId_Hid = 24,
|
||||||
|
PmModuleId_WlanSockets = 25,
|
||||||
|
|
||||||
|
PmModuleId_Fs = 27,
|
||||||
|
PmModuleId_Audio = 28,
|
||||||
|
|
||||||
|
PmModuleId_TmaHostIo = 30,
|
||||||
|
PmModuleId_Bluetooth = 31,
|
||||||
|
PmModuleId_Bpc = 32,
|
||||||
|
PmModuleId_Fan = 33,
|
||||||
|
PmModuleId_Pcm = 34,
|
||||||
|
PmModuleId_Nfc = 35,
|
||||||
|
PmModuleId_Apm = 36,
|
||||||
|
PmModuleId_Btm = 37,
|
||||||
|
PmModuleId_Nifm = 38,
|
||||||
|
PmModuleId_GpioLow = 39,
|
||||||
|
PmModuleId_Npns = 40,
|
||||||
|
PmModuleId_Lm = 41,
|
||||||
|
PmModuleId_Bcat = 42,
|
||||||
|
PmModuleId_Time = 43,
|
||||||
|
PmModuleId_Pctl = 44,
|
||||||
|
PmModuleId_Erpt = 45,
|
||||||
|
PmModuleId_Eupld = 46,
|
||||||
|
PmModuleId_Friends = 47,
|
||||||
|
PmModuleId_Bgtc = 48,
|
||||||
|
PmModuleId_Account = 49,
|
||||||
|
PmModuleId_Sasbus = 50,
|
||||||
|
PmModuleId_Ntc = 51,
|
||||||
|
PmModuleId_Idle = 52,
|
||||||
|
PmModuleId_Tcap = 53,
|
||||||
|
PmModuleId_PsmLow = 54,
|
||||||
|
PmModuleId_Ndd = 55,
|
||||||
|
PmModuleId_Olsc = 56,
|
||||||
|
|
||||||
|
PmModuleId_Ns = 61,
|
||||||
|
|
||||||
|
PmModuleId_Nvservices = 101,
|
||||||
|
|
||||||
|
PmModuleId_Spsm = 127,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::psc {
|
||||||
|
|
||||||
|
enum PmState {
|
||||||
|
PmState_Awake = 0,
|
||||||
|
PmState_ReadyAwaken = 1,
|
||||||
|
PmState_ReadySleep = 2,
|
||||||
|
PmState_ReadySleepCritical = 3,
|
||||||
|
PmState_ReadyAwakenCritical = 4,
|
||||||
|
PmState_ReadyShutdown = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 MaximumDependencyLevels = 20;
|
||||||
|
|
||||||
|
struct PmFlag {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
using PmFlagSet = util::BitFlagSet<BITSIZEOF(u32), PmFlag>;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/psc/psc_types.hpp>
|
||||||
|
#include <stratosphere/psc/psc_pm_module_id.hpp>
|
||||||
|
|
||||||
|
namespace ams::psc::sf {
|
||||||
|
|
||||||
|
class IPmModule : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
Initialize = 0,
|
||||||
|
GetRequest = 1,
|
||||||
|
Acknowledge = 2,
|
||||||
|
Finalize = 3,
|
||||||
|
AcknowledgeEx = 4,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result Initialize(ams::sf::OutCopyHandle out, psc::PmModuleId module_id, const ams::sf::InBuffer &child_list) = 0;
|
||||||
|
virtual Result GetRequest(ams::sf::Out<PmState> out_state, ams::sf::Out<PmFlagSet> out_flags) = 0;
|
||||||
|
virtual Result Acknowledge() = 0;
|
||||||
|
virtual Result Finalize() = 0;
|
||||||
|
virtual Result AcknowledgeEx(PmState state) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(Initialize),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetRequest),
|
||||||
|
MAKE_SERVICE_COMMAND_META(Acknowledge),
|
||||||
|
MAKE_SERVICE_COMMAND_META(Finalize),
|
||||||
|
MAKE_SERVICE_COMMAND_META(AcknowledgeEx, hos::Version_600), /* TODO: This is really 5.1.0... */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp>
|
||||||
|
|
||||||
|
namespace ams::psc::sf {
|
||||||
|
|
||||||
|
class IPmService : public ams::sf::IServiceObject {
|
||||||
|
protected:
|
||||||
|
enum class CommandId {
|
||||||
|
Initialize = 0,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result Initialize(ams::sf::Out<std::shared_ptr<psc::sf::IPmModule>> out) = 0;
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MAKE_SERVICE_COMMAND_META(Initialize),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -19,3 +19,7 @@
|
||||||
#include "settings/settings_types.hpp"
|
#include "settings/settings_types.hpp"
|
||||||
#include "settings/settings_fwdbg_types.hpp"
|
#include "settings/settings_fwdbg_types.hpp"
|
||||||
#include "settings/settings_fwdbg_api.hpp"
|
#include "settings/settings_fwdbg_api.hpp"
|
||||||
|
#include "settings/system/settings_firmware_version.hpp"
|
||||||
|
#include "settings/system/settings_product_model.hpp"
|
||||||
|
#include "settings/system/settings_region.hpp"
|
||||||
|
#include "settings/system/settings_serial_number.hpp"
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/settings/settings_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
struct alignas(4) FirmwareVersion {
|
||||||
|
u8 major;
|
||||||
|
u8 minor;
|
||||||
|
u8 micro;
|
||||||
|
u8 padding1;
|
||||||
|
u8 revision_major;
|
||||||
|
u8 revision_minor;
|
||||||
|
u8 padding2;
|
||||||
|
u8 padding3;
|
||||||
|
char platform[0x20];
|
||||||
|
char revision[0x40];
|
||||||
|
char display_version[0x18];
|
||||||
|
char display_name[0x80];
|
||||||
|
|
||||||
|
constexpr int GetComparableVersion() const {
|
||||||
|
return (static_cast<int>(major) << 16) | (static_cast<int>(minor) << 8) | (static_cast<int>(micro) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator==(const FirmwareVersion &lhs, const FirmwareVersion &rhs) {
|
||||||
|
return lhs.GetComparableVersion() == rhs.GetComparableVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator!=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) {
|
||||||
|
return lhs.GetComparableVersion() != rhs.GetComparableVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator<=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) {
|
||||||
|
return lhs.GetComparableVersion() <= rhs.GetComparableVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator>=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) {
|
||||||
|
return lhs.GetComparableVersion() >= rhs.GetComparableVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator<(const FirmwareVersion &lhs, const FirmwareVersion &rhs) {
|
||||||
|
return lhs.GetComparableVersion() < rhs.GetComparableVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator>(const FirmwareVersion &lhs, const FirmwareVersion &rhs) {
|
||||||
|
return lhs.GetComparableVersion() > rhs.GetComparableVersion();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void GetFirmwareVersion(FirmwareVersion *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/settings/settings_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
enum ProductModel {
|
||||||
|
ProductModel_Invalid = 0,
|
||||||
|
ProductModel_Nx = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
ProductModel GetProductModel();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/settings/settings_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
enum RegionCode {
|
||||||
|
RegionCode_Japan = 0,
|
||||||
|
RegionCode_Usa = 1,
|
||||||
|
RegionCode_Europe = 2,
|
||||||
|
RegionCode_Australia = 3,
|
||||||
|
RegionCode_HongKongTaiwanKorea = 4,
|
||||||
|
RegionCode_China = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
void GetRegionCode(RegionCode *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/settings/settings_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
struct SerialNumber {
|
||||||
|
char str[0x18];
|
||||||
|
};
|
||||||
|
|
||||||
|
void GetSerialNumber(SerialNumber *out);
|
||||||
|
|
||||||
|
}
|
26
libraries/libstratosphere/include/stratosphere/time.hpp
Normal file
26
libraries/libstratosphere/include/stratosphere/time.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
#include <stratosphere/time/time_posix_time.hpp>
|
||||||
|
#include <stratosphere/time/time_steady_clock_time_point.hpp>
|
||||||
|
#include <stratosphere/time/time_api.hpp>
|
||||||
|
#include <stratosphere/time/time_standard_steady_clock.hpp>
|
||||||
|
#include <stratosphere/time/time_standard_user_system_clock.hpp>
|
||||||
|
#include <stratosphere/time/time_standard_network_system_clock.hpp>
|
||||||
|
#include <stratosphere/time/impl/util/time_impl_util_api.hpp>
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
#include <stratosphere/time/time_posix_time.hpp>
|
||||||
|
#include <stratosphere/time/time_steady_clock_time_point.hpp>
|
||||||
|
|
||||||
|
namespace ams::time::impl::util {
|
||||||
|
|
||||||
|
Result GetSpanBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
#include <stratosphere/time/time_posix_time.hpp>
|
||||||
|
#include <stratosphere/time/time_steady_clock_time_point.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
Result Initialize();
|
||||||
|
Result InitializeForSystem();
|
||||||
|
Result InitializeForSystemUser();
|
||||||
|
|
||||||
|
Result Finalize();
|
||||||
|
|
||||||
|
bool IsInitialized();
|
||||||
|
|
||||||
|
Result GetElapsedSecondsBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
using SourceId = util::Uuid;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
struct PosixTime {
|
||||||
|
s64 value;
|
||||||
|
|
||||||
|
constexpr PosixTime &operator+=(const TimeSpan &ts) { this->value += ts.GetSeconds(); return *this; }
|
||||||
|
constexpr PosixTime &operator-=(const TimeSpan &ts) { this->value -= ts.GetSeconds(); return *this; }
|
||||||
|
|
||||||
|
constexpr friend PosixTime operator+(const PosixTime &lhs, const TimeSpan &rhs) { return { .value = lhs.value + rhs.GetSeconds() }; }
|
||||||
|
constexpr friend PosixTime operator-(const PosixTime &lhs, const TimeSpan &rhs) { return { .value = lhs.value - rhs.GetSeconds() }; }
|
||||||
|
|
||||||
|
constexpr friend TimeSpan operator-(const PosixTime &lhs, const PosixTime &rhs) { return TimeSpan::FromSeconds(lhs.value - rhs.value); }
|
||||||
|
|
||||||
|
constexpr friend bool operator==(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value == rhs.value; }
|
||||||
|
constexpr friend bool operator!=(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value != rhs.value; }
|
||||||
|
constexpr friend bool operator<=(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value <= rhs.value; }
|
||||||
|
constexpr friend bool operator>=(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value >= rhs.value; }
|
||||||
|
constexpr friend bool operator< (const PosixTime &lhs, const PosixTime &rhs) { return lhs.value < rhs.value; }
|
||||||
|
constexpr friend bool operator> (const PosixTime &lhs, const PosixTime &rhs) { return lhs.value > rhs.value; }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PosixTime) == sizeof(s64));
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
#include <stratosphere/time/time_system_clock_common.hpp>
|
||||||
|
#include <stratosphere/time/time_posix_time.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
class StandardNetworkSystemClock {
|
||||||
|
public:
|
||||||
|
using rep = SystemClockTraits::rep;
|
||||||
|
using period = SystemClockTraits::period;
|
||||||
|
using duration = SystemClockTraits::duration;
|
||||||
|
using time_point = SystemClockTraits::time_point;
|
||||||
|
static constexpr bool is_steady = false;
|
||||||
|
public:
|
||||||
|
static time_point now();
|
||||||
|
static std::time_t to_time_t(const StandardUserSystemClock::time_point &t);
|
||||||
|
static time_point from_time_t(std::time_t t);
|
||||||
|
public:
|
||||||
|
static Result GetCurrentTime(PosixTime *out);
|
||||||
|
/* TODO: static Result GetSystemClockContext(SystemClockContext *out); */
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
#include <stratosphere/time/time_steady_clock_time_point.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
class StandardSteadyClock {
|
||||||
|
public:
|
||||||
|
using rep = s64;
|
||||||
|
using period = std::ratio<1>;
|
||||||
|
using duration = std::chrono::duration<rep, period>;
|
||||||
|
using time_point = std::chrono::time_point<StandardSteadyClock>;
|
||||||
|
static constexpr bool is_steady = true;
|
||||||
|
public:
|
||||||
|
static time_point now();
|
||||||
|
public:
|
||||||
|
static Result GetCurrentTimePoint(SteadyClockTimePoint *out);
|
||||||
|
};
|
||||||
|
|
||||||
|
Result GetStandardSteadyClockCurrentTimePoint(SteadyClockTimePoint *out);
|
||||||
|
TimeSpan GetStandardSteadyClockInternalOffset();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
#include <stratosphere/time/time_system_clock_common.hpp>
|
||||||
|
#include <stratosphere/time/time_posix_time.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
class StandardUserSystemClock {
|
||||||
|
public:
|
||||||
|
using rep = SystemClockTraits::rep;
|
||||||
|
using period = SystemClockTraits::period;
|
||||||
|
using duration = SystemClockTraits::duration;
|
||||||
|
using time_point = SystemClockTraits::time_point;
|
||||||
|
static constexpr bool is_steady = false;
|
||||||
|
public:
|
||||||
|
static time_point now();
|
||||||
|
static std::time_t to_time_t(const StandardUserSystemClock::time_point &t);
|
||||||
|
static time_point from_time_t(std::time_t t);
|
||||||
|
public:
|
||||||
|
static Result GetCurrentTime(PosixTime *out);
|
||||||
|
/* TODO: static Result GetSystemClockContext(SystemClockContext *out); */
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
struct SteadyClockTimePoint {
|
||||||
|
s64 value;
|
||||||
|
SourceId source_id;
|
||||||
|
|
||||||
|
constexpr SteadyClockTimePoint &operator+=(const TimeSpan &ts) { this->value += ts.GetSeconds(); return *this; }
|
||||||
|
constexpr SteadyClockTimePoint &operator-=(const TimeSpan &ts) { this->value -= ts.GetSeconds(); return *this; }
|
||||||
|
|
||||||
|
constexpr friend SteadyClockTimePoint operator+(const SteadyClockTimePoint &lhs, const TimeSpan &rhs) { return { .value = lhs.value + rhs.GetSeconds(), .source_id = lhs.source_id }; }
|
||||||
|
constexpr friend SteadyClockTimePoint operator-(const SteadyClockTimePoint &lhs, const TimeSpan &rhs) { return { .value = lhs.value - rhs.GetSeconds(), .source_id = lhs.source_id }; }
|
||||||
|
|
||||||
|
constexpr friend bool operator==(const SteadyClockTimePoint &lhs, const SteadyClockTimePoint &rhs) { return lhs.value == rhs.value && lhs.source_id == rhs.source_id; }
|
||||||
|
constexpr friend bool operator!=(const SteadyClockTimePoint &lhs, const SteadyClockTimePoint &rhs) { return !(lhs == rhs); }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/time/time_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
class SystemClockTraits {
|
||||||
|
public:
|
||||||
|
using rep = s64;
|
||||||
|
using period = std::ratio<1>;
|
||||||
|
using duration = std::chrono::duration<rep, period>;
|
||||||
|
using time_point = std::chrono::time_point<SystemClockTraits>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::crypto {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool g_initialized;
|
||||||
|
os::Mutex g_lock(false);
|
||||||
|
|
||||||
|
void InitializeCsrng() {
|
||||||
|
AMS_ASSERT(!g_initialized);
|
||||||
|
sm::DoWithSession([&]() {
|
||||||
|
R_ABORT_UNLESS(::csrngInitialize());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size) {
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_lock);
|
||||||
|
|
||||||
|
if (AMS_UNLIKELY(!g_initialized)) {
|
||||||
|
InitializeCsrng();
|
||||||
|
g_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(csrngGetRandomBytes(dst, dst_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
extern lmem::HeapHandle g_heap_handle;
|
||||||
|
|
||||||
|
class Allocator {
|
||||||
|
public:
|
||||||
|
void *operator new(size_t sz) { return lmem::AllocateFromExpHeap(g_heap_handle, sz); }
|
||||||
|
void *operator new(size_t sz, size_t algn) { return lmem::AllocateFromExpHeap(g_heap_handle, sz, static_cast<s32>(algn)); }
|
||||||
|
void *operator new[](size_t sz) { return lmem::AllocateFromExpHeap(g_heap_handle, sz); }
|
||||||
|
void *operator new[](size_t sz, size_t algn) { return lmem::AllocateFromExpHeap(g_heap_handle, sz, static_cast<s32>(algn)); }
|
||||||
|
|
||||||
|
void operator delete(void *p) { lmem::FreeToExpHeap(g_heap_handle, p); }
|
||||||
|
void operator delete[](void *p) { lmem::FreeToExpHeap(g_heap_handle, p); }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void *Allocate(size_t sz) {
|
||||||
|
return lmem::AllocateFromExpHeap(g_heap_handle, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void *AllocateWithAlign(size_t sz, size_t align) {
|
||||||
|
return lmem::AllocateFromExpHeap(g_heap_handle, sz, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Deallocate(void *p) {
|
||||||
|
return lmem::FreeToExpHeap(g_heap_handle, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DeallocateWithSize(void *p, size_t size) {
|
||||||
|
return lmem::FreeToExpHeap(g_heap_handle, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_attachment_impl.hpp"
|
||||||
|
#include "erpt_srv_attachment.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
AttachmentFileName Attachment::FileName(AttachmentId attachment_id) {
|
||||||
|
char uuid_str[AttachmentFileNameLength];
|
||||||
|
attachment_id.uuid.ToString(uuid_str, sizeof(uuid_str));
|
||||||
|
|
||||||
|
AttachmentFileName attachment_name;
|
||||||
|
std::snprintf(attachment_name.name, sizeof(attachment_name.name), "%s/%s.att", ReportStoragePath, uuid_str);
|
||||||
|
return attachment_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attachment::Attachment(JournalRecord<AttachmentInfo> *r) : record(r) {
|
||||||
|
this->record->AddReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
Attachment::~Attachment() {
|
||||||
|
this->CloseStream();
|
||||||
|
if (this->record->RemoveReference()) {
|
||||||
|
this->DeleteStream(this->FileName().name);
|
||||||
|
delete this->record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentFileName Attachment::FileName() {
|
||||||
|
return FileName(this->record->info.attachment_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Attachment::Open(AttachmentOpenType type) {
|
||||||
|
switch (type) {
|
||||||
|
case AttachmentOpenType_Create: return this->OpenStream(this->FileName().name, StreamMode_Write, AttachmentStreamBufferSize);
|
||||||
|
case AttachmentOpenType_Read: return this->OpenStream(this->FileName().name, StreamMode_Read, AttachmentStreamBufferSize);
|
||||||
|
default: return erpt::ResultInvalidArgument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Attachment::Read(u32 *out_read_count, u8 *dst, u32 dst_size) {
|
||||||
|
return this->ReadStream(out_read_count, dst, dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Attachment::Delete() {
|
||||||
|
return this->DeleteStream(this->FileName().name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Attachment::Close() {
|
||||||
|
return this->CloseStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Attachment::GetFlags(AttachmentFlagSet *out) {
|
||||||
|
*out = this->record->info.flags;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Attachment::SetFlags(AttachmentFlagSet flags) {
|
||||||
|
if (((~this->record->info.flags) & flags).IsAnySet()) {
|
||||||
|
this->record->info.flags |= flags;
|
||||||
|
return Journal::Commit();
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Attachment::GetSize(s64 *out) {
|
||||||
|
return this->GetStreamSize(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_stream.hpp"
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
enum AttachmentOpenType {
|
||||||
|
AttachmentOpenType_Create = 0,
|
||||||
|
AttachmentOpenType_Read = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 AttachmentStreamBufferSize = 1_KB;
|
||||||
|
|
||||||
|
class Attachment : public Allocator, public Stream {
|
||||||
|
private:
|
||||||
|
JournalRecord<AttachmentInfo> *record;
|
||||||
|
private:
|
||||||
|
AttachmentFileName FileName();
|
||||||
|
public:
|
||||||
|
static AttachmentFileName FileName(AttachmentId attachment_id);
|
||||||
|
public:
|
||||||
|
explicit Attachment(JournalRecord<AttachmentInfo> *r);
|
||||||
|
~Attachment();
|
||||||
|
|
||||||
|
Result Open(AttachmentOpenType type);
|
||||||
|
Result Read(u32 *out_read_count, u8 *dst, u32 dst_size);
|
||||||
|
Result Delete();
|
||||||
|
void Close();
|
||||||
|
|
||||||
|
Result GetFlags(AttachmentFlagSet *out);
|
||||||
|
Result SetFlags(AttachmentFlagSet flags);
|
||||||
|
Result GetSize(s64 *out);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result Write(T val) {
|
||||||
|
return this->WriteStream(reinterpret_cast<const u8 *>(std::addressof(val)), sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result Write(const T *buf, u32 buffer_size) {
|
||||||
|
return this->WriteStream(reinterpret_cast<const u8 *>(buf), buffer_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_attachment_impl.hpp"
|
||||||
|
#include "erpt_srv_attachment.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
AttachmentImpl::AttachmentImpl() : attachment(nullptr) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentImpl::~AttachmentImpl() {
|
||||||
|
R_ABORT_UNLESS(this->Close());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AttachmentImpl::Open(const AttachmentId &attachment_id) {
|
||||||
|
R_UNLESS(this->attachment == nullptr, erpt::ResultAlreadyInitialized());
|
||||||
|
|
||||||
|
JournalRecord<AttachmentInfo> *record = Journal::Retrieve(attachment_id);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultNotFound());
|
||||||
|
|
||||||
|
this->attachment = new Attachment(record);
|
||||||
|
R_UNLESS(this->attachment != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
auto attachment_guard = SCOPE_GUARD { delete this->attachment; this->attachment = nullptr; };
|
||||||
|
|
||||||
|
R_TRY(this->attachment->Open(AttachmentOpenType_Read));
|
||||||
|
attachment_guard.Cancel();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AttachmentImpl::Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) {
|
||||||
|
R_UNLESS(this->attachment != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->attachment->Read(out_count.GetPointer(), static_cast<u8 *>(out_buffer.GetPointer()), static_cast<u32>(out_buffer.GetSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AttachmentImpl::SetFlags(AttachmentFlagSet flags) {
|
||||||
|
R_UNLESS(this->attachment != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->attachment->SetFlags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AttachmentImpl::GetFlags(ams::sf::Out<AttachmentFlagSet> out) {
|
||||||
|
R_UNLESS(this->attachment != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->attachment->GetFlags(out.GetPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AttachmentImpl::Close() {
|
||||||
|
if (this->attachment != nullptr) {
|
||||||
|
this->attachment->Close();
|
||||||
|
delete this->attachment;
|
||||||
|
this->attachment = nullptr;
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AttachmentImpl::GetSize(ams::sf::Out<s64> out) {
|
||||||
|
R_UNLESS(this->attachment != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->attachment->GetSize(out.GetPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class Attachment;
|
||||||
|
|
||||||
|
class AttachmentImpl final : public erpt::sf::IAttachment {
|
||||||
|
private:
|
||||||
|
Attachment *attachment;
|
||||||
|
public:
|
||||||
|
AttachmentImpl();
|
||||||
|
~AttachmentImpl();
|
||||||
|
public:
|
||||||
|
virtual Result Open(const AttachmentId &attachment_id) override final;
|
||||||
|
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) override final;
|
||||||
|
virtual Result SetFlags(AttachmentFlagSet flags) override final;
|
||||||
|
virtual Result GetFlags(ams::sf::Out<AttachmentFlagSet> out) override final;
|
||||||
|
virtual Result Close() override final;
|
||||||
|
virtual Result GetSize(ams::sf::Out<s64> out) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_cipher.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
u8 Cipher::s_key[crypto::Aes128CtrEncryptor::KeySize + crypto::Aes128CtrEncryptor::IvSize + crypto::Aes128CtrEncryptor::BlockSize];
|
||||||
|
bool Cipher::s_need_to_store_cipher = false;
|
||||||
|
|
||||||
|
}
|
125
libraries/libstratosphere/source/erpt/srv/erpt_srv_cipher.hpp
Normal file
125
libraries/libstratosphere/source/erpt/srv/erpt_srv_cipher.hpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_formatter.hpp"
|
||||||
|
#include "erpt_srv_keys.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class Cipher : private Formatter {
|
||||||
|
private:
|
||||||
|
static constexpr u32 RsaKeySize = 0x100;
|
||||||
|
static constexpr u32 SaltSize = 0x20;
|
||||||
|
|
||||||
|
static u8 s_key[crypto::Aes128CtrEncryptor::KeySize + crypto::Aes128CtrEncryptor::IvSize + crypto::Aes128CtrEncryptor::BlockSize];
|
||||||
|
static bool s_need_to_store_cipher;
|
||||||
|
|
||||||
|
struct Header {
|
||||||
|
u32 magic;
|
||||||
|
u32 field_type;
|
||||||
|
u32 element_count;
|
||||||
|
u32 reserved;
|
||||||
|
u8 data[0];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Header) == 0x10);
|
||||||
|
|
||||||
|
static constexpr u32 HeaderMagic = util::FourCC<'C', 'R', 'P', 'T'>::Code;
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
static Result EncryptArray(Report *report, FieldId field_id, T *arr, u32 arr_size) {
|
||||||
|
const u32 data_size = util::AlignUp(arr_size * sizeof(T), crypto::Aes128CtrEncryptor::BlockSize);
|
||||||
|
|
||||||
|
Header *hdr = reinterpret_cast<Header *>(AllocateWithAlign(sizeof(Header) + data_size, crypto::Aes128CtrEncryptor::BlockSize));
|
||||||
|
R_UNLESS(hdr != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
ON_SCOPE_EXIT { Deallocate(hdr); };
|
||||||
|
|
||||||
|
hdr->magic = HeaderMagic;
|
||||||
|
hdr->field_type = static_cast<u32>(FieldToTypeMap[field_id]);
|
||||||
|
hdr->element_count = arr_size;
|
||||||
|
hdr->reserved = 0;
|
||||||
|
|
||||||
|
std::memset(hdr->data, 0, data_size);
|
||||||
|
std::memcpy(hdr->data, arr, arr_size * sizeof(T));
|
||||||
|
|
||||||
|
crypto::EncryptAes128Ctr(hdr->data, data_size, s_key, crypto::Aes128CtrEncryptor::KeySize, s_key + crypto::Aes128CtrEncryptor::KeySize, crypto::Aes128CtrEncryptor::IvSize, hdr->data, data_size);
|
||||||
|
|
||||||
|
ON_SCOPE_EXIT { std::memset(hdr, 0, sizeof(hdr) + data_size); s_need_to_store_cipher = true; };
|
||||||
|
|
||||||
|
return Formatter::AddField(report, field_id, reinterpret_cast<u8 *>(hdr), sizeof(hdr) + data_size);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static Result Begin(Report *report, u32 record_count) {
|
||||||
|
s_need_to_store_cipher = false;
|
||||||
|
crypto::GenerateCryptographicallyRandomBytes(s_key, sizeof(s_key));
|
||||||
|
|
||||||
|
return Formatter::Begin(report, record_count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result End(Report *report) {
|
||||||
|
u8 cipher[RsaKeySize] = {};
|
||||||
|
|
||||||
|
if (s_need_to_store_cipher) {
|
||||||
|
u8 salt[SaltSize];
|
||||||
|
crypto::RsaOaepEncryptor<RsaKeySize, crypto::Sha256Generator> oaep;
|
||||||
|
crypto::GenerateCryptographicallyRandomBytes(salt, sizeof(salt));
|
||||||
|
|
||||||
|
oaep.Initialize(GetPublicKeyModulus(), GetPublicKeyModulusSize(), GetPublicKeyExponent(), GetPublicKeyExponentSize());
|
||||||
|
oaep.Encrypt(cipher, sizeof(cipher), s_key, sizeof(s_key), salt, sizeof(salt));
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter::AddField(report, FieldId_CipherKey, cipher, sizeof(cipher));
|
||||||
|
std::memset(s_key, 0, sizeof(s_key));
|
||||||
|
|
||||||
|
return Formatter::End(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result AddField(Report *report, FieldId field_id, bool value) {
|
||||||
|
return Formatter::AddField(report, field_id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddField(Report *report, FieldId field_id, T value) {
|
||||||
|
return Formatter::AddField<T>(report, field_id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result AddField(Report *report, FieldId field_id, char *str, u32 len) {
|
||||||
|
if (FieldToFlagMap[field_id] == FieldFlag_Encrypt) {
|
||||||
|
return EncryptArray<char>(report, field_id, str, len);
|
||||||
|
} else {
|
||||||
|
return Formatter::AddField(report, field_id, str, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result AddField(Report *report, FieldId field_id, u8 *bin, u32 len) {
|
||||||
|
if (FieldToFlagMap[field_id] == FieldFlag_Encrypt) {
|
||||||
|
return EncryptArray<u8>(report, field_id, bin, len);
|
||||||
|
} else {
|
||||||
|
return Formatter::AddField(report, field_id, bin, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddField(Report *report, FieldId field_id, T *arr, u32 len) {
|
||||||
|
if (FieldToFlagMap[field_id] == FieldFlag_Encrypt) {
|
||||||
|
return EncryptArray<T>(report, field_id, arr, len);
|
||||||
|
} else {
|
||||||
|
return Formatter::AddField<T>(report, field_id, arr, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
131
libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp
Normal file
131
libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_context.hpp"
|
||||||
|
#include "erpt_srv_cipher.hpp"
|
||||||
|
#include "erpt_srv_context_record.hpp"
|
||||||
|
#include "erpt_srv_report.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ContextList = util::IntrusiveListBaseTraits<Context>::ListType;
|
||||||
|
|
||||||
|
ContextList g_category_list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Context::Context(CategoryId cat, u32 max_records) : category(cat), max_record_count(max_records), record_count(0) {
|
||||||
|
g_category_list.push_front(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Context::~Context() {
|
||||||
|
g_category_list.erase(g_category_list.iterator_to(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Context::AddCategoryToReport(Report *report) {
|
||||||
|
R_SUCCEED_IF(this->record_list.empty());
|
||||||
|
|
||||||
|
for (auto it = this->record_list.begin(); it != this->record_list.end(); it++) {
|
||||||
|
for (u32 i = 0; i < it->ctx.field_count; i++) {
|
||||||
|
auto *field = std::addressof(it->ctx.fields[i]);
|
||||||
|
u8 *arr_buf = it->ctx.array_buffer;
|
||||||
|
|
||||||
|
switch (field->type) {
|
||||||
|
case FieldType_Bool: R_TRY(Cipher::AddField(report, field->id, field->value_bool)); break;
|
||||||
|
case FieldType_NumericU8: R_TRY(Cipher::AddField(report, field->id, field->value_u8)); break;
|
||||||
|
case FieldType_NumericU16: R_TRY(Cipher::AddField(report, field->id, field->value_u16)); break;
|
||||||
|
case FieldType_NumericU32: R_TRY(Cipher::AddField(report, field->id, field->value_u32)); break;
|
||||||
|
case FieldType_NumericU64: R_TRY(Cipher::AddField(report, field->id, field->value_u64)); break;
|
||||||
|
case FieldType_NumericI8: R_TRY(Cipher::AddField(report, field->id, field->value_i8)); break;
|
||||||
|
case FieldType_NumericI16: R_TRY(Cipher::AddField(report, field->id, field->value_i16)); break;
|
||||||
|
case FieldType_NumericI32: R_TRY(Cipher::AddField(report, field->id, field->value_i32)); break;
|
||||||
|
case FieldType_NumericI64: R_TRY(Cipher::AddField(report, field->id, field->value_i64)); break;
|
||||||
|
case FieldType_String: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast<char *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(char))); break;
|
||||||
|
case FieldType_U8Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< u8 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(u8))); break;
|
||||||
|
case FieldType_U32Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< u32 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(u32))); break;
|
||||||
|
case FieldType_U64Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< u64 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(u64))); break;
|
||||||
|
case FieldType_I8Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< s8 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(s8))); break;
|
||||||
|
case FieldType_I32Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< s32 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(s32))); break;
|
||||||
|
case FieldType_I64Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< s64 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(s64))); break;
|
||||||
|
default: return erpt::ResultInvalidArgument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Context::AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size) {
|
||||||
|
ContextRecord *record = new ContextRecord();
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
auto guard = SCOPE_GUARD { delete record; };
|
||||||
|
|
||||||
|
R_TRY(record->Initialize(entry, data, data_size));
|
||||||
|
|
||||||
|
guard.Cancel();
|
||||||
|
this->AddContextRecordToCategory(record);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Context::AddContextRecordToCategory(ContextRecord *record) {
|
||||||
|
if (this->record_count < this->max_record_count) {
|
||||||
|
this->record_list.push_front(*record);
|
||||||
|
this->record_count++;
|
||||||
|
} else {
|
||||||
|
ContextRecord *back = std::addressof(this->record_list.back());
|
||||||
|
this->record_list.pop_back();
|
||||||
|
this->record_list.push_front(*record);
|
||||||
|
delete back;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Context::SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size) {
|
||||||
|
for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) {
|
||||||
|
if (it->category == entry->category) {
|
||||||
|
return it->AddContextToCategory(entry, data, data_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return erpt::ResultCategoryNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Context::SubmitContextRecord(ContextRecord *record) {
|
||||||
|
for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) {
|
||||||
|
if (it->category == record->ctx.category) {
|
||||||
|
return it->AddContextRecordToCategory(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return erpt::ResultCategoryNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Context::WriteContextsToReport(Report *report) {
|
||||||
|
R_TRY(report->Open(ReportOpenType_Create));
|
||||||
|
R_TRY(Cipher::Begin(report, ContextRecord::GetRecordCount()));
|
||||||
|
|
||||||
|
for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) {
|
||||||
|
R_TRY(it->AddCategoryToReport(report));
|
||||||
|
}
|
||||||
|
|
||||||
|
Cipher::End(report);
|
||||||
|
report->Close();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_cipher.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class ContextRecord;
|
||||||
|
class Report;
|
||||||
|
|
||||||
|
class Context : public Allocator, public util::IntrusiveListBaseNode<Context> {
|
||||||
|
private:
|
||||||
|
const CategoryId category;
|
||||||
|
const u32 max_record_count;
|
||||||
|
u32 record_count;
|
||||||
|
util::IntrusiveListBaseTraits<ContextRecord>::ListType record_list;
|
||||||
|
public:
|
||||||
|
Context(CategoryId cat, u32 max_records);
|
||||||
|
~Context();
|
||||||
|
|
||||||
|
Result AddCategoryToReport(Report *report);
|
||||||
|
Result AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size);
|
||||||
|
Result AddContextRecordToCategory(ContextRecord *record);
|
||||||
|
public:
|
||||||
|
static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size);
|
||||||
|
static Result SubmitContextRecord(ContextRecord *record);
|
||||||
|
static Result WriteContextsToReport(Report *report);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_context_impl.hpp"
|
||||||
|
#include "erpt_srv_manager_impl.hpp"
|
||||||
|
#include "erpt_srv_context.hpp"
|
||||||
|
#include "erpt_srv_reporter.hpp"
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
Result ContextImpl::SubmitContext(const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer) {
|
||||||
|
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
||||||
|
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
||||||
|
|
||||||
|
const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize());
|
||||||
|
const u32 data_size = static_cast<u32>(data_buffer.GetSize());
|
||||||
|
|
||||||
|
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(data_size <= ArrayBufferSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
return Context::SubmitContext(ctx, data, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer) {
|
||||||
|
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
||||||
|
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
||||||
|
const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer());
|
||||||
|
|
||||||
|
const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize());
|
||||||
|
const u32 data_size = static_cast<u32>(data_buffer.GetSize());
|
||||||
|
const u32 meta_size = static_cast<u32>(meta_buffer.GetSize());
|
||||||
|
|
||||||
|
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
Reporter reporter(report_type, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0);
|
||||||
|
R_TRY(reporter.CreateReport());
|
||||||
|
|
||||||
|
ManagerImpl::NotifyAll();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) {
|
||||||
|
Reporter::SetInitialLaunchSettingsCompletionTime(time_point);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::ClearInitialLaunchSettingsCompletionTime() {
|
||||||
|
Reporter::ClearInitialLaunchSettingsCompletionTime();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::UpdatePowerOnTime() {
|
||||||
|
Reporter::UpdatePowerOnTime();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::UpdateAwakeTime() {
|
||||||
|
Reporter::UpdateAwakeTime();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::SubmitMultipleCategoryContext(const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer) {
|
||||||
|
R_UNLESS(0 <= ctx_entry.category_count && ctx_entry.category_count <= CategoriesPerMultipleCategoryContext, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
const u8 *str = reinterpret_cast<const u8 *>(str_buffer.GetPointer());
|
||||||
|
const u32 str_size = static_cast<u32>(str_buffer.GetSize());
|
||||||
|
|
||||||
|
u32 total_field_count = 0, total_arr_count = 0;
|
||||||
|
for (u32 i = 0; i < ctx_entry.category_count; i++) {
|
||||||
|
ContextEntry entry = {
|
||||||
|
.version = ctx_entry.version,
|
||||||
|
.field_count = ctx_entry.field_counts[i],
|
||||||
|
.category = ctx_entry.categories[i],
|
||||||
|
};
|
||||||
|
R_UNLESS(entry.field_count <= erpt::FieldsPerContext, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(entry.field_count + total_field_count <= erpt::FieldsPerMultipleCategoryContext, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(ctx_entry.array_buf_counts[i] <= ArrayBufferSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(ctx_entry.array_buf_counts[i] + total_arr_count <= str_size, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
std::memcpy(entry.fields, ctx_entry.fields + total_field_count, entry.field_count * sizeof(FieldEntry));
|
||||||
|
|
||||||
|
R_TRY(Context::SubmitContext(std::addressof(entry), str + total_arr_count, ctx_entry.array_buf_counts[i]));
|
||||||
|
|
||||||
|
total_field_count += entry.field_count;
|
||||||
|
total_arr_count += ctx_entry.array_buf_counts[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::UpdateApplicationLaunchTime() {
|
||||||
|
Reporter::UpdateApplicationLaunchTime();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::ClearApplicationLaunchTime() {
|
||||||
|
Reporter::ClearApplicationLaunchTime();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data) {
|
||||||
|
const char *name = reinterpret_cast<const char *>(attachment_name.GetPointer());
|
||||||
|
const u8 *data = reinterpret_cast<const u8 *>(attachment_data.GetPointer());
|
||||||
|
|
||||||
|
const u32 name_size = static_cast<u32>(attachment_name.GetSize());
|
||||||
|
const u32 data_size = static_cast<u32>(attachment_data.GetSize());
|
||||||
|
|
||||||
|
R_UNLESS(data != nullptr, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(data_size <= AttachmentSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(name != nullptr, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(name_size <= AttachmentNameSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
char name_safe[AttachmentNameSizeMax];
|
||||||
|
util::Strlcpy(name_safe, name, sizeof(name_safe));
|
||||||
|
|
||||||
|
return JournalForAttachments::SubmitAttachment(out.GetPointer(), name_safe, data, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer) {
|
||||||
|
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
||||||
|
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
||||||
|
const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize());
|
||||||
|
const u32 data_size = static_cast<u32>(data_buffer.GetSize());
|
||||||
|
|
||||||
|
const AttachmentId *attachments = reinterpret_cast<const AttachmentId *>(attachment_ids_buffer.GetPointer());
|
||||||
|
const u32 num_attachments = attachment_ids_buffer.GetSize() / sizeof(*attachments);
|
||||||
|
|
||||||
|
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
Reporter reporter(report_type, ctx, data, data_size, nullptr, attachments, num_attachments);
|
||||||
|
R_TRY(reporter.CreateReport());
|
||||||
|
|
||||||
|
ManagerImpl::NotifyAll();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class ContextImpl final : public erpt::sf::IContext {
|
||||||
|
public:
|
||||||
|
virtual Result SubmitContext(const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer) override final;
|
||||||
|
virtual Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer) override final;
|
||||||
|
virtual Result SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) override final;
|
||||||
|
virtual Result ClearInitialLaunchSettingsCompletionTime() override final;
|
||||||
|
virtual Result UpdatePowerOnTime() override final;
|
||||||
|
virtual Result UpdateAwakeTime() override final;
|
||||||
|
virtual Result SubmitMultipleCategoryContext(const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer) override final;
|
||||||
|
virtual Result UpdateApplicationLaunchTime() override final;
|
||||||
|
virtual Result ClearApplicationLaunchTime() override final;
|
||||||
|
virtual Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data) override final;
|
||||||
|
virtual Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_context_record.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
u32 ContextRecord::s_record_count = 0;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool IsArrayFieldType(FieldType type) {
|
||||||
|
return type == FieldType_String ||
|
||||||
|
type == FieldType_U8Array ||
|
||||||
|
type == FieldType_U32Array ||
|
||||||
|
type == FieldType_U64Array ||
|
||||||
|
type == FieldType_I32Array ||
|
||||||
|
type == FieldType_I64Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextRecord::ContextRecord() {
|
||||||
|
this->ctx = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextRecord::ContextRecord(CategoryId category) {
|
||||||
|
this->ctx = {
|
||||||
|
.category = category,
|
||||||
|
.array_buffer = static_cast<u8 *>(Allocate(ArrayBufferSizeDefault)),
|
||||||
|
};
|
||||||
|
if (this->ctx.array_buffer != nullptr) {
|
||||||
|
this->ctx.array_buffer_size = ArrayBufferSizeDefault;
|
||||||
|
this->ctx.array_free_count = ArrayBufferSizeDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextRecord::~ContextRecord() {
|
||||||
|
if (this->ctx.array_buffer != nullptr) {
|
||||||
|
Deallocate(this->ctx.array_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
AMS_ABORT_UNLESS(s_record_count >= this->ctx.field_count);
|
||||||
|
s_record_count -= this->ctx.field_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size) {
|
||||||
|
R_UNLESS(data_size <= ArrayBufferSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
this->ctx.version = ctx_ptr->version;
|
||||||
|
this->ctx.field_count = ctx_ptr->field_count;
|
||||||
|
this->ctx.category = ctx_ptr->category;
|
||||||
|
this->ctx.array_buffer = nullptr;
|
||||||
|
this->ctx.array_buffer_size = data_size;
|
||||||
|
this->ctx.array_free_count = 0;
|
||||||
|
|
||||||
|
auto guard = SCOPE_GUARD { this->ctx.field_count = 0; };
|
||||||
|
|
||||||
|
R_UNLESS(this->ctx.field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(0 <= this->ctx.category && this->ctx.category < CategoryId_Count, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
for (u32 i = 0; i < this->ctx.field_count; i++) {
|
||||||
|
this->ctx.fields[i] = ctx_ptr->fields[i];
|
||||||
|
|
||||||
|
R_UNLESS(0 <= this->ctx.fields[i].id && this->ctx.fields[i].id < FieldId_Count, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(0 <= this->ctx.fields[i].type && this->ctx.fields[i].type < FieldType_Count, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
R_UNLESS(this->ctx.fields[i].type == FieldToTypeMap[this->ctx.fields[i].id], erpt::ResultFieldTypeMismatch());
|
||||||
|
R_UNLESS(this->ctx.category == FieldToCategoryMap[this->ctx.fields[i].id], erpt::ResultFieldCategoryMismatch());
|
||||||
|
|
||||||
|
if (IsArrayFieldType(this->ctx.fields[i].type)) {
|
||||||
|
const u32 start_idx = this->ctx.fields[i].value_array.start_idx;
|
||||||
|
const u32 size = this->ctx.fields[i].value_array.size;
|
||||||
|
const u32 end_idx = start_idx + size;
|
||||||
|
|
||||||
|
R_UNLESS(start_idx <= data_size, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(size <= data_size, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(end_idx <= data_size, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(size <= ArrayFieldSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_size > 0) {
|
||||||
|
this->ctx.array_buffer = static_cast<u8 *>(AllocateWithAlign(data_size, alignof(u64)));
|
||||||
|
R_UNLESS(this->ctx.array_buffer != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
std::memcpy(this->ctx.array_buffer, data, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
guard.Cancel();
|
||||||
|
s_record_count += this->ctx.field_count;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Add(FieldId field_id, bool value_bool) {
|
||||||
|
R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace());
|
||||||
|
|
||||||
|
s_record_count++;
|
||||||
|
auto &field = this->ctx.fields[this->ctx.field_count++];
|
||||||
|
|
||||||
|
field.id = field_id;
|
||||||
|
field.type = FieldType_Bool;
|
||||||
|
|
||||||
|
field.value_bool = value_bool;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Add(FieldId field_id, u32 value_u32) {
|
||||||
|
R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace());
|
||||||
|
|
||||||
|
s_record_count++;
|
||||||
|
auto &field = this->ctx.fields[this->ctx.field_count++];
|
||||||
|
|
||||||
|
field.id = field_id;
|
||||||
|
field.type = FieldType_NumericU32;
|
||||||
|
|
||||||
|
field.value_u32 = value_u32;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Add(FieldId field_id, u64 value_u64) {
|
||||||
|
R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace());
|
||||||
|
|
||||||
|
s_record_count++;
|
||||||
|
auto &field = this->ctx.fields[this->ctx.field_count++];
|
||||||
|
|
||||||
|
field.id = field_id;
|
||||||
|
field.type = FieldType_NumericU64;
|
||||||
|
|
||||||
|
field.value_u64 = value_u64;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Add(FieldId field_id, s32 value_i32) {
|
||||||
|
R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace());
|
||||||
|
|
||||||
|
s_record_count++;
|
||||||
|
auto &field = this->ctx.fields[this->ctx.field_count++];
|
||||||
|
|
||||||
|
field.id = field_id;
|
||||||
|
field.type = FieldType_NumericI32;
|
||||||
|
|
||||||
|
field.value_i32 = value_i32;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Add(FieldId field_id, s64 value_i64) {
|
||||||
|
R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace());
|
||||||
|
|
||||||
|
s_record_count++;
|
||||||
|
auto &field = this->ctx.fields[this->ctx.field_count++];
|
||||||
|
|
||||||
|
field.id = field_id;
|
||||||
|
field.type = FieldType_NumericI64;
|
||||||
|
|
||||||
|
field.value_i64 = value_i64;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContextRecord::Add(FieldId field_id, const char *str, u32 str_size) {
|
||||||
|
R_UNLESS(this->ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace());
|
||||||
|
R_UNLESS(str_size <= this->ctx.array_free_count, erpt::ResultOutOfArraySpace());
|
||||||
|
|
||||||
|
const u32 start_idx = this->ctx.array_buffer_size - this->ctx.array_free_count;
|
||||||
|
this->ctx.array_free_count -= str_size;
|
||||||
|
|
||||||
|
s_record_count++;
|
||||||
|
auto &field = this->ctx.fields[this->ctx.field_count++];
|
||||||
|
|
||||||
|
field.id = field_id;
|
||||||
|
field.type = FieldType_String;
|
||||||
|
|
||||||
|
field.value_array = {
|
||||||
|
.start_idx = start_idx,
|
||||||
|
.size = str_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::memcpy(this->ctx.array_buffer + start_idx, str, str_size);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
|
||||||
|
class ContextRecord : public Allocator, public util::IntrusiveListBaseNode<ContextRecord> {
|
||||||
|
friend class Context;
|
||||||
|
private:
|
||||||
|
static u32 s_record_count;
|
||||||
|
public:
|
||||||
|
static u32 GetRecordCount() {
|
||||||
|
return s_record_count;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ContextEntry ctx;
|
||||||
|
public:
|
||||||
|
ContextRecord();
|
||||||
|
explicit ContextRecord(CategoryId category);
|
||||||
|
~ContextRecord();
|
||||||
|
|
||||||
|
Result Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size);
|
||||||
|
|
||||||
|
Result Add(FieldId field_id, bool value_bool);
|
||||||
|
Result Add(FieldId field_id, u32 value_u32);
|
||||||
|
Result Add(FieldId field_id, u64 value_u64);
|
||||||
|
Result Add(FieldId field_id, s32 value_i32);
|
||||||
|
Result Add(FieldId field_id, s64 value_i64);
|
||||||
|
Result Add(FieldId field_id, const char *str, u32 str_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
185
libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp
Normal file
185
libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_report.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class Formatter {
|
||||||
|
private:
|
||||||
|
enum ElementSize {
|
||||||
|
ElementSize_16 = 16,
|
||||||
|
ElementSize_32 = 32,
|
||||||
|
ElementSize_256 = 256,
|
||||||
|
ElementSize_16384 = 16384,
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
static ValueTypeTag GetTag(s8) { return ValueTypeTag::I8; }
|
||||||
|
static ValueTypeTag GetTag(s16) { return ValueTypeTag::I16; }
|
||||||
|
static ValueTypeTag GetTag(s32) { return ValueTypeTag::I32; }
|
||||||
|
static ValueTypeTag GetTag(s64) { return ValueTypeTag::I64; }
|
||||||
|
static ValueTypeTag GetTag(u8) { return ValueTypeTag::U8; }
|
||||||
|
static ValueTypeTag GetTag(u16) { return ValueTypeTag::U16; }
|
||||||
|
static ValueTypeTag GetTag(u32) { return ValueTypeTag::U32; }
|
||||||
|
static ValueTypeTag GetTag(u64) { return ValueTypeTag::U64; }
|
||||||
|
|
||||||
|
static Result AddId(Report *report, FieldId field_id) {
|
||||||
|
static_assert(MaxFieldStringSize < ElementSize_256);
|
||||||
|
|
||||||
|
const u32 field_len = static_cast<u32>(strnlen(FieldString[field_id], MaxFieldStringSize));
|
||||||
|
if (field_len < ElementSize_32) {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixStr) | field_len)));
|
||||||
|
} else {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str8)));
|
||||||
|
R_TRY(report->Write(static_cast<u8>(field_len)));
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(report->Write(FieldString[field_id], field_len));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddValue(Report *report, T value) {
|
||||||
|
const u8 tag = static_cast<u8>(GetTag(value));
|
||||||
|
|
||||||
|
T big_endian_value;
|
||||||
|
util::StoreBigEndian(std::addressof(big_endian_value), value);
|
||||||
|
|
||||||
|
R_TRY(report->Write(tag));
|
||||||
|
R_TRY(report->Write(reinterpret_cast<u8 *>(std::addressof(big_endian_value)), sizeof(big_endian_value)));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddValueArray(Report *report, T *arr, u32 arr_size) {
|
||||||
|
if (arr_size < ElementSize_16) {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixArray) | arr_size)));
|
||||||
|
} else {
|
||||||
|
R_UNLESS(arr_size < ElementSize_16384, erpt::ResultFormatterError());
|
||||||
|
|
||||||
|
u16 be_arr_size;
|
||||||
|
util::StoreBigEndian(std::addressof(be_arr_size), static_cast<u16>(arr_size));
|
||||||
|
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Array16)));
|
||||||
|
R_TRY(report->Write(be_arr_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < arr_size; i++) {
|
||||||
|
R_TRY(AddValue(report, arr[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddIdValuePair(Report *report, FieldId field_id, T value) {
|
||||||
|
R_TRY(AddId(report, field_id));
|
||||||
|
R_TRY(AddValue(report, value));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddIdValueArray(Report *report, FieldId field_id, T *arr, u32 arr_size) {
|
||||||
|
R_TRY(AddId(report, field_id));
|
||||||
|
R_TRY(AddValueArray(report, arr, arr_size));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static Result Begin(Report *report, u32 record_count) {
|
||||||
|
if (record_count < ElementSize_16) {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixMap) | record_count)));
|
||||||
|
} else {
|
||||||
|
R_UNLESS(record_count < ElementSize_16384, erpt::ResultFormatterError());
|
||||||
|
|
||||||
|
u16 be_count;
|
||||||
|
util::StoreBigEndian(std::addressof(be_count), static_cast<u16>(record_count));
|
||||||
|
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Map16)));
|
||||||
|
R_TRY(report->Write(be_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result End(Report *report) {
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddField(Report *report, FieldId field_id, T value) {
|
||||||
|
return AddIdValuePair<T>(report, field_id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Result AddField(Report *report, FieldId field_id, T *arr, u32 arr_size) {
|
||||||
|
return AddIdValueArray(report, field_id, arr, arr_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result AddField(Report *report, FieldId field_id, bool value) {
|
||||||
|
R_TRY(AddId(report, field_id));
|
||||||
|
R_TRY(report->Write(static_cast<u8>(value ? ValueTypeTag::True : ValueTypeTag::False)));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result AddField(Report *report, FieldId field_id, char *str, u32 len) {
|
||||||
|
R_TRY(AddId(report, field_id));
|
||||||
|
|
||||||
|
const u32 str_len = str != nullptr ? static_cast<u32>(strnlen(str, len)) : 0;
|
||||||
|
|
||||||
|
if (str_len < ElementSize_32) {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixStr) | str_len)));
|
||||||
|
} else if (str_len < ElementSize_256) {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str8)));
|
||||||
|
R_TRY(report->Write(static_cast<u8>(str_len)));
|
||||||
|
} else {
|
||||||
|
R_UNLESS(str_len < ElementSize_16384, erpt::ResultFormatterError());
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str16)));
|
||||||
|
|
||||||
|
u16 be_str_len;
|
||||||
|
util::StoreBigEndian(std::addressof(be_str_len), static_cast<u16>(str_len));
|
||||||
|
R_TRY(report->Write(be_str_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(report->Write(str, str_len));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result AddField(Report *report, FieldId field_id, u8 *bin, u32 len) {
|
||||||
|
R_TRY(AddId(report, field_id));
|
||||||
|
|
||||||
|
if (len < ElementSize_256) {
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Bin8)));
|
||||||
|
R_TRY(report->Write(static_cast<u8>(len)));
|
||||||
|
} else {
|
||||||
|
R_UNLESS(len < ElementSize_16384, erpt::ResultFormatterError());
|
||||||
|
R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Bin16)));
|
||||||
|
|
||||||
|
u16 be_len;
|
||||||
|
util::StoreBigEndian(std::addressof(be_len), static_cast<u16>(len));
|
||||||
|
R_TRY(report->Write(be_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(report->Write(bin, len));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
119
libraries/libstratosphere/source/erpt/srv/erpt_srv_journal.cpp
Normal file
119
libraries/libstratosphere/source/erpt/srv/erpt_srv_journal.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
void Journal::CleanupAttachments() {
|
||||||
|
return JournalForAttachments::CleanupAttachments();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Journal::CleanupReports() {
|
||||||
|
return JournalForReports::CleanupReports();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::Commit() {
|
||||||
|
/* Open the stream. */
|
||||||
|
Stream stream;
|
||||||
|
R_TRY(stream.OpenStream(JournalFileName, StreamMode_Write, JournalStreamBufferSize));
|
||||||
|
|
||||||
|
/* Commit the reports. */
|
||||||
|
R_TRY(JournalForReports::CommitJournal(std::addressof(stream)));
|
||||||
|
|
||||||
|
/* Commit the meta. */
|
||||||
|
R_TRY(JournalForMeta::CommitJournal(std::addressof(stream)));
|
||||||
|
|
||||||
|
/* Commit the attachments. */
|
||||||
|
R_TRY(JournalForAttachments::CommitJournal(std::addressof(stream)));
|
||||||
|
|
||||||
|
/* Close and commit the stream. */
|
||||||
|
stream.CloseStream();
|
||||||
|
stream.CommitStream();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::Delete(ReportId report_id) {
|
||||||
|
return JournalForReports::DeleteReport(report_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::GetAttachmentList(AttachmentList *out, ReportId report_id) {
|
||||||
|
return JournalForAttachments::GetAttachmentList(out, report_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Uuid Journal::GetJournalId() {
|
||||||
|
return JournalForMeta::GetJournalId();
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Journal::GetMaxReportSize() {
|
||||||
|
return JournalForReports::GetMaxReportSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::GetReportList(ReportList *out, ReportType type_filter) {
|
||||||
|
return JournalForReports::GetReportList(out, type_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Journal::GetStoredReportCount(ReportType type) {
|
||||||
|
return JournalForReports::GetStoredReportCount(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Journal::GetTransmittedCount(ReportType type) {
|
||||||
|
return JournalForMeta::GetTransmittedCount(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Journal::GetUntransmittedCount(ReportType type) {
|
||||||
|
return JournalForMeta::GetUntransmittedCount(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Journal::GetUsedStorage() {
|
||||||
|
return JournalForReports::GetUsedStorage() + JournalForAttachments::GetUsedStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::Restore() {
|
||||||
|
/* Open the stream. */
|
||||||
|
Stream stream;
|
||||||
|
R_TRY(stream.OpenStream(JournalFileName, StreamMode_Read, JournalStreamBufferSize));
|
||||||
|
|
||||||
|
/* Restore the reports. */
|
||||||
|
R_TRY(JournalForReports::RestoreJournal(std::addressof(stream)));
|
||||||
|
|
||||||
|
/* Restore the meta. */
|
||||||
|
R_TRY(JournalForMeta::RestoreJournal(std::addressof(stream)));
|
||||||
|
|
||||||
|
/* Restore the attachments. */
|
||||||
|
R_TRY(JournalForAttachments::RestoreJournal(std::addressof(stream)));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
JournalRecord<ReportInfo> *Journal::Retrieve(ReportId report_id) {
|
||||||
|
return JournalForReports::RetrieveRecord(report_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
JournalRecord<AttachmentInfo> *Journal::Retrieve(AttachmentId attachment_id) {
|
||||||
|
return JournalForAttachments::RetrieveRecord(attachment_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::Store(JournalRecord<ReportInfo> *record) {
|
||||||
|
return JournalForReports::StoreRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Journal::Store(JournalRecord<AttachmentInfo> *record) {
|
||||||
|
return JournalForAttachments::StoreRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
119
libraries/libstratosphere/source/erpt/srv/erpt_srv_journal.hpp
Normal file
119
libraries/libstratosphere/source/erpt/srv/erpt_srv_journal.hpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_ref_count.hpp"
|
||||||
|
#include "erpt_srv_journal_record.hpp"
|
||||||
|
#include "erpt_srv_stream.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
constexpr inline s32 JournalVersion = 1;
|
||||||
|
|
||||||
|
constexpr inline u32 JournalStreamBufferSize = 4_KB;
|
||||||
|
|
||||||
|
struct JournalMeta {
|
||||||
|
s32 version;
|
||||||
|
u32 transmitted_count[ReportType_Count];
|
||||||
|
u32 untransmitted_count[ReportType_Count];
|
||||||
|
util::Uuid journal_id;
|
||||||
|
u32 reserved[4];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(JournalMeta) == 0x34);
|
||||||
|
|
||||||
|
class JournalForMeta {
|
||||||
|
private:
|
||||||
|
static JournalMeta s_journal_meta;
|
||||||
|
public:
|
||||||
|
static void InitializeJournal();
|
||||||
|
static Result CommitJournal(Stream *stream);
|
||||||
|
static Result RestoreJournal(Stream *stream);
|
||||||
|
static u32 GetTransmittedCount(ReportType type);
|
||||||
|
static u32 GetUntransmittedCount(ReportType type);
|
||||||
|
static void IncrementCount(bool transmitted, ReportType type);
|
||||||
|
static util::Uuid GetJournalId();
|
||||||
|
};
|
||||||
|
|
||||||
|
class JournalForReports {
|
||||||
|
private:
|
||||||
|
using RecordListType = util::IntrusiveListBaseTraits<JournalRecord<ReportInfo>>::ListType;
|
||||||
|
static RecordListType s_record_list;
|
||||||
|
static u32 s_record_count;
|
||||||
|
static u32 s_record_count_by_type[ReportType_Count];
|
||||||
|
static u32 s_used_storage;
|
||||||
|
private:
|
||||||
|
static void EraseReportImpl(JournalRecord<ReportInfo> *record, bool increment_count, bool force_delete_attachments);
|
||||||
|
public:
|
||||||
|
static void CleanupReports();
|
||||||
|
static Result CommitJournal(Stream *stream);
|
||||||
|
static Result DeleteReport(ReportId report_id);
|
||||||
|
static Result DeleteReportWithAttachments();
|
||||||
|
static s64 GetMaxReportSize();
|
||||||
|
static Result GetReportList(ReportList *out, ReportType type_filter);
|
||||||
|
static u32 GetStoredReportCount(ReportType type);
|
||||||
|
static u32 GetUsedStorage();
|
||||||
|
static Result RestoreJournal(Stream *stream);
|
||||||
|
|
||||||
|
static JournalRecord<ReportInfo> *RetrieveRecord(ReportId report_id);
|
||||||
|
static Result StoreRecord(JournalRecord<ReportInfo> *record);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JournalForAttachments {
|
||||||
|
private:
|
||||||
|
using AttachmentListType = util::IntrusiveListBaseTraits<JournalRecord<AttachmentInfo>>::ListType;
|
||||||
|
static AttachmentListType s_attachment_list;
|
||||||
|
static u32 s_attachment_count;
|
||||||
|
static u32 s_used_storage;
|
||||||
|
public:
|
||||||
|
static void CleanupAttachments();
|
||||||
|
static Result CommitJournal(Stream *stream);
|
||||||
|
static Result DeleteAttachments(ReportId report_id);
|
||||||
|
static Result GetAttachmentList(AttachmentList *out, ReportId report_id);
|
||||||
|
static u32 GetUsedStorage();
|
||||||
|
static Result RestoreJournal(Stream *stream);
|
||||||
|
|
||||||
|
static JournalRecord<AttachmentInfo> *RetrieveRecord(AttachmentId attachment_id);
|
||||||
|
static Result SetOwner(AttachmentId attachment_id, ReportId report_id);
|
||||||
|
static Result StoreRecord(JournalRecord<AttachmentInfo> *record);
|
||||||
|
|
||||||
|
static Result SubmitAttachment(AttachmentId *out, char *name, const u8 *data, u32 data_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Journal {
|
||||||
|
public:
|
||||||
|
static void CleanupAttachments();
|
||||||
|
static void CleanupReports();
|
||||||
|
static Result Commit();
|
||||||
|
static Result Delete(ReportId report_id);
|
||||||
|
static Result GetAttachmentList(AttachmentList *out, ReportId report_id);
|
||||||
|
static util::Uuid GetJournalId();
|
||||||
|
static s64 GetMaxReportSize();
|
||||||
|
static Result GetReportList(ReportList *out, ReportType type_filter);
|
||||||
|
static u32 GetStoredReportCount(ReportType type);
|
||||||
|
static u32 GetTransmittedCount(ReportType type);
|
||||||
|
static u32 GetUntransmittedCount(ReportType type);
|
||||||
|
static u32 GetUsedStorage();
|
||||||
|
static Result Restore();
|
||||||
|
|
||||||
|
static JournalRecord<ReportInfo> *Retrieve(ReportId report_id);
|
||||||
|
static JournalRecord<AttachmentInfo> *Retrieve(AttachmentId attachment_id);
|
||||||
|
|
||||||
|
static Result Store(JournalRecord<ReportInfo> *record);
|
||||||
|
static Result Store(JournalRecord<AttachmentInfo> *record);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
#include "erpt_srv_attachment.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
util::IntrusiveListBaseTraits<JournalRecord<AttachmentInfo>>::ListType JournalForAttachments::s_attachment_list;
|
||||||
|
u32 JournalForAttachments::s_attachment_count = 0;
|
||||||
|
u32 JournalForAttachments::s_used_storage = 0;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline u32 AttachmentUsedStorageMax = 4_MB;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void JournalForAttachments::CleanupAttachments() {
|
||||||
|
for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); /* ... */) {
|
||||||
|
auto *record = std::addressof(*it);
|
||||||
|
it = s_attachment_list.erase(s_attachment_list.iterator_to(*record));
|
||||||
|
if (record->RemoveReference()) {
|
||||||
|
Stream::DeleteStream(Attachment::FileName(record->info.attachment_id).name);
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AMS_ASSERT(s_attachment_list.empty());
|
||||||
|
|
||||||
|
s_attachment_count = 0;
|
||||||
|
s_used_storage = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::CommitJournal(Stream *stream) {
|
||||||
|
R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(s_attachment_count)), sizeof(s_attachment_count)));
|
||||||
|
for (auto it = s_attachment_list.crbegin(); it != s_attachment_list.crend(); it++) {
|
||||||
|
R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(it->info)), sizeof(it->info)));
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::DeleteAttachments(ReportId report_id) {
|
||||||
|
for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); /* ... */) {
|
||||||
|
auto *record = std::addressof(*it);
|
||||||
|
if (record->info.owner_report_id == report_id) {
|
||||||
|
/* Erase from the list. */
|
||||||
|
it = s_attachment_list.erase(s_attachment_list.iterator_to(*record));
|
||||||
|
|
||||||
|
/* Update storage tracking counts. */
|
||||||
|
--s_attachment_count;
|
||||||
|
s_used_storage -= static_cast<u32>(record->info.attachment_size);
|
||||||
|
|
||||||
|
/* Delete the object, if we should. */
|
||||||
|
if (record->RemoveReference()) {
|
||||||
|
Stream::DeleteStream(Attachment::FileName(record->info.attachment_id).name);
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Not attached, just advance. */
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::GetAttachmentList(AttachmentList *out, ReportId report_id) {
|
||||||
|
u32 count = 0;
|
||||||
|
for (auto it = s_attachment_list.cbegin(); it != s_attachment_list.cend() && count < util::size(out->attachments); it++) {
|
||||||
|
if (report_id == it->info.owner_report_id) {
|
||||||
|
out->attachments[count++] = it->info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->attachment_count = count;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 JournalForAttachments::GetUsedStorage() {
|
||||||
|
return s_used_storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::RestoreJournal(Stream *stream) {
|
||||||
|
/* Clear the used storage. */
|
||||||
|
s_used_storage = 0;
|
||||||
|
|
||||||
|
/* Read the count from storage. */
|
||||||
|
u32 read_size;
|
||||||
|
u32 count;
|
||||||
|
R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(count)), sizeof(count)));
|
||||||
|
|
||||||
|
R_UNLESS(read_size == sizeof(count), erpt::ResultCorruptJournal());
|
||||||
|
R_UNLESS(count <= AttachmentCountMax, erpt::ResultCorruptJournal());
|
||||||
|
|
||||||
|
/* If we fail in the middle of reading reports, we want to do cleanup. */
|
||||||
|
auto cleanup_guard = SCOPE_GUARD { CleanupAttachments(); };
|
||||||
|
|
||||||
|
AttachmentInfo info;
|
||||||
|
for (u32 i = 0; i < count; i++) {
|
||||||
|
R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(info)), sizeof(info)));
|
||||||
|
|
||||||
|
R_UNLESS(read_size == sizeof(info), erpt::ResultCorruptJournal());
|
||||||
|
|
||||||
|
auto *record = new JournalRecord<AttachmentInfo>(info);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
auto record_guard = SCOPE_GUARD { delete record; };
|
||||||
|
|
||||||
|
if (R_FAILED(Stream::GetStreamSize(std::addressof(record->info.attachment_size), Attachment::FileName(record->info.attachment_id).name))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record->info.flags.Test<AttachmentFlag::HasOwner>() && JournalForReports::RetrieveRecord(record->info.owner_report_id) != nullptr) {
|
||||||
|
/* NOTE: Nintendo does not check the result of storing the new record... */
|
||||||
|
record_guard.Cancel();
|
||||||
|
StoreRecord(record);
|
||||||
|
} else {
|
||||||
|
/* If the attachment has no owner (or we deleted the report), delete the file associated with it. */
|
||||||
|
Stream::DeleteStream(Attachment::FileName(record->info.attachment_id).name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_guard.Cancel();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
JournalRecord<AttachmentInfo> *JournalForAttachments::RetrieveRecord(AttachmentId attachment_id) {
|
||||||
|
for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); it++) {
|
||||||
|
return std::addressof(*it);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::SetOwner(AttachmentId attachment_id, ReportId report_id) {
|
||||||
|
for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); it++) {
|
||||||
|
auto *record = std::addressof(*it);
|
||||||
|
if (record->info.attachment_id == attachment_id) {
|
||||||
|
R_UNLESS(!record->info.flags.Test<AttachmentFlag::HasOwner>(), erpt::ResultAlreadyOwned());
|
||||||
|
|
||||||
|
record->info.owner_report_id = report_id;
|
||||||
|
record->info.flags.Set<AttachmentFlag::HasOwner>();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return erpt::ResultInvalidArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::StoreRecord(JournalRecord<AttachmentInfo> *record) {
|
||||||
|
/* Check if the record already exists. */
|
||||||
|
for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); it++) {
|
||||||
|
R_UNLESS(it->info.attachment_id != record->info.attachment_id, erpt::ResultAlreadyExists());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a reference to the new record. */
|
||||||
|
record->AddReference();
|
||||||
|
|
||||||
|
/* Push the record into the list. */
|
||||||
|
s_attachment_list.push_front(*record);
|
||||||
|
s_attachment_count++;
|
||||||
|
s_used_storage += static_cast<u32>(record->info.attachment_size);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForAttachments::SubmitAttachment(AttachmentId *out, char *name, const u8 *data, u32 data_size) {
|
||||||
|
R_UNLESS(data_size > 0, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(data_size < AttachmentSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
const auto name_len = std::strlen(name);
|
||||||
|
R_UNLESS(name_len < AttachmentNameSizeMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
/* Ensure that we have free space. */
|
||||||
|
while (s_used_storage > AttachmentUsedStorageMax) {
|
||||||
|
R_TRY(JournalForReports::DeleteReportWithAttachments());
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentInfo info;
|
||||||
|
info.attachment_id.uuid = util::GenerateUuid();
|
||||||
|
info.flags = erpt::srv::MakeNoAttachmentFlags();
|
||||||
|
info.attachment_size = data_size;
|
||||||
|
util::Strlcpy(info.attachment_name, name, sizeof(info.attachment_name));
|
||||||
|
|
||||||
|
auto *record = new JournalRecord<AttachmentInfo>(info);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
record->AddReference();
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
if (record->RemoveReference()) {
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
auto attachment = std::make_unique<Attachment>(record);
|
||||||
|
R_UNLESS(attachment != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
R_TRY(attachment->Open(AttachmentOpenType_Create));
|
||||||
|
ON_SCOPE_EXIT { attachment->Close(); };
|
||||||
|
|
||||||
|
R_TRY(attachment->Write(data, data_size));
|
||||||
|
R_TRY(StoreRecord(record));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
JournalMeta JournalForMeta::s_journal_meta;
|
||||||
|
|
||||||
|
void JournalForMeta::InitializeJournal() {
|
||||||
|
std::memset(std::addressof(s_journal_meta), 0, sizeof(s_journal_meta));
|
||||||
|
s_journal_meta.journal_id = util::GenerateUuid();
|
||||||
|
s_journal_meta.version = JournalVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForMeta::CommitJournal(Stream *stream) {
|
||||||
|
return stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(s_journal_meta)), sizeof(s_journal_meta));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForMeta::RestoreJournal(Stream *stream) {
|
||||||
|
u32 size;
|
||||||
|
if (R_FAILED(stream->ReadStream(std::addressof(size), reinterpret_cast<u8 *>(std::addressof(s_journal_meta)), sizeof(s_journal_meta))) || size != sizeof(s_journal_meta)) {
|
||||||
|
InitializeJournal();
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 JournalForMeta::GetTransmittedCount(ReportType type) {
|
||||||
|
if (ReportType_Start <= type && type < ReportType_End) {
|
||||||
|
return s_journal_meta.transmitted_count[type];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 JournalForMeta::GetUntransmittedCount(ReportType type) {
|
||||||
|
if (ReportType_Start <= type && type < ReportType_End) {
|
||||||
|
return s_journal_meta.untransmitted_count[type];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JournalForMeta::IncrementCount(bool transmitted, ReportType type) {
|
||||||
|
if (ReportType_Start <= type && type < ReportType_End) {
|
||||||
|
if (transmitted) {
|
||||||
|
s_journal_meta.transmitted_count[type]++;
|
||||||
|
} else {
|
||||||
|
s_journal_meta.untransmitted_count[type]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Uuid JournalForMeta::GetJournalId() {
|
||||||
|
return s_journal_meta.journal_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
#include "erpt_srv_report.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
util::IntrusiveListBaseTraits<JournalRecord<ReportInfo>>::ListType JournalForReports::s_record_list;
|
||||||
|
u32 JournalForReports::s_record_count = 0;
|
||||||
|
u32 JournalForReports::s_record_count_by_type[ReportType_Count] = {};
|
||||||
|
u32 JournalForReports::s_used_storage = 0;
|
||||||
|
|
||||||
|
void JournalForReports::CleanupReports() {
|
||||||
|
for (auto it = s_record_list.begin(); it != s_record_list.end(); /* ... */) {
|
||||||
|
auto *record = std::addressof(*it);
|
||||||
|
it = s_record_list.erase(s_record_list.iterator_to(*record));
|
||||||
|
if (record->RemoveReference()) {
|
||||||
|
Stream::DeleteStream(Report::FileName(record->info.id, false).name);
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AMS_ASSERT(s_record_list.empty());
|
||||||
|
|
||||||
|
s_record_count = 0;
|
||||||
|
s_used_storage = 0;
|
||||||
|
|
||||||
|
std::memset(s_record_count_by_type, 0, sizeof(s_record_count_by_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForReports::CommitJournal(Stream *stream) {
|
||||||
|
R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(s_record_count)), sizeof(s_record_count)));
|
||||||
|
for (auto it = s_record_list.crbegin(); it != s_record_list.crend(); it++) {
|
||||||
|
R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(it->info)), sizeof(it->info)));
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JournalForReports::EraseReportImpl(JournalRecord<ReportInfo> *record, bool increment_count, bool force_delete_attachments) {
|
||||||
|
/* Erase from the list. */
|
||||||
|
s_record_list.erase(s_record_list.iterator_to(*record));
|
||||||
|
|
||||||
|
/* Update storage tracking counts. */
|
||||||
|
--s_record_count;
|
||||||
|
--s_record_count_by_type[record->info.type];
|
||||||
|
s_used_storage -= static_cast<u32>(record->info.report_size);
|
||||||
|
|
||||||
|
/* If we should increment count, do so. */
|
||||||
|
if (increment_count) {
|
||||||
|
JournalForMeta::IncrementCount(record->info.flags.Test<ReportFlag::Transmitted>(), record->info.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete any attachments. */
|
||||||
|
if (force_delete_attachments || record->info.flags.Test<ReportFlag::HasAttachment>()) {
|
||||||
|
JournalForAttachments::DeleteAttachments(record->info.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete the object, if we should. */
|
||||||
|
if (record->RemoveReference()) {
|
||||||
|
Stream::DeleteStream(Report::FileName(record->info.id, false).name);
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForReports::DeleteReport(ReportId report_id) {
|
||||||
|
for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) {
|
||||||
|
auto *record = std::addressof(*it);
|
||||||
|
if (record->info.id == report_id) {
|
||||||
|
EraseReportImpl(record, false, false);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return erpt::ResultInvalidArgument();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForReports::DeleteReportWithAttachments() {
|
||||||
|
for (auto it = s_record_list.rbegin(); it != s_record_list.rend(); it++) {
|
||||||
|
auto *record = std::addressof(*it);
|
||||||
|
if (record->info.flags.Test<ReportFlag::HasAttachment>()) {
|
||||||
|
EraseReportImpl(record, true, true);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return erpt::ResultNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 JournalForReports::GetMaxReportSize() {
|
||||||
|
s64 max_size;
|
||||||
|
for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) {
|
||||||
|
max_size = std::max(max_size, it->info.report_size);
|
||||||
|
}
|
||||||
|
return max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForReports::GetReportList(ReportList *out, ReportType type_filter) {
|
||||||
|
u32 count = 0;
|
||||||
|
for (auto it = s_record_list.cbegin(); it != s_record_list.cend() && count < util::size(out->reports); it++) {
|
||||||
|
if (type_filter == ReportType_Any || type_filter == it->info.type) {
|
||||||
|
out->reports[count++] = it->info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->report_count = count;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 JournalForReports::GetStoredReportCount(ReportType type) {
|
||||||
|
if (ReportType_Start <= type && type < ReportType_End) {
|
||||||
|
return s_record_count_by_type[type];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 JournalForReports::GetUsedStorage() {
|
||||||
|
return s_used_storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForReports::RestoreJournal(Stream *stream) {
|
||||||
|
/* Clear the used storage. */
|
||||||
|
s_used_storage = 0;
|
||||||
|
|
||||||
|
/* Read the count from storage. */
|
||||||
|
u32 read_size;
|
||||||
|
u32 count;
|
||||||
|
R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(count)), sizeof(count)));
|
||||||
|
|
||||||
|
R_UNLESS(read_size == sizeof(count), erpt::ResultCorruptJournal());
|
||||||
|
R_UNLESS(count <= ReportCountMax, erpt::ResultCorruptJournal());
|
||||||
|
|
||||||
|
/* If we fail in the middle of reading reports, we want to do cleanup. */
|
||||||
|
auto cleanup_guard = SCOPE_GUARD { CleanupReports(); };
|
||||||
|
|
||||||
|
ReportInfo info;
|
||||||
|
for (u32 i = 0; i < count; i++) {
|
||||||
|
R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(info)), sizeof(info)));
|
||||||
|
|
||||||
|
R_UNLESS(read_size == sizeof(info), erpt::ResultCorruptJournal());
|
||||||
|
R_UNLESS(ReportType_Start <= info.type, erpt::ResultCorruptJournal());
|
||||||
|
R_UNLESS(info.type < ReportType_End, erpt::ResultCorruptJournal());
|
||||||
|
|
||||||
|
auto *record = new JournalRecord<ReportInfo>(info);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* NOTE: Nintendo does not ensure that the newly allocated record does not leak in the failure case. */
|
||||||
|
/* We will ensure it is freed if we early error. */
|
||||||
|
auto record_guard = SCOPE_GUARD { delete record; };
|
||||||
|
|
||||||
|
if (record->info.report_size == 0) {
|
||||||
|
R_UNLESS(R_SUCCEEDED(Stream::GetStreamSize(std::addressof(record->info.report_size), Report::FileName(record->info.id, false).name)), erpt::ResultCorruptJournal());
|
||||||
|
}
|
||||||
|
|
||||||
|
record_guard.Cancel();
|
||||||
|
|
||||||
|
/* NOTE: Nintendo does not check the result of storing the new record... */
|
||||||
|
StoreRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_guard.Cancel();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
JournalRecord<ReportInfo> *JournalForReports::RetrieveRecord(ReportId report_id) {
|
||||||
|
for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) {
|
||||||
|
return std::addressof(*it);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JournalForReports::StoreRecord(JournalRecord<ReportInfo> *record) {
|
||||||
|
/* Check if the record already exists. */
|
||||||
|
for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) {
|
||||||
|
R_UNLESS(it->info.id != record->info.id, erpt::ResultAlreadyExists());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete an older report if we need to. */
|
||||||
|
if (s_record_count >= ReportCountMax) {
|
||||||
|
/* Nintendo deletes the oldest report from the type with the most reports. */
|
||||||
|
/* This is an approximation of FIFO. */
|
||||||
|
ReportType most_used_type = record->info.type;
|
||||||
|
u32 most_used_count = s_record_count_by_type[most_used_type];
|
||||||
|
|
||||||
|
for (int i = ReportType_Start; i < ReportType_End; i++) {
|
||||||
|
if (s_record_count_by_type[i] > most_used_count) {
|
||||||
|
most_used_type = static_cast<ReportType>(i);
|
||||||
|
most_used_count = s_record_count_by_type[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = s_record_list.rbegin(); it != s_record_list.rend(); it++) {
|
||||||
|
if (it->info.type != most_used_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EraseReportImpl(std::addressof(*it), true, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AMS_ASSERT(s_record_count < ReportCountMax);
|
||||||
|
|
||||||
|
/* Add a reference to the new record. */
|
||||||
|
record->AddReference();
|
||||||
|
|
||||||
|
/* Push the record into the list. */
|
||||||
|
s_record_list.push_front(*record);
|
||||||
|
s_record_count++;
|
||||||
|
s_record_count_by_type[record->info.type]++;
|
||||||
|
s_used_storage += static_cast<u32>(record->info.report_size);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_ref_count.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
template<typename Info>
|
||||||
|
class JournalRecord : public Allocator, public RefCount, public util::IntrusiveListBaseNode<JournalRecord<Info>> {
|
||||||
|
public:
|
||||||
|
Info info;
|
||||||
|
|
||||||
|
JournalRecord() {
|
||||||
|
std::memset(std::addressof(this->info), 0, sizeof(this->info));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit JournalRecord(Info info) : info(info) { /* ... */ }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
98
libraries/libstratosphere/source/erpt/srv/erpt_srv_keys.cpp
Normal file
98
libraries/libstratosphere/source/erpt/srv/erpt_srv_keys.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_keys.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr const u8 PublicKeyModulusProduction[] = {
|
||||||
|
0x00,
|
||||||
|
0xAB, 0xB6, 0x6C, 0x43, 0x86, 0xDF, 0x52, 0x5F, 0xB9, 0xD3, 0x61, 0xEB, 0xFB, 0x16, 0x2B, 0x44,
|
||||||
|
0xE1, 0x1F, 0xDD, 0x81, 0xFA, 0x20, 0x48, 0x7B, 0xDB, 0x17, 0x9F, 0x9A, 0x92, 0x1E, 0x0A, 0x80,
|
||||||
|
0xD1, 0x1A, 0x4F, 0xD7, 0x49, 0xFE, 0xBA, 0x65, 0xE4, 0x61, 0x08, 0x26, 0x43, 0x7B, 0x4A, 0x16,
|
||||||
|
0x59, 0x60, 0xD1, 0xE0, 0x42, 0x0A, 0x26, 0x54, 0xC4, 0xC7, 0x2A, 0xE3, 0x17, 0x1F, 0x8E, 0x35,
|
||||||
|
0x79, 0xC0, 0x1B, 0xA1, 0xF8, 0x6F, 0x5C, 0xDC, 0x05, 0x2D, 0x90, 0x75, 0xD5, 0x98, 0x7E, 0x5A,
|
||||||
|
0x07, 0x3F, 0x4E, 0x78, 0xF1, 0x69, 0x2F, 0xE9, 0x2E, 0x50, 0x01, 0x9F, 0xCE, 0x35, 0xC8, 0x4D,
|
||||||
|
0x65, 0x23, 0xA8, 0x9F, 0xC3, 0x3C, 0x4A, 0xF2, 0x29, 0x4D, 0x10, 0x03, 0x1C, 0xB4, 0x0E, 0x64,
|
||||||
|
0xB6, 0xDD, 0xB2, 0x74, 0xE3, 0x32, 0x84, 0x25, 0x99, 0xEA, 0xE1, 0x6C, 0x78, 0x24, 0xF2, 0xB0,
|
||||||
|
0xD2, 0x2C, 0xA5, 0x1A, 0x70, 0xA6, 0x49, 0x08, 0x73, 0x8A, 0x74, 0x3A, 0x12, 0x0E, 0x1B, 0x68,
|
||||||
|
0xD1, 0x6A, 0x6C, 0x3F, 0x2C, 0x2C, 0x53, 0xD5, 0xCE, 0x5A, 0x07, 0xA2, 0xB9, 0x2E, 0x0A, 0x77,
|
||||||
|
0x51, 0x4B, 0xD2, 0x8E, 0x4F, 0xA3, 0xA8, 0x56, 0x99, 0x6F, 0x63, 0xBC, 0x23, 0x04, 0x6E, 0x71,
|
||||||
|
0x57, 0x7C, 0xFD, 0x84, 0xA7, 0xF8, 0x8D, 0x7F, 0xD6, 0xA0, 0x6E, 0x92, 0xBC, 0xCC, 0x28, 0x82,
|
||||||
|
0x60, 0xE9, 0x78, 0xC1, 0x31, 0x82, 0x4F, 0xF8, 0xC5, 0xDB, 0xB6, 0x6B, 0xF9, 0x62, 0x95, 0xD3,
|
||||||
|
0xC8, 0x63, 0x59, 0x53, 0x3F, 0x82, 0xEB, 0x06, 0xA7, 0xB8, 0x55, 0xEC, 0x9E, 0x33, 0x04, 0xCF,
|
||||||
|
0x5E, 0x42, 0x32, 0x09, 0x26, 0xFF, 0xB4, 0x5E, 0xBD, 0xD7, 0xA8, 0x6B, 0x2C, 0xF5, 0x68, 0x86,
|
||||||
|
0xCD, 0x8A, 0x13, 0xF3, 0x1C, 0x5F, 0xE6, 0x4F, 0xFC, 0xD1, 0x07, 0x28, 0x5C, 0x2D, 0xA7, 0xF7
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 PublicKeyModulusDevelopment[] = {
|
||||||
|
0x00,
|
||||||
|
0xAE, 0x7D, 0x6C, 0xD0, 0xC3, 0x13, 0x61, 0x01, 0x9D, 0x1B, 0x55, 0xA0, 0xE5, 0xF4, 0x3D, 0x56,
|
||||||
|
0x7D, 0xCA, 0x0E, 0x49, 0xFB, 0x82, 0x08, 0x06, 0x33, 0xB6, 0x37, 0xB3, 0x4A, 0x3F, 0x57, 0x39,
|
||||||
|
0x05, 0x84, 0x18, 0x3D, 0x82, 0xD8, 0x8F, 0xBC, 0xF3, 0xE1, 0x66, 0xEE, 0xD2, 0x80, 0x43, 0xF8,
|
||||||
|
0xA7, 0xB7, 0x5E, 0x5B, 0x5C, 0xF9, 0x9D, 0x7F, 0xE9, 0x6C, 0x93, 0x8A, 0x65, 0xBB, 0xD1, 0xDD,
|
||||||
|
0x56, 0xFF, 0x7C, 0x9D, 0x24, 0x66, 0x09, 0x84, 0x21, 0x2C, 0x7F, 0x0A, 0xB8, 0x31, 0x42, 0x29,
|
||||||
|
0xE6, 0xD3, 0x20, 0x76, 0xA1, 0x1F, 0x7E, 0x59, 0x5B, 0x7C, 0xF6, 0xC6, 0x02, 0xDB, 0xC9, 0x1B,
|
||||||
|
0xB9, 0x24, 0x99, 0xAD, 0x0F, 0x7B, 0x0D, 0x8E, 0x7E, 0x01, 0xFE, 0x95, 0xCE, 0x9B, 0xB5, 0x09,
|
||||||
|
0xC5, 0xF5, 0xA5, 0x6A, 0x82, 0xF6, 0x57, 0xF8, 0x06, 0x72, 0xAE, 0x73, 0x71, 0xD1, 0x09, 0x2B,
|
||||||
|
0xE2, 0x84, 0x0D, 0x66, 0x39, 0xB6, 0x21, 0x8B, 0x35, 0xE4, 0xDF, 0x90, 0x36, 0xE1, 0x3F, 0xC0,
|
||||||
|
0x9F, 0xF8, 0x85, 0x03, 0xD6, 0xCA, 0xBB, 0x1A, 0x62, 0x2D, 0xE5, 0x03, 0xF6, 0x47, 0x00, 0x6E,
|
||||||
|
0x98, 0x5A, 0x1C, 0x51, 0x94, 0x47, 0xF6, 0x83, 0x0C, 0x25, 0xBD, 0xBE, 0xBD, 0x6A, 0x35, 0xC0,
|
||||||
|
0xAB, 0x65, 0xF8, 0x01, 0xF4, 0xC3, 0x2A, 0xA3, 0xBC, 0xD7, 0xD9, 0xF7, 0x2A, 0x98, 0x27, 0xE1,
|
||||||
|
0x3F, 0x9A, 0xCF, 0xDF, 0xB1, 0x30, 0x82, 0xA4, 0xAA, 0x78, 0xCA, 0xC8, 0xB8, 0x34, 0xFA, 0xA7,
|
||||||
|
0x75, 0x23, 0xC9, 0x9C, 0x11, 0x68, 0x7E, 0x0F, 0x80, 0x8F, 0x90, 0xA6, 0xDE, 0x2B, 0x47, 0x5B,
|
||||||
|
0x94, 0x6F, 0xB9, 0x67, 0x4C, 0xC1, 0xAE, 0x50, 0x8F, 0xD8, 0xE3, 0xD1, 0xF2, 0x92, 0x54, 0x4C,
|
||||||
|
0x25, 0x02, 0x5B, 0x31, 0x65, 0x5E, 0x41, 0x81, 0x34, 0xF4, 0xF1, 0x34, 0xE7, 0x64, 0x7A, 0xC1
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 PublicKeyExponent[] = {
|
||||||
|
0x01, 0x00, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
bool IsProductionModeImpl() {
|
||||||
|
bool is_prod = true;
|
||||||
|
if (settings::fwdbg::GetSettingsItemValue(std::addressof(is_prod), sizeof(is_prod), "erpt", "production_mode") != sizeof(is_prod)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return is_prod;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsProductionMode() {
|
||||||
|
static bool s_is_prod_mode = IsProductionModeImpl();
|
||||||
|
return s_is_prod_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 *GetPublicKeyModulus() {
|
||||||
|
return IsProductionMode() ? PublicKeyModulusProduction : PublicKeyModulusDevelopment;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetPublicKeyModulusSize() {
|
||||||
|
return IsProductionMode() ? sizeof(PublicKeyModulusProduction) : sizeof(PublicKeyModulusDevelopment);
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 *GetPublicKeyExponent() {
|
||||||
|
return PublicKeyExponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetPublicKeyExponentSize() {
|
||||||
|
return sizeof(PublicKeyExponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
libraries/libstratosphere/source/erpt/srv/erpt_srv_keys.hpp
Normal file
27
libraries/libstratosphere/source/erpt/srv/erpt_srv_keys.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
const u8 *GetPublicKeyModulus();
|
||||||
|
size_t GetPublicKeyModulusSize();
|
||||||
|
|
||||||
|
const u8 *GetPublicKeyExponent();
|
||||||
|
size_t GetPublicKeyExponentSize();
|
||||||
|
|
||||||
|
}
|
132
libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp
Normal file
132
libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_context_record.hpp"
|
||||||
|
#include "erpt_srv_context.hpp"
|
||||||
|
#include "erpt_srv_reporter.hpp"
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
#include "erpt_srv_service.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
lmem::HeapHandle g_heap_handle;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr fs::SystemSaveDataId SystemSaveDataId = 0x80000000000000D1;
|
||||||
|
constexpr u32 SystemSaveDataFlags = fs::SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData;
|
||||||
|
constexpr s64 SystemSaveDataSize = 11_MB;
|
||||||
|
constexpr s64 SystemSaveDataJournalSize = 2720_KB;
|
||||||
|
|
||||||
|
Result ExtendSystemSaveData() {
|
||||||
|
s64 cur_journal_size;
|
||||||
|
s64 cur_savedata_size;
|
||||||
|
|
||||||
|
R_TRY(fs::GetSaveDataJournalSize(std::addressof(cur_journal_size), SystemSaveDataId));
|
||||||
|
R_TRY(fs::GetSaveDataAvailableSize(std::addressof(cur_savedata_size), SystemSaveDataId));
|
||||||
|
|
||||||
|
if (cur_journal_size < SystemSaveDataJournalSize || cur_savedata_size < SystemSaveDataSize) {
|
||||||
|
if (hos::GetVersion() >= hos::Version_300) {
|
||||||
|
R_TRY(fs::ExtendSaveData(fs::SaveDataSpaceId::System, SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MountSystemSaveData() {
|
||||||
|
fs::DisableAutoSaveDataCreation();
|
||||||
|
|
||||||
|
/* Extend the system save data. */
|
||||||
|
/* NOTE: Nintendo does not check result of this. */
|
||||||
|
ExtendSystemSaveData();
|
||||||
|
|
||||||
|
R_TRY_CATCH(fs::MountSystemSaveData(ReportStoragePath, SystemSaveDataId)) {
|
||||||
|
R_CATCH(fs::ResultTargetNotFound) {
|
||||||
|
R_TRY(fs::CreateSystemSaveData(SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize, SystemSaveDataFlags));
|
||||||
|
R_TRY(fs::MountSystemSaveData(ReportStoragePath, SystemSaveDataId));
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Initialize(u8 *mem, size_t mem_size) {
|
||||||
|
R_ABORT_UNLESS(time::Initialize());
|
||||||
|
|
||||||
|
g_heap_handle = lmem::CreateExpHeap(mem, mem_size, lmem::CreateOption_ThreadSafe);
|
||||||
|
AMS_ABORT_UNLESS(g_heap_handle != nullptr);
|
||||||
|
|
||||||
|
fs::SetAllocator(Allocate, DeallocateWithSize);
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(fs::MountSdCardErrorReportDirectoryForAtmosphere(ReportOnSdStoragePath));
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(MountSystemSaveData());
|
||||||
|
|
||||||
|
for (auto i = 0; i < CategoryId_Count; i++) {
|
||||||
|
Context *ctx = new Context(static_cast<CategoryId>(i), 1);
|
||||||
|
AMS_ABORT_UNLESS(ctx != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Journal::Restore();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InitializeAndStartService() {
|
||||||
|
return InitializeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) {
|
||||||
|
return Reporter::SetSerialNumberAndOsVersion(sn, sn_len, os, os_len, os_priv, os_priv_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetProductModel(const char *model, u32 model_len) {
|
||||||
|
/* NOTE: Nintendo does not check that this allocation succeeds. */
|
||||||
|
auto *record = new ContextRecord(CategoryId_ProductModelInfo);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
R_TRY(record->Add(FieldId_ProductModel, model, model_len));
|
||||||
|
R_TRY(Context::SubmitContextRecord(record));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetRegionSetting(const char *region, u32 region_len) {
|
||||||
|
/* NOTE: Nintendo does not check that this allocation succeeds. */
|
||||||
|
auto *record = new ContextRecord(CategoryId_RegionSettingInfo);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
R_TRY(record->Add(FieldId_RegionSetting, region, region_len));
|
||||||
|
R_TRY(Context::SubmitContextRecord(record));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetRedirectNewReportsToSdCard(bool redirect) {
|
||||||
|
Reporter::SetRedirectNewReportsToSdCard(redirect);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait() {
|
||||||
|
return WaitService();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_manager_impl.hpp"
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ManagerList = util::IntrusiveListBaseTraits<ManagerImpl>::ListType;
|
||||||
|
|
||||||
|
ManagerList g_manager_list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagerImpl::ManagerImpl() : system_event(os::EventClearMode_AutoClear, true) {
|
||||||
|
g_manager_list.push_front(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagerImpl::~ManagerImpl() {
|
||||||
|
g_manager_list.erase(g_manager_list.iterator_to(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManagerImpl::NotifyOne() {
|
||||||
|
this->system_event.Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::NotifyAll() {
|
||||||
|
for (auto &manager : g_manager_list) {
|
||||||
|
manager.NotifyOne();
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::GetReportList(const ams::sf::OutBuffer &out_list, ReportType type_filter) {
|
||||||
|
R_UNLESS(out_list.GetSize() == sizeof(ReportList), erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
return Journal::GetReportList(reinterpret_cast<ReportList *>(out_list.GetPointer()), type_filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::GetEvent(ams::sf::OutCopyHandle out) {
|
||||||
|
out.SetValue(this->system_event.GetReadableHandle());
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::CleanupReports() {
|
||||||
|
Journal::CleanupReports();
|
||||||
|
Journal::CleanupAttachments();
|
||||||
|
return Journal::Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::DeleteReport(const ReportId &report_id) {
|
||||||
|
R_TRY(Journal::Delete(report_id));
|
||||||
|
return Journal::Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out) {
|
||||||
|
StorageUsageStatistics stats = {};
|
||||||
|
|
||||||
|
stats.journal_uuid = Journal::GetJournalId();
|
||||||
|
stats.used_storage_size = Journal::GetUsedStorage();
|
||||||
|
stats.max_report_size = Journal::GetMaxReportSize();
|
||||||
|
|
||||||
|
for (int i = ReportType_Start; i < ReportType_End; i++) {
|
||||||
|
const auto type = static_cast<ReportType>(i);
|
||||||
|
stats.report_count[i] = Journal::GetStoredReportCount(type);
|
||||||
|
stats.transmitted_count[i] = Journal::GetTransmittedCount(type);
|
||||||
|
stats.untransmitted_count[i] = Journal::GetUntransmittedCount(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.SetValue(stats);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ManagerImpl::GetAttachmentList(const ams::sf::OutBuffer &out_list, const ReportId &report_id) {
|
||||||
|
R_UNLESS(out_list.GetSize() == sizeof(AttachmentList), erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
return Journal::GetAttachmentList(reinterpret_cast<AttachmentList *>(out_list.GetPointer()), report_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class ManagerImpl final : public erpt::sf::IManager, public util::IntrusiveListBaseNode<ManagerImpl> {
|
||||||
|
private:
|
||||||
|
os::SystemEvent system_event;
|
||||||
|
public:
|
||||||
|
ManagerImpl();
|
||||||
|
~ManagerImpl();
|
||||||
|
private:
|
||||||
|
void NotifyOne();
|
||||||
|
public:
|
||||||
|
static Result NotifyAll();
|
||||||
|
public:
|
||||||
|
virtual Result GetReportList(const ams::sf::OutBuffer &out_list, ReportType type_filter) override final;
|
||||||
|
virtual Result GetEvent(ams::sf::OutCopyHandle out) override final;
|
||||||
|
virtual Result CleanupReports() override final;
|
||||||
|
virtual Result DeleteReport(const ReportId &report_id) override final;
|
||||||
|
virtual Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out) override final;
|
||||||
|
virtual Result GetAttachmentList(const ams::sf::OutBuffer &out_buf, const ReportId &report_id) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class RefCount {
|
||||||
|
private:
|
||||||
|
static constexpr u32 MaxReferenceCount = 1000;
|
||||||
|
std::atomic<u32> ref_count;
|
||||||
|
public:
|
||||||
|
RefCount() : ref_count(0) { /* ... */ }
|
||||||
|
|
||||||
|
void AddReference() {
|
||||||
|
const auto prev = this->ref_count.fetch_add(1);
|
||||||
|
AMS_ABORT_UNLESS(prev <= MaxReferenceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveReference() {
|
||||||
|
auto prev = this->ref_count.fetch_sub(1);
|
||||||
|
AMS_ABORT_UNLESS(prev != 0);
|
||||||
|
return prev == 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_report_impl.hpp"
|
||||||
|
#include "erpt_srv_report.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
ReportFileName Report::FileName(ReportId report_id, bool redirect_to_sd) {
|
||||||
|
ReportFileName report_name;
|
||||||
|
std::snprintf(report_name.name, sizeof(report_name.name),
|
||||||
|
"%s:/%08x-%04x-%04x-%02x%02x-%04x%08x",
|
||||||
|
(redirect_to_sd ? ReportOnSdStoragePath : ReportStoragePath),
|
||||||
|
report_id.uuid_data.time_low,
|
||||||
|
report_id.uuid_data.time_mid,
|
||||||
|
report_id.uuid_data.time_high_and_version,
|
||||||
|
report_id.uuid_data.clock_high,
|
||||||
|
report_id.uuid_data.clock_low,
|
||||||
|
static_cast<u32>((report_id.uuid_data.node >> BITSIZEOF(u32)) & 0x0000FFFF),
|
||||||
|
static_cast<u32>((report_id.uuid_data.node >> 0) & 0xFFFFFFFF));
|
||||||
|
return report_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Report::Report(JournalRecord<ReportInfo> *r, bool redirect_to_sd) : record(r), redirect_to_sd_card(redirect_to_sd) {
|
||||||
|
this->record->AddReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
Report::~Report() {
|
||||||
|
this->CloseStream();
|
||||||
|
if (this->record->RemoveReference()) {
|
||||||
|
this->DeleteStream(this->FileName().name);
|
||||||
|
delete this->record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportFileName Report::FileName() {
|
||||||
|
return FileName(this->record->info.id, this->redirect_to_sd_card);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Report::Open(ReportOpenType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ReportOpenType_Create: return this->OpenStream(this->FileName().name, StreamMode_Write, ReportStreamBufferSize);
|
||||||
|
case ReportOpenType_Read: return this->OpenStream(this->FileName().name, StreamMode_Read, ReportStreamBufferSize);
|
||||||
|
default: return erpt::ResultInvalidArgument();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Report::Read(u32 *out_read_count, u8 *dst, u32 dst_size) {
|
||||||
|
return this->ReadStream(out_read_count, dst, dst_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Report::Delete() {
|
||||||
|
return this->DeleteStream(this->FileName().name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Report::Close() {
|
||||||
|
return this->CloseStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Report::GetFlags(ReportFlagSet *out) {
|
||||||
|
*out = this->record->info.flags;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Report::SetFlags(ReportFlagSet flags) {
|
||||||
|
if (((~this->record->info.flags) & flags).IsAnySet()) {
|
||||||
|
this->record->info.flags |= flags;
|
||||||
|
return Journal::Commit();
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Report::GetSize(s64 *out) {
|
||||||
|
return this->GetStreamSize(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_stream.hpp"
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
enum ReportOpenType {
|
||||||
|
ReportOpenType_Create = 0,
|
||||||
|
ReportOpenType_Read = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline u32 ReportStreamBufferSize = 1_KB;
|
||||||
|
|
||||||
|
class Report : public Allocator, public Stream {
|
||||||
|
private:
|
||||||
|
JournalRecord<ReportInfo> *record;
|
||||||
|
bool redirect_to_sd_card;
|
||||||
|
private:
|
||||||
|
ReportFileName FileName();
|
||||||
|
public:
|
||||||
|
static ReportFileName FileName(ReportId report_id, bool redirect_to_sd);
|
||||||
|
public:
|
||||||
|
explicit Report(JournalRecord<ReportInfo> *r, bool redirect_to_sd);
|
||||||
|
~Report();
|
||||||
|
|
||||||
|
Result Open(ReportOpenType type);
|
||||||
|
Result Read(u32 *out_read_count, u8 *dst, u32 dst_size);
|
||||||
|
Result Delete();
|
||||||
|
void Close();
|
||||||
|
|
||||||
|
Result GetFlags(ReportFlagSet *out);
|
||||||
|
Result SetFlags(ReportFlagSet flags);
|
||||||
|
Result GetSize(s64 *out);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result Write(T val) {
|
||||||
|
return this->WriteStream(reinterpret_cast<const u8 *>(std::addressof(val)), sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result Write(const T *buf, u32 buffer_size) {
|
||||||
|
return this->WriteStream(reinterpret_cast<const u8 *>(buf), buffer_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_report_impl.hpp"
|
||||||
|
#include "erpt_srv_report.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
ReportImpl::ReportImpl() : report(nullptr) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportImpl::~ReportImpl() {
|
||||||
|
R_ABORT_UNLESS(this->Close());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReportImpl::Open(const ReportId &report_id) {
|
||||||
|
R_UNLESS(this->report == nullptr, erpt::ResultAlreadyInitialized());
|
||||||
|
|
||||||
|
JournalRecord<ReportInfo> *record = Journal::Retrieve(report_id);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultNotFound());
|
||||||
|
|
||||||
|
this->report = new Report(record, false);
|
||||||
|
R_UNLESS(this->report != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
auto report_guard = SCOPE_GUARD { delete this->report; this->report = nullptr; };
|
||||||
|
|
||||||
|
R_TRY(this->report->Open(ReportOpenType_Read));
|
||||||
|
report_guard.Cancel();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReportImpl::Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) {
|
||||||
|
R_UNLESS(this->report != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->report->Read(out_count.GetPointer(), static_cast<u8 *>(out_buffer.GetPointer()), static_cast<u32>(out_buffer.GetSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReportImpl::SetFlags(ReportFlagSet flags) {
|
||||||
|
R_UNLESS(this->report != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->report->SetFlags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReportImpl::GetFlags(ams::sf::Out<ReportFlagSet> out) {
|
||||||
|
R_UNLESS(this->report != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->report->GetFlags(out.GetPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReportImpl::Close() {
|
||||||
|
if (this->report != nullptr) {
|
||||||
|
this->report->Close();
|
||||||
|
delete this->report;
|
||||||
|
this->report = nullptr;
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReportImpl::GetSize(ams::sf::Out<s64> out) {
|
||||||
|
R_UNLESS(this->report != nullptr, erpt::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->report->GetSize(out.GetPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class Report;
|
||||||
|
|
||||||
|
class ReportImpl final : public erpt::sf::IReport {
|
||||||
|
private:
|
||||||
|
Report *report;
|
||||||
|
public:
|
||||||
|
ReportImpl();
|
||||||
|
~ReportImpl();
|
||||||
|
public:
|
||||||
|
virtual Result Open(const ReportId &report_id) override final;
|
||||||
|
virtual Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) override final;
|
||||||
|
virtual Result SetFlags(ReportFlagSet flags) override final;
|
||||||
|
virtual Result GetFlags(ams::sf::Out<ReportFlagSet> out) override final;
|
||||||
|
virtual Result Close() override final;
|
||||||
|
virtual Result GetSize(ams::sf::Out<s64> out) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
226
libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp
Normal file
226
libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_reporter.hpp"
|
||||||
|
#include "erpt_srv_report.hpp"
|
||||||
|
#include "erpt_srv_journal.hpp"
|
||||||
|
#include "erpt_srv_context_record.hpp"
|
||||||
|
#include "erpt_srv_context.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
bool Reporter::s_redirect_new_reports = true;
|
||||||
|
char Reporter::s_serial_number[24] = "Unknown";
|
||||||
|
char Reporter::s_os_version[24] = "Unknown";
|
||||||
|
char Reporter::s_private_os_version[96] = "Unknown";
|
||||||
|
std::optional<os::Tick> Reporter::s_application_launch_time;
|
||||||
|
std::optional<os::Tick> Reporter::s_awake_time;
|
||||||
|
std::optional<os::Tick> Reporter::s_power_on_time;
|
||||||
|
std::optional<time::SteadyClockTimePoint> Reporter::s_initial_launch_settings_completion_time;
|
||||||
|
|
||||||
|
Reporter::Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments)
|
||||||
|
: type(type), ctx(ctx), data(data), data_size(data_size), meta(meta), attachments(attachments), num_attachments(num_attachments), occurrence_tick()
|
||||||
|
{
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::CreateReport() {
|
||||||
|
R_TRY(this->ValidateReportContext());
|
||||||
|
R_TRY(this->CollectUniqueReportFields());
|
||||||
|
R_TRY(this->SubmitReportDefaults());
|
||||||
|
R_TRY(this->SubmitReportContexts());
|
||||||
|
R_TRY(this->LinkAttachments());
|
||||||
|
R_TRY(this->CreateReportFile());
|
||||||
|
|
||||||
|
this->SaveSyslogReportIfRequired();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::ValidateReportContext() {
|
||||||
|
R_UNLESS(this->ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing());
|
||||||
|
R_UNLESS(this->ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
bool found_error_code = false;
|
||||||
|
for (u32 i = 0; i < this->ctx->field_count; i++) {
|
||||||
|
if (this->ctx->fields[i].id == FieldId_ErrorCode) {
|
||||||
|
found_error_code = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing());
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::CollectUniqueReportFields() {
|
||||||
|
this->occurrence_tick = os::GetSystemTick();
|
||||||
|
if (hos::GetVersion() >= hos::Version_300) {
|
||||||
|
this->steady_clock_internal_offset_seconds = time::GetStandardSteadyClockInternalOffset().GetSeconds();
|
||||||
|
} else {
|
||||||
|
this->steady_clock_internal_offset_seconds = 0;
|
||||||
|
}
|
||||||
|
this->report_id.uuid = util::GenerateUuid();
|
||||||
|
this->report_id.uuid.ToString(this->identifier_str, sizeof(this->identifier_str));
|
||||||
|
if (R_FAILED(time::StandardNetworkSystemClock::GetCurrentTime(std::addressof(this->timestamp_network)))) {
|
||||||
|
this->timestamp_network = {0};
|
||||||
|
}
|
||||||
|
R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(this->steady_clock_current_timepoint)));
|
||||||
|
R_TRY(time::StandardUserSystemClock::GetCurrentTime(std::addressof(this->timestamp_user)));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::SubmitReportDefaults() {
|
||||||
|
bool found_abort_flag = false, found_syslog_flag = false;
|
||||||
|
for (u32 i = 0; i < this->ctx->field_count; i++) {
|
||||||
|
if (this->ctx->fields[i].id == FieldId_AbortFlag) {
|
||||||
|
found_abort_flag = true;
|
||||||
|
}
|
||||||
|
if (this->ctx->fields[i].id == FieldId_HasSyslogFlag) {
|
||||||
|
found_syslog_flag = true;
|
||||||
|
}
|
||||||
|
if (found_abort_flag && found_syslog_flag) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextRecord *record = new ContextRecord(CategoryId_ErrorInfoDefaults);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
auto record_guard = SCOPE_GUARD { delete record; };
|
||||||
|
|
||||||
|
if (!found_abort_flag) {
|
||||||
|
record->Add(FieldId_AbortFlag, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_syslog_flag) {
|
||||||
|
record->Add(FieldId_HasSyslogFlag, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(Context::SubmitContextRecord(record));
|
||||||
|
|
||||||
|
record_guard.Cancel();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::SubmitReportContexts() {
|
||||||
|
ContextRecord *record = new ContextRecord(CategoryId_ErrorInfoAuto);
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
auto record_guard = SCOPE_GUARD { delete record; };
|
||||||
|
|
||||||
|
record->Add(FieldId_OsVersion, s_os_version, strnlen(s_os_version, sizeof(s_os_version)));
|
||||||
|
record->Add(FieldId_PrivateOsVersion, s_private_os_version, strnlen(s_private_os_version, sizeof(s_private_os_version)));
|
||||||
|
record->Add(FieldId_SerialNumber, s_serial_number, strnlen(s_serial_number, sizeof(s_serial_number)));
|
||||||
|
record->Add(FieldId_ReportIdentifier, this->identifier_str, sizeof(this->identifier_str));
|
||||||
|
record->Add(FieldId_OccurrenceTimestamp, this->timestamp_user.value);
|
||||||
|
record->Add(FieldId_OccurrenceTimestampNet, this->timestamp_network.value);
|
||||||
|
record->Add(FieldId_ReportVisibilityFlag, this->type == ReportType_Visible);
|
||||||
|
record->Add(FieldId_OccurrenceTick, this->occurrence_tick.GetInt64Value());
|
||||||
|
record->Add(FieldId_SteadyClockInternalOffset, this->steady_clock_internal_offset_seconds);
|
||||||
|
record->Add(FieldId_SteadyClockCurrentTimePointValue, this->steady_clock_current_timepoint.value);
|
||||||
|
|
||||||
|
if (s_initial_launch_settings_completion_time) {
|
||||||
|
s64 elapsed_seconds;
|
||||||
|
if (R_SUCCEEDED(time::GetElapsedSecondsBetween(std::addressof(elapsed_seconds), *s_initial_launch_settings_completion_time, this->steady_clock_current_timepoint))) {
|
||||||
|
record->Add(FieldId_ElapsedTimeSinceInitialLaunch, elapsed_seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_power_on_time) {
|
||||||
|
record->Add(FieldId_ElapsedTimeSincePowerOn, (this->occurrence_tick - *s_power_on_time).ToTimeSpan().GetSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_awake_time) {
|
||||||
|
record->Add(FieldId_ElapsedTimeSincePowerOn, (this->occurrence_tick - *s_awake_time).ToTimeSpan().GetSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_application_launch_time) {
|
||||||
|
record->Add(FieldId_ApplicationAliveTime, (this->occurrence_tick - *s_application_launch_time).ToTimeSpan().GetSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(Context::SubmitContextRecord(record));
|
||||||
|
record_guard.Cancel();
|
||||||
|
|
||||||
|
R_TRY(Context::SubmitContext(this->ctx, this->data, this->data_size));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::LinkAttachments() {
|
||||||
|
for (u32 i = 0; i < this->num_attachments; i++) {
|
||||||
|
R_TRY(JournalForAttachments::SetOwner(this->attachments[i], this->report_id));
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Reporter::CreateReportFile() {
|
||||||
|
/* Make a journal record. */
|
||||||
|
auto *record = new JournalRecord<ReportInfo>;
|
||||||
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
record->AddReference();
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
if (record->RemoveReference()) {
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
record->info.type = this->type;
|
||||||
|
record->info.id = this->report_id;
|
||||||
|
record->info.flags = erpt::srv::MakeNoReportFlags();
|
||||||
|
record->info.timestamp_user = this->timestamp_user;
|
||||||
|
record->info.timestamp_network = this->timestamp_network;
|
||||||
|
if (this->meta != nullptr) {
|
||||||
|
record->info.meta_data = *this->meta;
|
||||||
|
}
|
||||||
|
if (this->num_attachments > 0) {
|
||||||
|
record->info.flags.Set<ReportFlag::HasAttachment>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto report = std::make_unique<Report>(record, s_redirect_new_reports);
|
||||||
|
R_UNLESS(report != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
R_TRY(Context::WriteContextsToReport(report.get()));
|
||||||
|
R_TRY(report->GetSize(std::addressof(record->info.report_size)));
|
||||||
|
|
||||||
|
if (!s_redirect_new_reports) {
|
||||||
|
/* If we're not redirecting new reports, then we want to store the report in the journal. */
|
||||||
|
R_TRY(Journal::Store(record));
|
||||||
|
} else {
|
||||||
|
/* If we are redirecting new reports, we don't want to store the report in the journal. */
|
||||||
|
/* We should take this opportunity to delete any attachments associated with the report. */
|
||||||
|
R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(this->report_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(Journal::Commit());
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reporter::SaveSyslogReportIfRequired() {
|
||||||
|
bool needs_save_syslog = true;
|
||||||
|
for (u32 i = 0; i < this->ctx->field_count; i++) {
|
||||||
|
static_assert(FieldToTypeMap[FieldId_HasSyslogFlag] == FieldType_Bool);
|
||||||
|
if (this->ctx->fields[i].id == FieldId_HasSyslogFlag && (this->ctx->fields[i].value_bool == false)) {
|
||||||
|
needs_save_syslog = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needs_save_syslog) {
|
||||||
|
/* Here nintendo sends a report to srepo:u (vtable offset 0xE8) with data this->report_id. */
|
||||||
|
/* We will not send report ids to srepo:u. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class Reporter {
|
||||||
|
private:
|
||||||
|
static bool s_redirect_new_reports;
|
||||||
|
static char s_serial_number[24];
|
||||||
|
static char s_os_version[24];
|
||||||
|
static char s_private_os_version[96];
|
||||||
|
static std::optional<os::Tick> s_application_launch_time;
|
||||||
|
static std::optional<os::Tick> s_awake_time;
|
||||||
|
static std::optional<os::Tick> s_power_on_time;
|
||||||
|
static std::optional<time::SteadyClockTimePoint> s_initial_launch_settings_completion_time;
|
||||||
|
private:
|
||||||
|
const ReportType type;
|
||||||
|
const ContextEntry * const ctx;
|
||||||
|
const u8 * const data;
|
||||||
|
const u32 data_size;
|
||||||
|
const ReportMetaData * const meta;
|
||||||
|
const AttachmentId * const attachments;
|
||||||
|
const u32 num_attachments;
|
||||||
|
char identifier_str[0x40];
|
||||||
|
time::PosixTime timestamp_user;
|
||||||
|
time::PosixTime timestamp_network;
|
||||||
|
os::Tick occurrence_tick;
|
||||||
|
s64 steady_clock_internal_offset_seconds;
|
||||||
|
ReportId report_id;
|
||||||
|
time::SteadyClockTimePoint steady_clock_current_timepoint;
|
||||||
|
public:
|
||||||
|
static void ClearApplicationLaunchTime() { s_application_launch_time = std::nullopt; }
|
||||||
|
static void ClearInitialLaunchSettingsCompletionTime() { s_initial_launch_settings_completion_time = std::nullopt; }
|
||||||
|
|
||||||
|
static void SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time) { s_initial_launch_settings_completion_time = time; }
|
||||||
|
|
||||||
|
static void UpdateApplicationLaunchTime() { s_application_launch_time = os::GetSystemTick(); }
|
||||||
|
static void UpdateAwakeTime() { s_awake_time = os::GetSystemTick(); }
|
||||||
|
static void UpdatePowerOnTime() { s_power_on_time = os::GetSystemTick(); }
|
||||||
|
|
||||||
|
static Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) {
|
||||||
|
R_UNLESS(sn_len <= sizeof(s_serial_number), erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(os_len <= sizeof(s_os_version), erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(os_priv_len <= sizeof(s_private_os_version), erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
std::memcpy(s_serial_number, sn, sn_len);
|
||||||
|
std::memcpy(s_os_version, os, os_len);
|
||||||
|
std::memcpy(s_private_os_version, os_priv, os_priv_len);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetRedirectNewReportsToSdCard(bool en) { s_redirect_new_reports = en; }
|
||||||
|
private:
|
||||||
|
Result ValidateReportContext();
|
||||||
|
Result CollectUniqueReportFields();
|
||||||
|
Result SubmitReportDefaults();
|
||||||
|
Result SubmitReportContexts();
|
||||||
|
Result LinkAttachments();
|
||||||
|
Result CreateReportFile();
|
||||||
|
void SaveSyslogReportIfRequired();
|
||||||
|
void SaveSyslogReport();
|
||||||
|
public:
|
||||||
|
Reporter(ReportType type, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments);
|
||||||
|
|
||||||
|
Result CreateReport();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
134
libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp
Normal file
134
libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_service.hpp"
|
||||||
|
#include "erpt_srv_context_impl.hpp"
|
||||||
|
#include "erpt_srv_session_impl.hpp"
|
||||||
|
#include "erpt_srv_stream.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct ErrorReportServerOptions {
|
||||||
|
static constexpr size_t PointerBufferSize = 0;
|
||||||
|
static constexpr size_t MaxDomains = 64;
|
||||||
|
static constexpr size_t MaxDomainObjects = 2 * ReportCountMax + 5 + 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline size_t ErrorReportNumServers = 2;
|
||||||
|
constexpr inline size_t ErrorReportReportSessions = 5;
|
||||||
|
constexpr inline size_t ErrorReportContextSessions = 10;
|
||||||
|
constexpr inline size_t ErrorReportMaxSessions = ErrorReportReportSessions + ErrorReportContextSessions;
|
||||||
|
|
||||||
|
constexpr inline s32 ErrorReportServerThreadPriority = 21;
|
||||||
|
|
||||||
|
constexpr inline sm::ServiceName ErrorReportContextServiceName = sm::ServiceName::Encode("erpt:c");
|
||||||
|
constexpr inline sm::ServiceName ErrorReportReportServiceName = sm::ServiceName::Encode("erpt:r");
|
||||||
|
|
||||||
|
alignas(os::ThreadStackAlignment) u8 g_server_thread_stack[16_KB];
|
||||||
|
|
||||||
|
class ErrorReportServiceManager : public ams::sf::hipc::ServerManager<ErrorReportNumServers, ErrorReportServerOptions, ErrorReportMaxSessions> {
|
||||||
|
private:
|
||||||
|
os::ThreadType thread;
|
||||||
|
std::shared_ptr<erpt::srv::ContextImpl> context_session_object;
|
||||||
|
private:
|
||||||
|
static void ThreadFunction(void *_this) {
|
||||||
|
reinterpret_cast<ErrorReportServiceManager *>(_this)->SetupAndLoopProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupAndLoopProcess();
|
||||||
|
public:
|
||||||
|
ErrorReportServiceManager(erpt::srv::ContextImpl *c)
|
||||||
|
: context_session_object(ams::sf::ServiceObjectTraits<erpt::srv::ContextImpl>::SharedPointerHelper::GetEmptyDeleteSharedPointer(c))
|
||||||
|
{
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Initialize() {
|
||||||
|
R_ABORT_UNLESS(this->RegisterServer<erpt::srv::ContextImpl>(ErrorReportContextServiceName, ErrorReportContextSessions, this->context_session_object));
|
||||||
|
R_ABORT_UNLESS(this->RegisterServer<erpt::srv::SessionImpl>(ErrorReportReportServiceName, ErrorReportReportSessions));
|
||||||
|
|
||||||
|
this->ResumeProcessing();
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->thread), ThreadFunction, this, g_server_thread_stack, sizeof(g_server_thread_stack), ErrorReportServerThreadPriority));
|
||||||
|
|
||||||
|
os::StartThread(std::addressof(this->thread));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait() {
|
||||||
|
os::WaitThread(std::addressof(this->thread));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ErrorReportServiceManager::SetupAndLoopProcess() {
|
||||||
|
const psc::PmModuleId dependencies[] = { psc::PmModuleId_Fs };
|
||||||
|
psc::PmModule pm_module;
|
||||||
|
psc::PmState pm_state;
|
||||||
|
psc::PmFlagSet pm_flags;
|
||||||
|
os::WaitableHolderType module_event_holder;
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(pm_module.Initialize(psc::PmModuleId_Erpt, dependencies, util::size(dependencies), os::EventClearMode_ManualClear));
|
||||||
|
|
||||||
|
os::InitializeWaitableHolder(std::addressof(module_event_holder), pm_module.GetEventPointer()->GetBase());
|
||||||
|
os::SetWaitableHolderUserData(std::addressof(module_event_holder), static_cast<uintptr_t>(psc::PmModuleId_Erpt));
|
||||||
|
this->AddUserWaitableHolder(std::addressof(module_event_holder));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
/* NOTE: Nintendo checks the user holder data to determine what's signaled, we will prefer to just check the address. */
|
||||||
|
auto *signaled_holder = this->WaitSignaled();
|
||||||
|
if (signaled_holder != std::addressof(module_event_holder)) {
|
||||||
|
R_ABORT_UNLESS(this->Process(signaled_holder));
|
||||||
|
} else {
|
||||||
|
pm_module.GetEventPointer()->Clear();
|
||||||
|
if (R_SUCCEEDED(pm_module.GetRequest(std::addressof(pm_state), std::addressof(pm_flags)))) {
|
||||||
|
switch (pm_state) {
|
||||||
|
case psc::PmState_Awake:
|
||||||
|
case psc::PmState_ReadyAwaken:
|
||||||
|
Stream::EnableFsAccess(true);
|
||||||
|
break;
|
||||||
|
case psc::PmState_ReadySleep:
|
||||||
|
case psc::PmState_ReadyShutdown:
|
||||||
|
Stream::EnableFsAccess(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
R_ABORT_UNLESS(pm_module.Acknowledge(pm_state, ResultSuccess()));
|
||||||
|
} else {
|
||||||
|
AMS_ASSERT(false);
|
||||||
|
}
|
||||||
|
this->AddUserWaitableHolder(signaled_holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
erpt::srv::ContextImpl g_context_object;
|
||||||
|
ErrorReportServiceManager g_erpt_server_manager(std::addressof(g_context_object));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InitializeService() {
|
||||||
|
return g_erpt_server_manager.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitService() {
|
||||||
|
return g_erpt_server_manager.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
Result InitializeService();
|
||||||
|
void WaitService();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_session_impl.hpp"
|
||||||
|
#include "erpt_srv_report_impl.hpp"
|
||||||
|
#include "erpt_srv_manager_impl.hpp"
|
||||||
|
#include "erpt_srv_attachment_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
Result SessionImpl::OpenReport(ams::sf::Out<std::shared_ptr<erpt::sf::IReport>> out) {
|
||||||
|
/* Create an interface. */
|
||||||
|
auto intf = std::shared_ptr<ReportImpl>(new (std::nothrow) ReportImpl);
|
||||||
|
R_UNLESS(intf != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* Return it. */
|
||||||
|
out.SetValue(std::move(intf));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SessionImpl::OpenManager(ams::sf::Out<std::shared_ptr<erpt::sf::IManager>> out) {
|
||||||
|
/* Create an interface. */
|
||||||
|
auto intf = std::shared_ptr<ManagerImpl>(new (std::nothrow) ManagerImpl);
|
||||||
|
R_UNLESS(intf != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* Return it. */
|
||||||
|
out.SetValue(std::move(intf));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SessionImpl::OpenAttachment(ams::sf::Out<std::shared_ptr<erpt::sf::IAttachment>> out) {
|
||||||
|
/* Create an interface. */
|
||||||
|
auto intf = std::shared_ptr<AttachmentImpl>(new (std::nothrow) AttachmentImpl);
|
||||||
|
R_UNLESS(intf != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* Return it. */
|
||||||
|
out.SetValue(std::move(intf));
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
class SessionImpl final : public erpt::sf::ISession {
|
||||||
|
public:
|
||||||
|
virtual Result OpenReport(ams::sf::Out<std::shared_ptr<erpt::sf::IReport>> out) override final;
|
||||||
|
virtual Result OpenManager(ams::sf::Out<std::shared_ptr<erpt::sf::IManager>> out) override final;
|
||||||
|
virtual Result OpenAttachment(ams::sf::Out<std::shared_ptr<erpt::sf::IAttachment>> out) override final;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
188
libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp
Normal file
188
libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "erpt_srv_allocator.hpp"
|
||||||
|
#include "erpt_srv_stream.hpp"
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
bool Stream::s_can_access_fs = true;
|
||||||
|
|
||||||
|
void Stream::EnableFsAccess(bool en) {
|
||||||
|
s_can_access_fs = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::DeleteStream(const char *path) {
|
||||||
|
R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState());
|
||||||
|
return fs::DeleteFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::CommitStream() {
|
||||||
|
R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState());
|
||||||
|
fs::CommitSaveData(ReportStoragePath);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::GetStreamSize(s64 *out, const char *path) {
|
||||||
|
R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState());
|
||||||
|
|
||||||
|
fs::FileHandle file;
|
||||||
|
R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read));
|
||||||
|
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||||
|
|
||||||
|
return fs::GetFileSize(out, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream::Stream() : buffer_size(0), file_position(0), buffer_count(0), buffer(nullptr), stream_mode(StreamMode_Invalid), initialized(false) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream::~Stream() {
|
||||||
|
this->CloseStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::OpenStream(const char *path, StreamMode mode, u32 buffer_size) {
|
||||||
|
R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState());
|
||||||
|
R_UNLESS(!this->initialized, erpt::ResultAlreadyInitialized());
|
||||||
|
|
||||||
|
if (mode == StreamMode_Write) {
|
||||||
|
while (true) {
|
||||||
|
R_TRY_CATCH(fs::OpenFile(std::addressof(this->file_handle), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend)) {
|
||||||
|
R_CATCH(fs::ResultPathNotFound) {
|
||||||
|
R_TRY(fs::CreateFile(path, 0));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fs::SetFileSize(this->file_handle, 0);
|
||||||
|
} else {
|
||||||
|
R_UNLESS(mode == StreamMode_Read, erpt::ResultInvalidArgument());
|
||||||
|
}
|
||||||
|
auto file_guard = SCOPE_GUARD { if (mode == StreamMode_Write) { fs::CloseFile(this->file_handle); } };
|
||||||
|
|
||||||
|
std::strncpy(this->file_name, path, sizeof(this->file_name));
|
||||||
|
|
||||||
|
this->buffer = reinterpret_cast<u8 *>(Allocate(buffer_size));
|
||||||
|
R_UNLESS(this->buffer != nullptr, erpt::ResultOutOfMemory());
|
||||||
|
|
||||||
|
this->buffer_size = buffer_size;
|
||||||
|
this->buffer_count = 0;
|
||||||
|
this->buffer_position = 0;
|
||||||
|
this->file_position = 0;
|
||||||
|
this->stream_mode = mode;
|
||||||
|
this->initialized = true;
|
||||||
|
|
||||||
|
file_guard.Cancel();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::ReadStream(u32 *out, u8 *dst, u32 dst_size) {
|
||||||
|
R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState());
|
||||||
|
R_UNLESS(this->initialized, erpt::ResultNotInitialized());
|
||||||
|
R_UNLESS(this->stream_mode == StreamMode_Read, erpt::ResultNotInitialized());
|
||||||
|
R_UNLESS(out != nullptr, erpt::ResultInvalidArgument());
|
||||||
|
R_UNLESS(dst != nullptr, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
fs::FileHandle tmp_file;
|
||||||
|
size_t fs_read_size;
|
||||||
|
u32 read_count = 0;
|
||||||
|
bool opened = false;
|
||||||
|
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
*out = read_count;
|
||||||
|
|
||||||
|
if (opened) {
|
||||||
|
fs::CloseFile(tmp_file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while (dst_size > 0) {
|
||||||
|
if (u32 cur = std::min<u32>(this->buffer_count - this->buffer_position, dst_size); cur > 0) {
|
||||||
|
std::memcpy(dst, this->buffer + this->buffer_position, cur);
|
||||||
|
this->buffer_position += cur;
|
||||||
|
dst += cur;
|
||||||
|
dst_size -= cur;
|
||||||
|
read_count += cur;
|
||||||
|
} else {
|
||||||
|
if (!opened) {
|
||||||
|
R_TRY(fs::OpenFile(std::addressof(tmp_file), this->file_name, fs::OpenMode_Read));
|
||||||
|
opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(fs::ReadFile(std::addressof(fs_read_size), tmp_file, this->file_position, this->buffer, this->buffer_size));
|
||||||
|
|
||||||
|
this->buffer_position = 0;
|
||||||
|
this->file_position += static_cast<u32>(fs_read_size);
|
||||||
|
this->buffer_count = static_cast<u32>(fs_read_size);
|
||||||
|
|
||||||
|
if (this->buffer_count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::WriteStream(const u8 *src, u32 src_size) {
|
||||||
|
R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState());
|
||||||
|
R_UNLESS(this->initialized, erpt::ResultNotInitialized());
|
||||||
|
R_UNLESS(this->stream_mode == StreamMode_Write, erpt::ResultNotInitialized());
|
||||||
|
R_UNLESS(src != nullptr || src_size == 0, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
|
while (src_size > 0) {
|
||||||
|
if (u32 cur = std::min<u32>(this->buffer_size - this->buffer_count, src_size); cur > 0) {
|
||||||
|
std::memcpy(this->buffer + this->buffer_count, src, cur);
|
||||||
|
this->buffer_count += cur;
|
||||||
|
src += cur;
|
||||||
|
src_size -= cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->buffer_count == this->buffer_size) {
|
||||||
|
R_TRY(this->Flush());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::CloseStream() {
|
||||||
|
if (this->initialized) {
|
||||||
|
if (s_can_access_fs && this->stream_mode == StreamMode_Write) {
|
||||||
|
this->Flush();
|
||||||
|
fs::FlushFile(this->file_handle);
|
||||||
|
fs::CloseFile(this->file_handle);
|
||||||
|
}
|
||||||
|
Deallocate(this->buffer);
|
||||||
|
this->initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::GetStreamSize(s64 *out) {
|
||||||
|
return GetStreamSize(out, this->file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Stream::Flush() {
|
||||||
|
R_SUCCEED_IF(this->buffer_count == 0);
|
||||||
|
R_TRY(fs::WriteFile(this->file_handle, this->file_position, this->buffer, this->buffer_count, fs::WriteOption::None));
|
||||||
|
|
||||||
|
this->file_position += this->buffer_count;
|
||||||
|
this->buffer_count = 0;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
|
enum StreamMode {
|
||||||
|
StreamMode_Write = 0,
|
||||||
|
StreamMode_Read = 1,
|
||||||
|
StreamMode_Invalid = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Stream {
|
||||||
|
private:
|
||||||
|
static bool s_can_access_fs;
|
||||||
|
private:
|
||||||
|
u32 buffer_size;
|
||||||
|
u32 file_position;
|
||||||
|
u32 buffer_position;
|
||||||
|
u32 buffer_count;
|
||||||
|
u8 *buffer;
|
||||||
|
StreamMode stream_mode;
|
||||||
|
bool initialized;
|
||||||
|
fs::FileHandle file_handle;
|
||||||
|
char file_name[ReportFileNameLength];
|
||||||
|
public:
|
||||||
|
Stream();
|
||||||
|
~Stream();
|
||||||
|
|
||||||
|
Result OpenStream(const char *path, StreamMode mode, u32 buffer_size);
|
||||||
|
Result ReadStream(u32 *out, u8 *dst, u32 dst_size);
|
||||||
|
Result WriteStream(const u8 *src, u32 src_size);
|
||||||
|
void CloseStream();
|
||||||
|
|
||||||
|
Result GetStreamSize(s64 *out);
|
||||||
|
private:
|
||||||
|
Result Flush();
|
||||||
|
public:
|
||||||
|
static void EnableFsAccess(bool en);
|
||||||
|
static Result DeleteStream(const char *path);
|
||||||
|
static Result CommitStream();
|
||||||
|
static Result GetStreamSize(s64 *out, const char *path);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -116,4 +116,24 @@ namespace ams::fs {
|
||||||
return impl::WriteSaveDataFileSystemExtraData(space_id, id, extra_data);
|
return impl::WriteSaveDataFileSystemExtraData(space_id, id, extra_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetSaveDataAvailableSize(s64 *out, SaveDataId id) {
|
||||||
|
SaveDataExtraData extra_data;
|
||||||
|
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id));
|
||||||
|
|
||||||
|
*out = extra_data.available_size;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetSaveDataJournalSize(s64 *out, SaveDataId id) {
|
||||||
|
SaveDataExtraData extra_data;
|
||||||
|
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id));
|
||||||
|
|
||||||
|
*out = extra_data.journal_size;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size) {
|
||||||
|
return ::fsExtendSaveDataFileSystem(static_cast<::FsSaveDataSpaceId>(space_id), static_cast<u64>(id), available_size, journal_size);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace ams::fs {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const char AtmosphereErrorReportDirectory[] = "/atmosphere/erpt_reports";
|
||||||
|
|
||||||
/* NOTE: Nintendo does not attach a generator to a mounted SD card filesystem. */
|
/* NOTE: Nintendo does not attach a generator to a mounted SD card filesystem. */
|
||||||
/* However, it is desirable for homebrew to be able to access SD via common path. */
|
/* However, it is desirable for homebrew to be able to access SD via common path. */
|
||||||
class SdCardCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
|
class SdCardCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
|
||||||
|
@ -63,4 +65,27 @@ namespace ams::fs {
|
||||||
return fsa::Register(name, std::move(fsa), std::move(generator));
|
return fsa::Register(name, std::move(fsa), std::move(generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name) {
|
||||||
|
/* Validate the mount name. */
|
||||||
|
R_TRY(impl::CheckMountName(name));
|
||||||
|
|
||||||
|
/* Open the SD card. This uses libnx bindings. */
|
||||||
|
FsFileSystem fs;
|
||||||
|
R_TRY(fsOpenSdCardFileSystem(std::addressof(fs)));
|
||||||
|
|
||||||
|
/* Allocate a new filesystem wrapper. */
|
||||||
|
std::unique_ptr<fsa::IFileSystem> fsa = std::make_unique<RemoteFileSystem>(fs);
|
||||||
|
R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInSdCardA());
|
||||||
|
|
||||||
|
/* Ensure that the error report directory exists. */
|
||||||
|
R_TRY(fssystem::EnsureDirectoryRecursively(fsa.get(), AtmosphereErrorReportDirectory));
|
||||||
|
|
||||||
|
/* Create a subdirectory filesystem. */
|
||||||
|
auto subdir_fs = std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(fsa), AtmosphereErrorReportDirectory);
|
||||||
|
R_UNLESS(subdir_fs != nullptr, fs::ResultAllocationFailureInSdCardA());
|
||||||
|
|
||||||
|
/* Register. */
|
||||||
|
return fsa::Register(name, std::move(subdir_fs));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "psc_remote_pm_module.hpp"
|
||||||
|
|
||||||
|
namespace ams::psc {
|
||||||
|
|
||||||
|
PmModule::PmModule() : intf(nullptr), initialized(false), reserved(0) { /* ... */ }
|
||||||
|
|
||||||
|
PmModule::~PmModule() {
|
||||||
|
if (this->initialized) {
|
||||||
|
this->intf = nullptr;
|
||||||
|
os::DestroySystemEvent(this->system_event.GetBase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmModule::Initialize(const PmModuleId mid, const PmModuleId *dependencies, u32 dependency_count, os::EventClearMode clear_mode) {
|
||||||
|
R_UNLESS(!this->initialized, psc::ResultAlreadyInitialized());
|
||||||
|
|
||||||
|
static_assert(sizeof(*dependencies) == sizeof(u16));
|
||||||
|
::PscPmModule module;
|
||||||
|
R_TRY(::pscmGetPmModule(std::addressof(module), static_cast<::PscPmModuleId>(mid), reinterpret_cast<const u16 *>(dependencies), dependency_count, clear_mode == os::EventClearMode_AutoClear));
|
||||||
|
|
||||||
|
this->intf = std::make_shared<RemotePmModule>(module);
|
||||||
|
this->system_event.AttachReadableHandle(module.event.revent, false, clear_mode);
|
||||||
|
this->initialized = true;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmModule::Finalize() {
|
||||||
|
R_UNLESS(this->initialized, psc::ResultNotInitialized());
|
||||||
|
|
||||||
|
R_TRY(this->intf->Finalize());
|
||||||
|
this->intf = nullptr;
|
||||||
|
os::DestroySystemEvent(this->system_event.GetBase());
|
||||||
|
this->initialized = false;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmModule::GetRequest(PmState *out_state, PmFlagSet *out_flags) {
|
||||||
|
R_UNLESS(this->initialized, psc::ResultNotInitialized());
|
||||||
|
|
||||||
|
return this->intf->GetRequest(out_state, out_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PmModule::Acknowledge(PmState state, Result res) {
|
||||||
|
R_ABORT_UNLESS(res);
|
||||||
|
R_UNLESS(this->initialized, psc::ResultNotInitialized());
|
||||||
|
|
||||||
|
if (hos::GetVersion() >= hos::Version_600) {
|
||||||
|
return this->intf->AcknowledgeEx(state);
|
||||||
|
} else {
|
||||||
|
return this->intf->Acknowledge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os::SystemEvent *PmModule::GetEventPointer() {
|
||||||
|
return std::addressof(this->system_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::psc {
|
||||||
|
|
||||||
|
class RemotePmModule final : public psc::sf::IPmModule {
|
||||||
|
NON_COPYABLE(RemotePmModule);
|
||||||
|
NON_MOVEABLE(RemotePmModule);
|
||||||
|
private:
|
||||||
|
::PscPmModule module;
|
||||||
|
public:
|
||||||
|
constexpr RemotePmModule(const ::PscPmModule &m) : module(m) { /* ... */ }
|
||||||
|
virtual ~RemotePmModule() override {
|
||||||
|
::pscPmModuleClose(std::addressof(this->module));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Initialize(ams::sf::OutCopyHandle out, psc::PmModuleId module_id, const ams::sf::InBuffer &child_list) override final {
|
||||||
|
/* NOTE: This functionality is already implemented by the libnx command we use to instantiate the PscPmModule. */
|
||||||
|
AMS_ABORT();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result GetRequest(ams::sf::Out<PmState> out_state, ams::sf::Out<PmFlagSet> out_flags) override final {
|
||||||
|
static_assert(sizeof(PmState) == sizeof(::PscPmState));
|
||||||
|
static_assert(sizeof(PmFlagSet) == sizeof(u32));
|
||||||
|
return ::pscPmModuleGetRequest(std::addressof(this->module), reinterpret_cast<::PscPmState *>(out_state.GetPointer()), reinterpret_cast<u32 *>(out_flags.GetPointer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Acknowledge() override final {
|
||||||
|
/* NOTE: libnx does not separate acknowledge/acknowledgeEx. */
|
||||||
|
return ::pscPmModuleAcknowledge(std::addressof(this->module), static_cast<::PscPmState>(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result Finalize() override final {
|
||||||
|
return ::pscPmModuleFinalize(std::addressof(this->module));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result AcknowledgeEx(PmState state) override final {
|
||||||
|
static_assert(sizeof(state) == sizeof(::PscPmState));
|
||||||
|
return ::pscPmModuleAcknowledge(std::addressof(this->module), static_cast<::PscPmState>(state));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_firmware_version_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetFirmwareVersion(settings::system::FirmwareVersion *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(::SetSysFirmwareVersion));
|
||||||
|
return ::setsysGetFirmwareVersion(reinterpret_cast<::SetSysFirmwareVersion *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetFirmwareVersion(settings::system::FirmwareVersion *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_product_model_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetProductModel(s32 *out) {
|
||||||
|
return ::setsysGetProductModel(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetProductModel(s32 *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_region_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetRegionCode(s32 *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(::SetRegion));
|
||||||
|
return ::setGetRegionCode(reinterpret_cast<::SetRegion *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetRegionCode(s32 *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "settings_serial_number_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetSerialNumber(settings::system::SerialNumber *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(::SetSysSerialNumber));
|
||||||
|
return ::setsysGetSerialNumber(reinterpret_cast<::SetSysSerialNumber *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::settings::impl {
|
||||||
|
|
||||||
|
Result GetSerialNumber(settings::system::SerialNumber *out);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/settings_firmware_version_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
void GetFirmwareVersion(FirmwareVersion *out) {
|
||||||
|
R_ABORT_UNLESS(settings::impl::GetFirmwareVersion(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/settings_product_model_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
ProductModel GetProductModel() {
|
||||||
|
s32 model = 0;
|
||||||
|
R_ABORT_UNLESS(settings::impl::GetProductModel(std::addressof(model)));
|
||||||
|
return static_cast<ProductModel>(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/settings_region_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
void GetRegionCode(RegionCode *out) {
|
||||||
|
AMS_ABORT_UNLESS(out != nullptr);
|
||||||
|
s32 value = 0;
|
||||||
|
R_ABORT_UNLESS(settings::impl::GetRegionCode(std::addressof(value)));
|
||||||
|
*out = static_cast<RegionCode>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/settings_serial_number_impl.hpp"
|
||||||
|
|
||||||
|
namespace ams::settings::system {
|
||||||
|
|
||||||
|
void GetSerialNumber(SerialNumber *out) {
|
||||||
|
R_ABORT_UNLESS(settings::impl::GetSerialNumber(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::time::impl::util {
|
||||||
|
|
||||||
|
Result GetSpanBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to) {
|
||||||
|
AMS_ASSERT(out != nullptr);
|
||||||
|
|
||||||
|
R_UNLESS(out != nullptr, time::ResultInvalidPointer());
|
||||||
|
R_UNLESS(from.source_id == to.source_id, time::ResultNotComparable());
|
||||||
|
|
||||||
|
const bool no_overflow = (from.value >= 0 ? (to.value >= std::numeric_limits<s64>::min() + from.value)
|
||||||
|
: (to.value <= std::numeric_limits<s64>::max() + from.value));
|
||||||
|
R_UNLESS(no_overflow, time::ResultOverflowed());
|
||||||
|
|
||||||
|
*out = to.value - from.value;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
libraries/libstratosphere/source/time/time_api.cpp
Normal file
105
libraries/libstratosphere/source/time/time_api.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern TimeServiceType __nx_time_service_type;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
enum InitializeMode {
|
||||||
|
InitializeMode_None,
|
||||||
|
InitializeMode_Normal,
|
||||||
|
InitializeMode_Menu,
|
||||||
|
InitializeMode_System,
|
||||||
|
InitializeMode_Repair,
|
||||||
|
InitializeMode_SystemUser,
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 g_initialize_count = 0;
|
||||||
|
InitializeMode g_initialize_mode = InitializeMode_None;
|
||||||
|
|
||||||
|
/* TODO: os::SdkMutex */
|
||||||
|
os::Mutex g_initialize_mutex(false);
|
||||||
|
|
||||||
|
Result InitializeImpl(InitializeMode mode) {
|
||||||
|
std::scoped_lock lk(g_initialize_mutex);
|
||||||
|
|
||||||
|
if (g_initialize_count > 0) {
|
||||||
|
AMS_ABORT_UNLESS(mode == g_initialize_mode);
|
||||||
|
g_initialize_count++;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case InitializeMode_Normal: __nx_time_service_type = ::TimeServiceType_User; break;
|
||||||
|
case InitializeMode_Menu: __nx_time_service_type = ::TimeServiceType_Menu; break;
|
||||||
|
case InitializeMode_System: __nx_time_service_type = ::TimeServiceType_System; break;
|
||||||
|
case InitializeMode_Repair: __nx_time_service_type = ::TimeServiceType_Repair; break;
|
||||||
|
case InitializeMode_SystemUser: __nx_time_service_type = ::TimeServiceType_SystemUser; break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(::timeInitialize());
|
||||||
|
|
||||||
|
g_initialize_count++;
|
||||||
|
g_initialize_mode = mode;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Initialize() {
|
||||||
|
return InitializeImpl(InitializeMode_Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InitializeForSystem() {
|
||||||
|
return InitializeImpl(InitializeMode_System);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InitializeForSystemUser() {
|
||||||
|
return InitializeImpl(InitializeMode_System);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Finalize() {
|
||||||
|
std::scoped_lock lk(g_initialize_mutex);
|
||||||
|
|
||||||
|
if (g_initialize_count > 0) {
|
||||||
|
if ((--g_initialize_count) == 0) {
|
||||||
|
::timeExit();
|
||||||
|
g_initialize_mode = InitializeMode_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInitialized() {
|
||||||
|
std::scoped_lock lk(g_initialize_mutex);
|
||||||
|
|
||||||
|
return g_initialize_count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetElapsedSecondsBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to) {
|
||||||
|
return impl::util::GetSpanBetween(out, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
Result StandardNetworkSystemClock::GetCurrentTime(PosixTime *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(u64));
|
||||||
|
return ::timeGetCurrentTime(::TimeType_NetworkSystemClock, reinterpret_cast<u64 *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardNetworkSystemClock::time_point StandardNetworkSystemClock::now() {
|
||||||
|
PosixTime posix_time = {};
|
||||||
|
if (R_FAILED(GetCurrentTime(std::addressof(posix_time)))) {
|
||||||
|
posix_time.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return time_point(duration(posix_time.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::time_t StandardNetworkSystemClock::to_time_t(const StandardNetworkSystemClock::time_point &t) {
|
||||||
|
return static_cast<std::time_t>(std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardNetworkSystemClock::time_point StandardNetworkSystemClock::from_time_t(std::time_t t) {
|
||||||
|
return time_point(duration(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Result StandardNetworkSystemClock::GetSystemClockContext(SystemClockContext *out); */
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
Result GetStandardSteadyClockCurrentTimePoint(SteadyClockTimePoint *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(::TimeSteadyClockTimePoint));
|
||||||
|
return ::timeGetStandardSteadyClockTimePoint(reinterpret_cast<::TimeSteadyClockTimePoint *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan GetStandardSteadyClockInternalOffset() {
|
||||||
|
static_assert(sizeof(TimeSpanType) == sizeof(s64));
|
||||||
|
TimeSpanType offset;
|
||||||
|
R_ABORT_UNLESS(::timeGetStandardSteadyClockInternalOffset(reinterpret_cast<s64 *>(std::addressof(offset))));
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result StandardSteadyClock::GetCurrentTimePoint(SteadyClockTimePoint *out) {
|
||||||
|
return GetStandardSteadyClockCurrentTimePoint(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardSteadyClock::time_point StandardSteadyClock::now() {
|
||||||
|
SteadyClockTimePoint steady_clock_time_point = {0, util::InvalidUuid};
|
||||||
|
if (R_FAILED(StandardSteadyClock::GetCurrentTimePoint(std::addressof(steady_clock_time_point)))) {
|
||||||
|
steady_clock_time_point.value = 0;
|
||||||
|
steady_clock_time_point.source_id = util::InvalidUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StandardSteadyClock::time_point(StandardSteadyClock::duration(steady_clock_time_point.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::time {
|
||||||
|
|
||||||
|
Result StandardUserSystemClock::GetCurrentTime(PosixTime *out) {
|
||||||
|
static_assert(sizeof(*out) == sizeof(u64));
|
||||||
|
return ::timeGetCurrentTime(::TimeType_UserSystemClock, reinterpret_cast<u64 *>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardUserSystemClock::time_point StandardUserSystemClock::now() {
|
||||||
|
PosixTime posix_time = {};
|
||||||
|
if (R_FAILED(GetCurrentTime(std::addressof(posix_time)))) {
|
||||||
|
posix_time.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return time_point(duration(posix_time.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::time_t StandardUserSystemClock::to_time_t(const StandardUserSystemClock::time_point &t) {
|
||||||
|
return static_cast<std::time_t>(std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardUserSystemClock::time_point StandardUserSystemClock::from_time_t(std::time_t t) {
|
||||||
|
return time_point(duration(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Result StandardUserSystemClock::GetSystemClockContext(SystemClockContext *out); */
|
||||||
|
|
||||||
|
}
|
|
@ -28,3 +28,5 @@
|
||||||
#include <vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp>
|
#include <vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp>
|
||||||
#include <vapours/crypto/crypto_rsa_oaep_sha256_decoder.hpp>
|
#include <vapours/crypto/crypto_rsa_oaep_sha256_decoder.hpp>
|
||||||
#include <vapours/crypto/crypto_rsa_oaep_sha256_decryptor.hpp>
|
#include <vapours/crypto/crypto_rsa_oaep_sha256_decryptor.hpp>
|
||||||
|
#include <vapours/crypto/crypto_rsa_oaep_sha256_encryptor.hpp>
|
||||||
|
#include <vapours/crypto/crypto_csrng.hpp>
|
||||||
|
|
26
libraries/libvapours/include/vapours/crypto/crypto_csrng.hpp
Normal file
26
libraries/libvapours/include/vapours/crypto/crypto_csrng.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours/common.hpp>
|
||||||
|
#include <vapours/assert.hpp>
|
||||||
|
#include <vapours/util.hpp>
|
||||||
|
|
||||||
|
namespace ams::crypto {
|
||||||
|
|
||||||
|
void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size);
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue