sprof: update for 13.1.0 (format version 1)

This commit is contained in:
Michael Scire 2021-10-26 00:51:44 -07:00
parent a14dc6ed89
commit 0e81eac9d1
12 changed files with 119 additions and 85 deletions

View File

@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
constexpr const sm::ServiceName ServiceNameForSystemProcess = sm::ServiceName::Encode("sprof:sp"); constexpr const sm::ServiceName ServiceNameForSystemProcess = sm::ServiceName::Encode("sprof:sp");
constexpr inline size_t BgAgentSessionCountMax = 2; constexpr inline size_t BgAgentSessionCountMax = 2;
constexpr inline size_t SystemProcessSessionCountMax = 5; constexpr inline size_t SystemProcessSessionCountMax = 10;
constexpr inline size_t SessionCountMax = BgAgentSessionCountMax + SystemProcessSessionCountMax; constexpr inline size_t SessionCountMax = BgAgentSessionCountMax + SystemProcessSessionCountMax;
@ -42,8 +42,8 @@ namespace ams::sprofile::srv {
struct ServerManagerOptions { struct ServerManagerOptions {
static constexpr size_t PointerBufferSize = 0x0; static constexpr size_t PointerBufferSize = 0x0;
static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 3 */ static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 9 */
static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 8 */ static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 14 */
static constexpr bool CanDeferInvokeRequest = false; static constexpr bool CanDeferInvokeRequest = false;
static constexpr bool CanManageMitmServers = false; static constexpr bool CanManageMitmServers = false;
}; };

View File

@ -18,8 +18,8 @@
#include "sprofile_srv_types.hpp" #include "sprofile_srv_types.hpp"
#define AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO(C, H) \ #define AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &data), (data)) \ AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &import), (import)) \
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &data), (data)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &import), (import)) \
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileImporter, AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO) AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileImporter, AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO)

View File

