summaryrefslogtreecommitdiff
path: root/src/core/file_sys
diff options
context:
space:
mode:
authorGravatar Zach Hilman2019-04-10 12:21:51 -0400
committerGravatar Zach Hilman2019-09-21 16:43:10 -0400
commit8500ca797f430226c86edf694db6a96ee14a8333 (patch)
tree01679e386bd3c3343c9c154e42c9f420fe514de1 /src/core/file_sys
parentbis_factory: Fix mod loader edge-case with homebrew title IDs (diff)
downloadyuzu-8500ca797f430226c86edf694db6a96ee14a8333.tar.gz
yuzu-8500ca797f430226c86edf694db6a96ee14a8333.tar.xz
yuzu-8500ca797f430226c86edf694db6a96ee14a8333.zip
registered_cache: Implement PlaceholderCache to manage placeholder and installing content
Diffstat (limited to 'src/core/file_sys')
-rw-r--r--src/core/file_sys/registered_cache.cpp150
-rw-r--r--src/core/file_sys/registered_cache.h25
2 files changed, 175 insertions, 0 deletions
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 3725b10f7..93a20ab94 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -127,6 +127,156 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
127 return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt); 127 return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
128} 128}
129 129
130PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
131
132bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
133 const auto path = GetRelativePathFromNcaID(id, false, true, false);
134
135 if (dir->GetFileRelative(path) != nullptr) {
136 return false;
137 }
138
139 Core::Crypto::SHA256Hash hash{};
140 mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
141 const auto dirname = fmt::format("000000{:02X}", hash[0]);
142
143 const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
144
145 if (dir2 == nullptr)
146 return false;
147
148 const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
149
150 if (file == nullptr)
151 return false;
152
153 return file->Resize(size);
154}
155
156bool PlaceholderCache::Delete(const NcaID& id) const {
157 const auto path = GetRelativePathFromNcaID(id, false, true, false);
158
159 if (dir->GetFileRelative(path) == nullptr) {
160 return false;
161 }
162
163 Core::Crypto::SHA256Hash hash{};
164 mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
165 const auto dirname = fmt::format("000000{:02X}", hash[0]);
166
167 const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
168
169 const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
170
171 return res;
172}
173
174bool PlaceholderCache::Exists(const NcaID& id) const {
175 const auto path = GetRelativePathFromNcaID(id, false, true, false);
176
177 return dir->GetFileRelative(path) != nullptr;
178}
179
180bool PlaceholderCache::Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const {
181 const auto path = GetRelativePathFromNcaID(id, false, true, false);
182 const auto file = dir->GetFileRelative(path);
183
184 if (file == nullptr)
185 return false;
186
187 return file->WriteBytes(data, offset) == data.size();
188}
189
190bool PlaceholderCache::Register(RegisteredCache* cache, const NcaID& placeholder,
191 const NcaID& install) const {
192 const auto path = GetRelativePathFromNcaID(placeholder, false, true, false);
193 const auto file = dir->GetFileRelative(path);
194
195 if (file == nullptr)
196 return false;
197
198 const auto res = cache->RawInstallNCA(NCA{file}, &VfsRawCopy, false, install);
199
200 if (res != InstallResult::Success)
201 return false;
202
203 return Delete(placeholder);
204}
205
206bool PlaceholderCache::CleanAll() const {
207 return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName());
208}
209
210std::optional<std::array<u8, 0x10>> PlaceholderCache::GetRightsID(const NcaID& id) const {
211 const auto path = GetRelativePathFromNcaID(id, false, true, false);
212 const auto file = dir->GetFileRelative(path);
213
214 if (file == nullptr)
215 return std::nullopt;
216
217 NCA nca{file};
218
219 if (nca.GetStatus() != Loader::ResultStatus::Success &&
220 nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
221 return std::nullopt;
222 }
223
224 const auto rights_id = nca.GetRightsId();
225 if (rights_id == NcaID{})
226 return std::nullopt;
227
228 return rights_id;
229}
230
231u64 PlaceholderCache::Size(const NcaID& id) const {
232 const auto path = GetRelativePathFromNcaID(id, false, true, false);
233 const auto file = dir->GetFileRelative(path);
234
235 if (file == nullptr)
236 return 0;
237
238 return file->GetSize();
239}
240
241bool PlaceholderCache::SetSize(const NcaID& id, u64 new_size) const {
242 const auto path = GetRelativePathFromNcaID(id, false, true, false);
243 const auto file = dir->GetFileRelative(path);
244
245 if (file == nullptr)
246 return false;
247
248 return file->Resize(new_size);
249}
250
251std::vector<NcaID> PlaceholderCache::List() const {
252 std::vector<NcaID> out;
253 for (const auto& sdir : dir->GetSubdirectories()) {
254 for (const auto& file : sdir->GetFiles()) {
255 const auto name = file->GetName();
256 if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
257 name[35] == 'a') {
258 out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
259 }
260 }
261 }
262 return out;
263}
264
265NcaID PlaceholderCache::Generate() {
266 std::random_device device;
267 std::mt19937 gen(device());
268 std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
269
270 NcaID out{};
271
272 const auto v1 = distribution(gen);
273 const auto v2 = distribution(gen);
274 std::memcpy(out.data(), &v1, sizeof(u64));
275 std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
276
277 return out;
278}
279
130VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, 280VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
131 std::string_view path) const { 281 std::string_view path) const {
132 const auto file = dir->GetFileRelative(path); 282 const auto file = dir->GetFileRelative(path);
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 4398d63e1..d1eec240e 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -25,6 +25,8 @@ enum class NCAContentType : u8;
25enum class TitleType : u8; 25enum class TitleType : u8;
26 26
27struct ContentRecord; 27struct ContentRecord;
28struct MetaRecord;
29class RegisteredCache;
28 30
29using NcaID = std::array<u8, 0x10>; 31using NcaID = std::array<u8, 0x10>;
30using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; 32using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
@@ -89,6 +91,27 @@ protected:
89 Core::Crypto::KeyManager keys; 91 Core::Crypto::KeyManager keys;
90}; 92};
91 93
94class PlaceholderCache {
95public:
96 explicit PlaceholderCache(VirtualDir dir);
97
98 bool Create(const NcaID& id, u64 size) const;
99 bool Delete(const NcaID& id) const;
100 bool Exists(const NcaID& id) const;
101 bool Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const;
102 bool Register(RegisteredCache* cache, const NcaID& placeholder, const NcaID& install) const;
103 bool CleanAll() const;
104 std::optional<std::array<u8, 0x10>> GetRightsID(const NcaID& id) const;
105 u64 Size(const NcaID& id) const;
106 bool SetSize(const NcaID& id, u64 new_size) const;
107 std::vector<NcaID> List() const;
108
109 static NcaID Generate();
110
111private:
112 VirtualDir dir;
113};
114
92/* 115/*
93 * A class that catalogues NCAs in the registered directory structure. 116 * A class that catalogues NCAs in the registered directory structure.
94 * Nintendo's registered format follows this structure: 117 * Nintendo's registered format follows this structure:
@@ -103,6 +126,8 @@ protected:
103 * when 4GB splitting can be ignored.) 126 * when 4GB splitting can be ignored.)
104 */ 127 */
105class RegisteredCache : public ContentProvider { 128class RegisteredCache : public ContentProvider {
129 friend class PlaceholderCache;
130
106public: 131public:
107 // Parsing function defines the conversion from raw file to NCA. If there are other steps 132 // Parsing function defines the conversion from raw file to NCA. If there are other steps
108 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom 133 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom