Merge pull request #2930 from DarkLordZach/gamecard-partitions
file_sys: Add code to access raw gamecard partitions and lazily load them
This commit is contained in:
		| @@ -31,7 +31,7 @@ constexpr std::array partition_names{ | |||||||
|  |  | ||||||
| XCI::XCI(VirtualFile file_) | XCI::XCI(VirtualFile file_) | ||||||
|     : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, |     : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, | ||||||
|       partitions(partition_names.size()) { |       partitions(partition_names.size()), partitions_raw(partition_names.size()) { | ||||||
|     if (file->ReadObject(&header) != sizeof(GamecardHeader)) { |     if (file->ReadObject(&header) != sizeof(GamecardHeader)) { | ||||||
|         status = Loader::ResultStatus::ErrorBadXCIHeader; |         status = Loader::ResultStatus::ErrorBadXCIHeader; | ||||||
|         return; |         return; | ||||||
| @@ -42,8 +42,10 @@ XCI::XCI(VirtualFile file_) | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PartitionFilesystem main_hfs( |     PartitionFilesystem main_hfs(std::make_shared<OffsetVfsFile>( | ||||||
|         std::make_shared<OffsetVfsFile>(file, header.hfs_size, header.hfs_offset)); |         file, file->GetSize() - header.hfs_offset, header.hfs_offset)); | ||||||
|  |  | ||||||
|  |     update_normal_partition_end = main_hfs.GetFileOffsets()["secure"]; | ||||||
|  |  | ||||||
|     if (main_hfs.GetStatus() != Loader::ResultStatus::Success) { |     if (main_hfs.GetStatus() != Loader::ResultStatus::Success) { | ||||||
|         status = main_hfs.GetStatus(); |         status = main_hfs.GetStatus(); | ||||||
| @@ -55,9 +57,7 @@ XCI::XCI(VirtualFile file_) | |||||||
|         const auto partition_idx = static_cast<std::size_t>(partition); |         const auto partition_idx = static_cast<std::size_t>(partition); | ||||||
|         auto raw = main_hfs.GetFile(partition_names[partition_idx]); |         auto raw = main_hfs.GetFile(partition_names[partition_idx]); | ||||||
|  |  | ||||||
|         if (raw != nullptr) { |         partitions_raw[static_cast<std::size_t>(partition)] = std::move(raw); | ||||||
|             partitions[partition_idx] = std::make_shared<PartitionFilesystem>(std::move(raw)); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     secure_partition = std::make_shared<NSP>( |     secure_partition = std::make_shared<NSP>( | ||||||
| @@ -71,13 +71,7 @@ XCI::XCI(VirtualFile file_) | |||||||
|         program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; |         program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto result = AddNCAFromPartition(XCIPartition::Update); |     auto result = AddNCAFromPartition(XCIPartition::Normal); | ||||||
|     if (result != Loader::ResultStatus::Success) { |  | ||||||
|         status = result; |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     result = AddNCAFromPartition(XCIPartition::Normal); |  | ||||||
|     if (result != Loader::ResultStatus::Success) { |     if (result != Loader::ResultStatus::Success) { | ||||||
|         status = result; |         status = result; | ||||||
|         return; |         return; | ||||||
| @@ -104,34 +98,114 @@ Loader::ResultStatus XCI::GetProgramNCAStatus() const { | |||||||
|     return program_nca_status; |     return program_nca_status; | ||||||
| } | } | ||||||
|  |  | ||||||
| VirtualDir XCI::GetPartition(XCIPartition partition) const { | VirtualDir XCI::GetPartition(XCIPartition partition) { | ||||||
|  |     const auto id = static_cast<std::size_t>(partition); | ||||||
|  |     if (partitions[id] == nullptr && partitions_raw[id] != nullptr) { | ||||||
|  |         partitions[id] = std::make_shared<PartitionFilesystem>(partitions_raw[id]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return partitions[static_cast<std::size_t>(partition)]; |     return partitions[static_cast<std::size_t>(partition)]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::vector<VirtualDir> XCI::GetPartitions() { | ||||||
|  |     std::vector<VirtualDir> out; | ||||||
|  |     for (const auto& id : | ||||||
|  |          {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { | ||||||
|  |         const auto part = GetPartition(id); | ||||||
|  |         if (part != nullptr) { | ||||||
|  |             out.push_back(part); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return out; | ||||||
|  | } | ||||||
|  |  | ||||||
| std::shared_ptr<NSP> XCI::GetSecurePartitionNSP() const { | std::shared_ptr<NSP> XCI::GetSecurePartitionNSP() const { | ||||||
|     return secure_partition; |     return secure_partition; | ||||||
| } | } | ||||||
|  |  | ||||||
| VirtualDir XCI::GetSecurePartition() const { | VirtualDir XCI::GetSecurePartition() { | ||||||
|     return GetPartition(XCIPartition::Secure); |     return GetPartition(XCIPartition::Secure); | ||||||
| } | } | ||||||
|  |  | ||||||
| VirtualDir XCI::GetNormalPartition() const { | VirtualDir XCI::GetNormalPartition() { | ||||||
|     return GetPartition(XCIPartition::Normal); |     return GetPartition(XCIPartition::Normal); | ||||||
| } | } | ||||||
|  |  | ||||||
| VirtualDir XCI::GetUpdatePartition() const { | VirtualDir XCI::GetUpdatePartition() { | ||||||
|     return GetPartition(XCIPartition::Update); |     return GetPartition(XCIPartition::Update); | ||||||
| } | } | ||||||
|  |  | ||||||
| VirtualDir XCI::GetLogoPartition() const { | VirtualDir XCI::GetLogoPartition() { | ||||||
|     return GetPartition(XCIPartition::Logo); |     return GetPartition(XCIPartition::Logo); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetPartitionRaw(XCIPartition partition) const { | ||||||
|  |     return partitions_raw[static_cast<std::size_t>(partition)]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetSecurePartitionRaw() const { | ||||||
|  |     return GetPartitionRaw(XCIPartition::Secure); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetStoragePartition0() const { | ||||||
|  |     return std::make_shared<OffsetVfsFile>(file, update_normal_partition_end, 0, "partition0"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetStoragePartition1() const { | ||||||
|  |     return std::make_shared<OffsetVfsFile>(file, file->GetSize() - update_normal_partition_end, | ||||||
|  |                                            update_normal_partition_end, "partition1"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetNormalPartitionRaw() const { | ||||||
|  |     return GetPartitionRaw(XCIPartition::Normal); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetUpdatePartitionRaw() const { | ||||||
|  |     return GetPartitionRaw(XCIPartition::Update); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VirtualFile XCI::GetLogoPartitionRaw() const { | ||||||
|  |     return GetPartitionRaw(XCIPartition::Logo); | ||||||
|  | } | ||||||
|  |  | ||||||
| u64 XCI::GetProgramTitleID() const { | u64 XCI::GetProgramTitleID() const { | ||||||
|     return secure_partition->GetProgramTitleID(); |     return secure_partition->GetProgramTitleID(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | u32 XCI::GetSystemUpdateVersion() { | ||||||
|  |     const auto update = GetPartition(XCIPartition::Update); | ||||||
|  |     if (update == nullptr) | ||||||
|  |         return 0; | ||||||
|  |  | ||||||
|  |     for (const auto& file : update->GetFiles()) { | ||||||
|  |         NCA nca{file, nullptr, 0, keys}; | ||||||
|  |  | ||||||
|  |         if (nca.GetStatus() != Loader::ResultStatus::Success) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |         if (nca.GetType() == NCAContentType::Meta && nca.GetTitleId() == 0x0100000000000816) { | ||||||
|  |             const auto dir = nca.GetSubdirectories()[0]; | ||||||
|  |             const auto cnmt = dir->GetFile("SystemUpdate_0100000000000816.cnmt"); | ||||||
|  |             if (cnmt == nullptr) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             CNMT cnmt_data{cnmt}; | ||||||
|  |  | ||||||
|  |             const auto metas = cnmt_data.GetMetaRecords(); | ||||||
|  |             if (metas.empty()) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             return metas[0].title_version; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | u64 XCI::GetSystemUpdateTitleID() const { | ||||||
|  |     return 0x0100000000000816; | ||||||
|  | } | ||||||
|  |  | ||||||
| bool XCI::HasProgramNCA() const { | bool XCI::HasProgramNCA() const { | ||||||
|     return program != nullptr; |     return program != nullptr; | ||||||
| } | } | ||||||
| @@ -201,7 +275,7 @@ std::array<u8, 0x200> XCI::GetCertificate() const { | |||||||
|  |  | ||||||
| Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | ||||||
|     const auto partition_index = static_cast<std::size_t>(part); |     const auto partition_index = static_cast<std::size_t>(part); | ||||||
|     const auto& partition = partitions[partition_index]; |     const auto partition = GetPartition(part); | ||||||
|  |  | ||||||
|     if (partition == nullptr) { |     if (partition == nullptr) { | ||||||
|         return Loader::ResultStatus::ErrorXCIMissingPartition; |         return Loader::ResultStatus::ErrorXCIMissingPartition; | ||||||
| @@ -232,7 +306,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | |||||||
|     return Loader::ResultStatus::Success; |     return Loader::ResultStatus::Success; | ||||||
| } | } | ||||||
|  |  | ||||||
| u8 XCI::GetFormatVersion() const { | u8 XCI::GetFormatVersion() { | ||||||
|     return GetLogoPartition() == nullptr ? 0x1 : 0x2; |     return GetLogoPartition() == nullptr ? 0x1 : 0x2; | ||||||
| } | } | ||||||
| } // namespace FileSys | } // namespace FileSys | ||||||
|   | |||||||
| @@ -81,14 +81,24 @@ public: | |||||||
|     Loader::ResultStatus GetStatus() const; |     Loader::ResultStatus GetStatus() const; | ||||||
|     Loader::ResultStatus GetProgramNCAStatus() const; |     Loader::ResultStatus GetProgramNCAStatus() const; | ||||||
|  |  | ||||||
|     u8 GetFormatVersion() const; |     u8 GetFormatVersion(); | ||||||
|  |  | ||||||
|  |     VirtualDir GetPartition(XCIPartition partition); | ||||||
|  |     std::vector<VirtualDir> GetPartitions(); | ||||||
|  |  | ||||||
|     VirtualDir GetPartition(XCIPartition partition) const; |  | ||||||
|     std::shared_ptr<NSP> GetSecurePartitionNSP() const; |     std::shared_ptr<NSP> GetSecurePartitionNSP() const; | ||||||
|     VirtualDir GetSecurePartition() const; |     VirtualDir GetSecurePartition(); | ||||||
|     VirtualDir GetNormalPartition() const; |     VirtualDir GetNormalPartition(); | ||||||
|     VirtualDir GetUpdatePartition() const; |     VirtualDir GetUpdatePartition(); | ||||||
|     VirtualDir GetLogoPartition() const; |     VirtualDir GetLogoPartition(); | ||||||
|  |  | ||||||
|  |     VirtualFile GetPartitionRaw(XCIPartition partition) const; | ||||||
|  |     VirtualFile GetSecurePartitionRaw() const; | ||||||
|  |     VirtualFile GetStoragePartition0() const; | ||||||
|  |     VirtualFile GetStoragePartition1() const; | ||||||
|  |     VirtualFile GetNormalPartitionRaw() const; | ||||||
|  |     VirtualFile GetUpdatePartitionRaw() const; | ||||||
|  |     VirtualFile GetLogoPartitionRaw() const; | ||||||
|  |  | ||||||
|     u64 GetProgramTitleID() const; |     u64 GetProgramTitleID() const; | ||||||
|     u32 GetSystemUpdateVersion(); |     u32 GetSystemUpdateVersion(); | ||||||
| @@ -123,6 +133,7 @@ private: | |||||||
|     Loader::ResultStatus program_nca_status; |     Loader::ResultStatus program_nca_status; | ||||||
|  |  | ||||||
|     std::vector<VirtualDir> partitions; |     std::vector<VirtualDir> partitions; | ||||||
|  |     std::vector<VirtualFile> partitions_raw; | ||||||
|     std::shared_ptr<NSP> secure_partition; |     std::shared_ptr<NSP> secure_partition; | ||||||
|     std::shared_ptr<NCA> program; |     std::shared_ptr<NCA> program; | ||||||
|     std::vector<std::shared_ptr<NCA>> ncas; |     std::vector<std::shared_ptr<NCA>> ncas; | ||||||
|   | |||||||
| @@ -65,6 +65,9 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { | |||||||
|         std::string name( |         std::string name( | ||||||
|             reinterpret_cast<const char*>(&file_data[strtab_offset + entry.strtab_offset])); |             reinterpret_cast<const char*>(&file_data[strtab_offset + entry.strtab_offset])); | ||||||
|  |  | ||||||
|  |         offsets.insert_or_assign(name, content_offset + entry.offset); | ||||||
|  |         sizes.insert_or_assign(name, entry.size); | ||||||
|  |  | ||||||
|         pfs_files.emplace_back(std::make_shared<OffsetVfsFile>( |         pfs_files.emplace_back(std::make_shared<OffsetVfsFile>( | ||||||
|             file, entry.size, content_offset + entry.offset, std::move(name))); |             file, entry.size, content_offset + entry.offset, std::move(name))); | ||||||
|     } |     } | ||||||
| @@ -78,6 +81,14 @@ Loader::ResultStatus PartitionFilesystem::GetStatus() const { | |||||||
|     return status; |     return status; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::map<std::string, u64> PartitionFilesystem::GetFileOffsets() const { | ||||||
|  |     return offsets; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::map<std::string, u64> PartitionFilesystem::GetFileSizes() const { | ||||||
|  |     return sizes; | ||||||
|  | } | ||||||
|  |  | ||||||
| std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const { | std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const { | ||||||
|     return pfs_files; |     return pfs_files; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,6 +29,9 @@ public: | |||||||
|  |  | ||||||
|     Loader::ResultStatus GetStatus() const; |     Loader::ResultStatus GetStatus() const; | ||||||
|  |  | ||||||
|  |     std::map<std::string, u64> GetFileOffsets() const; | ||||||
|  |     std::map<std::string, u64> GetFileSizes() const; | ||||||
|  |  | ||||||
|     std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; |     std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | ||||||
|     std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; |     std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | ||||||
|     std::string GetName() const override; |     std::string GetName() const override; | ||||||
| @@ -80,6 +83,9 @@ private: | |||||||
|     bool is_hfs = false; |     bool is_hfs = false; | ||||||
|     std::size_t content_offset = 0; |     std::size_t content_offset = 0; | ||||||
|  |  | ||||||
|  |     std::map<std::string, u64> offsets; | ||||||
|  |     std::map<std::string, u64> sizes; | ||||||
|  |  | ||||||
|     std::vector<VirtualFile> pfs_files; |     std::vector<VirtualFile> pfs_files; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user