From 107aa52cdbf9c6e7dc4a6e95da3ae18bc382778e Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sun, 4 Jun 2023 15:50:44 -0600
Subject: [PATCH] service: nfc: Add backup support

---
 src/common/fs/fs_paths.h                      |   1 +
 src/common/fs/path_util.cpp                   |   1 +
 src/common/fs/path_util.h                     |   1 +
 src/core/hle/service/nfc/common/device.cpp    | 160 +++++++++++++++---
 src/core/hle/service/nfc/common/device.h      |  10 +-
 .../hle/service/nfc/common/device_manager.cpp |  14 +-
 src/core/hle/service/nfc/nfc_interface.cpp    |   8 +-
 src/core/hle/service/nfc/nfc_result.h         |  20 ++-
 src/core/hle/service/nfp/nfp_interface.cpp    |   6 +-
 src/core/hle/service/nfp/nfp_result.h         |   2 +
 10 files changed, 184 insertions(+), 39 deletions(-)

diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h
index c77c112f1..61bac9eba 100644
--- a/src/common/fs/fs_paths.h
+++ b/src/common/fs/fs_paths.h
@@ -10,6 +10,7 @@
 
 // Sub-directories contained within a yuzu data directory
 
+#define AMIIBO_DIR "amiibo"
 #define CACHE_DIR "cache"
 #define CONFIG_DIR "config"
 #define DUMP_DIR "dump"
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index e026a13d9..d71cfacc6 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -114,6 +114,7 @@ public:
 #endif
 
         GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
+        GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR);
         GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache);
         GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config);
         GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 7cfe85b70..ba28964d0 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -12,6 +12,7 @@ namespace Common::FS {
 
 enum class YuzuPath {
     YuzuDir,        // Where yuzu stores its data.
+    AmiiboDir,      // Where Amiibo backups are stored.
     CacheDir,       // Where cached filesystem data is stored.
     ConfigDir,      // Where config files are stored.
     DumpDir,        // Where dumped data is stored.
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 0bd7900e1..b14f682b5 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -12,6 +12,11 @@
 #pragma warning(pop)
 #endif
 
+#include <fmt/format.h>
+
+#include "common/fs/file.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
 #include "common/input.h"
 #include "common/logging/log.h"
 #include "common/string_util.h"
@@ -136,7 +141,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
     if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
         LOG_INFO(Service_NFC, "Loading amiibo without keys");
         memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
-        BuildAmiiboWithoutKeys();
+        BuildAmiiboWithoutKeys(tag_data, encrypted_tag_data);
         is_plain_amiibo = true;
         is_write_protected = true;
         return true;
@@ -366,16 +371,25 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
 
     // The loaded amiibo is not encrypted
     if (is_plain_amiibo) {
+        std::vector<u8> data(sizeof(NFP::NTAG215File));
+        memcpy(data.data(), &tag_data, sizeof(tag_data));
+        WriteBackupData(tag_data.uid, data);
+
         device_state = DeviceState::TagMounted;
         mount_target = mount_target_;
         return ResultSuccess;
     }
 
     if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
-        LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
-        return ResultCorruptedData;
+        bool has_backup = HasBackup(encrypted_tag_data.uuid.uid).IsSuccess();
+        LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
+        return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
     }
 
+    std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
+    memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+    WriteBackupData(encrypted_tag_data.uuid.uid, data);
+
     device_state = DeviceState::TagMounted;
     mount_target = mount_target_;
     return ResultSuccess;
@@ -470,6 +484,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
     std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
     if (is_plain_amiibo) {
         memcpy(data.data(), &tag_data, sizeof(tag_data));
+        WriteBackupData(tag_data.uid, data);
     } else {
         if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
             LOG_ERROR(Service_NFP, "Failed to encode data");
@@ -477,6 +492,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
         }
 
         memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+        WriteBackupData(encrypted_tag_data.uuid.uid, data);
     }
 
     if (!npad_device->WriteNfc(data)) {
@@ -488,7 +504,7 @@ Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
 }
 
 Result NfcDevice::Restore() {
-    if (device_state != DeviceState::TagMounted) {
+    if (device_state != DeviceState::TagFound) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
             return ResultTagRemoved;
@@ -496,13 +512,59 @@ Result NfcDevice::Restore() {
         return ResultWrongDeviceState;
     }
 
-    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
-        LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return ResultWrongDeviceState;
+    NFC::TagInfo tag_info{};
+    std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
+    Result result = GetTagInfo(tag_info, false);
+
+    if (result.IsError()) {
+        return result;
     }
 
-    // TODO: Load amiibo from backup on system
-    LOG_ERROR(Service_NFP, "Not Implemented");
+    result = ReadBackupData(tag_info.uuid, data);
+
+    if (result.IsError()) {
+        return result;
+    }
+
+    NFP::NTAG215File temporary_tag_data{};
+    NFP::EncryptedNTAG215File temporary_encrypted_tag_data{};
+
+    // Fallback for encrypted amiibos without keys
+    if (is_write_protected) {
+        return ResultWriteAmiiboFailed;
+    }
+
+    // Fallback for plain amiibos
+    if (is_plain_amiibo) {
+        LOG_INFO(Service_NFP, "Restoring backup of plain amiibo");
+        memcpy(&temporary_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+        temporary_encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(temporary_tag_data);
+    }
+
+    if (!is_plain_amiibo) {
+        LOG_INFO(Service_NFP, "Restoring backup of encrypted amiibo");
+        temporary_tag_data = {};
+        memcpy(&temporary_encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+    }
+
+    if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
+        return ResultNotAnAmiibo;
+    }
+
+    if (!is_plain_amiibo) {
+        if (!NFP::AmiiboCrypto::DecodeAmiibo(temporary_encrypted_tag_data, temporary_tag_data)) {
+            LOG_ERROR(Service_NFP, "Can't decode amiibo");
+            return ResultCorruptedData;
+        }
+    }
+
+    // Overwrite tag contents with backup and mount the tag
+    tag_data = temporary_tag_data;
+    encrypted_tag_data = temporary_encrypted_tag_data;
+    device_state = DeviceState::TagMounted;
+    mount_target = NFP::MountTarget::All;
+    is_data_moddified = true;
+
     return ResultSuccess;
 }
 
@@ -1132,13 +1194,69 @@ Result NfcDevice::BreakTag(NFP::BreakType break_type) {
     return FlushWithBreak(break_type);
 }
 
-Result NfcDevice::ReadBackupData(std::span<u8> data) const {
-    // Not implemented
+Result NfcDevice::HasBackup(const NFC::UniqueSerialNumber& uid) const {
+    constexpr auto backup_dir = "backup";
+    const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+    const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
+
+    if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
+        return ResultUnableToAccessBackupFile;
+    }
+
     return ResultSuccess;
 }
 
-Result NfcDevice::WriteBackupData(std::span<const u8> data) {
-    // Not implemented
+Result NfcDevice::ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const {
+    constexpr auto backup_dir = "backup";
+    const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+    const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
+
+    const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
+                                       Common::FS::FileAccessMode::Read,
+                                       Common::FS::FileType::BinaryFile};
+
+    if (!keys_file.IsOpen()) {
+        LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
+        return ResultUnableToAccessBackupFile;
+    }
+
+    if (keys_file.Read(data) != data.size()) {
+        LOG_ERROR(Service_NFP, "Failed to read amiibo backup");
+        return ResultUnableToAccessBackupFile;
+    }
+
+    return ResultSuccess;
+}
+
+Result NfcDevice::WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data) {
+    constexpr auto backup_dir = "backup";
+    const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+    const auto file_name = fmt::format("{0:02x}.bin", fmt::join(uid, ""));
+
+    if (HasBackup(uid).IsError()) {
+        if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
+            return ResultBackupPathAlreadyExist;
+        }
+
+        if (!Common::FS::NewFile(yuzu_amiibo_dir / backup_dir / file_name)) {
+            return ResultBackupPathAlreadyExist;
+        }
+    }
+
+    const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
+                                       Common::FS::FileAccessMode::ReadWrite,
+                                       Common::FS::FileType::BinaryFile};
+
+    if (!keys_file.IsOpen()) {
+        LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
+        return ResultUnableToAccessBackupFile;
+    }
+
+    if (keys_file.Write(data) != data.size()) {
+        LOG_ERROR(Service_NFP, "Failed to write amiibo backup");
+        return ResultUnableToAccessBackupFile;
+    }
+
     return ResultSuccess;
 }
 
@@ -1177,7 +1295,8 @@ NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) co
     return amiibo_name;
 }
 
-void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) {
+void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
+                              const NFP::AmiiboName& amiibo_name) const {
     std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
 
     // Convert from utf8 to utf16
@@ -1258,22 +1377,23 @@ void NfcDevice::UpdateRegisterInfoCrc() {
     tag_data.register_info_crc = crc.checksum();
 }
 
-void NfcDevice::BuildAmiiboWithoutKeys() {
+void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
+                                       const NFP::EncryptedNTAG215File& encrypted_file) const {
     Service::Mii::MiiManager manager;
-    auto& settings = tag_data.settings;
+    auto& settings = stubbed_tag_data.settings;
 
-    tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_tag_data);
+    stubbed_tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_file);
 
     // Common info
-    tag_data.write_counter = 0;
-    tag_data.amiibo_version = 0;
+    stubbed_tag_data.write_counter = 0;
+    stubbed_tag_data.amiibo_version = 0;
     settings.write_date = GetAmiiboDate(GetCurrentPosixTime());
 
     // Register info
     SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
     settings.settings.font_region.Assign(0);
     settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
-    tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
+    stubbed_tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
 
     // Admin info
     settings.settings.amiibo_initialized.Assign(1);
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 6a37e8458..6f049b687 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -86,8 +86,9 @@ public:
     Result GetAll(NFP::NfpData& data) const;
     Result SetAll(const NFP::NfpData& data);
     Result BreakTag(NFP::BreakType break_type);
