1 // Copyright 2018 yuzu emulator team
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <memory>
6 #include "common/assert.h"
7 #include "common/common_types.h"
8 #include "common/logging/log.h"
9 #include "core/file_sys/card_image.h"
10 #include "core/file_sys/common_funcs.h"
11 #include "core/file_sys/content_archive.h"
12 #include "core/file_sys/nca_metadata.h"
13 #include "core/file_sys/patch_manager.h"
14 #include "core/file_sys/registered_cache.h"
15 #include "core/file_sys/romfs_factory.h"
16 #include "core/hle/kernel/process.h"
17 #include "core/hle/service/filesystem/filesystem.h"
18 #include "core/loader/loader.h"
19
20 namespace FileSys {
21
RomFSFactory(Loader::AppLoader & app_loader,ContentProvider & provider,Service::FileSystem::FileSystemController & controller)22 RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider,
23 Service::FileSystem::FileSystemController& controller)
24 : content_provider{provider}, filesystem_controller{controller} {
25 // Load the RomFS from the app
26 if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) {
27 LOG_ERROR(Service_FS, "Unable to read RomFS!");
28 }
29
30 updatable = app_loader.IsRomFSUpdatable();
31 ivfc_offset = app_loader.ReadRomFSIVFCOffset();
32 }
33
34 RomFSFactory::~RomFSFactory() = default;
35
SetPackedUpdate(VirtualFile update_raw)36 void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
37 this->update_raw = std::move(update_raw);
38 }
39
OpenCurrentProcess(u64 current_process_title_id) const40 ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
41 if (!updatable) {
42 return MakeResult<VirtualFile>(file);
43 }
44
45 const PatchManager patch_manager{current_process_title_id, filesystem_controller,
46 content_provider};
47 return MakeResult<VirtualFile>(
48 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
49 }
50
OpenPatchedRomFS(u64 title_id,ContentRecordType type) const51 ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
52 auto nca = content_provider.GetEntry(title_id, type);
53
54 if (nca == nullptr) {
55 // TODO: Find the right error code to use here
56 return RESULT_UNKNOWN;
57 }
58
59 const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
60
61 return MakeResult<VirtualFile>(
62 patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type));
63 }
64
OpenPatchedRomFSWithProgramIndex(u64 title_id,u8 program_index,ContentRecordType type) const65 ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
66 u64 title_id, u8 program_index, ContentRecordType type) const {
67 const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index);
68
69 return OpenPatchedRomFS(res_title_id, type);
70 }
71
Open(u64 title_id,StorageId storage,ContentRecordType type) const72 ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
73 ContentRecordType type) const {
74 const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
75 if (res == nullptr) {
76 // TODO(DarkLordZach): Find the right error code to use here
77 return RESULT_UNKNOWN;
78 }
79
80 const auto romfs = res->GetRomFS();
81 if (romfs == nullptr) {
82 // TODO(DarkLordZach): Find the right error code to use here
83 return RESULT_UNKNOWN;
84 }
85
86 return MakeResult<VirtualFile>(romfs);
87 }
88
GetEntry(u64 title_id,StorageId storage,ContentRecordType type) const89 std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,
90 ContentRecordType type) const {
91 switch (storage) {
92 case StorageId::None:
93 return content_provider.GetEntry(title_id, type);
94 case StorageId::NandSystem:
95 return filesystem_controller.GetSystemNANDContents()->GetEntry(title_id, type);
96 case StorageId::NandUser:
97 return filesystem_controller.GetUserNANDContents()->GetEntry(title_id, type);
98 case StorageId::SdCard:
99 return filesystem_controller.GetSDMCContents()->GetEntry(title_id, type);
100 case StorageId::Host:
101 case StorageId::GameCard:
102 default:
103 UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
104 return nullptr;
105 }
106 }
107
108 } // namespace FileSys
109