diff --git a/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp b/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp index 5e03944b0..713a208c2 100644 --- a/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp +++ b/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp @@ -25,6 +25,10 @@ namespace ams::mitm::sysupdater { /* ExFat NCAs prior to 2.0.0 do not actually include the exfat driver, and don't boot. */ constexpr inline u32 MinimumVersionForExFatDriver = 65536; + bool IsExFatDriverSupported(const ncm::ContentMetaInfo &info) { + return info.version >= MinimumVersionForExFatDriver && ((info.attributes & ncm::ContentMetaAttribute_IncludesExFatDriver) != 0); + } + template Result ForEachFileInDirectory(const char *root_path, F f) { /* Open the directory. */ @@ -123,9 +127,10 @@ namespace ams::mitm::sysupdater { return ResultSuccess(); } - Result ValidateSystemUpdate(Result *out_result, UpdateValidationInfo *out_info, const ncm::PackagedContentMetaReader &update_reader, const char *package_root) { + Result ValidateSystemUpdate(Result *out_result, Result *out_exfat_result, UpdateValidationInfo *out_info, const ncm::PackagedContentMetaReader &update_reader, const char *package_root) { /* Clear output. */ - *out_result = ResultSuccess(); + *out_result = ResultSuccess(); + *out_exfat_result = ResultSuccess(); /* We want to track all content the update requires. */ const size_t num_content_metas = update_reader.GetContentMetaCount(); @@ -264,11 +269,17 @@ namespace ams::mitm::sysupdater { if (R_SUCCEEDED(*out_result)) { for (size_t i = 0; i < num_content_metas; ++i) { if (!content_meta_valid[i]) { - *out_result = fs::ResultPathNotFound(); - *out_info = { - .invalid_key = update_reader.GetContentMetaInfo(i)->ToKey(), - }; - break; + const ncm::ContentMetaInfo *info = update_reader.GetContentMetaInfo(i); + + *out_info = { .invalid_key = info->ToKey(), }; + + if (IsExFatDriverSupported(*info)) { + *out_exfat_result = fs::ResultPathNotFound(); + /* Continue, in case there's a non-exFAT failure result. */ + } else { + *out_result = fs::ResultPathNotFound(); + break; + } } } } @@ -276,10 +287,6 @@ namespace ams::mitm::sysupdater { return ResultSuccess(); } - bool IsExFatDriverSupported(const ncm::ContentMetaInfo &info) { - return info.version >= MinimumVersionForExFatDriver && ((info.attributes & ncm::ContentMetaAttribute_IncludesExFatDriver) != 0); - } - Result FormatUserPackagePath(ncm::Path *out, const ncm::Path &user_path) { /* Ensure that the user path is valid. */ R_UNLESS(user_path.str[0] == '/', fs::ResultInvalidPath()); @@ -378,7 +385,7 @@ namespace ams::mitm::sysupdater { return ResultSuccess(); } - Result SystemUpdateService::ValidateUpdate(sf::Out out_validate_result, sf::Out out_validate_info, const ncm::Path &path) { + Result SystemUpdateService::ValidateUpdate(sf::Out out_validate_result, sf::Out out_validate_exfat_result, sf::Out out_validate_info, const ncm::Path &path) { /* Adjust the path. */ ncm::Path package_root; R_TRY(FormatUserPackagePath(std::addressof(package_root), path)); @@ -397,7 +404,7 @@ namespace ams::mitm::sysupdater { const auto reader = ncm::PackagedContentMetaReader(content_meta_buffer.Get(), content_meta_buffer.GetSize()); /* Validate the update. */ - R_TRY(ValidateSystemUpdate(out_validate_result.GetPointer(), out_validate_info.GetPointer(), reader, package_root.str)); + R_TRY(ValidateSystemUpdate(out_validate_result.GetPointer(), out_validate_exfat_result.GetPointer(), out_validate_info.GetPointer(), reader, package_root.str)); } return ResultSuccess(); diff --git a/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.hpp b/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.hpp index afb819532..f0d05b12c 100644 --- a/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.hpp +++ b/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.hpp @@ -40,14 +40,14 @@ namespace ams::mitm::sysupdater { namespace impl { - #define AMS_SYSUPDATER_SYSTEM_UPDATE_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 0, Result, GetUpdateInformation, (sf::Out out, const ncm::Path &path)) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, ValidateUpdate, (sf::Out out_validate_result, sf::Out out_validate_info, const ncm::Path &path)) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, SetupUpdate, (sf::CopyHandle transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat)) \ - AMS_SF_METHOD_INFO(C, H, 3, Result, SetupUpdateWithVariation, (sf::CopyHandle transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id)) \ - AMS_SF_METHOD_INFO(C, H, 4, Result, RequestPrepareUpdate, (sf::OutCopyHandle out_event_handle, sf::Out> out_async)) \ - AMS_SF_METHOD_INFO(C, H, 5, Result, GetPrepareUpdateProgress, (sf::Out out)) \ - AMS_SF_METHOD_INFO(C, H, 6, Result, HasPreparedUpdate, (sf::Out out)) \ + #define AMS_SYSUPDATER_SYSTEM_UPDATE_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, GetUpdateInformation, (sf::Out out, const ncm::Path &path)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, ValidateUpdate, (sf::Out out_validate_result, sf::Out out_validate_exfat_result, sf::Out out_validate_info, const ncm::Path &path)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, SetupUpdate, (sf::CopyHandle transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat)) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, SetupUpdateWithVariation, (sf::CopyHandle transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id)) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, RequestPrepareUpdate, (sf::OutCopyHandle out_event_handle, sf::Out> out_async)) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, GetPrepareUpdateProgress, (sf::Out out)) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, HasPreparedUpdate, (sf::Out out)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, ApplyPreparedUpdate, ()) AMS_SF_DEFINE_INTERFACE(ISystemUpdateInterface, AMS_SYSUPDATER_SYSTEM_UPDATE_INTERFACE_INFO) @@ -70,7 +70,7 @@ namespace ams::mitm::sysupdater { Result InitializeUpdateTask(os::ManagedHandle &transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id); public: Result GetUpdateInformation(sf::Out out, const ncm::Path &path); - Result ValidateUpdate(sf::Out out_validate_result, sf::Out out_validate_info, const ncm::Path &path); + Result ValidateUpdate(sf::Out out_validate_result, sf::Out out_validate_exfat_result, sf::Out out_validate_info, const ncm::Path &path); Result SetupUpdate(sf::CopyHandle transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat); Result SetupUpdateWithVariation(sf::CopyHandle transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id); Result RequestPrepareUpdate(sf::OutCopyHandle out_event_handle, sf::Out> out_async); diff --git a/troposphere/daybreak/source/ams_su.h b/troposphere/daybreak/source/ams_su.h index d38e183fe..35ef62146 100644 --- a/troposphere/daybreak/source/ams_su.h +++ b/troposphere/daybreak/source/ams_su.h @@ -29,6 +29,7 @@ typedef struct { typedef struct { Result result; + Result exfat_result; NcmContentMetaKey invalid_key; NcmContentId invalid_content_id; } AmsSuUpdateValidationInfo; diff --git a/troposphere/daybreak/source/ui.cpp b/troposphere/daybreak/source/ui.cpp index 12306a68a..dfbd4151e 100644 --- a/troposphere/daybreak/source/ui.cpp +++ b/troposphere/daybreak/source/ui.cpp @@ -814,6 +814,19 @@ namespace dbk { if (R_SUCCEEDED(m_validation_info.result)) { this->LogText("Update is valid!\n"); + if (R_FAILED(m_validation_info.exfat_result)) { + const u32 version = m_validation_info.invalid_key.version; + this->LogText("exFAT Validation failed with result: 0x%08x\n", m_validation_info.exfat_result); + this->LogText("Missing content:\n- Program id: %016lx\n- Version: %d.%d.%d\n", m_validation_info.invalid_key.id, (version >> 26) & 0x1f, (version >> 20) & 0x1f, (version >> 16) & 0xf); + + /* Log the missing content id. */ + this->LogText("- Content id: "); + for (size_t i = 0; i < sizeof(NcmContentId); i++) { + this->LogText("%02x", m_validation_info.invalid_content_id.c[i]); + } + this->LogText("\n"); + } + /* Enable the back and continue buttons and select the continue button. */ this->SetButtonEnabled(BackButtonId, true); this->SetButtonEnabled(ContinueButtonId, true); @@ -867,12 +880,18 @@ namespace dbk { } /* Check if exfat is supported. */ - g_exfat_supported = m_update_info.exfat_supported; + g_exfat_supported = m_update_info.exfat_supported && R_SUCCEEDED(m_validation_info.exfat_result); if (!g_exfat_supported) { g_use_exfat = false; } - ChangeMenu(std::make_shared(g_current_menu)); + /* Warn the user if they're updating with exFAT supposed to be supported but not present/corrupted. */ + if (m_update_info.exfat_supported && R_FAILED(m_validation_info.exfat_result)) { + ChangeMenu(std::make_shared(g_current_menu, std::make_shared(g_current_menu), "Warning: exFAT firmware is missing or corrupt", "Are you sure you want to proceed?")); + } else { + ChangeMenu(std::make_shared(g_current_menu)); + } + return; } }