-    Result ReadBackupData(std::span<u8> data) const;
-    Result WriteBackupData(std::span<const u8> data);
+    Result HasBackup(const NFC::UniqueSerialNumber& uid) const;
+    Result ReadBackupData(const NFC::UniqueSerialNumber& uid, std::span<u8> data) const;
+    Result WriteBackupData(const NFC::UniqueSerialNumber& uid, std::span<const u8> data);
     Result WriteNtf(std::span<const u8> data);
 
     u64 GetHandle() const;
@@ -103,14 +104,15 @@ private:
     void CloseNfcTag();
 
     NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
-    void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
+    void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
     NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
     u64 GetCurrentPosixTime() const;
     u64 RemoveVersionByte(u64 application_id) const;
     void UpdateSettingsCrc();
     void UpdateRegisterInfoCrc();
 
-    void BuildAmiiboWithoutKeys();
+    void BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
+                                const NFP::EncryptedNTAG215File& encrypted_file) const;
 
     bool is_controller_set{};
     int callback_key;
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index d5deaaf27..cffd602df 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -543,9 +543,14 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
 
     std::shared_ptr<NfcDevice> device = nullptr;
     auto result = GetDeviceHandle(device_handle, device);
+    NFC::TagInfo tag_info{};
 
     if (result.IsSuccess()) {
-        result = device->ReadBackupData(data);
+        result = device->GetTagInfo(tag_info, false);
+    }
+
+    if (result.IsSuccess()) {
+        result = device->ReadBackupData(tag_info.uuid, data);
         result = VerifyDeviceResult(device, result);
     }
 
@@ -557,9 +562,14 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
 
     std::shared_ptr<NfcDevice> device = nullptr;
     auto result = GetDeviceHandle(device_handle, device);
+    NFC::TagInfo tag_info{};
 
     if (result.IsSuccess()) {
-        result = device->WriteBackupData(data);
+        result = device->GetTagInfo(tag_info, false);
+    }
+
+    if (result.IsSuccess()) {
+        result = device->WriteBackupData(tag_info.uuid, data);
         result = VerifyDeviceResult(device, result);
     }
 
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 0fa29d398..198d0f2b9 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -302,7 +302,7 @@ Result NfcInterface::TranslateResultToServiceError(Result result) const {
         return TranslateResultToNfp(result);
     }
     default:
-        if (result != ResultUnknown216) {
+        if (result != ResultBackupPathAlreadyExist) {
             return result;
         }
         return ResultUnknown74;
@@ -343,6 +343,9 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
     if (result == ResultApplicationAreaIsNotInitialized) {
         return NFP::ResultApplicationAreaIsNotInitialized;
     }
+    if (result == ResultCorruptedDataWithBackup) {
+        return NFP::ResultCorruptedDataWithBackup;
+    }
     if (result == ResultCorruptedData) {
         return NFP::ResultCorruptedData;
     }
@@ -355,6 +358,9 @@ Result NfcInterface::TranslateResultToNfp(Result result) const {
     if (result == ResultNotAnAmiibo) {
         return NFP::ResultNotAnAmiibo;
     }
+    if (result == ResultUnableToAccessBackupFile) {
+        return NFP::ResultUnableToAccessBackupFile;
+    }
     LOG_WARNING(Service_NFC, "Result conversion not handled");
     return result;
 }
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 917d79ef8..59a808740 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -9,20 +9,22 @@ namespace Service::NFC {
 
 constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
 constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
-constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
+constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFC, 68);
 constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
 constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
 constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
 constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
 constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
-constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
+constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88);
 constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
-constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
-constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
-constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
-constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
-constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
-constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
-constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
+constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113);
+constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120);
+constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128);
+constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
+constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
+constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
+constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
+constexpr Result ResultNotAnAmiibo(ErrorModule::NFC, 178);
+constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
 
 } // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
index 21d159154..34ef9d82d 100644
--- a/src/core/hle/service/nfp/nfp_interface.cpp
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -126,7 +126,7 @@ void Interface::Flush(HLERequestContext& ctx) {
 void Interface::Restore(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
     auto result = GetManager()->Restore(device_handle);
     result = TranslateResultToServiceError(result);
@@ -394,7 +394,7 @@ void Interface::BreakTag(HLERequestContext& ctx) {
 void Interface::ReadBackupData(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
     std::vector<u8> backup_data{};
     auto result = GetManager()->ReadBackupData(device_handle, backup_data);
@@ -412,7 +412,7 @@ void Interface::WriteBackupData(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     const auto backup_data_buffer{ctx.ReadBuffer()};
-    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
     auto result = GetManager()->WriteBackupData(device_handle, backup_data_buffer);
     result = TranslateResultToServiceError(result);
diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h
index 4c126cd81..618533843 100644
--- a/src/core/hle/service/nfp/nfp_result.h
+++ b/src/core/hle/service/nfp/nfp_result.h
@@ -17,9 +17,11 @@ constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
 constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
 constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
 constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
+constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFP, 136);
 constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
 constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
 constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
 constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
+constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFP, 200);
 
 } // namespace Service::NFP