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