diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/file_sys/bis_factory.cpp | 9 | ||||
-rw-r--r-- | src/core/file_sys/bis_factory.h | 4 | ||||
-rw-r--r-- | src/core/file_sys/card_image.cpp | 2 | ||||
-rw-r--r-- | src/core/file_sys/card_image.h | 16 | ||||
-rw-r--r-- | src/core/file_sys/content_archive.cpp | 5 | ||||
-rw-r--r-- | src/core/file_sys/content_archive.h | 3 | ||||
-rw-r--r-- | src/core/file_sys/control_metadata.cpp | 6 | ||||
-rw-r--r-- | src/core/file_sys/control_metadata.h | 1 | ||||
-rw-r--r-- | src/core/file_sys/errors.h | 25 | ||||
-rw-r--r-- | src/core/file_sys/patch_manager.cpp | 62 | ||||
-rw-r--r-- | src/core/file_sys/registered_cache.cpp | 13 | ||||
-rw-r--r-- | src/core/file_sys/registered_cache.h | 3 | ||||
-rw-r--r-- | src/core/file_sys/savedata_factory.cpp | 32 | ||||
-rw-r--r-- | src/core/file_sys/savedata_factory.h | 3 | ||||
-rw-r--r-- | src/core/file_sys/submission_package.cpp | 2 | ||||
-rw-r--r-- | src/core/file_sys/submission_package.h | 2 |
16 files changed, 139 insertions, 49 deletions
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 76a2b7e86..e29f70b3a 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -8,8 +8,9 @@ namespace FileSys { -BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_) +BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), + dump_root(std::move(dump_root_)), sysnand_cache(std::make_unique<RegisteredCache>( GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), usrnand_cache(std::make_unique<RegisteredCache>( @@ -32,4 +33,10 @@ VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const { return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id)); } +VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const { + if (title_id == 0) + return nullptr; + return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id)); +} + } // namespace FileSys diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index 364d309bd..453c11ad2 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h @@ -17,17 +17,19 @@ class RegisteredCache; /// registered caches. class BISFactory { public: - explicit BISFactory(VirtualDir nand_root, VirtualDir load_root); + explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root); ~BISFactory(); RegisteredCache* GetSystemNANDContents() const; RegisteredCache* GetUserNANDContents() const; VirtualDir GetModificationLoadRoot(u64 title_id) const; + VirtualDir GetModificationDumpRoot(u64 title_id) const; private: VirtualDir nand_root; VirtualDir load_root; + VirtualDir dump_root; std::unique_ptr<RegisteredCache> sysnand_cache; std::unique_ptr<RegisteredCache> usrnand_cache; diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 1ece55731..2c145bd09 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -176,7 +176,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) { if (file->GetExtension() != "nca") continue; - auto nca = std::make_shared<NCA>(file); + auto nca = std::make_shared<NCA>(file, nullptr, 0, keys); // TODO(DarkLordZach): Add proper Rev1+ Support if (nca->IsUpdate()) continue; diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 8f62571cf..a350496f7 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -9,6 +9,7 @@ #include <vector> #include "common/common_types.h" #include "common/swap.h" +#include "core/crypto/key_manager.h" #include "core/file_sys/vfs.h" namespace Loader { @@ -31,7 +32,18 @@ enum class GamecardSize : u8 { }; struct GamecardInfo { - std::array<u8, 0x70> data; + u64_le firmware_version; + u32_le access_control_flags; + u32_le read_wait_time1; + u32_le read_wait_time2; + u32_le write_wait_time1; + u32_le write_wait_time2; + u32_le firmware_mode; + u32_le cup_version; + std::array<u8, 4> reserved1; + u64_le update_partition_hash; + u64_le cup_id; + std::array<u8, 0x38> reserved2; }; static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size."); @@ -107,5 +119,7 @@ private: std::shared_ptr<NSP> secure_partition; std::shared_ptr<NCA> program; std::vector<std::shared_ptr<NCA>> ncas; + + Core::Crypto::KeyManager keys; }; } // namespace FileSys diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index b46fe893c..19b6f8600 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -101,8 +101,9 @@ static bool IsValidNCA(const NCAHeader& header) { return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); } -NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) - : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { +NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset, + Core::Crypto::KeyManager keys_) + : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) { if (file == nullptr) { status = Loader::ResultStatus::ErrorNullFile; return; diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 4bba55607..99294cbb4 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -79,7 +79,8 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) { class NCA : public ReadOnlyVfsDirectory { public: explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, - u64 bktr_base_ivfc_offset = 0); + u64 bktr_base_ivfc_offset = 0, + Core::Crypto::KeyManager keys = Core::Crypto::KeyManager()); ~NCA() override; Loader::ResultStatus GetStatus() const; diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index a012c2be9..c8fa912bf 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -66,4 +66,10 @@ std::string NACP::GetVersionString() const { return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), raw->version_string.size()); } + +std::vector<u8> NACP::GetRawBytes() const { + std::vector<u8> out(sizeof(RawNACP)); + std::memcpy(out.data(), raw.get(), sizeof(RawNACP)); + return out; +} } // namespace FileSys diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 141f7e056..bfaad46b4 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -81,6 +81,7 @@ public: u64 GetTitleId() const; u64 GetDLCBaseTitleId() const; std::string GetVersionString() const; + std::vector<u8> GetRawBytes() const; private: std::unique_ptr<RawNACP> raw; diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index fea0593c7..e4a4ee4ab 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h @@ -8,25 +8,10 @@ namespace FileSys { -namespace ErrCodes { -enum { - NotFound = 1, - TitleNotFound = 1002, - SdCardNotFound = 2001, - RomFSNotFound = 2520, -}; -} - -constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound); - -// TODO(bunnei): Replace these with correct errors for Switch OS -constexpr ResultCode ERROR_INVALID_PATH(-1); -constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1); -constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1); -constexpr ResultCode ERROR_FILE_NOT_FOUND(-1); -constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1); -constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1); -constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1); -constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1); +constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1}; +constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002}; +constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001}; +constexpr ResultCode ERROR_INVALID_OFFSET{ErrorModule::FS, 6061}; +constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::FS, 6062}; } // namespace FileSys diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 0c1156989..e8df08724 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -19,12 +19,18 @@ #include "core/file_sys/vfs_vector.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" +#include "core/settings.h" namespace FileSys { constexpr u64 SINGLE_BYTE_MODULUS = 0x100; constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; +constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ + "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", + "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9", +}; + struct NSOBuildHeader { u32_le magic; INSERT_PADDING_BYTES(0x3C); @@ -56,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { if (exefs == nullptr) return exefs; + if (Settings::values.dump_exefs) { + LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); + const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); + if (dump_dir != nullptr) { + const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); + VfsRawCopyD(exefs, exefs_dir); + } + } + const auto installed = Service::FileSystem::GetUnionContents(); // Game Updates @@ -69,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { exefs = update->GetExeFS(); } + // LayeredExeFS + const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); + if (load_dir != nullptr && load_dir->GetSize() > 0) { + auto patch_dirs = load_dir->GetSubdirectories(); + std::sort( + patch_dirs.begin(), patch_dirs.end(), + [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); + + std::vector<VirtualDir> layers; + layers.reserve(patch_dirs.size() + 1); + for (const auto& subdir : patch_dirs) { + auto exefs_dir = subdir->GetSubdirectory("exefs"); + if (exefs_dir != nullptr) + layers.push_back(std::move(exefs_dir)); + } + layers.push_back(exefs); + + auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers)); + if (layered != nullptr) { + LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully"); + exefs = std::move(layered); + } + } + return exefs; } @@ -119,6 +158,18 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const { const auto build_id_raw = Common::HexArrayToString(header.build_id); const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); + if (Settings::values.dump_nso) { + LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id); + const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); + if (dump_dir != nullptr) { + const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); + const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id)); + + file->Resize(nso.size()); + file->WriteBytes(nso); + } + } + LOG_INFO(Loader, "Patching NSO for build_id={}", build_id); const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); @@ -301,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam if (IsDirValidAndNonEmpty(exefs_dir)) { bool ips = false; bool ipswitch = false; + bool layeredfs = false; for (const auto& file : exefs_dir->GetFiles()) { - if (file->GetExtension() == "ips") + if (file->GetExtension() == "ips") { ips = true; - else if (file->GetExtension() == "pchtxt") + } else if (file->GetExtension() == "pchtxt") { ipswitch = true; + } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(), + file->GetName()) != EXEFS_FILE_NAMES.end()) { + layeredfs = true; + } } if (ips) AppendCommaIfNotEmpty(types, "IPS"); if (ipswitch) AppendCommaIfNotEmpty(types, "IPSwitch"); + if (layeredfs) + AppendCommaIfNotEmpty(types, "LayeredExeFS"); } if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) AppendCommaIfNotEmpty(types, "LayeredFS"); diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 96302a241..a3f8f2f73 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -106,9 +106,12 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) { VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const { - if (dir->GetFileRelative(path) != nullptr) - return dir->GetFileRelative(path); - if (dir->GetDirectoryRelative(path) != nullptr) { + const auto file = dir->GetFileRelative(path); + if (file != nullptr) + return file; + + const auto nca_dir = dir->GetDirectoryRelative(path); + if (nca_dir != nullptr) { const auto nca_dir = dir->GetDirectoryRelative(path); VirtualFile file = nullptr; @@ -225,7 +228,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) { if (file == nullptr) continue; - const auto nca = std::make_shared<NCA>(parser(file, id)); + const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys); if (nca->GetStatus() != Loader::ResultStatus::Success || nca->GetType() != NCAContentType::Meta) { continue; @@ -315,7 +318,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t const auto raw = GetEntryRaw(title_id, type); if (raw == nullptr) return nullptr; - return std::make_unique<NCA>(raw); + return std::make_unique<NCA>(raw, nullptr, 0, keys); } std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const { diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 6cfb16017..6b89db8de 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -12,6 +12,7 @@ #include <vector> #include <boost/container/flat_map.hpp> #include "common/common_types.h" +#include "core/crypto/key_manager.h" #include "core/file_sys/vfs.h" namespace FileSys { @@ -133,6 +134,8 @@ private: VirtualDir dir; RegisteredCacheParsingFunction parser; + Core::Crypto::KeyManager keys; + // maps tid -> NcaID of meta boost::container::flat_map<u64, NcaID> meta_id; // maps tid -> meta diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index ef1aaebbb..5434f2149 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -83,28 +83,32 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr return MakeResult<VirtualDir>(std::move(out)); } -std::string SaveDataFactory::GetFullPath(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 && title_id == 0) - title_id = Core::CurrentProcess()->GetTitleID(); - - std::string out; +VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const { + return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space)); +} +std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { switch (space) { case SaveDataSpaceId::NandSystem: - out = "/system/"; - break; + return "/system/"; case SaveDataSpaceId::NandUser: - out = "/user/"; - break; + return "/user/"; case SaveDataSpaceId::TemporaryStorage: - out = "/temp/"; - break; + return "/temp/"; default: ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); + return "/unrecognized/"; ///< To prevent corruption when ignoring asserts. } +} + +std::string SaveDataFactory::GetFullPath(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 && title_id == 0) + title_id = Core::CurrentProcess()->GetTitleID(); + + std::string out = GetSaveDataSpaceIdPath(space); switch (type) { case SaveDataType::SystemSaveData: diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index d69ef6741..2a0088040 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -52,6 +52,9 @@ public: ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); + VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; + + static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id); diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 2aaba4179..e1a4210db 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp @@ -252,7 +252,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { continue; } - auto next_nca = std::make_shared<NCA>(next_file); + auto next_nca = std::make_shared<NCA>(next_file, nullptr, 0, keys); if (next_nca->GetType() == NCAContentType::Program) program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); if (next_nca->GetStatus() == Loader::ResultStatus::Success || diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index 338080b7e..9a28ed5bb 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h @@ -70,6 +70,8 @@ private: std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas; std::vector<VirtualFile> ticket_files; + Core::Crypto::KeyManager keys; + VirtualFile romfs; VirtualDir exefs; }; |