diff options
| author | 2018-10-28 14:59:17 -0400 | |
|---|---|---|
| committer | 2018-10-29 13:54:39 -0400 | |
| commit | 5ee19add1bf221bd5259e4df76089252f04ce060 (patch) | |
| tree | 85971cd6073c2d625a53ae30584b55db3cf37d67 /src | |
| parent | fsp_srv: Implement command 61: OpenSaveDataInfoReaderBySaveDataSpaceId (diff) | |
| download | yuzu-5ee19add1bf221bd5259e4df76089252f04ce060.tar.gz yuzu-5ee19add1bf221bd5259e4df76089252f04ce060.tar.xz yuzu-5ee19add1bf221bd5259e4df76089252f04ce060.zip | |
fsp_srv: Implement ISaveDataInfoReader
An object to read SaveDataInfo objects, which describe a unique save on the system. This implementation iterates through all the directories in the save data space and uses the paths to reconstruct the metadata.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 56102a3db..3d1c2ecda 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/hex_util.h" | ||
| 14 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 15 | #include "common/string_util.h" | 16 | #include "common/string_util.h" |
| 16 | #include "core/file_sys/directory.h" | 17 | #include "core/file_sys/directory.h" |
| @@ -451,6 +452,149 @@ private: | |||
| 451 | VfsDirectoryServiceWrapper backend; | 452 | VfsDirectoryServiceWrapper backend; |
| 452 | }; | 453 | }; |
| 453 | 454 | ||
| 455 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { | ||
| 456 | public: | ||
| 457 | explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space) | ||
| 458 | : ServiceFramework("ISaveDataInfoReader") { | ||
| 459 | static const FunctionInfo functions[] = { | ||
| 460 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, | ||
| 461 | }; | ||
| 462 | RegisterHandlers(functions); | ||
| 463 | |||
| 464 | FindAllSaves(space); | ||
| 465 | } | ||
| 466 | |||
| 467 | void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { | ||
| 468 | // Calculate how many entries we can fit in the output buffer | ||
| 469 | const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); | ||
| 470 | |||
| 471 | // Cap at total number of entries. | ||
| 472 | const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); | ||
| 473 | |||
| 474 | // Determine data start and end | ||
| 475 | const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index); | ||
| 476 | const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries); | ||
| 477 | const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); | ||
| 478 | |||
| 479 | next_entry_index += actual_entries; | ||
| 480 | |||
| 481 | // Write the data to memory | ||
| 482 | ctx.WriteBuffer(begin, range_size); | ||
| 483 | |||
| 484 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 485 | rb.Push(RESULT_SUCCESS); | ||
| 486 | rb.Push(actual_entries); | ||
| 487 | } | ||
| 488 | |||
| 489 | private: | ||
| 490 | static u64 stoull_be(std::string_view str) { | ||
| 491 | if (str.size() != 16) | ||
| 492 | return 0; | ||
| 493 | |||
| 494 | const auto bytes = Common::HexStringToArray<0x8>(str); | ||
| 495 | u64 out{}; | ||
| 496 | std::memcpy(&out, bytes.data(), sizeof(u64)); | ||
| 497 | |||
| 498 | return Common::swap64(out); | ||
| 499 | } | ||
| 500 | |||
| 501 | static std::array<u8, 0x10> ArraySwap(const std::array<u8, 0x10>& in) { | ||
| 502 | std::array<u8, 0x10> out; | ||
| 503 | for (std::size_t i = 0; i < in.size(); ++i) { | ||
| 504 | out[0xF - i] = in[i]; | ||
| 505 | } | ||
| 506 | |||
| 507 | return out; | ||
| 508 | } | ||
| 509 | |||
| 510 | void FindAllSaves(FileSys::SaveDataSpaceId space) { | ||
| 511 | const auto save_root = OpenSaveDataSpace(space); | ||
| 512 | ASSERT(save_root.Succeeded()); | ||
| 513 | |||
| 514 | for (const auto& type : (*save_root)->GetSubdirectories()) { | ||
| 515 | if (type->GetName() == "save") { | ||
| 516 | for (const auto& save_id : type->GetSubdirectories()) { | ||
| 517 | for (const auto& user_id : save_id->GetSubdirectories()) { | ||
| 518 | const auto save_id_numeric = stoull_be(save_id->GetName()); | ||
| 519 | const auto user_id_numeric = | ||
| 520 | ArraySwap(Common::HexStringToArray<0x10>(user_id->GetName())); | ||
| 521 | if (save_id_numeric != 0) { | ||
| 522 | // System Save Data | ||
| 523 | info.emplace_back(SaveDataInfo{ | ||
| 524 | 0, | ||
| 525 | space, | ||
| 526 | FileSys::SaveDataType::SystemSaveData, | ||
| 527 | {}, | ||
| 528 | user_id_numeric, | ||
| 529 | save_id_numeric, | ||
| 530 | 0, | ||
| 531 | user_id->GetSize(), | ||
| 532 | {}, | ||
| 533 | }); | ||
| 534 | |||
| 535 | continue; | ||
| 536 | } | ||
| 537 | |||
| 538 | for (const auto& title_id : user_id->GetSubdirectories()) { | ||
| 539 | const auto device = | ||
| 540 | std::all_of(user_id_numeric.begin(), user_id_numeric.end(), | ||
| 541 | [](u8 val) { return val == 0; }); | ||
| 542 | info.emplace_back(SaveDataInfo{ | ||
| 543 | 0, | ||
| 544 | space, | ||
| 545 | device ? FileSys::SaveDataType::DeviceSaveData | ||
| 546 | : FileSys::SaveDataType::SaveData, | ||
| 547 | {}, | ||
| 548 | user_id_numeric, | ||
| 549 | save_id_numeric, | ||
| 550 | stoull_be(title_id->GetName()), | ||
| 551 | title_id->GetSize(), | ||
| 552 | {}, | ||
| 553 | }); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | } | ||
| 557 | } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { | ||
| 558 | // Temporary Storage | ||
| 559 | for (const auto& user_id : type->GetSubdirectories()) { | ||
| 560 | for (const auto& title_id : user_id->GetSubdirectories()) { | ||
| 561 | if (!title_id->GetFiles().empty() || | ||
| 562 | !title_id->GetSubdirectories().empty()) { | ||
| 563 | info.emplace_back(SaveDataInfo{ | ||
| 564 | 0, | ||
| 565 | space, | ||
| 566 | FileSys::SaveDataType::TemporaryStorage, | ||
| 567 | {}, | ||
| 568 | Common::HexStringToArray<0x10, true>(user_id->GetName()), | ||
| 569 | stoull_be(type->GetName()), | ||
| 570 | stoull_be(title_id->GetName()), | ||
| 571 | title_id->GetSize(), | ||
| 572 | {}, | ||
| 573 | }); | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | } | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | struct SaveDataInfo { | ||
| 582 | u64_le save_id_unknown; | ||
| 583 | FileSys::SaveDataSpaceId space; | ||
| 584 | FileSys::SaveDataType type; | ||
| 585 | INSERT_PADDING_BYTES(0x6); | ||
| 586 | std::array<u8, 0x10> user_id; | ||
| 587 | u64_le save_id; | ||
| 588 | u64_le title_id; | ||
| 589 | u64_le save_image_size; | ||
| 590 | INSERT_PADDING_BYTES(0x28); | ||
| 591 | }; | ||
| 592 | static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); | ||
| 593 | |||
| 594 | std::vector<SaveDataInfo> info; | ||
| 595 | u64 next_entry_index = 0; | ||
| 596 | }; | ||
| 597 | |||
| 454 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | 598 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { |
| 455 | // clang-format off | 599 | // clang-format off |
| 456 | static const FunctionInfo functions[] = { | 600 | static const FunctionInfo functions[] = { |