[fs, qlaunch] add CreateSaveDataFileSystemWithCreationInfo2 and make qlaunch work again (#2760)

Fixes qlaunch regression I introduced previously. Add a few known structs.
Adds CreateSaveDataFileSystemWithCreationInfo2, which is called when games are started via qlaunch and corrupts save files.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2760
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
This commit is contained in:
unknown
2025-10-17 22:23:21 +02:00
committed by crueter
parent 3e8fe622a7
commit de46b8e817
13 changed files with 221 additions and 79 deletions
@@ -206,12 +206,12 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, D<&IApplicationManagerInterface::GetApplicationView>, "GetApplicationView"},
{1701, D<&IApplicationManagerInterface::GetApplicationViewDeprecated>, "GetApplicationViewDeprecated"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1704, D<&IApplicationManagerInterface::GetApplicationViewWithPromotionInfo>, "GetApplicationViewWithPromotionInfo"},
{1705, nullptr, "IsPatchAutoDeletableApplication"},
{1706, D<&IApplicationManagerInterface::Unknown1706>, "Unknown1706"},
{1706, D<&IApplicationManagerInterface::GetApplicationView>, "GetApplicationView"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
@@ -329,7 +329,7 @@ Result IApplicationManagerInterface::GetApplicationControlData(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
ApplicationControlSource application_control_source, u64 application_id) {
LOG_DEBUG(Service_NS, "called");
R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlData(
R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlDataOld(
out_buffer, out_actual_size, application_control_source, application_id));
}
@@ -410,7 +410,7 @@ Result IApplicationManagerInterface::IsAnyApplicationEntityInstalled(
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationView(
Result IApplicationManagerInterface::GetApplicationViewDeprecated(
OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
const auto size = (std::min)(out_application_views.size(), application_ids.size());
@@ -419,7 +419,7 @@ Result IApplicationManagerInterface::GetApplicationView(
for (size_t i = 0; i < size; i++) {
ApplicationView view{};
view.application_id = application_ids[i];
view.unk = 0x70000;
view.version = 0x70000;
view.flags = 0x401f17;
out_application_views[i] = view;
@@ -437,7 +437,7 @@ Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
for (size_t i = 0; i < size; i++) {
ApplicationViewWithPromotionInfo view{};
view.view.application_id = application_ids[i];
view.view.unk = 0x70000;
view.view.version = 0x70000;
view.view.flags = 0x401f17;
view.promotion = {};
@@ -447,6 +447,24 @@ Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationView(
OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
const auto size = (std::min)(out_application_views.size(), application_ids.size());
LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size());
for (size_t i = 0; i < size; i++) {
ApplicationView view{};
view.application_id = application_ids[i];
view.version = 0x70000;
view.flags = 0x401f17;
out_application_views[i] = view;
}
R_SUCCEED();
}
Result IApplicationManagerInterface::GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
u32 flags, u64 application_id, Uid account_id) {
@@ -535,31 +553,6 @@ Result IApplicationManagerInterface::RequestDownloadApplicationControlDataInBack
R_SUCCEED();
}
Result IApplicationManagerInterface::Unknown1706(
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_58,
InBuffer<BufferAttr_HipcMapAlias> in_buffer_8) {
LOG_WARNING(Service_NS, "(STUBBED) Unknown1706 called: out_size={} in_size={}",
out_buffer_58.size(), in_buffer_8.size());
if (out_buffer_58.size() < 0x58 || in_buffer_8.size() < 0x8) {
R_THROW(ResultUnknown);
}
u64 application_id = 0;
std::memcpy(&application_id, in_buffer_8.data(), sizeof(u64));
ApplicationView view{};
view.application_id = application_id;
view.unk = 0x70000;
view.flags = 0x401f17;
std::memset(out_buffer_58.data(), 0, out_buffer_58.size());
std::memcpy(out_buffer_58.data(), &view, sizeof(ApplicationView));
R_SUCCEED();
}
Result IApplicationManagerInterface::Unknown4022(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_NS, "(STUBBED) called");
@@ -33,12 +33,15 @@ public:
Result GetApplicationRecordUpdateSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetGameCardMountFailureEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsAnyApplicationEntityInstalled(Out<bool> out_is_any_application_entity_installed);
Result GetApplicationView(
Result GetApplicationViewDeprecated(
OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result GetApplicationViewWithPromotionInfo(
OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result GetApplicationView(
OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views,
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
u32 flags, u64 application_id, Uid account_id);
@@ -59,8 +62,6 @@ public:
Result RequestDownloadApplicationControlDataInBackground(u64 unk,
u64 application_id);
Result Unknown1706(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer_58,
InBuffer<BufferAttr_HipcMapAlias> in_buffer_8);
private:
KernelHelpers::ServiceContext service_context;
+20 -14
View File
@@ -42,20 +42,26 @@ struct ApplicationRecord {
};
static_assert(sizeof(ApplicationRecord) == 0x18, "ApplicationRecord has incorrect size.");
/// ApplicationDownloadState
struct ApplicationDownloadState {
u64 downloaded_size;
u64 total_size;
u32 unk_x10;
u8 state;
u8 unk_x19;
std::array<u8, 0x2> unk_x1a;
u64 unk_x20;
};
static_assert(sizeof(ApplicationDownloadState) == 0x20,
"ApplicationDownloadState has incorrect size.");
/// ApplicationView
struct ApplicationView {
u64 application_id; ///< ApplicationId.
u32 unk; ///< Unknown.
u32 flags; ///< Flags.
std::array<u8, 0x10> unk_x10; ///< Unknown.
u32 unk_x20; ///< Unknown.
u16 unk_x24; ///< Unknown.
std::array<u8, 0x2> unk_x26; ///< Unknown.
std::array<u8, 0x8> unk_x28; ///< Unknown.
std::array<u8, 0x10> unk_x30; ///< Unknown.
u32 unk_x40; ///< Unknown.
u8 unk_x44; ///< Unknown.
std::array<u8, 0xb> unk_x45; ///< Unknown.
u64 application_id; ///< ApplicationId.
u32 version; ///< Application Version(?)
u32 flags; ///< Flags.
ApplicationDownloadState download_state; ///< \ref ApplicationDownloadState
ApplicationDownloadState download_progress; ///< \ref ApplicationDownloadState
};
static_assert(sizeof(ApplicationView) == 0x50, "ApplicationView has incorrect size.");
@@ -82,13 +88,13 @@ struct PromotionInfo {
};
static_assert(sizeof(PromotionInfo) == 0x20, "PromotionInfo has incorrect size.");
// TODO(Maufeat): NsApplicationViewWithPromotionInfo is on SDK20+ 0x78 bytes
/// NsApplicationViewWithPromotionInfo
struct ApplicationViewWithPromotionInfo {
ApplicationView view; ///< \ref NsApplicationView
PromotionInfo promotion; ///< \ref NsPromotionInfo
std::array<u8, 0x8> padding{}; ///< Extra padding for newer HOS versions
};
static_assert(sizeof(ApplicationViewWithPromotionInfo) == 0x78,
static_assert(sizeof(ApplicationViewWithPromotionInfo) == 0x70,
"ApplicationViewWithPromotionInfo has incorrect size.");
struct ApplicationOccupiedSizeEntity {
@@ -22,12 +22,12 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
: ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData>, "GetApplicationControlData"},
{0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataOld>, "GetApplicationControlDataOld"},
{1, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"},
{2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
{3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{4, nullptr, "SelectApplicationDesiredLanguage"},
{5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDisplayData>, "GetApplicationDisplayData"},
{5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIconSize>, "GetApplicationControlDataWithIconSize"},
};
// clang-format on
@@ -36,7 +36,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataOld(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
ApplicationControlSource application_control_source, u64 application_id) {
LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}",
@@ -124,32 +124,87 @@ Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLan
R_SUCCEED();
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationDisplayData(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u64> out_size, u64 language_code,
u64 application_id) {
LOG_INFO(Service_NS, "called with application_id={:016X}, language_code={:016X}",
application_id, language_code);
constexpr u64 payload_size = sizeof(ApplicationDisplayData);
if (out_buffer.size() < payload_size) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={}, expected_min={})",
out_buffer.size(), payload_size);
R_THROW(ResultUnknown);
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
ApplicationControlSource application_control_source, u64 application_id) {
LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}",
application_control_source, application_id);
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
const auto size = out_buffer.size();
ApplicationDisplayData display_data{};
const auto icon_size = control.second ? control.second->GetSize() : 0;
const auto total_size = sizeof(FileSys::RawNACP) + icon_size;
std::memset(display_data.application_name.data(), 0, display_data.application_name.size());
std::memset(display_data.developer_name.data(), 0, display_data.developer_name.size());
if (size < total_size) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
size);
R_THROW(ResultUnknown);
}
std::memcpy(out_buffer.data(), &display_data, payload_size);
*out_size = payload_size;
if (control.first != nullptr) {
const auto bytes = control.first->GetRawBytes();
std::memcpy(out_buffer.data(), bytes.data(), bytes.size());
} else {
LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero",
application_id);
std::memset(out_buffer.data(), 0, sizeof(FileSys::RawNACP));
}
if (control.second != nullptr) {
control.second->Read(out_buffer.data() + sizeof(FileSys::RawNACP), icon_size);
} else {
LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}", application_id);
}
*out_actual_size = static_cast<u32>(total_size);
R_SUCCEED();
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIconSize(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_total_size,
ApplicationControlSource application_control_source,
u64 application_id) {
LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}",
application_control_source, application_id);
constexpr size_t kExpectedBufferSize = 0x14000;
constexpr size_t kNACPSize = sizeof(FileSys::RawNACP);
constexpr size_t kMaxIconSize = kExpectedBufferSize - kNACPSize;
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
const auto size = out_buffer.size();
if (size < kExpectedBufferSize) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, required={:016X})", size, kExpectedBufferSize);
R_THROW(ResultUnknown);
}
// Copy NACP
if (control.first != nullptr) {
const auto bytes = control.first->GetRawBytes();
std::memcpy(out_buffer.data(), bytes.data(), bytes.size());
} else {
std::memset(out_buffer.data(), 0, kNACPSize);
}
// Copy icon, pad with zeros if needed
size_t icon_size = control.second ? control.second->GetSize() : 0;
if (icon_size > kMaxIconSize) {
icon_size = kMaxIconSize; // Truncate if too large
}
if (control.second != nullptr && icon_size > 0) {
control.second->Read(out_buffer.data() + kNACPSize, icon_size);
} else {
std::memset(out_buffer.data() + kNACPSize, 0, kMaxIconSize);
}
*out_total_size = kExpectedBufferSize;
R_SUCCEED();
}
@@ -19,7 +19,7 @@ public:
explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
~IReadOnlyApplicationControlDataInterface() override;
Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Result GetApplicationControlDataOld(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u32> out_actual_size,
ApplicationControlSource application_control_source,
u64 application_id);
@@ -27,10 +27,15 @@ public:
u32 supported_languages);
Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code,
ApplicationLanguage application_language);
Result GetApplicationDisplayData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_size, u64 language_code,
u64 application_id);
Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u32> out_actual_size,
ApplicationControlSource application_control_source,
u64 application_id);
Result GetApplicationControlDataWithIconSize(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_total_size,
ApplicationControlSource application_control_source,
u64 application_id);
};
} // namespace Service::NS