diff --git a/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp b/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp index 3083970dc..fc72bbf6c 100644 --- a/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp +++ b/libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp @@ -21,7 +21,7 @@ namespace ams::fs::impl { #define ADD_ENUM_CASE(v) case v: return #v template<> const char *IdString::ToString(pkg1::KeyGeneration id) { - static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_13_0_0); + static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_14_0_0); switch (id) { using enum pkg1::KeyGeneration; case KeyGeneration_1_0_0: return "1.0.0-2.3.0"; @@ -36,7 +36,8 @@ namespace ams::fs::impl { case KeyGeneration_9_0_0: return "9.0.0-9.0.1"; case KeyGeneration_9_1_0: return "9.1.0-12.0.3"; case KeyGeneration_12_1_0: return "12.1.0"; - case KeyGeneration_13_0_0: return "13.0.0-"; + case KeyGeneration_13_0_0: return "13.0.0-13.2.1"; + case KeyGeneration_14_0_0: return "14.0.0-"; default: return "Unknown"; } } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp index 1c5c3bc59..d76d4122f 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp @@ -17,6 +17,7 @@ #include "sprofile_srv_profile_manager.hpp" #include "sprofile_srv_service_for_bg_agent.hpp" #include "sprofile_srv_service_for_system_process.hpp" +#include "sprofile_srv_service_getter.hpp" namespace ams::sprofile::srv { @@ -55,6 +56,9 @@ namespace ams::sprofile::srv { constinit util::TypedStorage> g_bg_service_object = {}; constinit util::TypedStorage> g_sp_service_object = {}; + constinit util::TypedStorage> g_bg_service_getter = {}; + constinit util::TypedStorage> g_sp_service_getter = {}; + constinit util::TypedStorage g_server_manager = {}; alignas(os::ThreadStackAlignment) constinit u8 g_ipc_thread_stack[0x3000]; @@ -95,12 +99,21 @@ namespace ams::sprofile::srv { util::ConstructAt(g_bg_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager)); util::ConstructAt(g_sp_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager)); + /* Create the service getters. */ + util::ConstructAt(g_bg_service_getter, util::GetReference(g_bg_service_object).GetShared(), util::GetReference(g_sp_service_object).GetShared()); + util::ConstructAt(g_sp_service_getter, nullptr, util::GetReference(g_sp_service_object).GetShared()); + /* Create the server manager. */ util::ConstructAt(g_server_manager); /* Create services. */ - R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_bg_service_object).GetShared(), ServiceNameForBgAgent, BgAgentSessionCountMax)); - R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_sp_service_object).GetShared(), ServiceNameForSystemProcess, SystemProcessSessionCountMax)); + if (hos::GetVersion() >= hos::Version_14_0_0) { + R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_bg_service_getter).GetShared(), ServiceNameForBgAgent, BgAgentSessionCountMax)); + R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_sp_service_getter).GetShared(), ServiceNameForSystemProcess, SystemProcessSessionCountMax)); + } else { + R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_bg_service_object).GetShared(), ServiceNameForBgAgent, BgAgentSessionCountMax)); + R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_sp_service_object).GetShared(), ServiceNameForSystemProcess, SystemProcessSessionCountMax)); + } } void StartIpcServer() { diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp index ea32ace89..225d9d032 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp @@ -33,7 +33,7 @@ namespace ams::sprofile::srv { /* Check the size was correct. */ AMS_ABORT_UNLESS(size == read_size); - return ResultSuccess(); + R_SUCCEED(); } Result WriteFile(const char *path, const void *src, size_t size) { @@ -51,7 +51,7 @@ namespace ams::sprofile::srv { R_ABORT_UNLESS(fs::SetFileSize(file, size)); /* Write the file. */ - return fs::WriteFile(file, 0, src, size, fs::WriteOption::Flush); + R_RETURN(fs::WriteFile(file, 0, src, size, fs::WriteOption::Flush)); } Result MoveFile(const char *src_path, const char *dst_path) { @@ -70,7 +70,15 @@ namespace ams::sprofile::srv { /* Move the source file to the destination file. */ R_TRY(fs::RenameFile(src_path, dst_path)); - return ResultSuccess(); + R_SUCCEED(); + } + + Result DeleteFile(const char *path) { + R_TRY_CATCH(fs::DeleteFile(path)) { + R_CATCH(fs::ResultPathNotFound) { /* It's okay if the file doesn't exist. */ } + } R_END_TRY_CATCH; + + R_SUCCEED(); } Result EnsureDirectory(const char *path) { @@ -78,7 +86,7 @@ namespace ams::sprofile::srv { R_CATCH(fs::ResultPathAlreadyExists) { /* It's okay if the directory already exists. */ } } R_END_TRY_CATCH; - return ResultSuccess(); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp index e20b2b811..a14be7506 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp @@ -21,6 +21,7 @@ namespace ams::sprofile::srv { Result ReadFile(const char *path, void *dst, size_t size, s64 offset); Result WriteFile(const char *path, const void *src, size_t size); Result MoveFile(const char *src_path, const char *dst_path); + Result DeleteFile(const char *path); Result EnsureDirectory(const char *path); diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_controller_for_debug.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_controller_for_debug.hpp index dfee5499e..836dfd184 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_controller_for_debug.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_controller_for_debug.hpp @@ -21,4 +21,4 @@ AMS_SF_METHOD_INFO(C, H, 2001, Result, GetRaw, (sf::Out out_type, sf::Out out_value, sprofile::Identifier profile, sprofile::Identifier key), (out_type, out_value, profile, key)) -AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileControllerForDebug, AMS_SPROFILE_I_PROFILE_CONTROLLER_FOR_DEBUG_INTERFACE_INFO) +AMS_SF_DEFINE_INTERFACE(ams::sprofile::srv, IProfileControllerForDebug, AMS_SPROFILE_I_PROFILE_CONTROLLER_FOR_DEBUG_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_importer.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_importer.hpp index 556ebfe45..fb592cae3 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_importer.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_importer.hpp @@ -22,4 +22,4 @@ AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \ 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::srv, IProfileImporter, AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_reader.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_reader.hpp index ca1bc7153..9d2458588 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_reader.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_reader.hpp @@ -23,4 +23,4 @@ AMS_SF_METHOD_INFO(C, H, 3, Result, GetUnsigned32, (sf::Out out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetByte, (sf::Out 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::srv, IProfileReader, AMS_SPROFILE_I_PROFILE_READER_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_update_observer.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_update_observer.hpp index efef72ea7..1830e1551 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_update_observer.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_update_observer.hpp @@ -21,4 +21,4 @@ AMS_SF_METHOD_INFO(C, H, 1, Result, Unlisten, (sprofile::Identifier profile), (profile)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetEventHandle, (ams::sf::OutCopyHandle out), (out)) -AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileUpdateObserver, AMS_SPROFILE_I_PROFILE_UPDATE_OBSERVER_INTERFACE_INFO) +AMS_SF_DEFINE_INTERFACE(ams::sprofile::srv, IProfileUpdateObserver, AMS_SPROFILE_I_PROFILE_UPDATE_OBSERVER_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_bg_agent.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_bg_agent.hpp index 985202c80..a850f8ad1 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_bg_agent.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_bg_agent.hpp @@ -17,10 +17,10 @@ #include #include "sprofile_srv_i_profile_importer.hpp" -#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out> out), (out)) \ +#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 200, Result, GetImportableProfileUrls, (sf::Out out_count, const sf::OutArray &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \ - AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out out, sprofile::Identifier revision_key), (out, revision_key)) \ + AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out out, sprofile::Identifier revision_key), (out, revision_key)) \ AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ()) -AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO) +AMS_SF_DEFINE_INTERFACE(ams::sprofile::srv, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_system_process.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_system_process.hpp index 25292821e..9171a5476 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_system_process.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_system_process.hpp @@ -20,8 +20,8 @@ #include "sprofile_srv_i_profile_controller_for_debug.hpp" #define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_SYSTEM_PROCESS_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileReader, (sf::Out> out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 101, Result, OpenProfileUpdateObserver, (sf::Out> out), (out)) \ - AMS_SF_METHOD_INFO(C, H, 900, Result, OpenProfileControllerForDebug, (sf::Out> out), (out)) + AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileReader, (sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 101, Result, OpenProfileUpdateObserver, (sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 900, Result, OpenProfileControllerForDebug, (sf::Out> out), (out)) -AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForSystemProcess, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_SYSTEM_PROCESS_INTERFACE_INFO) +AMS_SF_DEFINE_INTERFACE(ams::sprofile::srv, ISprofileServiceForSystemProcess, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_SYSTEM_PROCESS_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_getter.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_getter.hpp new file mode 100644 index 000000000..838157065 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_getter.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "sprofile_srv_i_service_for_system_process.hpp" +#include "sprofile_srv_i_service_for_bg_agent.hpp" + +#define AMS_SPROFILE_I_SERVICE_GETTER_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, GetServiceForSystemProcess, (sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, GetServiceForBgAgent, (sf::Out> out), (out)) + +AMS_SF_DEFINE_INTERFACE(ams::sprofile::srv, IServiceGetter, AMS_SPROFILE_I_SERVICE_GETTER_INTERFACE_INFO) \ No newline at end of file diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer.hpp index 6ed8ae2b6..94a91e796 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer.hpp @@ -20,16 +20,22 @@ namespace ams::sprofile::srv { class ProfileImporter { + private: + struct ImportingProfile { + Identifier identifier_0; + Identifier identifier_1; + bool is_new_import; + }; private: bool m_committed; bool m_imported_metadata; int m_importing_count; util::optional m_metadata; - Identifier m_importing_profiles[50]; - util::BitFlagSet<50> m_imported_profiles; + ImportingProfile m_importing_profiles[50]; + util::BitFlagSet<50> m_is_profile_importable; Identifier m_revision_key; public: - ProfileImporter(const util::optional &meta) : m_committed(false), m_imported_metadata(false), m_importing_count(0), m_metadata(util::nullopt), m_imported_profiles(), m_revision_key() { + ProfileImporter(const util::optional &meta) : m_committed(false), m_imported_metadata(false), m_importing_count(0), m_metadata(util::nullopt), m_is_profile_importable(), m_revision_key() { if (meta.has_value()) { m_metadata = *meta; } @@ -62,12 +68,23 @@ namespace ams::sprofile::srv { /* Import the service revision key. */ m_revision_key = meta.revision_key; - /* Import all profiles. */ + /* Set all profiles as importable. */ + for (auto i = 0u; i < std::min(meta.num_entries, util::size(meta.entries)); ++i) { + m_is_profile_importable[i] = true; + } + + /* Determine import status for all profiles. */ for (auto i = 0u; i < std::min(meta.num_entries, util::size(meta.entries)); ++i) { const auto &import_entry = meta.entries[i]; - if (!this->HasProfile(import_entry.identifier_0, import_entry.identifier_1)) { - m_importing_profiles[m_importing_count++] = import_entry.identifier_0; - } + + const bool is_new_import = !this->HasProfile(import_entry.identifier_0, import_entry.identifier_1); + + m_importing_profiles[i] = { + .identifier_0 = import_entry.identifier_0, + .identifier_1 = import_entry.identifier_1, + .is_new_import = is_new_import, + }; + m_is_profile_importable[i] = is_new_import; } } @@ -76,9 +93,9 @@ namespace ams::sprofile::srv { if (m_imported_metadata) { /* Find the specified profile. */ for (auto i = 0; i < m_importing_count; ++i) { - if (m_importing_profiles[i] == profile) { - /* Require the profile not already be imported. */ - return !m_imported_profiles[i]; + if (m_importing_profiles[i].identifier_0 == profile) { + /* Require the profile be importable. */ + return m_is_profile_importable[i]; } } } @@ -88,10 +105,10 @@ namespace ams::sprofile::srv { } void OnImportProfile(Identifier profile) { - /* Set the profile as imported. */ + /* Set the profile as not importable (as it's imported). */ for (auto i = 0; i < m_importing_count; ++i) { - if (m_importing_profiles[i] == profile) { - m_imported_profiles[i] = true; + if (m_importing_profiles[i].identifier_0 == profile) { + m_is_profile_importable[i] = false; break; } } @@ -109,13 +126,39 @@ namespace ams::sprofile::srv { } /* We need to have imported everything we intended to import. */ - return m_imported_profiles.PopCount() == m_importing_count; + return m_is_profile_importable.IsAllOff(); } int GetImportingCount() const { return m_importing_count; } - Identifier GetImportingProfile(int i) const { return m_importing_profiles[i]; } + const ImportingProfile &GetImportingProfile(int i) const { return m_importing_profiles[i]; } Identifier GetRevisionKey() const { return m_revision_key; } + + Result CleanupOrphanedProfiles(auto cleanup_impl) const { + /* Cleanup any orphaned profiles in our metadata. */ + if (m_metadata.has_value()) { + for (auto i = 0u; i < std::min(m_metadata->num_entries, util::size(m_metadata->entries)); ++i) { + const auto &entry = m_metadata->entries[i]; + if (!this->IsImportingProfile(entry.identifier_0)) { + R_TRY(cleanup_impl(entry.identifier_0)); + } + } + } + + R_SUCCEED(); + } + private: + bool IsImportingProfile(Identifier profile) const { + /* Check if we're importing the desired profile. */ + for (auto i = 0; i < m_importing_count; ++i) { + if (m_importing_profiles[i].identifier_0 == profile) { + return true; + } + } + + /* We're not importing the desired profile. */ + return false; + } }; } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp index 2ca8d0ea1..0167371ba 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp @@ -28,7 +28,7 @@ namespace ams::sprofile::srv { R_TRY_CATCH(fs::CreateSystemSaveData(save_data_info.id, save_data_info.size, save_data_info.journal_size, save_data_info.flags)) { R_CATCH(fs::ResultPathAlreadyExists) { /* Nintendo accepts already-existing savedata here. */ } } R_END_TRY_CATCH; - return ResultSuccess(); + R_SUCCEED(); } void SafePrint(char *dst, size_t dst_size, const char *fmt, ...) __attribute__((format(printf, 3, 4))); @@ -135,20 +135,44 @@ namespace ams::sprofile::srv { const auto result = fs::MountSystemSaveData(m_save_data_info.mount_name, m_save_data_info.id); m_save_file_mounted = R_SUCCEEDED(result); - return result; + R_RETURN(result); } Result ProfileManager::OpenProfileImporter() { /* Acquire locks. */ std::scoped_lock lk1(m_profile_metadata_mutex); std::scoped_lock lk2(m_profile_importer_mutex); + std::scoped_lock lk3(m_general_mutex); /* Check that we don't already have an importer. */ R_UNLESS(!m_profile_importer.has_value(), sprofile::ResultInvalidState()); + /* Try to load profile metadata. NOTE: result is not checked, it is okay if this fails. */ + this->LoadPrimaryMetadataImpl(); + /* Create importer. */ m_profile_importer.emplace(m_profile_metadata); - return ResultSuccess(); + R_SUCCEED(); + } + + void ProfileManager::CloseProfileImporterImpl() { + /* Check pre-conditions. */ + AMS_ASSERT(m_profile_importer_mutex.IsLockedByCurrentThread()); + AMS_ASSERT(m_general_mutex.IsLockedByCurrentThread()); + AMS_ASSERT(m_fs_mutex.IsLockedByCurrentThread()); + + if (m_profile_importer.has_value()) { + /* Unmount save file. */ + fs::Unmount(m_save_data_info.mount_name); + m_save_file_mounted = false; + + /* Re-mount save file. */ + R_ABORT_UNLESS(fs::MountSystemSaveData(m_save_data_info.mount_name, m_save_data_info.id)); + m_save_file_mounted = true; + + /* Reset our importer. */ + m_profile_importer = util::nullopt; + } } void ProfileManager::CloseProfileImporter() { @@ -158,7 +182,7 @@ namespace ams::sprofile::srv { std::scoped_lock lk3(m_fs_mutex); /* Close our importer. */ - m_profile_importer = util::nullopt; + this->CloseProfileImporterImpl(); } Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) { @@ -202,7 +226,7 @@ namespace ams::sprofile::srv { /* Set profile imported. */ m_profile_importer->OnImportProfile(import.header.identifier_0); - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::Commit() { @@ -218,33 +242,20 @@ namespace ams::sprofile::srv { /* Commit, and if we fail remount our save. */ { - /* Setup guard in case we fail. */ - auto remount_guard = SCOPE_GUARD { - if (m_profile_importer.has_value()) { - /* Unmount save file. */ - fs::Unmount(m_save_data_info.mount_name); - m_save_file_mounted = false; - - /* Re-mount save file. */ - R_ABORT_UNLESS(fs::MountSystemSaveData(m_save_data_info.mount_name, m_save_data_info.id)); - m_save_file_mounted = true; - - /* Reset our importer. */ - m_profile_importer = util::nullopt; - } - }; + /* If we fail, close our importer. */ + ON_RESULT_FAILURE { this->CloseProfileImporterImpl(); }; /* Check that we can commit the importer. */ R_UNLESS(m_profile_importer->CanCommit(), sprofile::ResultInvalidState()); - /* Commit. */ - R_TRY(this->CommitImpl()); + /* Commit newly imported profiles. */ + R_TRY(this->CommitImportedProfiles()); + + /* Cleanup orphaned profiles. */ + R_TRY(this->CleanupOrphanedProfiles()); /* Commit the save file. */ R_TRY(fs::CommitSaveData(m_save_data_info.mount_name)); - - /* We successfully committed. */ - remount_guard.Cancel(); } /* NOTE: Here nintendo generates an "sprofile_update_profile" sreport with the new and old revision keys. */ @@ -252,7 +263,7 @@ namespace ams::sprofile::srv { /* Handle tasks for when we've committed (including notifying update observers). */ this->OnCommitted(); - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) { @@ -292,7 +303,28 @@ namespace ams::sprofile::srv { /* Import the metadata. */ m_profile_importer->ImportMetadata(import.metadata); - return ResultSuccess(); + R_SUCCEED(); + } + + Result ProfileManager::LoadPrimaryMetadataImpl() { + /* Check pre-conditions. */ + AMS_ASSERT(m_profile_metadata_mutex.IsLockedByCurrentThread()); + AMS_ASSERT(m_general_mutex.IsLockedByCurrentThread()); + + /* If we don't have metadata, load it. */ + if (!m_profile_metadata.has_value()) { + /* Emplace our metadata. */ + m_profile_metadata.emplace(); + ON_RESULT_FAILURE { m_profile_metadata = util::nullopt; }; + + /* Read profile metadata. */ + char path[0x30]; + CreatePrimaryMetadataPath(path, sizeof(path), m_save_data_info.mount_name); + R_TRY(ReadFile(path, std::addressof(*m_profile_metadata), sizeof(*m_profile_metadata), 0)); + } + + /* We now have loaded metadata. */ + R_SUCCEED(); } Result ProfileManager::LoadPrimaryMetadata(ProfileMetadata *out) { @@ -300,24 +332,12 @@ namespace ams::sprofile::srv { std::scoped_lock lk1(m_profile_metadata_mutex); std::scoped_lock lk2(m_general_mutex); - /* If we don't have metadata, load it. */ - if (!m_profile_metadata.has_value()) { - /* Emplace our metadata. */ - m_profile_metadata.emplace(); - auto meta_guard = SCOPE_GUARD { m_profile_metadata = util::nullopt; }; - - /* Read profile metadata. */ - char path[0x30]; - CreatePrimaryMetadataPath(path, sizeof(path), m_save_data_info.mount_name); - R_TRY(ReadFile(path, std::addressof(*m_profile_metadata), sizeof(*m_profile_metadata), 0)); - - /* We read the metadata successfully. */ - meta_guard.Cancel(); - } + /* Load our metadata. */ + R_TRY(this->LoadPrimaryMetadataImpl()); /* Set the output. */ *out = *m_profile_metadata; - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::LoadProfile(Identifier profile) { @@ -339,7 +359,7 @@ namespace ams::sprofile::srv { /* We succeeded. */ prof_guard.Cancel(); - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::GetDataEntry(ProfileDataEntry *out, Identifier profile, Identifier key) { @@ -353,12 +373,12 @@ namespace ams::sprofile::srv { for (auto i = 0u; i < std::min(m_service_profile->data.num_entries, util::size(m_service_profile->data.entries)); ++i) { if (m_service_profile->data.entries[i].key == key) { *out = m_service_profile->data.entries[i]; - return ResultSuccess(); + R_SUCCEED(); } } } - return sprofile::ResultKeyNotFound(); + R_THROW(sprofile::ResultKeyNotFound()); } Result ProfileManager::GetSigned64(s64 *out, Identifier profile, Identifier key) { @@ -371,7 +391,7 @@ namespace ams::sprofile::srv { /* Set the output value. */ *out = entry.value_s64; - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::GetUnsigned64(u64 *out, Identifier profile, Identifier key) { @@ -384,7 +404,7 @@ namespace ams::sprofile::srv { /* Set the output value. */ *out = entry.value_u64; - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::GetSigned32(s32 *out, Identifier profile, Identifier key) { @@ -397,7 +417,7 @@ namespace ams::sprofile::srv { /* Set the output value. */ *out = entry.value_s32; - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::GetUnsigned32(u32 *out, Identifier profile, Identifier key) { @@ -410,7 +430,7 @@ namespace ams::sprofile::srv { /* Set the output value. */ *out = entry.value_u32; - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::GetByte(u8 *out, Identifier profile, Identifier key) { @@ -423,7 +443,7 @@ namespace ams::sprofile::srv { /* Set the output value. */ *out = entry.value_u8; - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::GetRaw(u8 *out_type, u64 *out_value, Identifier profile, Identifier key) { @@ -434,10 +454,10 @@ namespace ams::sprofile::srv { /* Set the output type and value. */ *out_type = entry.type; *out_value = entry.value_u64; - return ResultSuccess(); + R_SUCCEED(); } - Result ProfileManager::CommitImpl() { + Result ProfileManager::CommitImportedProfiles() { /* Ensure primary directories. */ R_TRY(this->EnsurePrimaryDirectories()); @@ -452,16 +472,32 @@ namespace ams::sprofile::srv { R_TRY(MoveFile(tmp_path, pri_path)); } - /* Move all profiles. */ + /* Move all newly imported profiles. */ for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) { - const auto id = m_profile_importer->GetImportingProfile(i); + const auto &profile = m_profile_importer->GetImportingProfile(i); - CreateTemporaryProfilePath(tmp_path, sizeof(tmp_path), m_save_data_info.mount_name, id); - CreatePrimaryProfilePath(pri_path, sizeof(pri_path), m_save_data_info.mount_name, id); - R_TRY(MoveFile(tmp_path, pri_path)); + if (profile.is_new_import) { + CreateTemporaryProfilePath(tmp_path, sizeof(tmp_path), m_save_data_info.mount_name, profile.identifier_0); + CreatePrimaryProfilePath(pri_path, sizeof(pri_path), m_save_data_info.mount_name, profile.identifier_0); + R_TRY(MoveFile(tmp_path, pri_path)); + } } - return ResultSuccess(); + R_SUCCEED(); + } + + Result ProfileManager::CleanupOrphanedProfiles() { + /* Check pre-conditions. */ + AMS_ASSERT(m_profile_importer.has_value()); + + /* Declare re-usable path. */ + char pri_path[0x30]; + + /* Cleanup the profiles. */ + R_RETURN(m_profile_importer->CleanupOrphanedProfiles([&](Identifier profile) ALWAYS_INLINE_LAMBDA -> Result { + CreatePrimaryProfilePath(pri_path, sizeof(pri_path), m_save_data_info.mount_name, profile); + R_RETURN(DeleteFile(pri_path)); + })); } void ProfileManager::OnCommitted() { @@ -470,7 +506,7 @@ namespace ams::sprofile::srv { /* If we need to, invalidate the loaded service profile. */ if (m_service_profile.has_value()) { for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) { - if (m_service_profile->name == m_profile_importer->GetImportingProfile(i)) { + if (m_service_profile->name == m_profile_importer->GetImportingProfile(i).identifier_0) { m_service_profile = util::nullopt; break; } @@ -482,7 +518,11 @@ namespace ams::sprofile::srv { /* Invoke any listeners. */ for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) { - m_update_observer_manager.OnUpdate(m_profile_importer->GetImportingProfile(i)); + const auto &profile = m_profile_importer->GetImportingProfile(i); + + if (profile.is_new_import) { + m_update_observer_manager.OnUpdate(profile.identifier_0); + } } /* Reset profile importer. */ @@ -499,7 +539,7 @@ namespace ams::sprofile::srv { CreatePrimaryProfileDirectoryPath(path, sizeof(path), m_save_data_info.mount_name); R_TRY(EnsureDirectory(path)); - return ResultSuccess(); + R_SUCCEED(); } Result ProfileManager::EnsureTemporaryDirectories() { @@ -512,7 +552,7 @@ namespace ams::sprofile::srv { CreateTemporaryProfileDirectoryPath(path, sizeof(path), m_save_data_info.mount_name); R_TRY(EnsureDirectory(path)); - return ResultSuccess(); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp index df976637e..40484b998 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp @@ -68,7 +68,11 @@ namespace ams::sprofile::srv { ProfileUpdateObserverManager &GetUpdateObserverManager() { return m_update_observer_manager; } private: - Result CommitImpl(); + Result CommitImportedProfiles(); + Result CleanupOrphanedProfiles(); + + Result LoadPrimaryMetadataImpl(); + void CloseProfileImporterImpl(); void OnCommitted(); diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp index 522868424..da5a452e1 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp @@ -28,11 +28,11 @@ namespace ams::sprofile::srv { AutoUnregisterObserver(ProfileUpdateObserverManager *manager) : m_manager(manager) { /* ... */ } virtual ~AutoUnregisterObserver() { m_manager->CloseObserver(this); } }; - static_assert(sprofile::IsIProfileUpdateObserver); + static_assert(sprofile::srv::IsIProfileUpdateObserver); } - Result ProfileUpdateObserverManager::OpenObserver(sf::Out> &out, MemoryResource *memory_resource) { + Result ProfileUpdateObserverManager::OpenObserver(sf::Out> &out, MemoryResource *memory_resource) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp index 2041d6176..aa6a276d1 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp @@ -78,7 +78,7 @@ namespace ams::sprofile::srv { } } }; - static_assert(sprofile::IsIProfileUpdateObserver); + static_assert(sprofile::srv::IsIProfileUpdateObserver); class ProfileUpdateObserverManager { public: @@ -90,7 +90,7 @@ namespace ams::sprofile::srv { public: ProfileUpdateObserverManager() : m_observer_count(0), m_mutex() { /* ... */ } public: - Result OpenObserver(sf::Out> &out, MemoryResource *memory_resource); + Result OpenObserver(sf::Out> &out, MemoryResource *memory_resource); void CloseObserver(ProfileUpdateObserverImpl *observer); void OnUpdate(Identifier profile) { diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp index 67778a01a..9c3c8c86b 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp @@ -21,7 +21,7 @@ namespace ams::sprofile::srv { - Result ServiceForBgAgent::OpenProfileImporter(sf::Out> out) { + Result ServiceForBgAgent::OpenProfileImporter(sf::Out> out) { /* Allocate an object. */ auto obj = sf::ObjectFactory::CreateSharedEmplaced(m_memory_resource, m_profile_manager); R_UNLESS(obj != nullptr, sprofile::ResultAllocationFailed()); diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.hpp index 8ebdac189..43d308966 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.hpp @@ -28,11 +28,11 @@ namespace ams::sprofile::srv { public: constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ } public: - Result OpenProfileImporter(sf::Out> out); + Result OpenProfileImporter(sf::Out> out); Result GetImportableProfileUrls(sf::Out out_count, const sf::OutArray &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg); Result IsUpdateNeeded(sf::Out out, Identifier revision_key); Result Reset(); }; - static_assert(sprofile::IsISprofileServiceForBgAgent); + static_assert(sprofile::srv::IsISprofileServiceForBgAgent); } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp index 1f7d3244b..b4f7b1a54 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp @@ -21,7 +21,7 @@ namespace ams::sprofile::srv { - Result ServiceForSystemProcess::OpenProfileReader(sf::Out> out) { + Result ServiceForSystemProcess::OpenProfileReader(sf::Out> out) { /* Allocate an object. */ auto obj = sf::ObjectFactory::CreateSharedEmplaced(m_memory_resource, m_profile_manager); R_UNLESS(obj != nullptr, sprofile::ResultAllocationFailed()); @@ -31,11 +31,11 @@ namespace ams::sprofile::srv { return ResultSuccess(); } - Result ServiceForSystemProcess::OpenProfileUpdateObserver(sf::Out> out) { + Result ServiceForSystemProcess::OpenProfileUpdateObserver(sf::Out> out) { return m_profile_manager->GetUpdateObserverManager().OpenObserver(out, m_memory_resource); } - Result ServiceForSystemProcess::OpenProfileControllerForDebug(sf::Out> out) { + Result ServiceForSystemProcess::OpenProfileControllerForDebug(sf::Out> out) { /* Require debug mode in order to open a debug controller. */ R_UNLESS(settings::fwdbg::IsDebugModeEnabled(), sprofile::ResultNotPermitted()); diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.hpp index d8758716b..d5186fbf4 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.hpp @@ -28,10 +28,10 @@ namespace ams::sprofile::srv { public: constexpr ServiceForSystemProcess(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ } public: - Result OpenProfileReader(sf::Out> out); - Result OpenProfileUpdateObserver(sf::Out> out); - Result OpenProfileControllerForDebug(sf::Out> out); + Result OpenProfileReader(sf::Out> out); + Result OpenProfileUpdateObserver(sf::Out> out); + Result OpenProfileControllerForDebug(sf::Out> out); }; - static_assert(sprofile::IsISprofileServiceForSystemProcess); + static_assert(sprofile::srv::IsISprofileServiceForSystemProcess); } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.cpp new file mode 100644 index 000000000..577ef8b98 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "sprofile_srv_service_getter.hpp" + +namespace ams::sprofile::srv { + + Result ServiceGetter::GetServiceForSystemProcess(sf::Out> out) { + /* Check that we have a service-for-system-process. */ + R_UNLESS(m_service_for_system_process != nullptr, sprofile::ResultNotPermitted()); + + /* Set the output. */ + *out = m_service_for_system_process; + R_SUCCEED(); + } + + Result ServiceGetter::GetServiceForBgAgent(sf::Out> out) { + /* Check that we have a service-for-bg-agent. */ + R_UNLESS(m_service_for_bg_agent != nullptr, sprofile::ResultNotPermitted()); + + /* Set the output. */ + *out = m_service_for_bg_agent; + R_SUCCEED(); + } + +} diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.hpp new file mode 100644 index 000000000..accf6524e --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "sprofile_srv_i_service_getter.hpp" + +namespace ams::sprofile::srv { + + class ServiceGetter { + private: + sf::SharedPointer<::ams::sprofile::srv::ISprofileServiceForBgAgent> m_service_for_bg_agent; + sf::SharedPointer<::ams::sprofile::srv::ISprofileServiceForSystemProcess> m_service_for_system_process; + public: + constexpr ServiceGetter(sf::SharedPointer<::ams::sprofile::srv::ISprofileServiceForBgAgent> &&bg, sf::SharedPointer<::ams::sprofile::srv::ISprofileServiceForSystemProcess> &&sp) : m_service_for_bg_agent(bg), m_service_for_system_process(sp) { /* ... */ } + public: + Result GetServiceForSystemProcess(sf::Out> out); + Result GetServiceForBgAgent(sf::Out> out); + }; + static_assert(sprofile::srv::IsIServiceGetter); + +}