partition_filesystem.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cstddef>
  6. #include <cstring>
  7. #include <iterator>
  8. #include <utility>
  9. #include "common/file_util.h"
  10. #include "common/logging/log.h"
  11. #include "core/file_sys/partition_filesystem.h"
  12. #include "core/file_sys/vfs_offset.h"
  13. #include "core/loader/loader.h"
  14. namespace FileSys {
  15. bool PartitionFilesystem::Header::HasValidMagicValue() const {
  16. return magic == Common::MakeMagic('H', 'F', 'S', '0') ||
  17. magic == Common::MakeMagic('P', 'F', 'S', '0');
  18. }
  19. PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
  20. // At least be as large as the header
  21. if (file->GetSize() < sizeof(Header)) {
  22. status = Loader::ResultStatus::ErrorBadPFSHeader;
  23. return;
  24. }
  25. // For cartridges, HFSs can get very large, so we need to calculate the size up to
  26. // the actual content itself instead of just blindly reading in the entire file.
  27. if (sizeof(Header) != file->ReadObject(&pfs_header)) {
  28. status = Loader::ResultStatus::ErrorBadPFSHeader;
  29. return;
  30. }
  31. if (!pfs_header.HasValidMagicValue()) {
  32. status = Loader::ResultStatus::ErrorBadPFSHeader;
  33. return;
  34. }
  35. is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
  36. std::size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry);
  37. std::size_t metadata_size =
  38. sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size;
  39. // Actually read in now...
  40. std::vector<u8> file_data = file->ReadBytes(metadata_size);
  41. const std::size_t total_size = file_data.size();
  42. if (total_size != metadata_size) {
  43. status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
  44. return;
  45. }
  46. std::size_t entries_offset = sizeof(Header);
  47. std::size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size);
  48. content_offset = strtab_offset + pfs_header.strtab_size;
  49. for (u16 i = 0; i < pfs_header.num_entries; i++) {
  50. FSEntry entry;
  51. memcpy(&entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry));
  52. std::string name(
  53. reinterpret_cast<const char*>(&file_data[strtab_offset + entry.strtab_offset]));
  54. pfs_files.emplace_back(std::make_shared<OffsetVfsFile>(
  55. file, entry.size, content_offset + entry.offset, std::move(name)));
  56. }
  57. status = Loader::ResultStatus::Success;
  58. }
  59. Loader::ResultStatus PartitionFilesystem::GetStatus() const {
  60. return status;
  61. }
  62. std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const {
  63. return pfs_files;
  64. }
  65. std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const {
  66. return pfs_dirs;
  67. }
  68. std::string PartitionFilesystem::GetName() const {
  69. return is_hfs ? "HFS0" : "PFS0";
  70. }
  71. std::shared_ptr<VfsDirectory> PartitionFilesystem::GetParentDirectory() const {
  72. // TODO(DarkLordZach): Add support for nested containers.
  73. return nullptr;
  74. }
  75. void PartitionFilesystem::PrintDebugInfo() const {
  76. LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic);
  77. LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
  78. for (u32 i = 0; i < pfs_header.num_entries; i++) {
  79. LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes)", i,
  80. pfs_files[i]->GetName(), pfs_files[i]->GetSize());
  81. }
  82. }
  83. bool PartitionFilesystem::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
  84. const auto iter = std::find(pfs_files.begin(), pfs_files.end(), file);
  85. if (iter == pfs_files.end())
  86. return false;
  87. const std::ptrdiff_t offset = std::distance(pfs_files.begin(), iter);
  88. pfs_files[offset] = std::move(pfs_files.back());
  89. pfs_files.pop_back();
  90. pfs_dirs.emplace_back(std::move(dir));
  91. return true;
  92. }
  93. } // namespace FileSys