summaryrefslogtreecommitdiffstats
path: root/src/core/file_sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/file_sys')
-rw-r--r--src/core/file_sys/card_image.cpp4
-rw-r--r--src/core/file_sys/control_metadata.cpp43
-rw-r--r--src/core/file_sys/control_metadata.h6
-rw-r--r--src/core/file_sys/program_metadata.cpp54
-rw-r--r--src/core/file_sys/program_metadata.h14
-rw-r--r--src/core/file_sys/savedata_factory.cpp58
-rw-r--r--src/core/file_sys/savedata_factory.h4
7 files changed, 144 insertions, 39 deletions
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index f23d9373b..5d02865f4 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -232,8 +232,8 @@ const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const {
std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
const auto program_id = secure_partition->GetProgramTitleID();
- const auto iter = std::find_if(
- ncas.begin(), ncas.end(), [this, type, program_id](const std::shared_ptr<NCA>& nca) {
+ const auto iter =
+ std::find_if(ncas.begin(), ncas.end(), [type, program_id](const std::shared_ptr<NCA>& nca) {
return nca->GetType() == type && nca->GetTitleId() == program_id;
});
return iter == ncas.end() ? nullptr : *iter;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index be25da2f6..50f44f598 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "common/settings.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/file_sys/control_metadata.h"
@@ -37,6 +38,27 @@ std::string LanguageEntry::GetDeveloperName() const {
developer_name.size());
}
+constexpr std::array<Language, 18> language_to_codes = {{
+ Language::Japanese,
+ Language::AmericanEnglish,
+ Language::French,
+ Language::German,
+ Language::Italian,
+ Language::Spanish,
+ Language::Chinese,
+ Language::Korean,
+ Language::Dutch,
+ Language::Portuguese,
+ Language::Russian,
+ Language::Taiwanese,
+ Language::BritishEnglish,
+ Language::CanadianFrench,
+ Language::LatinAmericanSpanish,
+ Language::Chinese,
+ Language::Taiwanese,
+ Language::BrazilianPortuguese,
+}};
+
NACP::NACP() = default;
NACP::NACP(VirtualFile file) {
@@ -45,9 +67,13 @@ NACP::NACP(VirtualFile file) {
NACP::~NACP() = default;
-const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
- if (language != Language::Default) {
- return raw.language_entries.at(static_cast<u8>(language));
+const LanguageEntry& NACP::GetLanguageEntry() const {
+ Language language = language_to_codes[Settings::values.language_index.GetValue()];
+
+ {
+ const auto& language_entry = raw.language_entries.at(static_cast<u8>(language));
+ if (!language_entry.GetApplicationName().empty())
+ return language_entry;
}
for (const auto& language_entry : raw.language_entries) {
@@ -55,16 +81,15 @@ const LanguageEntry& NACP::GetLanguageEntry(Language language) const {
return language_entry;
}
- // Fallback to English
- return GetLanguageEntry(Language::AmericanEnglish);
+ return raw.language_entries.at(static_cast<u8>(Language::AmericanEnglish));
}
-std::string NACP::GetApplicationName(Language language) const {
- return GetLanguageEntry(language).GetApplicationName();
+std::string NACP::GetApplicationName() const {
+ return GetLanguageEntry().GetApplicationName();
}
-std::string NACP::GetDeveloperName(Language language) const {
- return GetLanguageEntry(language).GetDeveloperName();
+std::string NACP::GetDeveloperName() const {
+ return GetLanguageEntry().GetDeveloperName();
}
u64 NACP::GetTitleId() const {
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 75295519c..6a81873b1 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -101,9 +101,9 @@ public:
explicit NACP(VirtualFile file);
~NACP();
- const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const;
- std::string GetApplicationName(Language language = Language::Default) const;
- std::string GetDeveloperName(Language language = Language::Default) const;
+ const LanguageEntry& GetLanguageEntry() const;
+ std::string GetApplicationName() const;
+ std::string GetDeveloperName() const;
u64 GetTitleId() const;
u64 GetDLCBaseTitleId() const;
std::string GetVersionString() const;
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index e0cdf3520..f00479bd3 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -33,11 +33,55 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
return Loader::ResultStatus::ErrorBadACIHeader;
}
- if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) {
+ // Load acid_file_access per-component instead of the entire struct, since this struct does not
+ // reflect the layout of the real data.
+ std::size_t current_offset = acid_header.fac_offset;
+ if (sizeof(FileAccessControl::version) != file->ReadBytes(&acid_file_access.version,
+ sizeof(FileAccessControl::version),
+ current_offset)) {
+ return Loader::ResultStatus::ErrorBadFileAccessControl;
+ }
+ if (sizeof(FileAccessControl::permissions) !=
+ file->ReadBytes(&acid_file_access.permissions, sizeof(FileAccessControl::permissions),
+ current_offset += sizeof(FileAccessControl::version) + 3)) {
+ return Loader::ResultStatus::ErrorBadFileAccessControl;
+ }
+ if (sizeof(FileAccessControl::unknown) !=
+ file->ReadBytes(&acid_file_access.unknown, sizeof(FileAccessControl::unknown),
+ current_offset + sizeof(FileAccessControl::permissions))) {
return Loader::ResultStatus::ErrorBadFileAccessControl;
}
- if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) {
+ // Load aci_file_access per-component instead of the entire struct, same as acid_file_access
+ current_offset = aci_header.fah_offset;
+ if (sizeof(FileAccessHeader::version) != file->ReadBytes(&aci_file_access.version,
+ sizeof(FileAccessHeader::version),
+ current_offset)) {
+ return Loader::ResultStatus::ErrorBadFileAccessHeader;
+ }
+ if (sizeof(FileAccessHeader::permissions) !=
+ file->ReadBytes(&aci_file_access.permissions, sizeof(FileAccessHeader::permissions),
+ current_offset += sizeof(FileAccessHeader::version) + 3)) {
+ return Loader::ResultStatus::ErrorBadFileAccessHeader;
+ }
+ if (sizeof(FileAccessHeader::unk_offset) !=
+ file->ReadBytes(&aci_file_access.unk_offset, sizeof(FileAccessHeader::unk_offset),
+ current_offset += sizeof(FileAccessHeader::permissions))) {
+ return Loader::ResultStatus::ErrorBadFileAccessHeader;
+ }
+ if (sizeof(FileAccessHeader::unk_size) !=
+ file->ReadBytes(&aci_file_access.unk_size, sizeof(FileAccessHeader::unk_size),
+ current_offset += sizeof(FileAccessHeader::unk_offset))) {
+ return Loader::ResultStatus::ErrorBadFileAccessHeader;
+ }
+ if (sizeof(FileAccessHeader::unk_offset_2) !=
+ file->ReadBytes(&aci_file_access.unk_offset_2, sizeof(FileAccessHeader::unk_offset_2),
+ current_offset += sizeof(FileAccessHeader::unk_size))) {
+ return Loader::ResultStatus::ErrorBadFileAccessHeader;
+ }
+ if (sizeof(FileAccessHeader::unk_size_2) !=
+ file->ReadBytes(&aci_file_access.unk_size_2, sizeof(FileAccessHeader::unk_size_2),
+ current_offset + sizeof(FileAccessHeader::unk_offset_2))) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
@@ -83,7 +127,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address
}
bool ProgramMetadata::Is64BitProgram() const {
- return npdm_header.has_64_bit_instructions;
+ return npdm_header.has_64_bit_instructions.As<bool>();
}
ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {
@@ -152,9 +196,7 @@ void ProgramMetadata::Print() const {
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
- u64_le permissions_l; // local copy to fix alignment error
- std::memcpy(&permissions_l, &acid_file_access.permissions, sizeof(permissions_l));
- LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", permissions_l);
+ LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);
// Begin ACI0 printing (actual perms, unsigned)
LOG_DEBUG(Service_FS, "Magic: {:.4}", aci_header.magic.data());
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index e8fb4e27f..2e8960b07 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -144,20 +144,18 @@ private:
static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong");
-#pragma pack(push, 1)
-
+ // FileAccessControl and FileAccessHeader need loaded per-component: this layout does not
+ // reflect the real layout to avoid reference binding to misaligned addresses
struct FileAccessControl {
u8 version;
- INSERT_PADDING_BYTES(3);
+ // 3 padding bytes
u64_le permissions;
std::array<u8, 0x20> unknown;
};
- static_assert(sizeof(FileAccessControl) == 0x2C, "FS access control structure size is wrong");
-
struct FileAccessHeader {
u8 version;
- INSERT_PADDING_BYTES(3);
+ // 3 padding bytes
u64_le permissions;
u32_le unk_offset;
u32_le unk_size;
@@ -165,10 +163,6 @@ private:
u32_le unk_size_2;
};
- static_assert(sizeof(FileAccessHeader) == 0x1C, "FS access header structure size is wrong");
-
-#pragma pack(pop)
-
Header npdm_header;
AciHeader aci_header;
AcidHeader acid_header;
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 8c1b2523c..1567da231 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/uuid.h"
#include "core/core.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs.h"
@@ -59,6 +60,36 @@ bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataA
attr.title_id == 0 && attr.save_id == 0);
}
+std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
+ u128 user_id) {
+ // Only detect nand user saves.
+ const auto space_id_path = [space_id]() -> std::string_view {
+ switch (space_id) {
+ case SaveDataSpaceId::NandUser:
+ return "/user/save";
+ default:
+ return "";
+ }
+ }();
+
+ if (space_id_path.empty()) {
+ return "";
+ }
+
+ Common::UUID uuid;
+ std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID));
+
+ // Only detect account/device saves from the future location.
+ switch (type) {
+ case SaveDataType::SaveData:
+ return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id);
+ case SaveDataType::DeviceSaveData:
+ return fmt::format("{}/device/{:016X}/1", space_id_path, title_id);
+ default:
+ return "";
+ }
+}
+
} // Anonymous namespace
std::string SaveDataAttribute::DebugInfo() const {
@@ -82,7 +113,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
- GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+ GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->CreateDirectoryRelative(save_directory);
@@ -99,7 +130,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
const SaveDataAttribute& meta) const {
const auto save_directory =
- GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+ GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->GetDirectoryRelative(save_directory);
@@ -134,9 +165,9 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
}
}
-std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId space,
- SaveDataType type, u64 title_id, u128 user_id,
- u64 save_id) {
+std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir,
+ SaveDataSpaceId space, SaveDataType type, u64 title_id,
+ u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
@@ -145,6 +176,17 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
}
}
+ // For compat with a future impl.
+ if (std::string future_path =
+ GetFutureSaveDataPath(space, type, title_id & ~(0xFFULL), user_id);
+ !future_path.empty()) {
+ // Check if this location exists, and prefer it over the old.
+ if (const auto future_dir = dir->GetDirectoryRelative(future_path); future_dir != nullptr) {
+ LOG_INFO(Service_FS, "Using save at new location: {}", future_path);
+ return future_path;
+ }
+ }
+
std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
@@ -167,7 +209,8 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
- const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
+ const auto path =
+ GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME);
@@ -185,7 +228,8 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const {
- const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
+ const auto path =
+ GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index a763b94c8..d3633ef03 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -95,8 +95,8 @@ public:
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
- static std::string GetFullPath(Core::System& system, SaveDataSpaceId space, SaveDataType type,
- u64 title_id, u128 user_id, u64 save_id);
+ static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space,
+ SaveDataType type, u64 title_id, u128 user_id, u64 save_id);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,