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 <fmt/format.h>
6 #include "common/file_util.h"
7 #include "core/file_sys/bis_factory.h"
8 #include "core/file_sys/mode.h"
9 #include "core/file_sys/registered_cache.h"
10 #include "core/file_sys/vfs.h"
11 
12 namespace FileSys {
13 
14 constexpr u64 NAND_USER_SIZE = 0x680000000;  // 26624 MiB
15 constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB
16 constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB
17 
BISFactory(VirtualDir nand_root_,VirtualDir load_root_,VirtualDir dump_root_)18 BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
19     : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
20       dump_root(std::move(dump_root_)),
21       sysnand_cache(std::make_unique<RegisteredCache>(
22           GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
23       usrnand_cache(std::make_unique<RegisteredCache>(
24           GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))),
25       sysnand_placeholder(std::make_unique<PlaceholderCache>(
26           GetOrCreateDirectoryRelative(nand_root, "/system/Contents/placehld"))),
27       usrnand_placeholder(std::make_unique<PlaceholderCache>(
28           GetOrCreateDirectoryRelative(nand_root, "/user/Contents/placehld"))) {}
29 
30 BISFactory::~BISFactory() = default;
31 
GetSystemNANDContentDirectory() const32 VirtualDir BISFactory::GetSystemNANDContentDirectory() const {
33     return GetOrCreateDirectoryRelative(nand_root, "/system/Contents");
34 }
35 
GetUserNANDContentDirectory() const36 VirtualDir BISFactory::GetUserNANDContentDirectory() const {
37     return GetOrCreateDirectoryRelative(nand_root, "/user/Contents");
38 }
39 
GetSystemNANDContents() const40 RegisteredCache* BISFactory::GetSystemNANDContents() const {
41     return sysnand_cache.get();
42 }
43 
GetUserNANDContents() const44 RegisteredCache* BISFactory::GetUserNANDContents() const {
45     return usrnand_cache.get();
46 }
47 
GetSystemNANDPlaceholder() const48 PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const {
49     return sysnand_placeholder.get();
50 }
51 
GetUserNANDPlaceholder() const52 PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const {
53     return usrnand_placeholder.get();
54 }
55 
GetModificationLoadRoot(u64 title_id) const56 VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
57     // LayeredFS doesn't work on updates and title id-less homebrew
58     if (title_id == 0 || (title_id & 0xFFF) == 0x800)
59         return nullptr;
60     return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
61 }
62 
GetModificationDumpRoot(u64 title_id) const63 VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
64     if (title_id == 0)
65         return nullptr;
66     return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
67 }
68 
OpenPartition(BisPartitionId id) const69 VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
70     switch (id) {
71     case BisPartitionId::CalibrationFile:
72         return GetOrCreateDirectoryRelative(nand_root, "/prodinfof");
73     case BisPartitionId::SafeMode:
74         return GetOrCreateDirectoryRelative(nand_root, "/safe");
75     case BisPartitionId::System:
76         return GetOrCreateDirectoryRelative(nand_root, "/system");
77     case BisPartitionId::User:
78         return GetOrCreateDirectoryRelative(nand_root, "/user");
79     default:
80         return nullptr;
81     }
82 }
83 
OpenPartitionStorage(BisPartitionId id,VirtualFilesystem file_system) const84 VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
85                                              VirtualFilesystem file_system) const {
86     auto& keys = Core::Crypto::KeyManager::Instance();
87     Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
88         Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
89     keys.PopulateFromPartitionData(pdm);
90 
91     switch (id) {
92     case BisPartitionId::CalibrationBinary:
93         return pdm.GetDecryptedProdInfo();
94     case BisPartitionId::BootConfigAndPackage2Part1:
95     case BisPartitionId::BootConfigAndPackage2Part2:
96     case BisPartitionId::BootConfigAndPackage2Part3:
97     case BisPartitionId::BootConfigAndPackage2Part4:
98     case BisPartitionId::BootConfigAndPackage2Part5:
99     case BisPartitionId::BootConfigAndPackage2Part6: {
100         const auto new_id = static_cast<u8>(id) -
101                             static_cast<u8>(BisPartitionId::BootConfigAndPackage2Part1) +
102                             static_cast<u8>(Core::Crypto::Package2Type::NormalMain);
103         return pdm.GetPackage2Raw(static_cast<Core::Crypto::Package2Type>(new_id));
104     }
105     default:
106         return nullptr;
107     }
108 }
109 
GetImageDirectory() const110 VirtualDir BISFactory::GetImageDirectory() const {
111     return GetOrCreateDirectoryRelative(nand_root, "/user/Album");
112 }
113 
GetSystemNANDFreeSpace() const114 u64 BISFactory::GetSystemNANDFreeSpace() const {
115     const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
116     if (sys_dir == nullptr) {
117         return GetSystemNANDTotalSpace();
118     }
119 
120     return GetSystemNANDTotalSpace() - sys_dir->GetSize();
121 }
122 
GetSystemNANDTotalSpace() const123 u64 BISFactory::GetSystemNANDTotalSpace() const {
124     return NAND_SYSTEM_SIZE;
125 }
126 
GetUserNANDFreeSpace() const127 u64 BISFactory::GetUserNANDFreeSpace() const {
128     // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes.
129     // Set the free space to be 1 MiB less than the total as a workaround to this issue.
130     return GetUserNANDTotalSpace() - 0x100000;
131 }
132 
GetUserNANDTotalSpace() const133 u64 BISFactory::GetUserNANDTotalSpace() const {
134     return NAND_USER_SIZE;
135 }
136 
GetFullNANDTotalSpace() const137 u64 BISFactory::GetFullNANDTotalSpace() const {
138     return NAND_TOTAL_SIZE;
139 }
140 
GetBCATDirectory(u64 title_id) const141 VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const {
142     return GetOrCreateDirectoryRelative(nand_root,
143                                         fmt::format("/system/save/bcat/{:016X}", title_id));
144 }
145 
146 } // namespace FileSys
147