/* * 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 namespace ams::fssrv { namespace { constinit bool g_is_debug_flag_enabled = false; } bool IsDebugFlagEnabled() { return g_is_debug_flag_enabled; } void SetDebugFlagEnabled(bool en) { /* Set global debug flag. */ g_is_debug_flag_enabled = en; } namespace impl { namespace { constexpr u8 LatestFsAccessControlInfoVersion = 1; } AccessControl::AccessControl(const void *data, s64 data_size, const void *desc, s64 desc_size) : AccessControl(data, data_size, desc, desc_size, g_is_debug_flag_enabled ? AllFlagBitsMask : DebugFlagDisableMask) { /* ... */ } AccessControl::AccessControl(const void *fac_data, s64 data_size, const void *fac_desc, s64 desc_size, u64 flag_mask) { /* If either our data or descriptor is null, give no permissions. */ if (fac_data == nullptr || fac_desc == nullptr) { m_flag_bits.emplace(util::ToUnderlying(AccessControlBits::Bits::None)); return; } /* Check that data/desc are big enough. */ AMS_ABORT_UNLESS(data_size >= static_cast(sizeof(AccessControlDataHeader))); AMS_ABORT_UNLESS(desc_size >= static_cast(sizeof(AccessControlDescriptor))); /* Copy in the data/descriptor. */ AccessControlDataHeader data = {}; AccessControlDescriptor desc = {}; std::memcpy(std::addressof(data), fac_data, sizeof(data)); std::memcpy(std::addressof(desc), fac_desc, sizeof(desc)); /* If we don't know how to parse the descriptors, don't. */ if (data.version != desc.version || data.version < LatestFsAccessControlInfoVersion) { m_flag_bits.emplace(util::ToUnderlying(AccessControlBits::Bits::None)); return; } /* Restrict the descriptor's flag bits. */ desc.flag_bits &= flag_mask; /* Create our flag bits. */ m_flag_bits.emplace(data.flag_bits & desc.flag_bits); /* Further check sizes. */ AMS_ABORT_UNLESS(data_size >= data.content_owner_infos_offset + data.content_owner_infos_size); AMS_ABORT_UNLESS(desc_size >= static_cast(sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64))); /* Read out the content data owner infos. */ uintptr_t data_start = reinterpret_cast(fac_data); uintptr_t desc_start = reinterpret_cast(fac_desc); if (data.content_owner_infos_size > 0) { /* Get the count. */ const u32 num_content_owner_infos = util::LoadLittleEndian(reinterpret_cast(data_start + data.content_owner_infos_offset)); /* Validate the id range. */ uintptr_t id_start = data_start + data.content_owner_infos_offset + sizeof(u32); uintptr_t id_end = id_start + sizeof(u64) * num_content_owner_infos; AMS_ABORT_UNLESS(id_end == data_start + data.content_owner_infos_offset + data.content_owner_infos_size); for (u32 i = 0; i < num_content_owner_infos; ++i) { /* Read the id. */ const u64 id = util::LoadLittleEndian(reinterpret_cast(id_start + i * sizeof(u64))); /* Check that the descriptor allows it. */ bool allowed = false; if (desc.content_owner_id_count != 0) { for (u8 n = 0; n < desc.content_owner_id_count; ++n) { if (id == util::LoadLittleEndian(reinterpret_cast(desc_start + sizeof(AccessControlDescriptor) + n * sizeof(u64)))) { allowed = true; break; } } } else if ((desc.content_owner_id_min == 0 && desc.content_owner_id_max == 0) || (desc.content_owner_id_min <= id && id <= desc.content_owner_id_max)) { allowed = true; } /* If the id is allowed, create it. */ if (allowed) { if (auto *info = new ContentOwnerInfo(id); info != nullptr) { m_content_owner_infos.push_front(*info); } } } } /* Read out the save data owner infos. */ AMS_ABORT_UNLESS(data_size >= data.save_data_owner_infos_offset + data.save_data_owner_infos_size); AMS_ABORT_UNLESS(desc_size >= static_cast(sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64) + desc.save_data_owner_id_count * sizeof(u64))); if (data.save_data_owner_infos_size > 0) { /* Get the count. */ const u32 num_save_data_owner_infos = util::LoadLittleEndian(reinterpret_cast(data_start + data.save_data_owner_infos_offset)); /* Get accessibility region.*/ uintptr_t accessibility_start = data_start + data.save_data_owner_infos_offset + sizeof(u32); /* Validate the id range. */ uintptr_t id_start = accessibility_start + util::AlignUp(num_save_data_owner_infos * sizeof(Accessibility), alignof(u32)); uintptr_t id_end = id_start + sizeof(u64) * num_save_data_owner_infos; AMS_ABORT_UNLESS(id_end == data_start + data.save_data_owner_infos_offset + data.save_data_owner_infos_size); for (u32 i = 0; i < num_save_data_owner_infos; ++i) { /* Read the accessibility/id. */ static_assert(sizeof(Accessibility) == 1); const Accessibility accessibility = *reinterpret_cast(accessibility_start + i * sizeof(Accessibility)); const u64 id = util::LoadLittleEndian(reinterpret_cast(id_start + i * sizeof(u64))); /* Check that the descriptor allows it. */ bool allowed = false; if (desc.save_data_owner_id_count != 0) { for (u8 n = 0; n < desc.save_data_owner_id_count; ++n) { if (id == util::LoadLittleEndian(reinterpret_cast(desc_start + sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64) + n * sizeof(u64)))) { allowed = true; break; } } } else if ((desc.save_data_owner_id_min == 0 && desc.save_data_owner_id_max == 0) || (desc.save_data_owner_id_min <= id && id <= desc.save_data_owner_id_max)) { allowed = true; } /* If the id is allowed, create it. */ if (allowed) { if (auto *info = new SaveDataOwnerInfo(id, accessibility); info != nullptr) { m_save_data_owner_infos.push_front(*info); } } } } } AccessControl::~AccessControl() { /* Delete all content owner infos. */ while (!m_content_owner_infos.empty()) { auto *info = std::addressof(*m_content_owner_infos.rbegin()); m_content_owner_infos.erase(m_content_owner_infos.iterator_to(*info)); delete info; } /* Delete all save data owner infos. */ while (!m_save_data_owner_infos.empty()) { auto *info = std::addressof(*m_save_data_owner_infos.rbegin()); m_save_data_owner_infos.erase(m_save_data_owner_infos.iterator_to(*info)); delete info; } } bool AccessControl::HasContentOwnerId(u64 owner_id) const { /* Check if we have a matching id. */ for (const auto &info : m_content_owner_infos) { if (info.GetId() == owner_id) { return true; } } return false; } Accessibility AccessControl::GetAccessibilitySaveDataOwnedBy(u64 owner_id) const { /* Find a matching save data owner. */ for (const auto &info : m_save_data_owner_infos) { if (info.GetId() == owner_id) { return info.GetAccessibility(); } } /* Default to no accessibility. */ return Accessibility::MakeAccessibility(false, false); } void AccessControl::ListContentOwnerId(s32 *out_count, u64 *out_owner_ids, s32 offset, s32 count) const { /* If we have nothing to read, just give the count. */ if (count == 0) { *out_count = m_content_owner_infos.size(); return; } /* Read out the ids. */ s32 read_offset = 0; s32 read_count = 0; if (out_owner_ids != nullptr) { auto *cur_out = out_owner_ids; for (const auto &info : m_content_owner_infos) { /* Skip until we get to the desired offset. */ if (read_offset < offset) { ++read_offset; continue; } /* Set the output value. */ *cur_out = info.GetId(); ++cur_out; ++read_count; /* If we've read as many as we can, finish. */ if (read_count == count) { break; } } } /* Set the out value. */ *out_count = read_count; } void AccessControl::ListSaveDataOwnedId(s32 *out_count, ncm::ApplicationId *out_owner_ids, s32 offset, s32 count) const { /* If we have nothing to read, just give the count. */ if (count == 0) { *out_count = m_save_data_owner_infos.size(); return; } /* Read out the ids. */ s32 read_offset = 0; s32 read_count = 0; if (out_owner_ids != nullptr) { auto *cur_out = out_owner_ids; for (const auto &info : m_save_data_owner_infos) { /* Skip until we get to the desired offset. */ if (read_offset < offset) { ++read_offset; continue; } /* Set the output value. */ cur_out->value = info.GetId(); ++cur_out; ++read_count; /* If we've read as many as we can, finish. */ if (read_count == count) { break; } } } /* Set the out value. */ *out_count = read_count; } Accessibility AccessControl::GetAccessibilityFor(AccessibilityType type) const { switch (type) { using enum AccessibilityType; case MountLogo: return Accessibility::MakeAccessibility(m_flag_bits->CanMountLogoRead(), false); case MountContentMeta: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentMetaRead(), false); case MountContentControl: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentControlRead(), false); case MountContentManual: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentManualRead(), false); case MountContentData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentDataRead(), false); case MountApplicationPackage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountApplicationPackageRead(), false); case MountSaveDataStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSaveDataStorageRead(), m_flag_bits->CanMountSaveDataStorageWrite()); case MountContentStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentStorageRead(), m_flag_bits->CanMountContentStorageWrite()); case MountImageAndVideoStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountImageAndVideoStorageRead(), m_flag_bits->CanMountImageAndVideoStorageWrite()); case MountCloudBackupWorkStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountCloudBackupWorkStorageRead(), m_flag_bits->CanMountCloudBackupWorkStorageWrite()); case MountCustomStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountCustomStorage0Read(), m_flag_bits->CanMountCustomStorage0Write()); case MountBisCalibrationFile: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisCalibrationFileRead(), m_flag_bits->CanMountBisCalibrationFileWrite()); case MountBisSafeMode: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSafeModeRead(), m_flag_bits->CanMountBisSafeModeWrite()); case MountBisUser: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisUserRead(), m_flag_bits->CanMountBisUserWrite()); case MountBisSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemRead(), m_flag_bits->CanMountBisSystemWrite()); case MountBisSystemProperEncryption: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemProperEncryptionRead(), m_flag_bits->CanMountBisSystemProperEncryptionWrite()); case MountBisSystemProperPartition: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemProperPartitionRead(), m_flag_bits->CanMountBisSystemProperPartitionWrite()); case MountSdCard: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSdCardRead(), m_flag_bits->CanMountSdCardWrite()); case MountGameCard: return Accessibility::MakeAccessibility(m_flag_bits->CanMountGameCardRead(), false); case MountDeviceSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountDeviceSaveDataRead(), m_flag_bits->CanMountDeviceSaveDataWrite()); case MountSystemSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemSaveDataRead(), m_flag_bits->CanMountSystemSaveDataWrite()); case MountOthersSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSaveDataRead(), m_flag_bits->CanMountOthersSaveDataWrite()); case MountOthersSystemSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSystemSaveDataRead(), m_flag_bits->CanMountOthersSystemSaveDataWrite()); case OpenBisPartitionBootPartition1Root: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootPartition1RootRead(), m_flag_bits->CanOpenBisPartitionBootPartition1RootWrite()); case OpenBisPartitionBootPartition2Root: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootPartition2RootRead(), m_flag_bits->CanOpenBisPartitionBootPartition2RootWrite()); case OpenBisPartitionUserDataRoot: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserDataRootRead(), m_flag_bits->CanOpenBisPartitionUserDataRootWrite()); case OpenBisPartitionBootConfigAndPackage2Part1: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Write()); case OpenBisPartitionBootConfigAndPackage2Part2: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Write()); case OpenBisPartitionBootConfigAndPackage2Part3: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Write()); case OpenBisPartitionBootConfigAndPackage2Part4: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Write()); case OpenBisPartitionBootConfigAndPackage2Part5: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Write()); case OpenBisPartitionBootConfigAndPackage2Part6: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Write()); case OpenBisPartitionCalibrationBinary: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionCalibrationBinaryRead(), m_flag_bits->CanOpenBisPartitionCalibrationBinaryWrite()); case OpenBisPartitionCalibrationFile: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionCalibrationFileRead(), m_flag_bits->CanOpenBisPartitionCalibrationFileWrite()); case OpenBisPartitionSafeMode: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSafeModeRead(), m_flag_bits->CanOpenBisPartitionSafeModeWrite()); case OpenBisPartitionUser: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserRead(), m_flag_bits->CanOpenBisPartitionUserWrite()); case OpenBisPartitionSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemRead(), m_flag_bits->CanOpenBisPartitionSystemWrite()); case OpenBisPartitionSystemProperEncryption: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemProperEncryptionRead(), m_flag_bits->CanOpenBisPartitionSystemProperEncryptionWrite()); case OpenBisPartitionSystemProperPartition: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemProperPartitionRead(), m_flag_bits->CanOpenBisPartitionSystemProperPartitionWrite()); case OpenSdCardStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSdCardStorageRead(), m_flag_bits->CanOpenSdCardStorageWrite()); case OpenGameCardStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenGameCardStorageRead(), m_flag_bits->CanOpenGameCardStorageWrite()); case MountSystemDataPrivate: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemDataPrivateRead(), false); case MountHost: return Accessibility::MakeAccessibility(m_flag_bits->CanMountHostRead(), m_flag_bits->CanMountHostWrite()); case MountRegisteredUpdatePartition: return Accessibility::MakeAccessibility(m_flag_bits->CanMountRegisteredUpdatePartitionRead() && g_is_debug_flag_enabled, false); case MountSaveDataInternalStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSaveDataInternalStorageRead(), m_flag_bits->CanOpenSaveDataInternalStorageWrite()); case MountTemporaryDirectory: return Accessibility::MakeAccessibility(m_flag_bits->CanMountTemporaryDirectoryRead(), m_flag_bits->CanMountTemporaryDirectoryWrite()); case MountAllBaseFileSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanMountAllBaseFileSystemRead(), m_flag_bits->CanMountAllBaseFileSystemWrite()); case NotMount: return Accessibility::MakeAccessibility(false, false); AMS_UNREACHABLE_DEFAULT_CASE(); } } bool AccessControl::CanCall(OperationType type) const { switch (type) { using enum OperationType; case InvalidateBisCache: return m_flag_bits->CanInvalidateBisCache(); case EraseMmc: return m_flag_bits->CanEraseMmc(); case GetGameCardDeviceCertificate: return m_flag_bits->CanGetGameCardDeviceCertificate(); case GetGameCardIdSet: return m_flag_bits->CanGetGameCardIdSet(); case FinalizeGameCardDriver: return m_flag_bits->CanFinalizeGameCardDriver(); case GetGameCardAsicInfo: return m_flag_bits->CanGetGameCardAsicInfo(); case CreateSaveData: return m_flag_bits->CanCreateSaveData(); case DeleteSaveData: return m_flag_bits->CanDeleteSaveData(); case CreateSystemSaveData: return m_flag_bits->CanCreateSystemSaveData(); case CreateOthersSystemSaveData: return m_flag_bits->CanCreateOthersSystemSaveData(); case DeleteSystemSaveData: return m_flag_bits->CanDeleteSystemSaveData(); case OpenSaveDataInfoReader: return m_flag_bits->CanOpenSaveDataInfoReader(); case OpenSaveDataInfoReaderForSystem: return m_flag_bits->CanOpenSaveDataInfoReaderForSystem(); case OpenSaveDataInfoReaderForInternal: return m_flag_bits->CanOpenSaveDataInfoReaderForInternal(); case OpenSaveDataMetaFile: return m_flag_bits->CanOpenSaveDataMetaFile(); case SetCurrentPosixTime: return m_flag_bits->CanSetCurrentPosixTime(); case ReadSaveDataFileSystemExtraData: return m_flag_bits->CanReadSaveDataFileSystemExtraData(); case SetGlobalAccessLogMode: return m_flag_bits->CanSetGlobalAccessLogMode(); case SetSpeedEmulationMode: return m_flag_bits->CanSetSpeedEmulationMode(); case FillBis: return m_flag_bits->CanFillBis(); case CorruptSaveData: return m_flag_bits->CanCorruptSaveData(); case CorruptSystemSaveData: return m_flag_bits->CanCorruptSystemSaveData(); case VerifySaveData: return m_flag_bits->CanVerifySaveData(); case DebugSaveData: return m_flag_bits->CanDebugSaveData(); case FormatSdCard: return m_flag_bits->CanFormatSdCard(); case GetRightsId: return m_flag_bits->CanGetRightsId(); case RegisterExternalKey: return m_flag_bits->CanRegisterExternalKey(); case SetEncryptionSeed: return m_flag_bits->CanSetEncryptionSeed(); case WriteSaveDataFileSystemExtraDataTimeStamp: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataTimeStamp(); case WriteSaveDataFileSystemExtraDataFlags: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataFlags(); case WriteSaveDataFileSystemExtraDataCommitId: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataCommitId(); case WriteSaveDataFileSystemExtraDataAll: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataAll(); case ExtendSaveData: return m_flag_bits->CanExtendSaveData(); case ExtendSystemSaveData: return m_flag_bits->CanExtendSystemSaveData(); case ExtendOthersSystemSaveData: return m_flag_bits->CanExtendOthersSystemSaveData(); case RegisterUpdatePartition: return m_flag_bits->CanRegisterUpdatePartition() && g_is_debug_flag_enabled; case OpenSaveDataTransferManager: return m_flag_bits->CanOpenSaveDataTransferManager(); case OpenSaveDataTransferManagerVersion2: return m_flag_bits->CanOpenSaveDataTransferManagerVersion2(); case OpenSaveDataTransferManagerForSaveDataRepair: return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepair(); case OpenSaveDataTransferManagerForSaveDataRepairTool: return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepairTool(); case OpenSaveDataTransferProhibiter: return m_flag_bits->CanOpenSaveDataTransferProhibiter(); case OpenSaveDataMover: return m_flag_bits->CanOpenSaveDataMover(); case OpenBisWiper: return m_flag_bits->CanOpenBisWiper(); case ListAccessibleSaveDataOwnerId: return m_flag_bits->CanListAccessibleSaveDataOwnerId(); case ControlMmcPatrol: return m_flag_bits->CanControlMmcPatrol(); case OverrideSaveDataTransferTokenSignVerificationKey: return m_flag_bits->CanOverrideSaveDataTransferTokenSignVerificationKey(); case OpenSdCardDetectionEventNotifier: return m_flag_bits->CanOpenSdCardDetectionEventNotifier(); case OpenGameCardDetectionEventNotifier: return m_flag_bits->CanOpenGameCardDetectionEventNotifier(); case OpenSystemDataUpdateEventNotifier: return m_flag_bits->CanOpenSystemDataUpdateEventNotifier(); case NotifySystemDataUpdateEvent: return m_flag_bits->CanNotifySystemDataUpdateEvent(); case OpenAccessFailureDetectionEventNotifier: return m_flag_bits->CanOpenAccessFailureDetectionEventNotifier(); case GetAccessFailureDetectionEvent: return m_flag_bits->CanGetAccessFailureDetectionEvent(); case IsAccessFailureDetected: return m_flag_bits->CanIsAccessFailureDetected(); case ResolveAccessFailure: return m_flag_bits->CanResolveAccessFailure(); case AbandonAccessFailure: return m_flag_bits->CanAbandonAccessFailure(); case QuerySaveDataInternalStorageTotalSize: return m_flag_bits->CanQuerySaveDataInternalStorageTotalSize(); case GetSaveDataCommitId: return m_flag_bits->CanGetSaveDataCommitId(); case SetSdCardAccessibility: return m_flag_bits->CanSetSdCardAccessibility(); case SimulateDevice: return m_flag_bits->CanSimulateDevice(); case CreateSaveDataWithHashSalt: return m_flag_bits->CanCreateSaveDataWithHashSalt(); case RegisterProgramIndexMapInfo: return m_flag_bits->CanRegisterProgramIndexMapInfo(); case ChallengeCardExistence: return m_flag_bits->CanChallengeCardExistence(); case CreateOwnSaveData: return m_flag_bits->CanCreateOwnSaveData(); case DeleteOwnSaveData: return m_flag_bits->CanDeleteOwnSaveData(); case ReadOwnSaveDataFileSystemExtraData: return m_flag_bits->CanReadOwnSaveDataFileSystemExtraData(); case ExtendOwnSaveData: return m_flag_bits->CanExtendOwnSaveData(); case OpenOwnSaveDataTransferProhibiter: return m_flag_bits->CanOpenOwnSaveDataTransferProhibiter(); case FindOwnSaveDataWithFilter: return m_flag_bits->CanFindOwnSaveDataWithFilter(); case OpenSaveDataTransferManagerForRepair: return m_flag_bits->CanOpenSaveDataTransferManagerForRepair(); case SetDebugConfiguration: return m_flag_bits->CanSetDebugConfiguration(); case OpenDataStorageByPath: return m_flag_bits->CanOpenDataStorageByPath(); AMS_UNREACHABLE_DEFAULT_CASE(); } } } }