diff options
Diffstat (limited to 'src/frontend_common/content_manager.h')
| -rw-r--r-- | src/frontend_common/content_manager.h | 155 |
1 files changed, 144 insertions, 11 deletions
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h index 23f2979db..0b0fee73e 100644 --- a/src/frontend_common/content_manager.h +++ b/src/frontend_common/content_manager.h | |||
| @@ -11,10 +11,12 @@ | |||
| 11 | #include "core/file_sys/content_archive.h" | 11 | #include "core/file_sys/content_archive.h" |
| 12 | #include "core/file_sys/mode.h" | 12 | #include "core/file_sys/mode.h" |
| 13 | #include "core/file_sys/nca_metadata.h" | 13 | #include "core/file_sys/nca_metadata.h" |
| 14 | #include "core/file_sys/patch_manager.h" | ||
| 14 | #include "core/file_sys/registered_cache.h" | 15 | #include "core/file_sys/registered_cache.h" |
| 15 | #include "core/file_sys/submission_package.h" | 16 | #include "core/file_sys/submission_package.h" |
| 16 | #include "core/hle/service/filesystem/filesystem.h" | 17 | #include "core/hle/service/filesystem/filesystem.h" |
| 17 | #include "core/loader/loader.h" | 18 | #include "core/loader/loader.h" |
| 19 | #include "core/loader/nca.h" | ||
| 18 | 20 | ||
| 19 | namespace ContentManager { | 21 | namespace ContentManager { |
| 20 | 22 | ||
| @@ -25,6 +27,12 @@ enum class InstallResult { | |||
| 25 | BaseInstallAttempted, | 27 | BaseInstallAttempted, |
| 26 | }; | 28 | }; |
| 27 | 29 | ||
| 30 | enum class GameVerificationResult { | ||
| 31 | Success, | ||
| 32 | Failed, | ||
| 33 | NotImplemented, | ||
| 34 | }; | ||
| 35 | |||
| 28 | /** | 36 | /** |
| 29 | * \brief Removes a single installed DLC | 37 | * \brief Removes a single installed DLC |
| 30 | * \param fs_controller [FileSystemController] reference from the Core::System instance | 38 | * \param fs_controller [FileSystemController] reference from the Core::System instance |
| @@ -119,14 +127,14 @@ inline bool RemoveMod(const Service::FileSystem::FileSystemController& fs_contro | |||
| 119 | * \param system Raw pointer to the system instance | 127 | * \param system Raw pointer to the system instance |
| 120 | * \param vfs Raw pointer to the VfsFilesystem instance in Core::System | 128 | * \param vfs Raw pointer to the VfsFilesystem instance in Core::System |
| 121 | * \param filename Path to the NSP file | 129 | * \param filename Path to the NSP file |
| 122 | * \param callback Optional callback to report the progress of the installation. The first size_t | 130 | * \param callback Callback to report the progress of the installation. The first size_t |
| 123 | * parameter is the total size of the virtual file and the second is the current progress. If you | 131 | * parameter is the total size of the virtual file and the second is the current progress. If you |
| 124 | * return false to the callback, it will cancel the installation as soon as possible. | 132 | * return true to the callback, it will cancel the installation as soon as possible. |
| 125 | * \return [InstallResult] representing how the installation finished | 133 | * \return [InstallResult] representing how the installation finished |
| 126 | */ | 134 | */ |
| 127 | inline InstallResult InstallNSP( | 135 | inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vfs, |
| 128 | Core::System* system, FileSys::VfsFilesystem* vfs, const std::string& filename, | 136 | const std::string& filename, |
| 129 | const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) { | 137 | const std::function<bool(size_t, size_t)>& callback) { |
| 130 | const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | 138 | const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, |
| 131 | std::size_t block_size) { | 139 | std::size_t block_size) { |
| 132 | if (src == nullptr || dest == nullptr) { | 140 | if (src == nullptr || dest == nullptr) { |
| @@ -184,15 +192,15 @@ inline InstallResult InstallNSP( | |||
| 184 | * \param filename Path to the NCA file | 192 | * \param filename Path to the NCA file |
| 185 | * \param registered_cache Raw pointer to the registered cache that the NCA will be installed to | 193 | * \param registered_cache Raw pointer to the registered cache that the NCA will be installed to |
| 186 | * \param title_type Type of NCA package to install | 194 | * \param title_type Type of NCA package to install |
| 187 | * \param callback Optional callback to report the progress of the installation. The first size_t | 195 | * \param callback Callback to report the progress of the installation. The first size_t |
| 188 | * parameter is the total size of the virtual file and the second is the current progress. If you | 196 | * parameter is the total size of the virtual file and the second is the current progress. If you |
| 189 | * return false to the callback, it will cancel the installation as soon as possible. | 197 | * return true to the callback, it will cancel the installation as soon as possible. |
| 190 | * \return [InstallResult] representing how the installation finished | 198 | * \return [InstallResult] representing how the installation finished |
| 191 | */ | 199 | */ |
| 192 | inline InstallResult InstallNCA( | 200 | inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string& filename, |
| 193 | FileSys::VfsFilesystem* vfs, const std::string& filename, | 201 | FileSys::RegisteredCache* registered_cache, |
| 194 | FileSys::RegisteredCache* registered_cache, const FileSys::TitleType title_type, | 202 | const FileSys::TitleType title_type, |
| 195 | const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) { | 203 | const std::function<bool(size_t, size_t)>& callback) { |
| 196 | const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | 204 | const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, |
| 197 | std::size_t block_size) { | 205 | std::size_t block_size) { |
| 198 | if (src == nullptr || dest == nullptr) { | 206 | if (src == nullptr || dest == nullptr) { |
| @@ -235,4 +243,129 @@ inline InstallResult InstallNCA( | |||
| 235 | } | 243 | } |
| 236 | } | 244 | } |
| 237 | 245 | ||
| 246 | /** | ||
| 247 | * \brief Verifies the installed contents for a given ManualContentProvider | ||
| 248 | * \param system Raw pointer to the system instance | ||
| 249 | * \param provider Raw pointer to the content provider that's tracking indexed games | ||
| 250 | * \param callback Callback to report the progress of the installation. The first size_t | ||
| 251 | * parameter is the total size of the installed contents and the second is the current progress. If | ||
| 252 | * you return true to the callback, it will cancel the installation as soon as possible. | ||
| 253 | * \return A list of entries that failed to install. Returns an empty vector if successful. | ||
| 254 | */ | ||
| 255 | inline std::vector<std::string> VerifyInstalledContents( | ||
| 256 | Core::System* system, FileSys::ManualContentProvider* provider, | ||
| 257 | const std::function<bool(size_t, size_t)>& callback) { | ||
| 258 | // Get content registries. | ||
| 259 | auto bis_contents = system->GetFileSystemController().GetSystemNANDContents(); | ||
| 260 | auto user_contents = system->GetFileSystemController().GetUserNANDContents(); | ||
| 261 | |||
| 262 | std::vector<FileSys::RegisteredCache*> content_providers; | ||
| 263 | if (bis_contents) { | ||
| 264 | content_providers.push_back(bis_contents); | ||
| 265 | } | ||
| 266 | if (user_contents) { | ||
| 267 | content_providers.push_back(user_contents); | ||
| 268 | } | ||
| 269 | |||
| 270 | // Get associated NCA files. | ||
| 271 | std::vector<FileSys::VirtualFile> nca_files; | ||
| 272 | |||
| 273 | // Get all installed IDs. | ||
| 274 | size_t total_size = 0; | ||
| 275 | for (auto nca_provider : content_providers) { | ||
| 276 | const auto entries = nca_provider->ListEntriesFilter(); | ||
| 277 | |||
| 278 | for (const auto& entry : entries) { | ||
| 279 | auto nca_file = nca_provider->GetEntryRaw(entry.title_id, entry.type); | ||
| 280 | if (!nca_file) { | ||
| 281 | continue; | ||
| 282 | } | ||
| 283 | |||
| 284 | total_size += nca_file->GetSize(); | ||
| 285 | nca_files.push_back(std::move(nca_file)); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | // Declare a list of file names which failed to verify. | ||
| 290 | std::vector<std::string> failed; | ||
| 291 | |||
| 292 | size_t processed_size = 0; | ||
| 293 | bool cancelled = false; | ||
| 294 | auto nca_callback = [&](size_t nca_processed, size_t nca_total) { | ||
| 295 | cancelled = callback(total_size, processed_size + nca_processed); | ||
| 296 | return !cancelled; | ||
| 297 | }; | ||
| 298 | |||
| 299 | // Using the NCA loader, determine if all NCAs are valid. | ||
| 300 | for (auto& nca_file : nca_files) { | ||
| 301 | Loader::AppLoader_NCA nca_loader(nca_file); | ||
| 302 | |||
| 303 | auto status = nca_loader.VerifyIntegrity(nca_callback); | ||
| 304 | if (cancelled) { | ||
| 305 | break; | ||
| 306 | } | ||
| 307 | if (status != Loader::ResultStatus::Success) { | ||
| 308 | FileSys::NCA nca(nca_file); | ||
| 309 | const auto title_id = nca.GetTitleId(); | ||
| 310 | std::string title_name = "unknown"; | ||
| 311 | |||
| 312 | const auto control = provider->GetEntry(FileSys::GetBaseTitleID(title_id), | ||
| 313 | FileSys::ContentRecordType::Control); | ||
| 314 | if (control && control->GetStatus() == Loader::ResultStatus::Success) { | ||
| 315 | const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), | ||
| 316 | *provider}; | ||
| 317 | const auto [nacp, logo] = pm.ParseControlNCA(*control); | ||
| 318 | if (nacp) { | ||
| 319 | title_name = nacp->GetApplicationName(); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | if (title_id > 0) { | ||
| 324 | failed.push_back( | ||
| 325 | fmt::format("{} ({:016X}) ({})", nca_file->GetName(), title_id, title_name)); | ||
| 326 | } else { | ||
| 327 | failed.push_back(fmt::format("{} (unknown)", nca_file->GetName())); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | processed_size += nca_file->GetSize(); | ||
| 332 | } | ||
| 333 | return failed; | ||
| 334 | } | ||
| 335 | |||
| 336 | /** | ||
| 337 | * \brief Verifies the contents of a given game | ||
| 338 | * \param system Raw pointer to the system instance | ||
| 339 | * \param game_path Patch to the game file | ||
| 340 | * \param callback Callback to report the progress of the installation. The first size_t | ||
| 341 | * parameter is the total size of the installed contents and the second is the current progress. If | ||
| 342 | * you return true to the callback, it will cancel the installation as soon as possible. | ||
| 343 | * \return GameVerificationResult representing how the verification process finished | ||
| 344 | */ | ||
| 345 | inline GameVerificationResult VerifyGameContents( | ||
| 346 | Core::System* system, const std::string& game_path, | ||
| 347 | const std::function<bool(size_t, size_t)>& callback) { | ||
| 348 | const auto loader = Loader::GetLoader( | ||
| 349 | *system, system->GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read)); | ||
| 350 | if (loader == nullptr) { | ||
| 351 | return GameVerificationResult::NotImplemented; | ||
| 352 | } | ||
| 353 | |||
| 354 | bool cancelled = false; | ||
| 355 | auto loader_callback = [&](size_t processed, size_t total) { | ||
| 356 | cancelled = callback(total, processed); | ||
| 357 | return !cancelled; | ||
| 358 | }; | ||
| 359 | |||
| 360 | const auto status = loader->VerifyIntegrity(loader_callback); | ||
| 361 | if (cancelled || status == Loader::ResultStatus::ErrorIntegrityVerificationNotImplemented) { | ||
| 362 | return GameVerificationResult::NotImplemented; | ||
| 363 | } | ||
| 364 | |||
| 365 | if (status == Loader::ResultStatus::ErrorIntegrityVerificationFailed) { | ||
| 366 | return GameVerificationResult::Failed; | ||
| 367 | } | ||
| 368 | return GameVerificationResult::Success; | ||
| 369 | } | ||
| 370 | |||
| 238 | } // namespace ContentManager | 371 | } // namespace ContentManager |