summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp134
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h6
-rw-r--r--src/core/file_sys/romfs.cpp83
-rw-r--r--src/core/file_sys/vfs_concat.cpp4
-rw-r--r--src/core/file_sys/vfs_concat.h2
-rw-r--r--src/core/file_sys/vfs_layered.cpp21
6 files changed, 137 insertions, 113 deletions
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index f1d3e4129..dd9cca103 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cstring> 4#include <cstring>
5#include <span>
5#include <string_view> 6#include <string_view>
6#include "common/alignment.h" 7#include "common/alignment.h"
7#include "common/assert.h" 8#include "common/assert.h"
@@ -134,7 +135,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
134 135
135 child->size = child->source->GetSize(); 136 child->size = child->source->GetSize();
136 137
137 AddFile(parent, child); 138 AddFile(parent, std::move(child));
138 } 139 }
139 140
140 for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { 141 for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) {
@@ -163,36 +164,24 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
163 164
164bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 165bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
165 std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { 166 std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) {
166 // Check whether it's already in the known directories.
167 const auto [it, is_new] = directories.emplace(dir_ctx->path, nullptr);
168 if (!is_new) {
169 return false;
170 }
171
172 // Add a new directory. 167 // Add a new directory.
173 num_dirs++; 168 num_dirs++;
174 dir_table_size += 169 dir_table_size +=
175 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); 170 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
176 dir_ctx->parent = parent_dir_ctx; 171 dir_ctx->parent = std::move(parent_dir_ctx);
177 it->second = dir_ctx; 172 directories.emplace_back(std::move(dir_ctx));
178 173
179 return true; 174 return true;
180} 175}
181 176
182bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 177bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
183 std::shared_ptr<RomFSBuildFileContext> file_ctx) { 178 std::shared_ptr<RomFSBuildFileContext> file_ctx) {
184 // Check whether it's already in the known files.
185 const auto [it, is_new] = files.emplace(file_ctx->path, nullptr);
186 if (!is_new) {
187 return false;
188 }
189
190 // Add a new file. 179 // Add a new file.
191 num_files++; 180 num_files++;
192 file_table_size += 181 file_table_size +=
193 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); 182 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
194 file_ctx->parent = parent_dir_ctx; 183 file_ctx->parent = std::move(parent_dir_ctx);
195 it->second = file_ctx; 184 files.emplace_back(std::move(file_ctx));
196 185
197 return true; 186 return true;
198} 187}
@@ -201,7 +190,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_)
201 : base(std::move(base_)), ext(std::move(ext_)) { 190 : base(std::move(base_)), ext(std::move(ext_)) {
202 root = std::make_shared<RomFSBuildDirectoryContext>(); 191 root = std::make_shared<RomFSBuildDirectoryContext>();
203 root->path = "\0"; 192 root->path = "\0";
204 directories.emplace(root->path, root); 193 directories.emplace_back(root);
205 num_dirs = 1; 194 num_dirs = 1;
206 dir_table_size = 0x18; 195 dir_table_size = 0x18;
207 196
@@ -210,28 +199,43 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_)
210 199
211RomFSBuildContext::~RomFSBuildContext() = default; 200RomFSBuildContext::~RomFSBuildContext() = default;
212 201
213std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { 202std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() {
214 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); 203 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
215 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); 204 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
216 dir_hash_table_size = 4 * dir_hash_table_entry_count; 205 dir_hash_table_size = 4 * dir_hash_table_entry_count;
217 file_hash_table_size = 4 * file_hash_table_entry_count; 206 file_hash_table_size = 4 * file_hash_table_entry_count;
218 207
219 // Assign metadata pointers 208 // Assign metadata pointers.
220 RomFSHeader header{}; 209 RomFSHeader header{};
221 210
222 std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY); 211 std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size +
223 std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY); 212 dir_table_size);
224 213 u32* const dir_hash_table_pointer = reinterpret_cast<u32*>(metadata.data());
225 std::vector<u8> dir_table(dir_table_size); 214 u8* const dir_table_pointer = metadata.data() + dir_hash_table_size;
226 std::vector<u8> file_table(file_table_size); 215 u32* const file_hash_table_pointer =
227 216 reinterpret_cast<u32*>(metadata.data() + dir_hash_table_size + dir_table_size);
228 std::shared_ptr<RomFSBuildFileContext> cur_file; 217 u8* const file_table_pointer =
218 metadata.data() + dir_hash_table_size + dir_table_size + file_hash_table_size;
219
220 std::span<u32> dir_hash_table(dir_hash_table_pointer, dir_hash_table_entry_count);
221 std::span<u32> file_hash_table(file_hash_table_pointer, file_hash_table_entry_count);
222 std::span<u8> dir_table(dir_table_pointer, dir_table_size);
223 std::span<u8> file_table(file_table_pointer, file_table_size);
224
225 // Initialize hash tables.
226 std::memset(dir_hash_table.data(), 0xFF, dir_hash_table.size_bytes());
227 std::memset(file_hash_table.data(), 0xFF, file_hash_table.size_bytes());
228
229 // Sort tables by name.
230 std::sort(files.begin(), files.end(),
231 [](const auto& a, const auto& b) { return a->path < b->path; });
232 std::sort(directories.begin(), directories.end(),
233 [](const auto& a, const auto& b) { return a->path < b->path; });
229 234
230 // Determine file offsets. 235 // Determine file offsets.
231 u32 entry_offset = 0; 236 u32 entry_offset = 0;
232 std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; 237 std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr;
233 for (const auto& it : files) { 238 for (const auto& cur_file : files) {
234 cur_file = it.second;
235 file_partition_size = Common::AlignUp(file_partition_size, 16); 239 file_partition_size = Common::AlignUp(file_partition_size, 16);
236 cur_file->offset = file_partition_size; 240 cur_file->offset = file_partition_size;
237 file_partition_size += cur_file->size; 241 file_partition_size += cur_file->size;
@@ -243,34 +247,48 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
243 } 247 }
244 // Assign deferred parent/sibling ownership. 248 // Assign deferred parent/sibling ownership.
245 for (auto it = files.rbegin(); it != files.rend(); ++it) { 249 for (auto it = files.rbegin(); it != files.rend(); ++it) {
246 cur_file = it->second; 250 auto& cur_file = *it;
247 cur_file->sibling = cur_file->parent->file; 251 cur_file->sibling = cur_file->parent->file;
248 cur_file->parent->file = cur_file; 252 cur_file->parent->file = cur_file;
249 } 253 }
250 254
251 std::shared_ptr<RomFSBuildDirectoryContext> cur_dir;
252
253 // Determine directory offsets. 255 // Determine directory offsets.
254 entry_offset = 0; 256 entry_offset = 0;
255 for (const auto& it : directories) { 257 for (const auto& cur_dir : directories) {
256 cur_dir = it.second;
257 cur_dir->entry_offset = entry_offset; 258 cur_dir->entry_offset = entry_offset;
258 entry_offset += 259 entry_offset +=
259 static_cast<u32>(sizeof(RomFSDirectoryEntry) + 260 static_cast<u32>(sizeof(RomFSDirectoryEntry) +
260 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); 261 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
261 } 262 }
262 // Assign deferred parent/sibling ownership. 263 // Assign deferred parent/sibling ownership.
263 for (auto it = directories.rbegin(); it->second != root; ++it) { 264 for (auto it = directories.rbegin(); (*it) != root; ++it) {
264 cur_dir = it->second; 265 auto& cur_dir = *it;
265 cur_dir->sibling = cur_dir->parent->child; 266 cur_dir->sibling = cur_dir->parent->child;
266 cur_dir->parent->child = cur_dir; 267 cur_dir->parent->child = cur_dir;
267 } 268 }
268 269
269 std::multimap<u64, VirtualFile> out; 270 // Create output map.
271 std::vector<std::pair<u64, VirtualFile>> out;
272 out.reserve(num_files + 2);
273
274 // Set header fields.
275 header.header_size = sizeof(RomFSHeader);
276 header.file_hash_table_size = file_hash_table_size;
277 header.file_table_size = file_table_size;
278 header.dir_hash_table_size = dir_hash_table_size;
279 header.dir_table_size = dir_table_size;
280 header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
281 header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
282 header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
283 header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
284 header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
285
286 std::vector<u8> header_data(sizeof(RomFSHeader));
287 std::memcpy(header_data.data(), &header, header_data.size());
288 out.emplace_back(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
270 289
271 // Populate file tables. 290 // Populate file tables.
272 for (const auto& it : files) { 291 for (const auto& cur_file : files) {
273 cur_file = it.second;
274 RomFSFileEntry cur_entry{}; 292 RomFSFileEntry cur_entry{};
275 293
276 cur_entry.parent = cur_file->parent->entry_offset; 294 cur_entry.parent = cur_file->parent->entry_offset;
@@ -287,7 +305,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
287 305
288 cur_entry.name_size = name_size; 306 cur_entry.name_size = name_size;
289 307
290 out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); 308 out.emplace_back(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source));
291 std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); 309 std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
292 std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, 310 std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
293 Common::AlignUp(cur_entry.name_size, 4)); 311 Common::AlignUp(cur_entry.name_size, 4));
@@ -296,8 +314,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
296 } 314 }
297 315
298 // Populate dir tables. 316 // Populate dir tables.
299 for (const auto& it : directories) { 317 for (const auto& cur_dir : directories) {
300 cur_dir = it.second;
301 RomFSDirectoryEntry cur_entry{}; 318 RomFSDirectoryEntry cur_entry{};
302 319
303 cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; 320 cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset;
@@ -323,34 +340,13 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
323 cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); 340 cur_dir->path.data() + cur_dir->cur_path_ofs, name_size);
324 } 341 }
325 342
326 // Set header fields. 343 // Write metadata.
327 header.header_size = sizeof(RomFSHeader); 344 out.emplace_back(header.dir_hash_table_ofs,
328 header.file_hash_table_size = file_hash_table_size; 345 std::make_shared<VectorVfsFile>(std::move(metadata)));
329 header.file_table_size = file_table_size;
330 header.dir_hash_table_size = dir_hash_table_size;
331 header.dir_table_size = dir_table_size;
332 header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
333 header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
334 header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
335 header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
336 header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
337
338 std::vector<u8> header_data(sizeof(RomFSHeader));
339 std::memcpy(header_data.data(), &header, header_data.size());
340 out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
341 346
342 std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + 347 // Sort the output.
343 dir_table_size); 348 std::sort(out.begin(), out.end(),
344 std::size_t index = 0; 349 [](const auto& a, const auto& b) { return a.first < b.first; });
345 std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32));
346 index += dir_hash_table.size() * sizeof(u32);
347 std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size());
348 index += dir_table.size();
349 std::memcpy(metadata.data() + index, file_hash_table.data(),
350 file_hash_table.size() * sizeof(u32));
351 index += file_hash_table.size() * sizeof(u32);
352 std::memcpy(metadata.data() + index, file_table.data(), file_table.size());
353 out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata)));
354 350
355 return out; 351 return out;
356} 352}
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index 06e5d5a47..f387c79f1 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -22,14 +22,14 @@ public:
22 ~RomFSBuildContext(); 22 ~RomFSBuildContext();
23 23
24 // This finalizes the context. 24 // This finalizes the context.
25 std::multimap<u64, VirtualFile> Build(); 25 std::vector<std::pair<u64, VirtualFile>> Build();
26 26
27private: 27private:
28 VirtualDir base; 28 VirtualDir base;
29 VirtualDir ext; 29 VirtualDir ext;
30 std::shared_ptr<RomFSBuildDirectoryContext> root; 30 std::shared_ptr<RomFSBuildDirectoryContext> root;
31 std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories; 31 std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> directories;
32 std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files; 32 std::vector<std::shared_ptr<RomFSBuildFileContext>> files;
33 u64 num_dirs = 0; 33 u64 num_dirs = 0;
34 u64 num_files = 0; 34 u64 num_files = 0;
35 u64 dir_table_size = 0; 35 u64 dir_table_size = 0;
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 6de2103a0..6182598ae 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -55,44 +55,68 @@ struct FileEntry {
55}; 55};
56static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); 56static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
57 57
58template <typename Entry> 58struct RomFSTraversalContext {
59std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { 59 RomFSHeader header;
60 Entry entry{}; 60 VirtualFile file;
61 if (file->ReadObject(&entry, offset) != sizeof(Entry)) 61 std::vector<u8> directory_meta;
62 return {}; 62 std::vector<u8> file_meta;
63 std::string string(entry.name_length, '\0'); 63};
64 if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size()) 64
65template <typename EntryType, auto Member>
66std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, size_t offset) {
67 const size_t entry_end = offset + sizeof(EntryType);
68 const std::vector<u8>& vec = ctx.*Member;
69 const size_t size = vec.size();
70 const u8* data = vec.data();
71 EntryType entry{};
72
73 if (entry_end > size) {
65 return {}; 74 return {};
66 return {entry, string}; 75 }
76 std::memcpy(&entry, data + offset, sizeof(EntryType));
77
78 const size_t name_length = std::min(entry_end + entry.name_length, size) - entry_end;
79 std::string name(reinterpret_cast<const char*>(data + entry_end), name_length);
80
81 return {entry, std::move(name)};
82}
83
84std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
85 size_t directory_offset) {
86 return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
87}
88
89std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
90 size_t file_offset) {
91 return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
67} 92}
68 93
69void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, 94void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
70 u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { 95 std::shared_ptr<VectorVfsDirectory>& parent) {
71 while (this_file_offset != ROMFS_ENTRY_EMPTY) { 96 while (this_file_offset != ROMFS_ENTRY_EMPTY) {
72 auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); 97 auto entry = GetFileEntry(ctx, this_file_offset);
73 98
74 parent->AddFile(std::make_shared<OffsetVfsFile>( 99 parent->AddFile(std::make_shared<OffsetVfsFile>(ctx.file, entry.first.size,
75 file, entry.first.size, entry.first.offset + data_offset, entry.second)); 100 entry.first.offset + ctx.header.data_offset,
101 std::move(entry.second)));
76 102
77 this_file_offset = entry.first.sibling; 103 this_file_offset = entry.first.sibling;
78 } 104 }
79} 105}
80 106
81void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, 107void ProcessDirectory(const RomFSTraversalContext& ctx, u32 this_dir_offset,
82 std::size_t data_offset, u32 this_dir_offset,
83 std::shared_ptr<VectorVfsDirectory>& parent) { 108 std::shared_ptr<VectorVfsDirectory>& parent) {
84 while (this_dir_offset != ROMFS_ENTRY_EMPTY) { 109 while (this_dir_offset != ROMFS_ENTRY_EMPTY) {
85 auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); 110 auto entry = GetDirectoryEntry(ctx, this_dir_offset);
86 auto current = std::make_shared<VectorVfsDirectory>( 111 auto current = std::make_shared<VectorVfsDirectory>(
87 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); 112 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second);
88 113
89 if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { 114 if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
90 ProcessFile(file, file_offset, data_offset, entry.first.child_file, current); 115 ProcessFile(ctx, entry.first.child_file, current);
91 } 116 }
92 117
93 if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { 118 if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
94 ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir, 119 ProcessDirectory(ctx, entry.first.child_dir, current);
95 current);
96 } 120 }
97 121
98 parent->AddDirectory(current); 122 parent->AddDirectory(current);
@@ -107,22 +131,25 @@ VirtualDir ExtractRomFS(VirtualFile file) {
107 return root_container; 131 return root_container;
108 } 132 }
109 133
110 RomFSHeader header{}; 134 RomFSTraversalContext ctx{};
111 if (file->ReadObject(&header) != sizeof(RomFSHeader)) { 135
112 return root_container; 136 if (file->ReadObject(&ctx.header) != sizeof(RomFSHeader)) {
137 return nullptr;
113 } 138 }
114 139
115 if (header.header_size != sizeof(RomFSHeader)) { 140 if (ctx.header.header_size != sizeof(RomFSHeader)) {
116 return root_container; 141 return nullptr;
117 } 142 }
118 143
119 const u64 file_offset = header.file_meta.offset; 144 ctx.file = file;
120 const u64 dir_offset = header.directory_meta.offset; 145 ctx.directory_meta =
146 file->ReadBytes(ctx.header.directory_meta.size, ctx.header.directory_meta.offset);
147 ctx.file_meta = file->ReadBytes(ctx.header.file_meta.size, ctx.header.file_meta.offset);
121 148
122 ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); 149 ProcessDirectory(ctx, 0, root_container);
123 150
124 if (auto root = root_container->GetSubdirectory(""); root) { 151 if (auto root = root_container->GetSubdirectory(""); root) {
125 return std::make_shared<CachedVfsDirectory>(std::move(root)); 152 return root;
126 } 153 }
127 154
128 ASSERT(false); 155 ASSERT(false);
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 168b9cbec..7c7298527 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -59,8 +59,8 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
59 return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); 59 return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
60} 60}
61 61
62VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name, 62VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(
63 std::multimap<u64, VirtualFile>&& files) { 63 u8 filler_byte, std::string&& name, std::vector<std::pair<u64, VirtualFile>>&& files) {
64 // Fold trivial cases. 64 // Fold trivial cases.
65 if (files.empty()) { 65 if (files.empty()) {
66 return nullptr; 66 return nullptr;
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index cbddd12bd..b5f3d72e3 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -37,7 +37,7 @@ public:
37 /// Convenience function that turns a map of offsets to files into a concatenated file, filling 37 /// Convenience function that turns a map of offsets to files into a concatenated file, filling
38 /// gaps with a given filler byte. 38 /// gaps with a given filler byte.
39 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, 39 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name,
40 std::multimap<u64, VirtualFile>&& files); 40 std::vector<std::pair<u64, VirtualFile>>&& files);
41 41
42 std::string GetName() const override; 42 std::string GetName() const override;
43 std::size_t GetSize() const override; 43 std::size_t GetSize() const override;
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 08daca397..5551743fb 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -3,6 +3,7 @@
3 3
4#include <algorithm> 4#include <algorithm>
5#include <set> 5#include <set>
6#include <unordered_set>
6#include <utility> 7#include <utility>
7#include "core/file_sys/vfs_layered.h" 8#include "core/file_sys/vfs_layered.h"
8 9
@@ -59,13 +60,12 @@ std::string LayeredVfsDirectory::GetFullPath() const {
59 60
60std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { 61std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
61 std::vector<VirtualFile> out; 62 std::vector<VirtualFile> out;
62 std::set<std::string, std::less<>> out_names; 63 std::unordered_set<std::string> out_names;
63 64
64 for (const auto& layer : dirs) { 65 for (const auto& layer : dirs) {
65 for (auto& file : layer->GetFiles()) { 66 for (auto& file : layer->GetFiles()) {
66 auto file_name = file->GetName(); 67 const auto [it, is_new] = out_names.emplace(file->GetName());
67 if (!out_names.contains(file_name)) { 68 if (is_new) {
68 out_names.emplace(std::move(file_name));
69 out.emplace_back(std::move(file)); 69 out.emplace_back(std::move(file));
70 } 70 }
71 } 71 }
@@ -75,18 +75,19 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
75} 75}
76 76
77std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { 77std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
78 std::vector<std::string> names; 78 std::vector<VirtualDir> out;
79 std::unordered_set<std::string> out_names;
80
79 for (const auto& layer : dirs) { 81 for (const auto& layer : dirs) {
80 for (const auto& sd : layer->GetSubdirectories()) { 82 for (const auto& sd : layer->GetSubdirectories()) {
81 if (std::find(names.begin(), names.end(), sd->GetName()) == names.end()) 83 out_names.emplace(sd->GetName());
82 names.push_back(sd->GetName());
83 } 84 }
84 } 85 }
85 86
86 std::vector<VirtualDir> out; 87 out.reserve(out_names.size());
87 out.reserve(names.size()); 88 for (const auto& subdir : out_names) {
88 for (const auto& subdir : names)
89 out.emplace_back(GetSubdirectory(subdir)); 89 out.emplace_back(GetSubdirectory(subdir));
90 }
90 91
91 return out; 92 return out;
92} 93}