summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/submission_package.cpp169
-rw-r--r--src/core/file_sys/submission_package.h5
2 files changed, 101 insertions, 73 deletions
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 11264878d..09bf077cd 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -18,6 +18,39 @@
18#include "core/loader/loader.h" 18#include "core/loader/loader.h"
19 19
20namespace FileSys { 20namespace FileSys {
21namespace {
22void SetTicketKeys(const std::vector<VirtualFile>& files) {
23 Core::Crypto::KeyManager keys;
24
25 for (const auto& ticket_file : files) {
26 if (ticket_file == nullptr) {
27 continue;
28 }
29
30 if (ticket_file->GetExtension() != "tik") {
31 continue;
32 }
33
34 if (ticket_file->GetSize() <
35 Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
36 continue;
37 }
38
39 Core::Crypto::Key128 key{};
40 ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
41
42 // We get the name without the extension in order to create the rights ID.
43 std::string name_only(ticket_file->GetName());
44 name_only.erase(name_only.size() - 4);
45
46 const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
47 u128 rights_id;
48 std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
49 keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
50 }
51}
52} // Anonymous namespace
53
21NSP::NSP(VirtualFile file_) 54NSP::NSP(VirtualFile file_)
22 : file(std::move(file_)), status{Loader::ResultStatus::Success}, 55 : file(std::move(file_)), status{Loader::ResultStatus::Success},
23 pfs(std::make_shared<PartitionFilesystem>(file)) { 56 pfs(std::make_shared<PartitionFilesystem>(file)) {
@@ -26,83 +59,16 @@ NSP::NSP(VirtualFile file_)
26 return; 59 return;
27 } 60 }
28 61
62 const auto files = pfs->GetFiles();
63
29 if (IsDirectoryExeFS(pfs)) { 64 if (IsDirectoryExeFS(pfs)) {
30 extracted = true; 65 extracted = true;
31 exefs = pfs; 66 InitializeExeFSAndRomFS(files);
32
33 const auto& files = pfs->GetFiles();
34 const auto romfs_iter =
35 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
36 return file->GetName().find(".romfs") != std::string::npos;
37 });
38 if (romfs_iter != files.end())
39 romfs = *romfs_iter;
40 return; 67 return;
41 } 68 }
42 69
43 extracted = false; 70 SetTicketKeys(files);
44 const auto files = pfs->GetFiles(); 71 ReadNCAs(files);
45
46 Core::Crypto::KeyManager keys;
47 for (const auto& ticket_file : files) {
48 if (ticket_file->GetExtension() == "tik") {
49 if (ticket_file == nullptr ||
50 ticket_file->GetSize() <
51 Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
52 continue;
53 }
54
55 Core::Crypto::Key128 key{};
56 ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
57 std::string_view name_only(ticket_file->GetName());
58 name_only.remove_suffix(4);
59 const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
60 u128 rights_id;
61 std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
62 keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
63 }
64 }
65
66 for (const auto& outer_file : files) {
67 if (outer_file->GetName().substr(outer_file->GetName().size() - 9) == ".cnmt.nca") {
68 const auto nca = std::make_shared<NCA>(outer_file);
69 if (nca->GetStatus() != Loader::ResultStatus::Success) {
70 program_status[nca->GetTitleId()] = nca->GetStatus();
71 continue;
72 }
73
74 const auto section0 = nca->GetSubdirectories()[0];
75
76 for (const auto& inner_file : section0->GetFiles()) {
77 if (inner_file->GetExtension() != "cnmt")
78 continue;
79
80 const CNMT cnmt(inner_file);
81 auto& ncas_title = ncas[cnmt.GetTitleID()];
82
83 ncas_title[ContentRecordType::Meta] = nca;
84 for (const auto& rec : cnmt.GetContentRecords()) {
85 const auto id_string = Common::HexArrayToString(rec.nca_id, false);
86 const auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
87 if (next_file == nullptr) {
88 LOG_WARNING(Service_FS,
89 "NCA with ID {}.nca is listed in content metadata, but cannot "
90 "be found in PFS. NSP appears to be corrupted.",
91 id_string);
92 continue;
93 }
94
95 auto next_nca = std::make_shared<NCA>(next_file);
96 if (next_nca->GetType() == NCAContentType::Program)
97 program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
98 if (next_nca->GetStatus() == Loader::ResultStatus::Success)
99 ncas_title[rec.type] = std::move(next_nca);
100 }
101
102 break;
103 }
104 }
105 }
106} 72}
107 73
108NSP::~NSP() = default; 74NSP::~NSP() = default;
@@ -242,4 +208,63 @@ VirtualDir NSP::GetParentDirectory() const {
242bool NSP::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { 208bool NSP::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
243 return false; 209 return false;
244} 210}
211
212void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
213 exefs = pfs;
214
215 const auto romfs_iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& file) {
216 return file->GetName().rfind(".romfs") != std::string::npos;
217 });
218
219 if (romfs_iter == files.end()) {
220 return;
221 }
222
223 romfs = *romfs_iter;
224}
225
226void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
227 for (const auto& outer_file : files) {
228 if (outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
229 continue;
230 }
231
232 const auto nca = std::make_shared<NCA>(outer_file);
233 if (nca->GetStatus() != Loader::ResultStatus::Success) {
234 program_status[nca->GetTitleId()] = nca->GetStatus();
235 continue;
236 }
237
238 const auto section0 = nca->GetSubdirectories()[0];
239
240 for (const auto& inner_file : section0->GetFiles()) {
241 if (inner_file->GetExtension() != "cnmt")
242 continue;
243
244 const CNMT cnmt(inner_file);
245 auto& ncas_title = ncas[cnmt.GetTitleID()];
246
247 ncas_title[ContentRecordType::Meta] = nca;
248 for (const auto& rec : cnmt.GetContentRecords()) {
249 const auto id_string = Common::HexArrayToString(rec.nca_id, false);
250 const auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
251 if (next_file == nullptr) {
252 LOG_WARNING(Service_FS,
253 "NCA with ID {}.nca is listed in content metadata, but cannot "
254 "be found in PFS. NSP appears to be corrupted.",
255 id_string);
256 continue;
257 }
258
259 auto next_nca = std::make_shared<NCA>(next_file);
260 if (next_nca->GetType() == NCAContentType::Program)
261 program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
262 if (next_nca->GetStatus() == Loader::ResultStatus::Success)
263 ncas_title[rec.type] = std::move(next_nca);
264 }
265
266 break;
267 }
268 }
269}
245} // namespace FileSys 270} // namespace FileSys
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index e85a2b76e..da3dc5e9f 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -59,9 +59,12 @@ protected:
59 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; 59 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
60 60
61private: 61private:
62 void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files);
63 void ReadNCAs(const std::vector<VirtualFile>& files);
64
62 VirtualFile file; 65 VirtualFile file;
63 66
64 bool extracted; 67 bool extracted = false;
65 Loader::ResultStatus status; 68 Loader::ResultStatus status;
66 std::map<u64, Loader::ResultStatus> program_status; 69 std::map<u64, Loader::ResultStatus> program_status;
67 70