@ -21,6 +21,6 @@
AMS_SF_METHOD_INFO(C, H, 1, Result, GetUnsigned64, (sf::Out<u64> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetUnsigned64, (sf::Out<u64> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, GetSigned32, (sf::Out<s32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetSigned32, (sf::Out<s32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
AMS_SF_METHOD_INFO(C, H, 3, Result, GetUnsigned32, (sf::Out<u32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetUnsigned32, (sf::Out<u32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
AMS_SF_METHOD_INFO(C, H, 3, Result, GetByte, (sf::Out<u8> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) AMS_SF_METHOD_INFO(C, H, 4, Result, GetByte, (sf::Out<u8> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key))
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileReader, AMS_SPROFILE_I_PROFILE_READER_INTERFACE_INFO) AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileReader, AMS_SPROFILE_I_PROFILE_READER_INTERFACE_INFO)

View File

@ -19,7 +19,7 @@
#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \ #define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 200, Result, ReadMetadata, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg), (out_count, out, arg)) \ AMS_SF_METHOD_INFO(C, H, 200, Result, GetMetadataEntryData, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \ AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ()) AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())

View File

@ -38,7 +38,7 @@ namespace ams::sprofile::srv {
bool HasProfile(Identifier id0, Identifier id1) { bool HasProfile(Identifier id0, Identifier id1) {
/* Require that we have metadata. */ /* Require that we have metadata. */
if (m_metadata.has_value()) { if (m_metadata.has_value()) {
for (auto i = 0u; i < m_metadata->num_entries; ++i) { for (auto i = 0u; i < std::min<size_t>(m_metadata->num_entries, util::size(m_metadata->entries)); ++i) {
const auto &entry = m_metadata->entries[i]; const auto &entry = m_metadata->entries[i];
if (entry.identifier_0 == id0 && entry.identifier_1 == id1) { if (entry.identifier_0 == id0 && entry.identifier_1 == id1) {
return true; return true;
@ -63,7 +63,7 @@ namespace ams::sprofile::srv {
m_revision_key = meta.revision_key; m_revision_key = meta.revision_key;
/* Import all profiles. */ /* Import all profiles. */
for (auto i = 0u; i < meta.num_entries; ++i) { for (auto i = 0u; i < std::min<size_t>(meta.num_entries, util::size(meta.entries)); ++i) {
const auto &import_entry = meta.entries[i]; const auto &import_entry = meta.entries[i];
if (!this->HasProfile(import_entry.identifier_0, import_entry.identifier_1)) { if (!this->HasProfile(import_entry.identifier_0, import_entry.identifier_1)) {
m_importing_profiles[m_importing_count++] = import_entry.identifier_0; m_importing_profiles[m_importing_count++] = import_entry.identifier_0;

View File

@ -19,16 +19,16 @@
namespace ams::sprofile::srv { namespace ams::sprofile::srv {
Result ProfileImporterImpl::ImportProfile(const sprofile::srv::ProfileDataForImportData &data) { Result ProfileImporterImpl::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
return m_manager->ImportProfile(data); return m_manager->ImportProfile(import);
} }
Result ProfileImporterImpl::Commit() { Result ProfileImporterImpl::Commit() {
return m_manager->Commit(); return m_manager->Commit();
} }
Result ProfileImporterImpl::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data) { Result ProfileImporterImpl::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) {
return m_manager->ImportMetadata(data); return m_manager->ImportMetadata(import);
} }
} }

View File

@ -27,9 +27,9 @@ namespace ams::sprofile::srv {
public: public:
ProfileImporterImpl(ProfileManager *manager) : m_manager(manager) { /* ... */ } ProfileImporterImpl(ProfileManager *manager) : m_manager(manager) { /* ... */ }
public: public:
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &data); Result ImportProfile(const sprofile::srv::ProfileDataForImportData &import);
Result Commit(); Result Commit();
Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data); Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import);
}; };
static_assert(IsIProfileImporter<ProfileImporterImpl>); static_assert(IsIProfileImporter<ProfileImporterImpl>);

View File

@ -151,7 +151,7 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &data) { Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
/* Acquire locks. */ /* Acquire locks. */
std::scoped_lock lk1(m_profile_importer_mutex); std::scoped_lock lk1(m_profile_importer_mutex);
std::scoped_lock lk2(m_fs_mutex); std::scoped_lock lk2(m_fs_mutex);
@ -159,25 +159,37 @@ namespace ams::sprofile::srv {
/* Check that we have an importer. */ /* Check that we have an importer. */
R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState()); R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState());
/* Check that the metadata we're importing is valid. */ /* Check that the metadata we're importing is a valid version. */
R_UNLESS(data.data.version == ProfileDataVersion, sprofile::ResultInvalidDataVersion()); R_UNLESS(IsValidProfileFormatVersion(import.header.version), sprofile::ResultInvalidDataVersion());
/* Check that the metadata we're importing has a valid hash. */
{
crypto::Md5Generator md5;
md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.data), sizeof(import.data) - sizeof(import.data.entries[0]) * (util::size(import.data.entries) - std::min<size_t>(import.data.num_entries, util::size(import.data.entries))));
u8 hash[crypto::Md5Generator::HashSize];
md5.GetHash(hash, sizeof(hash));
R_UNLESS(crypto::IsSameBytes(hash, import.hash, sizeof(hash)), sprofile::ResultInvalidDataHash());
}
/* Succeed if we already have the profile. */ /* Succeed if we already have the profile. */
R_SUCCEED_IF(m_profile_importer->HasProfile(data.identifier_0, data.identifier_1)); R_SUCCEED_IF(m_profile_importer->HasProfile(import.header.identifier_0, import.header.identifier_1));
/* Check that we're importing the profile. */ /* Check that we're importing the profile. */
R_UNLESS(m_profile_importer->CanImportProfile(data.identifier_0), sprofile::ResultInvalidState()); R_UNLESS(m_profile_importer->CanImportProfile(import.header.identifier_0), sprofile::ResultInvalidState());
/* Create temporary directories. */ /* Create temporary directories. */
R_TRY(this->EnsureTemporaryDirectories()); R_TRY(this->EnsureTemporaryDirectories());
/* Create profile. */ /* Create profile. */
char path[0x30]; char path[0x30];
CreateTemporaryProfilePath(path, sizeof(path), m_save_data_info.mount_name, data.identifier_0); CreateTemporaryProfilePath(path, sizeof(path), m_save_data_info.mount_name, import.header.identifier_0);
R_TRY(WriteFile(path, std::addressof(data.data), sizeof(data.data))); R_TRY(WriteFile(path, std::addressof(import.data), sizeof(import.data)));
/* Set profile imported. */ /* Set profile imported. */
m_profile_importer->OnImportProfile(data.identifier_0); m_profile_importer->OnImportProfile(import.header.identifier_0);
return ResultSuccess(); return ResultSuccess();
} }
@ -231,7 +243,7 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data) { Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) {
/* Acquire locks. */ /* Acquire locks. */
std::scoped_lock lk1(m_profile_importer_mutex); std::scoped_lock lk1(m_profile_importer_mutex);
std::scoped_lock lk2(m_fs_mutex); std::scoped_lock lk2(m_fs_mutex);
@ -240,8 +252,21 @@ namespace ams::sprofile::srv {
R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState()); R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState());
R_UNLESS(m_profile_importer->CanImportMetadata(), sprofile::ResultInvalidState()); R_UNLESS(m_profile_importer->CanImportMetadata(), sprofile::ResultInvalidState());
/* Check that the metadata we're importing is valid. */ /* Check that the metadata we're importing is a valid version. */
R_UNLESS(data.metadata.version == ProfileMetadataVersion, sprofile::ResultInvalidMetadataVersion()); R_UNLESS(IsValidProfileFormatVersion(import.header.version), sprofile::ResultInvalidMetadataVersion());
/* Check that the metadata we're importing has a valid hash. */
{
crypto::Md5Generator md5;
md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.metadata), sizeof(import.metadata));
md5.Update(std::addressof(import.entries), sizeof(import.entries[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries)));
u8 hash[crypto::Md5Generator::HashSize];
md5.GetHash(hash, sizeof(hash));
R_UNLESS(crypto::IsSameBytes(hash, import.hash, sizeof(hash)), sprofile::ResultInvalidMetadataHash());
}
/* Create temporary directories. */ /* Create temporary directories. */
R_TRY(this->EnsureTemporaryDirectories()); R_TRY(this->EnsureTemporaryDirectories());
@ -249,10 +274,10 @@ namespace ams::sprofile::srv {
/* Create metadata. */ /* Create metadata. */
char path[0x30]; char path[0x30];
CreateTemporaryMetadataPath(path, sizeof(path), m_save_data_info.mount_name); CreateTemporaryMetadataPath(path, sizeof(path), m_save_data_info.mount_name);
R_TRY(WriteFile(path, std::addressof(data.metadata), sizeof(data.metadata))); R_TRY(WriteFile(path, std::addressof(import.metadata), sizeof(import.metadata)));
/* Import the metadata. */ /* Import the metadata. */
m_profile_importer->ImportMetadata(data.metadata); m_profile_importer->ImportMetadata(import.metadata);
return ResultSuccess(); return ResultSuccess();
} }
@ -309,15 +334,15 @@ namespace ams::sprofile::srv {
std::scoped_lock lk2(m_general_mutex); std::scoped_lock lk2(m_general_mutex);
/* Load the desired profile. */ /* Load the desired profile. */
R_TRY(this->LoadProfile(profile)); if (R_SUCCEEDED(this->LoadProfile(profile))) {
/* Find the specified key. */ /* Find the specified key. */
for (auto i = 0u; i < m_service_profile->data.num_entries; ++i) { for (auto i = 0u; i < std::min<size_t>(m_service_profile->data.num_entries, util::size(m_service_profile->data.entries)); ++i) {
if (m_service_profile->data.entries[i].key == key) { if (m_service_profile->data.entries[i].key == key) {
*out = m_service_profile->data.entries[i]; *out = m_service_profile->data.entries[i];
return ResultSuccess(); return ResultSuccess();
} }
} }
}
return sprofile::ResultKeyNotFound(); return sprofile::ResultKeyNotFound();
} }
@ -426,6 +451,8 @@ namespace ams::sprofile::srv {
} }
void ProfileManager::OnCommitted() { void ProfileManager::OnCommitted() {
/* TODO: Here, Nintendo sets the erpt ServiceProfileRevisionKey to the current revision key. */
/* If we need to, invalidate the loaded service profile. */ /* If we need to, invalidate the loaded service profile. */
if (m_service_profile.has_value()) { if (m_service_profile.has_value()) {
for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) { for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) {
@ -436,8 +463,6 @@ namespace ams::sprofile::srv {
} }
} }
/* TODO: Here, Nintendo sets the erpt ServiceProfileRevisionKey to the current revision key. */
/* Reset profile metadata. */ /* Reset profile metadata. */
m_profile_metadata = util::nullopt; m_profile_metadata = util::nullopt;
@ -445,6 +470,9 @@ namespace ams::sprofile::srv {
for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) { for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) {
m_update_observer_manager.OnUpdate(m_profile_importer->GetImportingProfile(i)); m_update_observer_manager.OnUpdate(m_profile_importer->GetImportingProfile(i));
} }
/* Reset profile importer. */
m_profile_importer = util::nullopt;
} }
Result ProfileManager::EnsurePrimaryDirectories() { Result ProfileManager::EnsurePrimaryDirectories() {

View File

@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
return ResultSuccess(); return ResultSuccess();
} }
Result ServiceForBgAgent::ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg) { Result ServiceForBgAgent::GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) {
/* Check size. */ /* Check size. */
R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument()); R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument());

