diff options
Diffstat (limited to 'src/core/file_sys')
| -rw-r--r-- | src/core/file_sys/bis_factory.cpp | 23 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 98 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.h | 4 | ||||
| -rw-r--r-- | src/core/file_sys/sdmc_factory.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 8 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.h | 6 |
8 files changed, 118 insertions, 31 deletions
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 8935a62c3..285277ef8 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -12,6 +12,10 @@ namespace FileSys { +constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB +constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB +constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB + 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_)), @@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const { u64 BISFactory::GetSystemNANDFreeSpace() const { const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system"); - if (sys_dir == nullptr) - return 0; + if (sys_dir == nullptr) { + return GetSystemNANDTotalSpace(); + } return GetSystemNANDTotalSpace() - sys_dir->GetSize(); } u64 BISFactory::GetSystemNANDTotalSpace() const { - return static_cast<u64>(Settings::values.nand_system_size); + return NAND_SYSTEM_SIZE; } u64 BISFactory::GetUserNANDFreeSpace() const { - const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user"); - if (usr_dir == nullptr) - return 0; - - return GetUserNANDTotalSpace() - usr_dir->GetSize(); + // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes. + // Set the free space to be 1 MiB less than the total as a workaround to this issue. + return GetUserNANDTotalSpace() - 0x100000; } u64 BISFactory::GetUserNANDTotalSpace() const { - return static_cast<u64>(Settings::values.nand_user_size); + return NAND_USER_SIZE; } u64 BISFactory::GetFullNANDTotalSpace() const { - return static_cast<u64>(Settings::values.nand_total_size); + return NAND_TOTAL_SIZE; } VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index d126ae8dd..2aff2708a 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp @@ -240,7 +240,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) RomFSBuildContext::~RomFSBuildContext() = default; -std::map<u64, VirtualFile> RomFSBuildContext::Build() { +std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); dir_hash_table_size = 4 * dir_hash_table_entry_count; @@ -294,7 +294,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { cur_dir->parent->child = cur_dir; } - std::map<u64, VirtualFile> out; + std::multimap<u64, VirtualFile> out; // Populate file tables. for (const auto& it : files) { diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h index a62502193..049de180b 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.h +++ b/src/core/file_sys/fsmitm_romfsbuild.h @@ -43,7 +43,7 @@ public: ~RomFSBuildContext(); // This finalizes the context. - std::map<u64, VirtualFile> Build(); + std::multimap<u64, VirtualFile> Build(); private: VirtualDir base; diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 27c1b0233..37351c561 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -547,6 +547,56 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); } +bool RegisteredCache::RemoveExistingEntry(u64 title_id) { + const auto delete_nca = [this](const NcaID& id) { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + + if (dir->GetFileRelative(path) == nullptr) { + return false; + } + + Core::Crypto::SHA256Hash hash{}; + mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); + const auto dirname = fmt::format("000000{:02X}", hash[0]); + + const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); + + const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false))); + + return res; + }; + + // If an entry exists in the registered cache, remove it + if (HasEntry(title_id, ContentRecordType::Meta)) { + LOG_INFO(Loader, + "Previously installed entry (v{}) for title_id={:016X} detected! " + "Attempting to remove...", + GetEntryVersion(title_id).value_or(0), title_id); + // Get all the ncas associated with the current CNMT and delete them + const auto meta_old_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{}); + const auto program_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{}); + const auto data_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{}); + const auto control_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{}); + const auto html_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{}); + const auto legal_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{}); + + delete_nca(meta_old_id); + delete_nca(program_id); + delete_nca(data_id); + delete_nca(control_id); + delete_nca(html_id); + delete_nca(legal_id); + return true; + } + return false; +} + InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, const VfsCopyFunction& copy) { const auto ncas = nsp.GetNCAsCollapsed(); @@ -560,31 +610,57 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex return InstallResult::ErrorMetaFailed; } - // Install Metadata File const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); - const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); - if (res != InstallResult::Success) - return res; + if ((*meta_iter)->GetSubdirectories().empty()) { + LOG_ERROR(Loader, + "The file you are attempting to install does not contain a section0 within the " + "metadata NCA and is therefore malformed. Verify that the file is valid."); + return InstallResult::ErrorMetaFailed; + } - // Install all the other NCAs const auto section0 = (*meta_iter)->GetSubdirectories()[0]; + + if (section0->GetFiles().empty()) { + LOG_ERROR(Loader, + "The file you are attempting to install does not contain a CNMT within the " + "metadata NCA and is therefore malformed. Verify that the file is valid."); + return InstallResult::ErrorMetaFailed; + } + const auto cnmt_file = section0->GetFiles()[0]; const CNMT cnmt(cnmt_file); + + const auto title_id = cnmt.GetTitleID(); + const auto result = RemoveExistingEntry(title_id); + + // Install Metadata File + const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); + if (res != InstallResult::Success) { + return res; + } + + // Install all the other NCAs for (const auto& record : cnmt.GetContentRecords()) { // Ignore DeltaFragments, they are not useful to us - if (record.type == ContentRecordType::DeltaFragment) + if (record.type == ContentRecordType::DeltaFragment) { continue; + } const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); - if (nca == nullptr) + if (nca == nullptr) { return InstallResult::ErrorCopyFailed; + } const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); - if (res2 != InstallResult::Success) + if (res2 != InstallResult::Success) { return res2; + } } Refresh(); + if (result) { + return InstallResult::OverwriteExisting; + } return InstallResult::Success; } @@ -610,8 +686,9 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); memcpy(&c_rec.nca_id, &c_rec.hash, 16); const CNMT new_cnmt(header, opt_header, {c_rec}, {}); - if (!RawInstallYuzuMeta(new_cnmt)) + if (!RawInstallYuzuMeta(new_cnmt)) { return InstallResult::ErrorMetaFailed; + } return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); } @@ -649,8 +726,9 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti } auto out = dir->CreateFileRelative(path); - if (out == nullptr) + if (out == nullptr) { return InstallResult::ErrorCopyFailed; + } return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success : InstallResult::ErrorCopyFailed; } diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index f339cd17b..29cf0d40c 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -34,6 +34,7 @@ using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile enum class InstallResult { Success, + OverwriteExisting, ErrorAlreadyExists, ErrorCopyFailed, ErrorMetaFailed, @@ -154,6 +155,9 @@ public: std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, std::optional<u64> title_id = {}) const override; + // Removes an existing entry based on title id + bool RemoveExistingEntry(u64 title_id); + // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure // there is a meta NCA and all of them are accessible. InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp index 5113a1ca6..6f732e4d8 100644 --- a/src/core/file_sys/sdmc_factory.cpp +++ b/src/core/file_sys/sdmc_factory.cpp @@ -10,6 +10,8 @@ namespace FileSys { +constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB + SDMCFactory::SDMCFactory(VirtualDir dir_) : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>( GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), @@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const { } u64 SDMCFactory::GetSDMCTotalSpace() const { - return static_cast<u64>(Settings::values.sdmc_size); + return SDMC_TOTAL_SIZE; } } // namespace FileSys diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 16d801c0c..e0ff70174 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp @@ -11,7 +11,7 @@ namespace FileSys { -static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& map) { +static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFile>& map) { const auto last_valid = --map.end(); for (auto iter = map.begin(); iter != last_valid;) { const auto old = iter++; @@ -27,12 +27,12 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s : name(std::move(name)) { std::size_t next_offset = 0; for (const auto& file : files_) { - files[next_offset] = file; + files.emplace(next_offset, file); next_offset += file->GetSize(); } } -ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) +ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name) : files(std::move(files_)), name(std::move(name)) { ASSERT(VerifyConcatenationMapContinuity(files)); } @@ -50,7 +50,7 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> f } VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, - std::map<u64, VirtualFile> files, + std::multimap<u64, VirtualFile> files, std::string name) { if (files.empty()) return nullptr; diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index c90f9d5d1..7a26343c0 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h @@ -15,7 +15,7 @@ namespace FileSys { // read-only. class ConcatenatedVfsFile : public VfsFile { ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); - ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); + ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name); public: ~ConcatenatedVfsFile() override; @@ -25,7 +25,7 @@ public: /// Convenience function that turns a map of offsets to files into a concatenated file, filling /// gaps with a given filler byte. - static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files, + static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::multimap<u64, VirtualFile> files, std::string name); std::string GetName() const override; @@ -40,7 +40,7 @@ public: private: // Maps starting offset to file -- more efficient. - std::map<u64, VirtualFile> files; + std::multimap<u64, VirtualFile> files; std::string name; }; |
