diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/file_sys/bis_factory.cpp | 2 | ||||
| -rw-r--r-- | src/core/file_sys/bis_factory.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.cpp | 358 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.h | 70 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.hpp | 106 | ||||
| -rw-r--r-- | src/core/file_sys/patch_manager.cpp | 66 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 9 | ||||
| -rw-r--r-- | src/core/file_sys/romfs.cpp | 9 | ||||
| -rw-r--r-- | src/core/file_sys/romfs.h | 8 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.h | 5 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 21 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.h | 58 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_layered.cpp | 15 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_layered.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_real.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_real.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_static.h | 3 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_vector.cpp | 7 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_vector.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 2 |
22 files changed, 378 insertions, 378 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ead86fd85..23fd6e920 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -33,7 +33,7 @@ add_library(core STATIC | |||
| 33 | file_sys/directory.h | 33 | file_sys/directory.h |
| 34 | file_sys/errors.h | 34 | file_sys/errors.h |
| 35 | file_sys/fsmitm_romfsbuild.cpp | 35 | file_sys/fsmitm_romfsbuild.cpp |
| 36 | file_sys/fsmitm_romfsbuild.hpp | 36 | file_sys/fsmitm_romfsbuild.h |
| 37 | file_sys/mode.h | 37 | file_sys/mode.h |
| 38 | file_sys/nca_metadata.cpp | 38 | file_sys/nca_metadata.cpp |
| 39 | file_sys/nca_metadata.h | 39 | file_sys/nca_metadata.h |
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 012e08e7d..6102ef476 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp | |||
| @@ -2,9 +2,9 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <fmt/format.h> | ||
| 5 | #include "core/file_sys/bis_factory.h" | 6 | #include "core/file_sys/bis_factory.h" |
| 6 | #include "core/file_sys/registered_cache.h" | 7 | #include "core/file_sys/registered_cache.h" |
| 7 | #include "fmt/format.h" | ||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h index 0d81967cc..c352e0925 100644 --- a/src/core/file_sys/bis_factory.h +++ b/src/core/file_sys/bis_factory.h | |||
| @@ -17,7 +17,7 @@ class RegisteredCache; | |||
| 17 | /// registered caches. | 17 | /// registered caches. |
| 18 | class BISFactory { | 18 | class BISFactory { |
| 19 | public: | 19 | public: |
| 20 | BISFactory(VirtualDir nand_root, VirtualDir load_root); | 20 | explicit BISFactory(VirtualDir nand_root, VirtualDir load_root); |
| 21 | ~BISFactory(); | 21 | ~BISFactory(); |
| 22 | 22 | ||
| 23 | std::shared_ptr<RegisteredCache> GetSystemNANDContents() const; | 23 | std::shared_ptr<RegisteredCache> GetSystemNANDContents() const; |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index a6fe6719d..21fc3d796 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -24,9 +24,9 @@ | |||
| 24 | 24 | ||
| 25 | #include <cstring> | 25 | #include <cstring> |
| 26 | #include "common/assert.h" | 26 | #include "common/assert.h" |
| 27 | #include "fsmitm_romfsbuild.hpp" | 27 | #include "core/file_sys/fsmitm_romfsbuild.h" |
| 28 | #include "vfs.h" | 28 | #include "core/file_sys/vfs.h" |
| 29 | #include "vfs_vector.h" | 29 | #include "core/file_sys/vfs_vector.h" |
| 30 | 30 | ||
| 31 | namespace FileSys { | 31 | namespace FileSys { |
| 32 | 32 | ||
| @@ -35,7 +35,7 @@ constexpr u64 FS_MAX_PATH = 0x301; | |||
| 35 | constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF; | 35 | constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF; |
| 36 | constexpr u32 ROMFS_FILEPARTITION_OFS = 0x200; | 36 | constexpr u32 ROMFS_FILEPARTITION_OFS = 0x200; |
| 37 | 37 | ||
| 38 | /* Types for building a RomFS. */ | 38 | // Types for building a RomFS. |
| 39 | struct RomFSHeader { | 39 | struct RomFSHeader { |
| 40 | u64 header_size; | 40 | u64 header_size; |
| 41 | u64 dir_hash_table_ofs; | 41 | u64 dir_hash_table_ofs; |
| @@ -57,7 +57,6 @@ struct RomFSDirectoryEntry { | |||
| 57 | u32 file; | 57 | u32 file; |
| 58 | u32 hash; | 58 | u32 hash; |
| 59 | u32 name_size; | 59 | u32 name_size; |
| 60 | char name[]; | ||
| 61 | }; | 60 | }; |
| 62 | static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size."); | 61 | static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size."); |
| 63 | 62 | ||
| @@ -68,37 +67,63 @@ struct RomFSFileEntry { | |||
| 68 | u64 size; | 67 | u64 size; |
| 69 | u32 hash; | 68 | u32 hash; |
| 70 | u32 name_size; | 69 | u32 name_size; |
| 71 | char name[]; | ||
| 72 | }; | 70 | }; |
| 73 | static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size."); | 71 | static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size."); |
| 74 | 72 | ||
| 75 | struct RomFSBuildFileContext; | 73 | struct RomFSBuildFileContext; |
| 76 | 74 | ||
| 77 | struct RomFSBuildDirectoryContext { | 75 | struct RomFSBuildDirectoryContext { |
| 78 | char* path; | 76 | std::string path = ""; |
| 79 | u32 cur_path_ofs; | 77 | u32 cur_path_ofs = 0; |
| 80 | u32 path_len; | 78 | u32 path_len = 0; |
| 81 | u32 entry_offset = 0; | 79 | u32 entry_offset = 0; |
| 82 | RomFSBuildDirectoryContext* parent = nullptr; | 80 | std::shared_ptr<RomFSBuildDirectoryContext> parent; |
| 83 | RomFSBuildDirectoryContext* child = nullptr; | 81 | std::shared_ptr<RomFSBuildDirectoryContext> child; |
| 84 | RomFSBuildDirectoryContext* sibling = nullptr; | 82 | std::shared_ptr<RomFSBuildDirectoryContext> sibling; |
| 85 | RomFSBuildFileContext* file = nullptr; | 83 | std::shared_ptr<RomFSBuildFileContext> file; |
| 86 | }; | 84 | }; |
| 87 | 85 | ||
| 88 | struct RomFSBuildFileContext { | 86 | struct RomFSBuildFileContext { |
| 89 | char* path; | 87 | std::string path = ""; |
| 90 | u32 cur_path_ofs; | 88 | u32 cur_path_ofs = 0; |
| 91 | u32 path_len; | 89 | u32 path_len = 0; |
| 92 | u32 entry_offset = 0; | 90 | u32 entry_offset = 0; |
| 93 | u64 offset = 0; | 91 | u64 offset = 0; |
| 94 | u64 size = 0; | 92 | u64 size = 0; |
| 95 | RomFSBuildDirectoryContext* parent = nullptr; | 93 | std::shared_ptr<RomFSBuildDirectoryContext> parent; |
| 96 | RomFSBuildFileContext* sibling = nullptr; | 94 | std::shared_ptr<RomFSBuildFileContext> sibling; |
| 97 | VirtualFile source = nullptr; | 95 | VirtualFile source = nullptr; |
| 96 | |||
| 97 | RomFSBuildFileContext() : path(""), cur_path_ofs(0), path_len(0) {} | ||
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| 100 | void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, RomFSBuildDirectoryContext* parent) { | 100 | static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t path_len) { |
| 101 | std::vector<RomFSBuildDirectoryContext*> child_dirs; | 101 | u32 hash = parent ^ 123456789; |
| 102 | for (u32 i = 0; i < path_len; i++) { | ||
| 103 | hash = (hash >> 5) | (hash << 27); | ||
| 104 | hash ^= path[start + i]; | ||
| 105 | } | ||
| 106 | |||
| 107 | return hash; | ||
| 108 | } | ||
| 109 | |||
| 110 | static u32 romfs_get_hash_table_count(u32 num_entries) { | ||
| 111 | if (num_entries < 3) { | ||
| 112 | return 3; | ||
| 113 | } else if (num_entries < 19) { | ||
| 114 | return num_entries | 1; | ||
| 115 | } | ||
| 116 | u32 count = num_entries; | ||
| 117 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || | ||
| 118 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { | ||
| 119 | count++; | ||
| 120 | } | ||
| 121 | return count; | ||
| 122 | } | ||
| 123 | |||
| 124 | void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, | ||
| 125 | std::shared_ptr<RomFSBuildDirectoryContext> parent) { | ||
| 126 | std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs; | ||
| 102 | 127 | ||
| 103 | VirtualDir dir; | 128 | VirtualDir dir; |
| 104 | 129 | ||
| @@ -111,41 +136,33 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, RomFSBuildDirector | |||
| 111 | 136 | ||
| 112 | for (const auto& kv : entries) { | 137 | for (const auto& kv : entries) { |
| 113 | if (kv.second == VfsEntryType::Directory) { | 138 | if (kv.second == VfsEntryType::Directory) { |
| 114 | RomFSBuildDirectoryContext* child = new RomFSBuildDirectoryContext({0}); | 139 | const auto child = std::make_shared<RomFSBuildDirectoryContext>(); |
| 115 | /* Set child's path. */ | 140 | // Set child's path. |
| 116 | child->cur_path_ofs = parent->path_len + 1; | 141 | child->cur_path_ofs = parent->path_len + 1; |
| 117 | child->path_len = child->cur_path_ofs + kv.first.size(); | 142 | child->path_len = child->cur_path_ofs + kv.first.size(); |
| 118 | child->path = new char[child->path_len + 1]; | 143 | child->path = parent->path + "/" + kv.first; |
| 119 | strcpy(child->path, parent->path); | 144 | |
| 145 | // Sanity check on path_len | ||
| 120 | ASSERT(child->path_len < FS_MAX_PATH); | 146 | ASSERT(child->path_len < FS_MAX_PATH); |
| 121 | strcat(child->path + parent->path_len, "/"); | ||
| 122 | strcat(child->path + parent->path_len, kv.first.c_str()); | ||
| 123 | 147 | ||
| 124 | if (!this->AddDirectory(parent, child, nullptr)) { | 148 | if (AddDirectory(parent, child)) { |
| 125 | delete child->path; | ||
| 126 | delete child; | ||
| 127 | } else { | ||
| 128 | child_dirs.push_back(child); | 149 | child_dirs.push_back(child); |
| 129 | } | 150 | } |
| 130 | } else { | 151 | } else { |
| 131 | RomFSBuildFileContext* child = new RomFSBuildFileContext({0}); | 152 | const auto child = std::make_shared<RomFSBuildFileContext>(); |
| 132 | /* Set child's path. */ | 153 | // Set child's path. |
| 133 | child->cur_path_ofs = parent->path_len + 1; | 154 | child->cur_path_ofs = parent->path_len + 1; |
| 134 | child->path_len = child->cur_path_ofs + kv.first.size(); | 155 | child->path_len = child->cur_path_ofs + kv.first.size(); |
| 135 | child->path = new char[child->path_len + 1]; | 156 | child->path = parent->path + "/" + kv.first; |
| 136 | strcpy(child->path, parent->path); | 157 | |
| 158 | // Sanity check on path_len | ||
| 137 | ASSERT(child->path_len < FS_MAX_PATH); | 159 | ASSERT(child->path_len < FS_MAX_PATH); |
| 138 | strcat(child->path + parent->path_len, "/"); | ||
| 139 | strcat(child->path + parent->path_len, kv.first.c_str()); | ||
| 140 | 160 | ||
| 141 | child->source = root_romfs->GetFileRelative(child->path); | 161 | child->source = root_romfs->GetFileRelative(child->path); |
| 142 | 162 | ||
| 143 | child->size = child->source->GetSize(); | 163 | child->size = child->source->GetSize(); |
| 144 | 164 | ||
| 145 | if (!this->AddFile(parent, child)) { | 165 | AddFile(parent, child); |
| 146 | delete child->path; | ||
| 147 | delete child; | ||
| 148 | } | ||
| 149 | } | 166 | } |
| 150 | } | 167 | } |
| 151 | 168 | ||
| @@ -154,213 +171,200 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, RomFSBuildDirector | |||
| 154 | } | 171 | } |
| 155 | } | 172 | } |
| 156 | 173 | ||
| 157 | bool RomFSBuildContext::AddDirectory(RomFSBuildDirectoryContext* parent_dir_ctx, | 174 | bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, |
| 158 | RomFSBuildDirectoryContext* dir_ctx, | 175 | std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { |
| 159 | RomFSBuildDirectoryContext** out_dir_ctx) { | 176 | // Check whether it's already in the known directories. |
| 160 | /* Check whether it's already in the known directories. */ | 177 | const auto existing = directories.find(dir_ctx->path); |
| 161 | auto existing = this->directories.find(dir_ctx->path); | 178 | if (existing != directories.end()) |
| 162 | if (existing != this->directories.end()) { | ||
| 163 | if (out_dir_ctx) { | ||
| 164 | *out_dir_ctx = existing->second; | ||
| 165 | } | ||
| 166 | return false; | 179 | return false; |
| 167 | } | ||
| 168 | 180 | ||
| 169 | /* Add a new directory. */ | 181 | // Add a new directory. |
| 170 | this->num_dirs++; | 182 | num_dirs++; |
| 171 | this->dir_table_size += | 183 | dir_table_size += |
| 172 | sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3); | 184 | sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3); |
| 173 | dir_ctx->parent = parent_dir_ctx; | 185 | dir_ctx->parent = parent_dir_ctx; |
| 174 | this->directories.insert({dir_ctx->path, dir_ctx}); | 186 | directories.emplace(dir_ctx->path, dir_ctx); |
| 175 | 187 | ||
| 176 | if (out_dir_ctx) { | ||
| 177 | *out_dir_ctx = dir_ctx; | ||
| 178 | } | ||
| 179 | return true; | 188 | return true; |
| 180 | } | 189 | } |
| 181 | 190 | ||
| 182 | bool RomFSBuildContext::AddFile(RomFSBuildDirectoryContext* parent_dir_ctx, | 191 | bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, |
| 183 | RomFSBuildFileContext* file_ctx) { | 192 | std::shared_ptr<RomFSBuildFileContext> file_ctx) { |
| 184 | /* Check whether it's already in the known files. */ | 193 | // Check whether it's already in the known files. |
| 185 | auto existing = this->files.find(file_ctx->path); | 194 | const auto existing = files.find(file_ctx->path); |
| 186 | if (existing != this->files.end()) { | 195 | if (existing != files.end()) { |
| 187 | return false; | 196 | return false; |
| 188 | } | 197 | } |
| 189 | 198 | ||
| 190 | /* Add a new file. */ | 199 | // Add a new file. |
| 191 | this->num_files++; | 200 | num_files++; |
| 192 | this->file_table_size += | 201 | file_table_size += |
| 193 | sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3); | 202 | sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3); |
| 194 | file_ctx->parent = parent_dir_ctx; | 203 | file_ctx->parent = parent_dir_ctx; |
| 195 | this->files.insert({file_ctx->path, file_ctx}); | 204 | files.emplace(file_ctx->path, file_ctx); |
| 196 | 205 | ||
| 197 | return true; | 206 | return true; |
| 198 | } | 207 | } |
| 199 | 208 | ||
| 200 | RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_)) { | 209 | RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_)) { |
| 201 | this->root = new RomFSBuildDirectoryContext({0}); | 210 | root = std::make_shared<RomFSBuildDirectoryContext>(); |
| 202 | this->root->path = new char[1]; | 211 | root->path = "\0"; |
| 203 | this->root->path[0] = '\x00'; | 212 | directories.emplace(root->path, root); |
| 204 | this->directories.insert({this->root->path, this->root}); | 213 | num_dirs = 1; |
| 205 | this->num_dirs = 1; | 214 | dir_table_size = 0x18; |
| 206 | this->dir_table_size = 0x18; | 215 | |
| 207 | 216 | VisitDirectory(base, root); | |
| 208 | VisitDirectory(base, this->root); | ||
| 209 | } | 217 | } |
| 210 | 218 | ||
| 219 | RomFSBuildContext::~RomFSBuildContext() = default; | ||
| 220 | |||
| 211 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { | 221 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { |
| 212 | std::map<u64, VirtualFile> out; | 222 | const auto dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); |
| 213 | RomFSBuildFileContext* cur_file; | 223 | const auto file_hash_table_entry_count = romfs_get_hash_table_count(num_files); |
| 214 | RomFSBuildDirectoryContext* cur_dir; | 224 | dir_hash_table_size = 4 * dir_hash_table_entry_count; |
| 215 | 225 | file_hash_table_size = 4 * file_hash_table_entry_count; | |
| 216 | const auto dir_hash_table_entry_count = romfs_get_hash_table_count(this->num_dirs); | 226 | |
| 217 | const auto file_hash_table_entry_count = romfs_get_hash_table_count(this->num_files); | 227 | // Assign metadata pointers |
| 218 | this->dir_hash_table_size = 4 * dir_hash_table_entry_count; | 228 | RomFSHeader header{}; |
| 219 | this->file_hash_table_size = 4 * file_hash_table_entry_count; | 229 | |
| 220 | 230 | std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY); | |
| 221 | /* Assign metadata pointers */ | 231 | std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY); |
| 222 | RomFSHeader* header = new RomFSHeader({0}); | 232 | |
| 223 | auto metadata = new u8[this->dir_hash_table_size + this->dir_table_size + | 233 | std::vector<u8> dir_table(dir_table_size); |
| 224 | this->file_hash_table_size + this->file_table_size]; | 234 | std::vector<u8> file_table(file_table_size); |
| 225 | auto dir_hash_table = reinterpret_cast<u32*>(metadata); | 235 | |
| 226 | const auto dir_table = reinterpret_cast<RomFSDirectoryEntry*>( | 236 | // Clear out hash tables. |
| 227 | reinterpret_cast<uintptr_t>(dir_hash_table) + this->dir_hash_table_size); | ||
| 228 | auto file_hash_table = | ||
| 229 | reinterpret_cast<u32*>(reinterpret_cast<uintptr_t>(dir_table) + this->dir_table_size); | ||
| 230 | const auto file_table = reinterpret_cast<RomFSFileEntry*>( | ||
| 231 | reinterpret_cast<uintptr_t>(file_hash_table) + this->file_hash_table_size); | ||
| 232 | |||
| 233 | /* Clear out hash tables. */ | ||
| 234 | for (u32 i = 0; i < dir_hash_table_entry_count; i++) | 237 | for (u32 i = 0; i < dir_hash_table_entry_count; i++) |
| 235 | dir_hash_table[i] = ROMFS_ENTRY_EMPTY; | 238 | dir_hash_table[i] = ROMFS_ENTRY_EMPTY; |
| 236 | for (u32 i = 0; i < file_hash_table_entry_count; i++) | 239 | for (u32 i = 0; i < file_hash_table_entry_count; i++) |
| 237 | file_hash_table[i] = ROMFS_ENTRY_EMPTY; | 240 | file_hash_table[i] = ROMFS_ENTRY_EMPTY; |
| 238 | 241 | ||
| 239 | out.clear(); | 242 | std::shared_ptr<RomFSBuildFileContext> cur_file; |
| 240 | 243 | ||
| 241 | /* Determine file offsets. */ | 244 | // Determine file offsets. |
| 242 | u32 entry_offset = 0; | 245 | u32 entry_offset = 0; |
| 243 | RomFSBuildFileContext* prev_file = nullptr; | 246 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; |
| 244 | for (const auto& it : this->files) { | 247 | for (const auto& it : files) { |
| 245 | cur_file = it.second; | 248 | cur_file = it.second; |
| 246 | this->file_partition_size = (this->file_partition_size + 0xFULL) & ~0xFULL; | 249 | file_partition_size = (file_partition_size + 0xFULL) & ~0xFULL; |
| 247 | cur_file->offset = this->file_partition_size; | 250 | cur_file->offset = file_partition_size; |
| 248 | this->file_partition_size += cur_file->size; | 251 | file_partition_size += cur_file->size; |
| 249 | cur_file->entry_offset = entry_offset; | 252 | cur_file->entry_offset = entry_offset; |
| 250 | entry_offset += | 253 | entry_offset += |
| 251 | sizeof(RomFSFileEntry) + ((cur_file->path_len - cur_file->cur_path_ofs + 3) & ~3); | 254 | sizeof(RomFSFileEntry) + ((cur_file->path_len - cur_file->cur_path_ofs + 3) & ~3); |
| 252 | prev_file = cur_file; | 255 | prev_file = cur_file; |
| 253 | } | 256 | } |
| 254 | /* Assign deferred parent/sibling ownership. */ | 257 | // Assign deferred parent/sibling ownership. |
| 255 | for (auto it = this->files.rbegin(); it != this->files.rend(); it++) { | 258 | for (auto it = files.rbegin(); it != files.rend(); ++it) { |
| 256 | cur_file = it->second; | 259 | cur_file = it->second; |
| 257 | cur_file->sibling = cur_file->parent->file; | 260 | cur_file->sibling = cur_file->parent->file; |
| 258 | cur_file->parent->file = cur_file; | 261 | cur_file->parent->file = cur_file; |
| 259 | } | 262 | } |
| 260 | 263 | ||
| 261 | /* Determine directory offsets. */ | 264 | std::shared_ptr<RomFSBuildDirectoryContext> cur_dir; |
| 265 | |||
| 266 | // Determine directory offsets. | ||
| 262 | entry_offset = 0; | 267 | entry_offset = 0; |
| 263 | for (const auto& it : this->directories) { | 268 | for (const auto& it : directories) { |
| 264 | cur_dir = it.second; | 269 | cur_dir = it.second; |
| 265 | cur_dir->entry_offset = entry_offset; | 270 | cur_dir->entry_offset = entry_offset; |
| 266 | entry_offset += | 271 | entry_offset += |
| 267 | sizeof(RomFSDirectoryEntry) + ((cur_dir->path_len - cur_dir->cur_path_ofs + 3) & ~3); | 272 | sizeof(RomFSDirectoryEntry) + ((cur_dir->path_len - cur_dir->cur_path_ofs + 3) & ~3); |
| 268 | } | 273 | } |
| 269 | /* Assign deferred parent/sibling ownership. */ | 274 | // Assign deferred parent/sibling ownership. |
| 270 | for (auto it = this->directories.rbegin(); it->second != this->root; it++) { | 275 | for (auto it = directories.rbegin(); it->second != root; ++it) { |
| 271 | cur_dir = it->second; | 276 | cur_dir = it->second; |
| 272 | cur_dir->sibling = cur_dir->parent->child; | 277 | cur_dir->sibling = cur_dir->parent->child; |
| 273 | cur_dir->parent->child = cur_dir; | 278 | cur_dir->parent->child = cur_dir; |
| 274 | } | 279 | } |
| 275 | 280 | ||
| 276 | /* Populate file tables. */ | 281 | std::map<u64, VirtualFile> out; |
| 277 | for (const auto& it : this->files) { | 282 | |
| 283 | // Populate file tables. | ||
| 284 | for (const auto& it : files) { | ||
| 278 | cur_file = it.second; | 285 | cur_file = it.second; |
| 279 | RomFSFileEntry* cur_entry = romfs_get_fentry(file_table, cur_file->entry_offset); | 286 | RomFSFileEntry cur_entry{}; |
| 280 | 287 | ||
| 281 | cur_entry->parent = cur_file->parent->entry_offset; | 288 | cur_entry.parent = cur_file->parent->entry_offset; |
| 282 | cur_entry->sibling = | 289 | cur_entry.sibling = |
| 283 | (cur_file->sibling == nullptr) ? ROMFS_ENTRY_EMPTY : cur_file->sibling->entry_offset; | 290 | cur_file->sibling == nullptr ? ROMFS_ENTRY_EMPTY : cur_file->sibling->entry_offset; |
| 284 | cur_entry->offset = cur_file->offset; | 291 | cur_entry.offset = cur_file->offset; |
| 285 | cur_entry->size = cur_file->size; | 292 | cur_entry.size = cur_file->size; |
| 286 | 293 | ||
| 287 | const auto name_size = cur_file->path_len - cur_file->cur_path_ofs; | 294 | const auto name_size = cur_file->path_len - cur_file->cur_path_ofs; |
| 288 | const auto hash = romfs_calc_path_hash(cur_file->parent->entry_offset, | 295 | const auto hash = romfs_calc_path_hash(cur_file->parent->entry_offset, cur_file->path, |
| 289 | reinterpret_cast<unsigned char*>(cur_file->path) + | 296 | cur_file->cur_path_ofs, name_size); |
| 290 | cur_file->cur_path_ofs, | 297 | cur_entry.hash = file_hash_table[hash % file_hash_table_entry_count]; |
| 291 | 0, name_size); | ||
| 292 | cur_entry->hash = file_hash_table[hash % file_hash_table_entry_count]; | ||
| 293 | file_hash_table[hash % file_hash_table_entry_count] = cur_file->entry_offset; | 298 | file_hash_table[hash % file_hash_table_entry_count] = cur_file->entry_offset; |
| 294 | 299 | ||
| 295 | cur_entry->name_size = name_size; | 300 | cur_entry.name_size = name_size; |
| 296 | memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3); | ||
| 297 | memcpy(cur_entry->name, cur_file->path + cur_file->cur_path_ofs, name_size); | ||
| 298 | 301 | ||
| 299 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source); | 302 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source); |
| 303 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); | ||
| 304 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, | ||
| 305 | (cur_entry.name_size + 3) & ~3); | ||
| 306 | std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), | ||
| 307 | cur_file->path.data() + cur_file->cur_path_ofs, name_size); | ||
| 300 | } | 308 | } |
| 301 | 309 | ||
| 302 | /* Populate dir tables. */ | 310 | // Populate dir tables. |
| 303 | for (const auto& it : this->directories) { | 311 | for (const auto& it : directories) { |
| 304 | cur_dir = it.second; | 312 | cur_dir = it.second; |
| 305 | RomFSDirectoryEntry* cur_entry = romfs_get_direntry(dir_table, cur_dir->entry_offset); | 313 | RomFSDirectoryEntry cur_entry{}; |
| 306 | cur_entry->parent = cur_dir == this->root ? 0 : cur_dir->parent->entry_offset; | 314 | |
| 307 | cur_entry->sibling = | 315 | cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; |
| 308 | (cur_dir->sibling == nullptr) ? ROMFS_ENTRY_EMPTY : cur_dir->sibling->entry_offset; | 316 | cur_entry.sibling = |
| 309 | cur_entry->child = | 317 | cur_dir->sibling == nullptr ? ROMFS_ENTRY_EMPTY : cur_dir->sibling->entry_offset; |
| 310 | (cur_dir->child == nullptr) ? ROMFS_ENTRY_EMPTY : cur_dir->child->entry_offset; | 318 | cur_entry.child = |
| 311 | cur_entry->file = | 319 | cur_dir->child == nullptr ? ROMFS_ENTRY_EMPTY : cur_dir->child->entry_offset; |
| 312 | (cur_dir->file == nullptr) ? ROMFS_ENTRY_EMPTY : cur_dir->file->entry_offset; | 320 | cur_entry.file = cur_dir->file == nullptr ? ROMFS_ENTRY_EMPTY : cur_dir->file->entry_offset; |
| 313 | 321 | ||
| 314 | u32 name_size = cur_dir->path_len - cur_dir->cur_path_ofs; | 322 | const auto name_size = cur_dir->path_len - cur_dir->cur_path_ofs; |
| 315 | u32 hash = romfs_calc_path_hash( | 323 | const auto hash = romfs_calc_path_hash(cur_dir == root ? 0 : cur_dir->parent->entry_offset, |
| 316 | cur_dir == this->root ? 0 : cur_dir->parent->entry_offset, | 324 | cur_dir->path, cur_dir->cur_path_ofs, name_size); |
| 317 | reinterpret_cast<unsigned char*>(cur_dir->path) + cur_dir->cur_path_ofs, 0, name_size); | 325 | cur_entry.hash = dir_hash_table[hash % dir_hash_table_entry_count]; |
| 318 | cur_entry->hash = dir_hash_table[hash % dir_hash_table_entry_count]; | ||
| 319 | dir_hash_table[hash % dir_hash_table_entry_count] = cur_dir->entry_offset; | 326 | dir_hash_table[hash % dir_hash_table_entry_count] = cur_dir->entry_offset; |
| 320 | 327 | ||
| 321 | cur_entry->name_size = name_size; | 328 | cur_entry.name_size = name_size; |
| 322 | memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3); | ||
| 323 | memcpy(cur_entry->name, cur_dir->path + cur_dir->cur_path_ofs, name_size); | ||
| 324 | } | ||
| 325 | 329 | ||
| 326 | /* Delete directories. */ | 330 | std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry, |
| 327 | for (const auto& it : this->directories) { | 331 | sizeof(RomFSDirectoryEntry)); |
| 328 | cur_dir = it.second; | 332 | std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry, |
| 329 | delete cur_dir->path; | 333 | sizeof(RomFSDirectoryEntry)); |
| 330 | delete cur_dir; | 334 | std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0, |
| 335 | (cur_entry.name_size + 3) & ~3); | ||
| 336 | std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), | ||
| 337 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); | ||
| 331 | } | 338 | } |
| 332 | this->root = nullptr; | ||
| 333 | this->directories.clear(); | ||
| 334 | 339 | ||
| 335 | /* Delete files. */ | 340 | // Set header fields. |
| 336 | for (const auto& it : this->files) { | 341 | header.header_size = sizeof(RomFSHeader); |
| 337 | cur_file = it.second; | 342 | header.file_hash_table_size = file_hash_table_size; |
| 338 | delete cur_file->path; | 343 | header.file_table_size = file_table_size; |
| 339 | delete cur_file; | 344 | header.dir_hash_table_size = dir_hash_table_size; |
| 340 | } | 345 | header.dir_table_size = dir_table_size; |
| 341 | this->files.clear(); | 346 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; |
| 342 | 347 | header.dir_hash_table_ofs = (header.file_partition_ofs + file_partition_size + 3ULL) & ~3ULL; | |
| 343 | /* Set header fields. */ | 348 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; |
| 344 | header->header_size = sizeof(*header); | 349 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; |
| 345 | header->file_hash_table_size = this->file_hash_table_size; | 350 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; |
| 346 | header->file_table_size = this->file_table_size; | ||
| 347 | header->dir_hash_table_size = this->dir_hash_table_size; | ||
| 348 | header->dir_table_size = this->dir_table_size; | ||
| 349 | header->file_partition_ofs = ROMFS_FILEPARTITION_OFS; | ||
| 350 | header->dir_hash_table_ofs = | ||
| 351 | (header->file_partition_ofs + this->file_partition_size + 3ULL) & ~3ULL; | ||
| 352 | header->dir_table_ofs = header->dir_hash_table_ofs + header->dir_hash_table_size; | ||
| 353 | header->file_hash_table_ofs = header->dir_table_ofs + header->dir_table_size; | ||
| 354 | header->file_table_ofs = header->file_hash_table_ofs + header->file_hash_table_size; | ||
| 355 | 351 | ||
| 356 | std::vector<u8> header_data(sizeof(RomFSHeader)); | 352 | std::vector<u8> header_data(sizeof(RomFSHeader)); |
| 357 | std::memcpy(header_data.data(), header, header_data.size()); | 353 | std::memcpy(header_data.data(), &header, header_data.size()); |
| 358 | out.emplace(0, std::make_shared<VectorVfsFile>(header_data)); | 354 | out.emplace(0, std::make_shared<VectorVfsFile>(header_data)); |
| 359 | 355 | ||
| 360 | std::vector<u8> meta_out(this->file_hash_table_size + this->file_table_size + | 356 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + |
| 361 | this->dir_hash_table_size + this->dir_table_size); | 357 | dir_table_size); |
| 362 | std::memcpy(meta_out.data(), metadata, meta_out.size()); | 358 | auto index = 0; |
| 363 | out.emplace(header->dir_hash_table_ofs, std::make_shared<VectorVfsFile>(meta_out)); | 359 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); |
| 360 | index += dir_hash_table.size() * sizeof(u32); | ||
| 361 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); | ||
| 362 | index += dir_table.size(); | ||
| 363 | std::memcpy(metadata.data() + index, file_hash_table.data(), | ||
| 364 | file_hash_table.size() * sizeof(u32)); | ||
| 365 | index += file_hash_table.size() * sizeof(u32); | ||
| 366 | std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); | ||
| 367 | out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(metadata)); | ||
| 364 | 368 | ||
| 365 | return out; | 369 | return out; |
| 366 | } | 370 | } |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h new file mode 100644 index 000000000..b0c3c123b --- /dev/null +++ b/src/core/file_sys/fsmitm_romfsbuild.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Atmosphère-NX | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Adapted by DarkLordZach for use/interaction with yuzu | ||
| 19 | * | ||
| 20 | * Modifications Copyright 2018 yuzu emulator team | ||
| 21 | * Licensed under GPLv2 or any later version | ||
| 22 | * Refer to the license.txt file included. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <map> | ||
| 28 | #include <memory> | ||
| 29 | #include <string> | ||
| 30 | #include <boost/detail/container_fwd.hpp> | ||
| 31 | #include "common/common_types.h" | ||
| 32 | #include "core/file_sys/vfs.h" | ||
| 33 | |||
| 34 | namespace FileSys { | ||
| 35 | |||
| 36 | struct RomFSBuildDirectoryContext; | ||
| 37 | struct RomFSBuildFileContext; | ||
| 38 | struct RomFSDirectoryEntry; | ||
| 39 | struct RomFSFileEntry; | ||
| 40 | |||
| 41 | class RomFSBuildContext { | ||
| 42 | public: | ||
| 43 | explicit RomFSBuildContext(VirtualDir base); | ||
| 44 | ~RomFSBuildContext(); | ||
| 45 | |||
| 46 | // This finalizes the context. | ||
| 47 | std::map<u64, VirtualFile> Build(); | ||
| 48 | |||
| 49 | private: | ||
| 50 | VirtualDir base; | ||
| 51 | std::shared_ptr<RomFSBuildDirectoryContext> root; | ||
| 52 | std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories; | ||
| 53 | std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files; | ||
| 54 | u64 num_dirs = 0; | ||
| 55 | u64 num_files = 0; | ||
| 56 | u64 dir_table_size = 0; | ||
| 57 | u64 file_table_size = 0; | ||
| 58 | u64 dir_hash_table_size = 0; | ||
| 59 | u64 file_hash_table_size = 0; | ||
| 60 | u64 file_partition_size = 0; | ||
| 61 | |||
| 62 | void VisitDirectory(VirtualDir filesys, std::shared_ptr<RomFSBuildDirectoryContext> parent); | ||
| 63 | |||
| 64 | bool AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, | ||
| 65 | std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx); | ||
| 66 | bool AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, | ||
| 67 | std::shared_ptr<RomFSBuildFileContext> file_ctx); | ||
| 68 | }; | ||
| 69 | |||
| 70 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/fsmitm_romfsbuild.hpp b/src/core/file_sys/fsmitm_romfsbuild.hpp deleted file mode 100644 index b897aab21..000000000 --- a/src/core/file_sys/fsmitm_romfsbuild.hpp +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Atmosphère-NX | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Adapted by DarkLordZach for use/interaction with yuzu | ||
| 19 | * | ||
| 20 | * Modifications Copyright 2018 yuzu emulator team | ||
| 21 | * Licensed under GPLv2 or any later version | ||
| 22 | * Refer to the license.txt file included. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | #include <map> | ||
| 27 | #include <boost/detail/container_fwd.hpp> | ||
| 28 | #include "common/common_types.h" | ||
| 29 | #include "vfs.h" | ||
| 30 | |||
| 31 | namespace FileSys { | ||
| 32 | |||
| 33 | /* Used as comparator for std::map<char *, RomFSBuild*Context> */ | ||
| 34 | struct build_ctx_cmp { | ||
| 35 | bool operator()(const char* a, const char* b) const { | ||
| 36 | return strcmp(a, b) < 0; | ||
| 37 | } | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct RomFSDirectoryEntry; | ||
| 41 | struct RomFSFileEntry; | ||
| 42 | struct RomFSBuildDirectoryContext; | ||
| 43 | struct RomFSBuildFileContext; | ||
| 44 | |||
| 45 | class RomFSBuildContext { | ||
| 46 | private: | ||
| 47 | VirtualDir base; | ||
| 48 | RomFSBuildDirectoryContext* root; | ||
| 49 | std::map<char*, RomFSBuildDirectoryContext*, build_ctx_cmp> directories; | ||
| 50 | std::map<char*, RomFSBuildFileContext*, build_ctx_cmp> files; | ||
| 51 | u64 num_dirs = 0; | ||
| 52 | u64 num_files = 0; | ||
| 53 | u64 dir_table_size = 0; | ||
| 54 | u64 file_table_size = 0; | ||
| 55 | u64 dir_hash_table_size = 0; | ||
| 56 | u64 file_hash_table_size = 0; | ||
| 57 | u64 file_partition_size = 0; | ||
| 58 | |||
| 59 | void VisitDirectory(VirtualDir filesys, RomFSBuildDirectoryContext* parent); | ||
| 60 | |||
| 61 | bool AddDirectory(RomFSBuildDirectoryContext* parent_dir_ctx, | ||
| 62 | RomFSBuildDirectoryContext* dir_ctx, | ||
| 63 | RomFSBuildDirectoryContext** out_dir_ctx); | ||
| 64 | bool AddFile(RomFSBuildDirectoryContext* parent_dir_ctx, RomFSBuildFileContext* file_ctx); | ||
| 65 | |||
| 66 | public: | ||
| 67 | explicit RomFSBuildContext(VirtualDir base); | ||
| 68 | |||
| 69 | /* This finalizes the context. */ | ||
| 70 | std::map<u64, VirtualFile> Build(); | ||
| 71 | }; | ||
| 72 | |||
| 73 | static inline RomFSDirectoryEntry* romfs_get_direntry(void* directories, uint32_t offset) { | ||
| 74 | return (RomFSDirectoryEntry*)((uintptr_t)directories + offset); | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline RomFSFileEntry* romfs_get_fentry(void* files, uint32_t offset) { | ||
| 78 | return (RomFSFileEntry*)((uintptr_t)files + offset); | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline uint32_t romfs_calc_path_hash(uint32_t parent, const unsigned char* path, | ||
| 82 | uint32_t start, size_t path_len) { | ||
| 83 | uint32_t hash = parent ^ 123456789; | ||
| 84 | for (uint32_t i = 0; i < path_len; i++) { | ||
| 85 | hash = (hash >> 5) | (hash << 27); | ||
| 86 | hash ^= path[start + i]; | ||
| 87 | } | ||
| 88 | |||
| 89 | return hash; | ||
| 90 | } | ||
| 91 | |||
| 92 | static inline uint32_t romfs_get_hash_table_count(uint32_t num_entries) { | ||
| 93 | if (num_entries < 3) { | ||
| 94 | return 3; | ||
| 95 | } else if (num_entries < 19) { | ||
| 96 | return num_entries | 1; | ||
| 97 | } | ||
| 98 | uint32_t count = num_entries; | ||
| 99 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || | ||
| 100 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { | ||
| 101 | count++; | ||
| 102 | } | ||
| 103 | return count; | ||
| 104 | } | ||
| 105 | |||
| 106 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 74a0acf1a..af3f9a78f 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -68,33 +68,10 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 68 | return exefs; | 68 | return exefs; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, | 71 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { |
| 72 | ContentRecordType type) const { | ||
| 73 | LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id, | ||
| 74 | static_cast<u8>(type)); | ||
| 75 | |||
| 76 | if (romfs == nullptr) | ||
| 77 | return romfs; | ||
| 78 | |||
| 79 | const auto installed = Service::FileSystem::GetUnionContents(); | ||
| 80 | |||
| 81 | // Game Updates | ||
| 82 | const auto update_tid = GetUpdateTitleID(title_id); | ||
| 83 | const auto update = installed->GetEntryRaw(update_tid, type); | ||
| 84 | if (update != nullptr) { | ||
| 85 | const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); | ||
| 86 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && | ||
| 87 | new_nca->GetRomFS() != nullptr) { | ||
| 88 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", | ||
| 89 | FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); | ||
| 90 | romfs = new_nca->GetRomFS(); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | // LayeredFS | ||
| 95 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | 72 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); |
| 96 | if (type == ContentRecordType::Program && load_dir != nullptr && load_dir->GetSize() > 0) { | 73 | if (type == ContentRecordType::Program && load_dir != nullptr && load_dir->GetSize() > 0) { |
| 97 | const auto extracted = ExtractRomFS(romfs); | 74 | auto extracted = ExtractRomFS(romfs); |
| 98 | 75 | ||
| 99 | if (extracted != nullptr) { | 76 | if (extracted != nullptr) { |
| 100 | auto patch_dirs = load_dir->GetSubdirectories(); | 77 | auto patch_dirs = load_dir->GetSubdirectories(); |
| @@ -106,25 +83,52 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, | |||
| 106 | std::vector<VirtualDir> layers; | 83 | std::vector<VirtualDir> layers; |
| 107 | layers.reserve(patch_dirs.size() + 1); | 84 | layers.reserve(patch_dirs.size() + 1); |
| 108 | for (const auto& subdir : patch_dirs) { | 85 | for (const auto& subdir : patch_dirs) { |
| 109 | const auto romfs_dir = subdir->GetSubdirectory("romfs"); | 86 | auto romfs_dir = subdir->GetSubdirectory("romfs"); |
| 110 | if (romfs_dir != nullptr) | 87 | if (romfs_dir != nullptr) |
| 111 | layers.push_back(romfs_dir); | 88 | layers.push_back(std::move(romfs_dir)); |
| 112 | } | 89 | } |
| 113 | 90 | ||
| 114 | layers.push_back(extracted); | 91 | layers.push_back(std::move(extracted)); |
| 115 | 92 | ||
| 116 | const auto layered = LayerDirectories(layers); | 93 | const auto layered = LayerDirectories(layers); |
| 117 | 94 | ||
| 118 | if (layered != nullptr) { | 95 | if (layered != nullptr) { |
| 119 | const auto packed = CreateRomFS(layered); | 96 | auto packed = CreateRomFS(layered); |
| 120 | 97 | ||
| 121 | if (packed != nullptr) { | 98 | if (packed != nullptr) { |
| 122 | LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); | 99 | LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); |
| 123 | romfs = packed; | 100 | romfs = std::move(packed); |
| 124 | } | 101 | } |
| 125 | } | 102 | } |
| 126 | } | 103 | } |
| 127 | } | 104 | } |
| 105 | } | ||
| 106 | |||
| 107 | VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, | ||
| 108 | ContentRecordType type) const { | ||
| 109 | LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id, | ||
| 110 | static_cast<u8>(type)); | ||
| 111 | |||
| 112 | if (romfs == nullptr) | ||
| 113 | return romfs; | ||
| 114 | |||
| 115 | const auto installed = Service::FileSystem::GetUnionContents(); | ||
| 116 | |||
| 117 | // Game Updates | ||
| 118 | const auto update_tid = GetUpdateTitleID(title_id); | ||
| 119 | const auto update = installed->GetEntryRaw(update_tid, type); | ||
| 120 | if (update != nullptr) { | ||
| 121 | const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); | ||
| 122 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && | ||
| 123 | new_nca->GetRomFS() != nullptr) { | ||
| 124 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", | ||
| 125 | FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); | ||
| 126 | romfs = new_nca->GetRomFS(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | // LayeredFS | ||
| 131 | ApplyLayeredFS(romfs, title_id, type); | ||
| 128 | 132 | ||
| 129 | return romfs; | 133 | return romfs; |
| 130 | } | 134 | } |
| @@ -153,7 +157,7 @@ std::map<PatchType, std::string> PatchManager::GetPatchVersionNames() const { | |||
| 153 | 157 | ||
| 154 | const auto lfs_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | 158 | const auto lfs_dir = Service::FileSystem::GetModificationLoadRoot(title_id); |
| 155 | if (lfs_dir != nullptr && lfs_dir->GetSize() > 0) | 159 | if (lfs_dir != nullptr && lfs_dir->GetSize() > 0) |
| 156 | out[PatchType::LayeredFS] = ""; | 160 | out.insert_or_assign(PatchType::LayeredFS, ""); |
| 157 | 161 | ||
| 158 | return out; | 162 | return out; |
| 159 | } | 163 | } |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 0dda0b861..653ef2e7b 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -18,6 +18,10 @@ | |||
| 18 | #include "core/loader/loader.h" | 18 | #include "core/loader/loader.h" |
| 19 | 19 | ||
| 20 | namespace FileSys { | 20 | namespace FileSys { |
| 21 | |||
| 22 | // The size of blocks to use when vfs raw copying into nand. | ||
| 23 | constexpr size_t VFS_RC_LARGE_COPY_BLOCK = 0x400000; | ||
| 24 | |||
| 21 | std::string RegisteredCacheEntry::DebugInfo() const { | 25 | std::string RegisteredCacheEntry::DebugInfo() const { |
| 22 | return fmt::format("title_id={:016X}, content_type={:02X}", title_id, static_cast<u8>(type)); | 26 | return fmt::format("title_id={:016X}, content_type={:02X}", title_id, static_cast<u8>(type)); |
| 23 | } | 27 | } |
| @@ -121,7 +125,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | |||
| 121 | if (concat.empty()) | 125 | if (concat.empty()) |
| 122 | return nullptr; | 126 | return nullptr; |
| 123 | 127 | ||
| 124 | file = FileSys::ConcatenateFiles(concat); | 128 | file = FileSys::ConcatenateFiles(concat, concat.front()->GetName()); |
| 125 | } | 129 | } |
| 126 | 130 | ||
| 127 | return file; | 131 | return file; |
| @@ -480,7 +484,8 @@ InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const Vfs | |||
| 480 | auto out = dir->CreateFileRelative(path); | 484 | auto out = dir->CreateFileRelative(path); |
| 481 | if (out == nullptr) | 485 | if (out == nullptr) |
| 482 | return InstallResult::ErrorCopyFailed; | 486 | return InstallResult::ErrorCopyFailed; |
| 483 | return copy(in, out, 0x400000) ? InstallResult::Success : InstallResult::ErrorCopyFailed; | 487 | return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success |
| 488 | : InstallResult::ErrorCopyFailed; | ||
| 484 | } | 489 | } |
| 485 | 490 | ||
| 486 | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | 491 | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { |
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 71e4e0e2f..205284a4d 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | #include "common/swap.h" | 6 | #include "common/swap.h" |
| 7 | #include "core/file_sys/fsmitm_romfsbuild.hpp" | 7 | #include "core/file_sys/fsmitm_romfsbuild.h" |
| 8 | #include "core/file_sys/romfs.h" | 8 | #include "core/file_sys/romfs.h" |
| 9 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| 10 | #include "core/file_sys/vfs_concat.h" | 10 | #include "core/file_sys/vfs_concat.h" |
| @@ -100,7 +100,7 @@ void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file | |||
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | VirtualDir ExtractRomFS(VirtualFile file, bool traverse_into_data) { | 103 | VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { |
| 104 | RomFSHeader header{}; | 104 | RomFSHeader header{}; |
| 105 | if (file->ReadObject(&header) != sizeof(RomFSHeader)) | 105 | if (file->ReadObject(&header) != sizeof(RomFSHeader)) |
| 106 | return nullptr; | 106 | return nullptr; |
| @@ -119,8 +119,9 @@ VirtualDir ExtractRomFS(VirtualFile file, bool traverse_into_data) { | |||
| 119 | 119 | ||
| 120 | VirtualDir out = std::move(root); | 120 | VirtualDir out = std::move(root); |
| 121 | 121 | ||
| 122 | while (out->GetSubdirectories().size() == 1 && out->GetFiles().size() == 0) { | 122 | while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { |
| 123 | if (out->GetSubdirectories().front()->GetName() == "data" && !traverse_into_data) | 123 | if (out->GetSubdirectories().front()->GetName() == "data" && |
| 124 | type == RomFSExtractionType::Truncated) | ||
| 124 | break; | 125 | break; |
| 125 | out = out->GetSubdirectories().front(); | 126 | out = out->GetSubdirectories().front(); |
| 126 | } | 127 | } |
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 8e82585a0..ecd1eb725 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h | |||
| @@ -32,9 +32,15 @@ struct IVFCHeader { | |||
| 32 | }; | 32 | }; |
| 33 | static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); | 33 | static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); |
| 34 | 34 | ||
| 35 | enum class RomFSExtractionType { | ||
| 36 | Full, // Includes data directory | ||
| 37 | Truncated, // Traverses into data directory | ||
| 38 | }; | ||
| 39 | |||
| 35 | // Converts a RomFS binary blob to VFS Filesystem | 40 | // Converts a RomFS binary blob to VFS Filesystem |
| 36 | // Returns nullptr on failure | 41 | // Returns nullptr on failure |
| 37 | VirtualDir ExtractRomFS(VirtualFile file, bool traverse_into_data = true); | 42 | VirtualDir ExtractRomFS(VirtualFile file, |
| 43 | RomFSExtractionType type = RomFSExtractionType::Truncated); | ||
| 38 | 44 | ||
| 39 | // Converts a VFS filesystem into a RomFS binary | 45 | // Converts a VFS filesystem into a RomFS binary |
| 40 | // Returns nullptr on failure | 46 | // Returns nullptr on failure |
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 218cfde66..5fbea1739 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -399,8 +399,8 @@ bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { | |||
| 399 | return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize(); | 399 | return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize(); |
| 400 | } | 400 | } |
| 401 | 401 | ||
| 402 | std::map<std::string, VfsEntryType> VfsDirectory::GetEntries() const { | 402 | std::map<std::string, VfsEntryType, std::less<>> VfsDirectory::GetEntries() const { |
| 403 | std::map<std::string, VfsEntryType> out; | 403 | std::map<std::string, VfsEntryType, std::less<>> out; |
| 404 | for (const auto& dir : GetSubdirectories()) | 404 | for (const auto& dir : GetSubdirectories()) |
| 405 | out.emplace(dir->GetName(), VfsEntryType::Directory); | 405 | out.emplace(dir->GetName(), VfsEntryType::Directory); |
| 406 | for (const auto& file : GetFiles()) | 406 | for (const auto& file : GetFiles()) |
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 6aec4c164..cea4aa8b8 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h | |||
| @@ -268,7 +268,7 @@ public: | |||
| 268 | 268 | ||
| 269 | // Gets all of the entries directly in the directory (files and dirs), returning a map between | 269 | // Gets all of the entries directly in the directory (files and dirs), returning a map between |
| 270 | // item name -> type. | 270 | // item name -> type. |
| 271 | virtual std::map<std::string, VfsEntryType> GetEntries() const; | 271 | virtual std::map<std::string, VfsEntryType, std::less<>> GetEntries() const; |
| 272 | 272 | ||
| 273 | // Interprets the file with name file instead as a directory of type directory. | 273 | // Interprets the file with name file instead as a directory of type directory. |
| 274 | // The directory must have a constructor that takes a single argument of type | 274 | // The directory must have a constructor that takes a single argument of type |
| @@ -323,6 +323,9 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block | |||
| 323 | // directory of src/dest. | 323 | // directory of src/dest. |
| 324 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000); | 324 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000); |
| 325 | 325 | ||
| 326 | // A method that performs a similar function to VfsRawCopy above, but instead copies entire | ||
| 327 | // directories. It suffers the same performance penalties as above and an implementation-specific | ||
| 328 | // Copy should always be preferred. | ||
| 326 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000); | 329 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000); |
| 327 | 330 | ||
| 328 | // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not | 331 | // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 0c07e162e..d9f9911da 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -10,8 +10,9 @@ | |||
| 10 | 10 | ||
| 11 | namespace FileSys { | 11 | namespace FileSys { |
| 12 | 12 | ||
| 13 | bool VerifyConcatenationMap(std::map<u64, VirtualFile> map) { | 13 | static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& map) { |
| 14 | for (auto iter = map.begin(); iter != --map.end();) { | 14 | const auto last_valid = --map.end(); |
| 15 | for (auto iter = map.begin(); iter != last_valid;) { | ||
| 15 | const auto old = iter++; | 16 | const auto old = iter++; |
| 16 | if (old->first + old->second->GetSize() != iter->first) { | 17 | if (old->first + old->second->GetSize() != iter->first) { |
| 17 | return false; | 18 | return false; |
| @@ -41,9 +42,11 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s | |||
| 41 | 42 | ||
| 42 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) | 43 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) |
| 43 | : files(std::move(files_)), name(std::move(name)) { | 44 | : files(std::move(files_)), name(std::move(name)) { |
| 44 | ASSERT(VerifyConcatenationMap(files)); | 45 | ASSERT(VerifyConcatenationMapContinuity(files)); |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 48 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; | ||
| 49 | |||
| 47 | std::string ConcatenatedVfsFile::GetName() const { | 50 | std::string ConcatenatedVfsFile::GetName() const { |
| 48 | if (files.empty()) | 51 | if (files.empty()) |
| 49 | return ""; | 52 | return ""; |
| @@ -77,25 +80,25 @@ bool ConcatenatedVfsFile::IsReadable() const { | |||
| 77 | } | 80 | } |
| 78 | 81 | ||
| 79 | std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { | 82 | std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { |
| 80 | std::pair<u64, VirtualFile> entry = *files.rbegin(); | 83 | auto entry = --files.end(); |
| 81 | for (auto iter = files.begin(); iter != files.end(); ++iter) { | 84 | for (auto iter = files.begin(); iter != files.end(); ++iter) { |
| 82 | if (iter->first > offset) { | 85 | if (iter->first > offset) { |
| 83 | entry = *--iter; | 86 | entry = --iter; |
| 84 | break; | 87 | break; |
| 85 | } | 88 | } |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | if (entry.first + entry.second->GetSize() <= offset) | 91 | if (entry->first + entry->second->GetSize() <= offset) |
| 89 | return 0; | 92 | return 0; |
| 90 | 93 | ||
| 91 | const auto read_in = | 94 | const auto read_in = |
| 92 | std::min(entry.first + entry.second->GetSize() - offset, entry.second->GetSize()); | 95 | std::min<u64>(entry->first + entry->second->GetSize() - offset, entry->second->GetSize()); |
| 93 | if (length > read_in) { | 96 | if (length > read_in) { |
| 94 | return entry.second->Read(data, read_in, offset - entry.first) + | 97 | return entry->second->Read(data, read_in, offset - entry->first) + |
| 95 | Read(data + read_in, length - read_in, offset + read_in); | 98 | Read(data + read_in, length - read_in, offset + read_in); |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | return entry.second->Read(data, std::min(read_in, length), offset - entry.first); | 101 | return entry->second->Read(data, std::min<u64>(read_in, length), offset - entry->first); |
| 99 | } | 102 | } |
| 100 | 103 | ||
| 101 | std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { | 104 | std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { |
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index c65c20d15..76211d38a 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -13,35 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace FileSys { | 14 | namespace FileSys { |
| 15 | 15 | ||
| 16 | class ConcatenatedVfsFile; | ||
| 17 | |||
| 18 | // Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | ||
| 19 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name = ""); | ||
| 20 | |||
| 21 | // Convenience function that turns a map of offsets to files into a concatenated file, filling gaps | ||
| 22 | // with template parameter. | ||
| 23 | template <u8 filler_byte> | ||
| 24 | VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name = "") { | ||
| 25 | if (files.empty()) | ||
| 26 | return nullptr; | ||
| 27 | if (files.size() == 1) | ||
| 28 | return files.begin()->second; | ||
| 29 | |||
| 30 | for (auto iter = files.begin(); iter != --files.end();) { | ||
| 31 | const auto old = iter++; | ||
| 32 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 33 | files.emplace(old->first + old->second->GetSize(), | ||
| 34 | std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first - | ||
| 35 | old->second->GetSize())); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | if (files.begin()->first != 0) | ||
| 40 | files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first)); | ||
| 41 | |||
| 42 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 43 | } | ||
| 44 | |||
| 45 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently | 16 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently |
| 46 | // read-only. | 17 | // read-only. |
| 47 | class ConcatenatedVfsFile : public VfsFile { | 18 | class ConcatenatedVfsFile : public VfsFile { |
| @@ -72,4 +43,33 @@ private: | |||
| 72 | std::string name; | 43 | std::string name; |
| 73 | }; | 44 | }; |
| 74 | 45 | ||
| 46 | // Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | ||
| 47 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); | ||
| 48 | |||
| 49 | // Convenience function that turns a map of offsets to files into a concatenated file, filling gaps | ||
| 50 | // with template parameter. | ||
| 51 | template <u8 filler_byte> | ||
| 52 | VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name) { | ||
| 53 | if (files.empty()) | ||
| 54 | return nullptr; | ||
| 55 | if (files.size() == 1) | ||
| 56 | return files.begin()->second; | ||
| 57 | |||
| 58 | const auto last_valid = --files.end(); | ||
| 59 | for (auto iter = files.begin(); iter != last_valid;) { | ||
| 60 | const auto old = iter++; | ||
| 61 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 62 | files.emplace(old->first + old->second->GetSize(), | ||
| 63 | std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first - | ||
| 64 | old->second->GetSize())); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | // Ensure the map starts at offset 0 (start of file), otherwise pad to fill. | ||
| 69 | if (files.begin()->first != 0) | ||
| 70 | files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first)); | ||
| 71 | |||
| 72 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 73 | } | ||
| 74 | |||
| 75 | } // namespace FileSys | 75 | } // namespace FileSys |
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index 802f49384..45563d7ae 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp | |||
| @@ -20,10 +20,11 @@ VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) { | |||
| 20 | LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) | 20 | LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) |
| 21 | : dirs(std::move(dirs)), name(std::move(name)) {} | 21 | : dirs(std::move(dirs)), name(std::move(name)) {} |
| 22 | 22 | ||
| 23 | LayeredVfsDirectory::~LayeredVfsDirectory() = default; | ||
| 24 | |||
| 23 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { | 25 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { |
| 24 | VirtualFile file; | ||
| 25 | for (const auto& layer : dirs) { | 26 | for (const auto& layer : dirs) { |
| 26 | file = layer->GetFileRelative(path); | 27 | const auto file = layer->GetFileRelative(path); |
| 27 | if (file != nullptr) | 28 | if (file != nullptr) |
| 28 | return file; | 29 | return file; |
| 29 | } | 30 | } |
| @@ -35,12 +36,12 @@ std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative( | |||
| 35 | std::string_view path) const { | 36 | std::string_view path) const { |
| 36 | std::vector<VirtualDir> out; | 37 | std::vector<VirtualDir> out; |
| 37 | for (const auto& layer : dirs) { | 38 | for (const auto& layer : dirs) { |
| 38 | const auto dir = layer->GetDirectoryRelative(path); | 39 | auto dir = layer->GetDirectoryRelative(path); |
| 39 | if (dir != nullptr) | 40 | if (dir != nullptr) |
| 40 | out.push_back(dir); | 41 | out.push_back(std::move(dir)); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | return LayerDirectories(out); | 44 | return LayerDirectories(std::move(out)); |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { | 47 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { |
| @@ -61,8 +62,9 @@ std::vector<std::shared_ptr<VfsFile>> LayeredVfsDirectory::GetFiles() const { | |||
| 61 | for (const auto& file : layer->GetFiles()) { | 62 | for (const auto& file : layer->GetFiles()) { |
| 62 | if (std::find_if(out.begin(), out.end(), [&file](const VirtualFile& comp) { | 63 | if (std::find_if(out.begin(), out.end(), [&file](const VirtualFile& comp) { |
| 63 | return comp->GetName() == file->GetName(); | 64 | return comp->GetName() == file->GetName(); |
| 64 | }) == out.end()) | 65 | }) == out.end()) { |
| 65 | out.push_back(file); | 66 | out.push_back(file); |
| 67 | } | ||
| 66 | } | 68 | } |
| 67 | } | 69 | } |
| 68 | 70 | ||
| @@ -79,6 +81,7 @@ std::vector<std::shared_ptr<VfsDirectory>> LayeredVfsDirectory::GetSubdirectorie | |||
| 79 | } | 81 | } |
| 80 | 82 | ||
| 81 | std::vector<VirtualDir> out; | 83 | std::vector<VirtualDir> out; |
| 84 | out.reserve(names.size()); | ||
| 82 | for (const auto& subdir : names) | 85 | for (const auto& subdir : names) |
| 83 | out.push_back(GetSubdirectory(subdir)); | 86 | out.push_back(GetSubdirectory(subdir)); |
| 84 | 87 | ||
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h index f345c2fb6..4f6e341ab 100644 --- a/src/core/file_sys/vfs_layered.h +++ b/src/core/file_sys/vfs_layered.h | |||
| @@ -21,6 +21,8 @@ class LayeredVfsDirectory : public VfsDirectory { | |||
| 21 | LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); | 21 | LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); |
| 22 | 22 | ||
| 23 | public: | 23 | public: |
| 24 | ~LayeredVfsDirectory() override; | ||
| 25 | |||
| 24 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; | 26 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; |
| 25 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; | 27 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; |
| 26 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; | 28 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index a58a02de7..9defad04c 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -413,11 +413,11 @@ std::string RealVfsDirectory::GetFullPath() const { | |||
| 413 | return out; | 413 | return out; |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | std::map<std::string, VfsEntryType> RealVfsDirectory::GetEntries() const { | 416 | std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const { |
| 417 | if (perms == Mode::Append) | 417 | if (perms == Mode::Append) |
| 418 | return {}; | 418 | return {}; |
| 419 | 419 | ||
| 420 | std::map<std::string, VfsEntryType> out; | 420 | std::map<std::string, VfsEntryType, std::less<>> out; |
| 421 | FileUtil::ForeachDirectoryEntry( | 421 | FileUtil::ForeachDirectoryEntry( |
| 422 | nullptr, path, | 422 | nullptr, path, |
| 423 | [&out](u64* entries_out, const std::string& directory, const std::string& filename) { | 423 | [&out](u64* entries_out, const std::string& directory, const std::string& filename) { |
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 3af2a6961..5b61db90d 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h | |||
| @@ -98,7 +98,7 @@ public: | |||
| 98 | bool DeleteFile(std::string_view name) override; | 98 | bool DeleteFile(std::string_view name) override; |
| 99 | bool Rename(std::string_view name) override; | 99 | bool Rename(std::string_view name) override; |
| 100 | std::string GetFullPath() const override; | 100 | std::string GetFullPath() const override; |
| 101 | std::map<std::string, VfsEntryType> GetEntries() const override; | 101 | std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override; |
| 102 | 102 | ||
| 103 | protected: | 103 | protected: |
| 104 | bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; | 104 | bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; |
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h index 5bc8ca52e..4dd47ffcc 100644 --- a/src/core/file_sys/vfs_static.h +++ b/src/core/file_sys/vfs_static.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <string_view> | 9 | #include <string_view> |
| 9 | 10 | ||
| @@ -15,7 +16,7 @@ template <u8 value> | |||
| 15 | class StaticVfsFile : public VfsFile { | 16 | class StaticVfsFile : public VfsFile { |
| 16 | public: | 17 | public: |
| 17 | explicit StaticVfsFile(size_t size = 0, std::string name = "", VirtualDir parent = nullptr) | 18 | explicit StaticVfsFile(size_t size = 0, std::string name = "", VirtualDir parent = nullptr) |
| 18 | : size(size), name(name), parent(parent) {} | 19 | : size(size), name(std::move(name)), parent(std::move(parent)) {} |
| 19 | 20 | ||
| 20 | std::string GetName() const override { | 21 | std::string GetName() const override { |
| 21 | return name; | 22 | return name; |
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index efca3d4ad..7033e2c88 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cstring> | ||
| 6 | #include <utility> | 7 | #include <utility> |
| 7 | #include "core/file_sys/vfs_vector.h" | 8 | #include "core/file_sys/vfs_vector.h" |
| 8 | 9 | ||
| @@ -10,6 +11,8 @@ namespace FileSys { | |||
| 10 | VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) | 11 | VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) |
| 11 | : data(std::move(initial_data)), name(std::move(name)), parent(std::move(parent)) {} | 12 | : data(std::move(initial_data)), name(std::move(name)), parent(std::move(parent)) {} |
| 12 | 13 | ||
| 14 | VectorVfsFile::~VectorVfsFile() = default; | ||
| 15 | |||
| 13 | std::string VectorVfsFile::GetName() const { | 16 | std::string VectorVfsFile::GetName() const { |
| 14 | return name; | 17 | return name; |
| 15 | } | 18 | } |
| @@ -20,7 +23,7 @@ size_t VectorVfsFile::GetSize() const { | |||
| 20 | 23 | ||
| 21 | bool VectorVfsFile::Resize(size_t new_size) { | 24 | bool VectorVfsFile::Resize(size_t new_size) { |
| 22 | data.resize(new_size); | 25 | data.resize(new_size); |
| 23 | return data.size() == new_size; | 26 | return true; |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | std::shared_ptr<VfsDirectory> VectorVfsFile::GetContainingDirectory() const { | 29 | std::shared_ptr<VfsDirectory> VectorVfsFile::GetContainingDirectory() const { |
| @@ -55,7 +58,7 @@ bool VectorVfsFile::Rename(std::string_view name_) { | |||
| 55 | } | 58 | } |
| 56 | 59 | ||
| 57 | void VectorVfsFile::Assign(std::vector<u8> new_data) { | 60 | void VectorVfsFile::Assign(std::vector<u8> new_data) { |
| 58 | data = new_data; | 61 | data = std::move(new_data); |
| 59 | } | 62 | } |
| 60 | 63 | ||
| 61 | VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_, | 64 | VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_, |
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index c84e137a9..115c3ae95 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h | |||
| @@ -13,6 +13,7 @@ class VectorVfsFile : public VfsFile { | |||
| 13 | public: | 13 | public: |
| 14 | explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name = "", | 14 | explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name = "", |
| 15 | VirtualDir parent = nullptr); | 15 | VirtualDir parent = nullptr); |
| 16 | ~VectorVfsFile() override; | ||
| 16 | 17 | ||
| 17 | std::string GetName() const override; | 18 | std::string GetName() const override; |
| 18 | size_t GetSize() const override; | 19 | size_t GetSize() const override; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7cfe8a32f..dc8b5407d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -784,7 +784,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 784 | ? FileSys::PatchManager(program_id).PatchRomFS(file, loader->ReadRomFSIVFCOffset()) | 784 | ? FileSys::PatchManager(program_id).PatchRomFS(file, loader->ReadRomFSIVFCOffset()) |
| 785 | : file; | 785 | : file; |
| 786 | 786 | ||
| 787 | const auto extracted = FileSys::ExtractRomFS(romfs, false); | 787 | const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); |
| 788 | if (extracted == nullptr) { | 788 | if (extracted == nullptr) { |
| 789 | failed(); | 789 | failed(); |
| 790 | return; | 790 | return; |