View File

@ -29,7 +29,7 @@ namespace ams::sprofile::srv {
constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ } constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ }
public: public:
Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out); Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out);
Result ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg); Result GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg);
Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key); Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key);
Result Reset(); Result Reset();
}; };

View File

@ -18,34 +18,11 @@
namespace ams::sprofile::srv { namespace ams::sprofile::srv {
struct ProfileMetadataEntry { constexpr inline const u32 ProfileFormatVersion = 1;
Identifier identifier_0;
Identifier identifier_1;
u8 unk_0E[0x32];
};
static_assert(util::is_pod<ProfileMetadataEntry>::value);
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
constexpr inline const u32 ProfileMetadataVersion = 0; constexpr inline bool IsValidProfileFormatVersion(u32 version) {
return version == ProfileFormatVersion;
struct ProfileMetadata { }
u32 version;
u32 num_entries;
Identifier revision_key;
u8 unk_10[0x30];
ProfileMetadataEntry entries[50];
};
static_assert(util::is_pod<ProfileMetadata>::value);
static_assert(sizeof(ProfileMetadata) == 0xCC0);
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
ProfileMetadata metadata;
u8 unk[0x8000 - sizeof(metadata)];
};
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
constexpr inline const u32 ProfileDataVersion = 0;
enum ValueType : u8 { enum ValueType : u8 {
ValueType_Byte = 0, ValueType_Byte = 0,
@ -70,9 +47,9 @@ namespace ams::sprofile::srv {
static_assert(sizeof(ProfileDataEntry) == 0x10); static_assert(sizeof(ProfileDataEntry) == 0x10);
struct ProfileData { struct ProfileData {
u32 version;
u32 num_entries; u32 num_entries;
u8 unk_08[0x28]; u8 unk_04[0x0C];
u8 unk_10[0x20];
ProfileDataEntry entries[(0x4000 - 0x30) / sizeof(ProfileDataEntry)]; ProfileDataEntry entries[(0x4000 - 0x30) / sizeof(ProfileDataEntry)];
}; };
static_assert(util::is_pod<ProfileData>::value); static_assert(util::is_pod<ProfileData>::value);
@ -86,28 +63,55 @@ namespace ams::sprofile::srv {
static_assert(sizeof(ServiceProfile) == 0x4008); static_assert(sizeof(ServiceProfile) == 0x4008);
struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode { struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct {
Identifier identifier_0; Identifier identifier_0;
Identifier identifier_1; Identifier identifier_1;
u8 unk_0E[2]; u8 unk_0E[2];
u32 version;
u8 unk_14[0x1C];
} header;
u8 hash[crypto::Md5Generator::HashSize];
ProfileData data; ProfileData data;
u8 unk_4010[0x4400 - 0x4010]; u8 unk_4040[0x4400 - 0x4040];
}; };
static_assert(util::is_pod<ProfileDataForImportData>::value); static_assert(util::is_pod<ProfileDataForImportData>::value);
static_assert(sizeof(ProfileDataForImportData) == 0x4400); static_assert(sizeof(ProfileDataForImportData) == 0x4400);
struct ReadMetadataEntry { struct ProfileMetadataEntry {
Identifier identifier_0;
Identifier identifier_1;
u8 unk_0E[0x32];
};
static_assert(util::is_pod<ProfileMetadataEntry>::value);
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
struct ProfileMetadataEntryData : public sf::PrefersMapAliasTransferMode {
u8 unk[0x100]; u8 unk[0x100];
}; };
static_assert(util::is_pod<ReadMetadataEntry>::value); static_assert(util::is_pod<ProfileMetadataEntryData>::value);
static_assert(sizeof(ReadMetadataEntry) == 0x100); static_assert(sizeof(ProfileMetadataEntryData) == 0x100);
struct ReadMetadataArgument : public sf::LargeData, public sf::PrefersMapAliasTransferMode { struct ProfileMetadata {
ProfileMetadata metadata; u32 num_entries;
ReadMetadataEntry entries[(0x8000 - sizeof(metadata)) / sizeof(ReadMetadataEntry)]; u32 unk_04;
u8 unk_7FC0[0x40]; Identifier revision_key;
u8 unk_10[0x30];
ProfileMetadataEntry entries[50];
}; };
static_assert(util::is_pod<ReadMetadataArgument>::value); static_assert(util::is_pod<ProfileMetadata>::value);
static_assert(sizeof(ReadMetadataArgument) == 0x8000); static_assert(sizeof(ProfileMetadata) == 0xCC0);
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct {
u32 version;
u8 unk_04[0x1C];
} header;
u8 hash[crypto::Md5Generator::HashSize];
ProfileMetadata metadata;
ProfileMetadataEntryData entries[50];
u8 unk[0x8000 - 0x3EF0];
};
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
} }

View File

@ -37,6 +37,8 @@ namespace ams::sprofile {
R_DEFINE_ERROR_RESULT(MaxObservers, 623); R_DEFINE_ERROR_RESULT(MaxObservers, 623);
R_DEFINE_ERROR_RESULT(InvalidMetadataVersion, 3210); R_DEFINE_ERROR_RESULT(InvalidMetadataVersion, 3210);
R_DEFINE_ERROR_RESULT(InvalidMetadataHash, 3211);
R_DEFINE_ERROR_RESULT(InvalidDataVersion, 3230); R_DEFINE_ERROR_RESULT(InvalidDataVersion, 3230);
R_DEFINE_ERROR_RESULT(InvalidDataHash, 3231);
} }