diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 46d438aca3..2a8eb71313 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -7,23 +7,20 @@ #include "common/logging/log.h" #include "core/file_sys/partition_filesystem.h" #include "core/loader/loader.h" +#include "vfs_offset.h" namespace FileSys { -Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, size_t offset) { - FileUtil::IOFile file(file_path, "rb"); - if (!file.IsOpen()) - return Loader::ResultStatus::Error; - +Loader::ResultStatus PartitionFilesystem::Load(std::shared_ptr file) { // At least be as large as the header - if (file.GetSize() < sizeof(Header)) + if (file->GetSize() < sizeof(Header)) return Loader::ResultStatus::Error; file.Seek(offset, SEEK_SET); // For cartridges, HFSs can get very large, so we need to calculate the size up to // the actual content itself instead of just blindly reading in the entire file. Header pfs_header; - if (!file.ReadBytes(&pfs_header, sizeof(Header))) + if (!file->ReadObject(&pfs_header)) return Loader::ResultStatus::Error; if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') && @@ -38,21 +35,12 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::string& file_path, siz sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; // Actually read in now... - file.Seek(offset, SEEK_SET); - std::vector file_data(metadata_size); + std::vector file_data = file->ReadBytes(metadata_size); - if (!file.ReadBytes(file_data.data(), metadata_size)) + if (file_data.size() != metadata_size) return Loader::ResultStatus::Error; - Loader::ResultStatus result = Load(file_data); - if (result != Loader::ResultStatus::Success) - LOG_ERROR(Service_FS, "Failed to load PFS from file {}!", file_path); - - return result; -} - -Loader::ResultStatus PartitionFilesystem::Load(const std::vector& file_data, size_t offset) { - size_t total_size = file_data.size() - offset; + size_t total_size = file_data.size(); if (total_size < sizeof(Header)) return Loader::ResultStatus::Error; @@ -65,72 +53,74 @@ Loader::ResultStatus PartitionFilesystem::Load(const std::vector& file_data, is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0'); size_t entries_offset = offset + sizeof(Header); - size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); size_t strtab_offset = entries_offset + (pfs_header.num_entries * entry_size); - for (u16 i = 0; i < pfs_header.num_entries; i++) { - FileEntry entry; - - memcpy(&entry.fs_entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry)); - entry.name = std::string(reinterpret_cast( - &file_data[strtab_offset + entry.fs_entry.strtab_offset])); - pfs_entries.push_back(std::move(entry)); - } - content_offset = strtab_offset + pfs_header.strtab_size; + for (u16 i = 0; i < pfs_header.num_entries; i++) { + FSEntry entry; + + memcpy(&entry, &file_data[entries_offset + (i * entry_size)], sizeof(FSEntry)); + std::string name( + reinterpret_cast(&file_data[strtab_offset + entry.strtab_offset])); + + pfs_files.emplace_back( + std::make_shared(file, entry.size, content_offset + entry.offset, name)); + } return Loader::ResultStatus::Success; } -u32 PartitionFilesystem::GetNumEntries() const { - return pfs_header.num_entries; +std::vector> PartitionFilesystem::GetFiles() const { + return pfs_files; } -u64 PartitionFilesystem::GetEntryOffset(u32 index) const { - if (index > GetNumEntries()) - return 0; - - return content_offset + pfs_entries[index].fs_entry.offset; +std::vector> PartitionFilesystem::GetSubdirectories() const { + return {}; } -u64 PartitionFilesystem::GetEntrySize(u32 index) const { - if (index > GetNumEntries()) - return 0; - - return pfs_entries[index].fs_entry.size; +bool PartitionFilesystem::IsWritable() const { + return false; } -std::string PartitionFilesystem::GetEntryName(u32 index) const { - if (index > GetNumEntries()) - return ""; - - return pfs_entries[index].name; +bool PartitionFilesystem::IsReadable() const { + return true; } -u64 PartitionFilesystem::GetFileOffset(const std::string& name) const { +std::string PartitionFilesystem::GetName() const { + return is_hfs ? "HFS0" : "PFS0"; +} + +std::shared_ptr PartitionFilesystem::GetParentDirectory() const { + // TODO(DarkLordZach): Add support for nested containers. + return nullptr; +} + +std::shared_ptr PartitionFilesystem::CreateSubdirectory(const std::string& name) { + return nullptr; +} + +std::shared_ptr PartitionFilesystem::CreateFile(const std::string& name) { + return nullptr; +} + +bool PartitionFilesystem::DeleteSubdirectory(const std::string& name) { + return false; +} + +bool PartitionFilesystem::DeleteFile(const std::string& name) { + return false; +} + +bool PartitionFilesystem::Rename(const std::string& name) { + return false; +} + +void PartitionFilesystem::PrintDebugInfo() const { + NGLOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic.data()); + NGLOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); for (u32 i = 0; i < pfs_header.num_entries; i++) { - if (pfs_entries[i].name == name) - return content_offset + pfs_entries[i].fs_entry.offset; - } - - return 0; -} - -u64 PartitionFilesystem::GetFileSize(const std::string& name) const { - for (u32 i = 0; i < pfs_header.num_entries; i++) { - if (pfs_entries[i].name == name) - return pfs_entries[i].fs_entry.size; - } - - return 0; -} - -void PartitionFilesystem::Print() const { - LOG_DEBUG(Service_FS, "Magic: {}", pfs_header.magic); - LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); - for (u32 i = 0; i < pfs_header.num_entries; i++) { - LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, - pfs_entries[i].name.c_str(), pfs_entries[i].fs_entry.size, - GetFileOffset(pfs_entries[i].name)); + NGLOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, + pfs_files[i]->GetName(), pfs_files[i]->GetSize(), + dynamic_cast(pfs_files[i].get())->GetOffset()); } } } // namespace FileSys diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h index 9c5810cf15..abee28b4b1 100644 --- a/src/core/file_sys/partition_filesystem.h +++ b/src/core/file_sys/partition_filesystem.h @@ -10,6 +10,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "core/file_sys/vfs.h" namespace Loader { enum class ResultStatus; @@ -21,19 +22,23 @@ namespace FileSys { * Helper which implements an interface to parse PFS/HFS filesystems. * Data can either be loaded from a file path or data with an offset into it. */ -class PartitionFilesystem { +class PartitionFilesystem : public VfsDirectory { public: - Loader::ResultStatus Load(const std::string& file_path, size_t offset = 0); - Loader::ResultStatus Load(const std::vector& file_data, size_t offset = 0); + Loader::ResultStatus Load(std::shared_ptr file); - u32 GetNumEntries() const; - u64 GetEntryOffset(u32 index) const; - u64 GetEntrySize(u32 index) const; - std::string GetEntryName(u32 index) const; - u64 GetFileOffset(const std::string& name) const; - u64 GetFileSize(const std::string& name) const; + std::vector> GetFiles() const override; + std::vector> GetSubdirectories() const override; + bool IsWritable() const override; + bool IsReadable() const override; + std::string GetName() const override; + std::shared_ptr GetParentDirectory() const override; + std::shared_ptr CreateSubdirectory(const std::string& name) override; + std::shared_ptr CreateFile(const std::string& name) override; + bool DeleteSubdirectory(const std::string& name) override; + bool DeleteFile(const std::string& name) override; + bool Rename(const std::string& name) override; - void Print() const; + void PrintDebugInfo() const; private: struct Header { @@ -72,16 +77,11 @@ private: #pragma pack(pop) - struct FileEntry { - FSEntry fs_entry; - std::string name; - }; - Header pfs_header; bool is_hfs; size_t content_offset; - std::vector pfs_entries; + std::vector> pfs_files; }; } // namespace FileSys diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index e45bc8af19..f5bb12b143 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -38,7 +38,7 @@ struct VfsFile : NonCopyable { static_assert(std::is_trivially_copyable::value, "Data type must be trivially copyable."); - return Read(data, number_elements * sizeof(T), offset); + return Read(reinterpret_cast(data), number_elements * sizeof(T), offset); } template @@ -49,10 +49,10 @@ struct VfsFile : NonCopyable { } template - size_t ReadObject(T& data, size_t offset = 0) const { + size_t ReadObject(T* data, size_t offset = 0) const { static_assert(std::is_trivially_copyable::value, "Data type must be trivially copyable."); - return Read(&data, sizeof(T), offset); + return Read(reinterpret_cast(data), sizeof(T), offset); } virtual bool WriteByte(u8 data, size_t offset = 0); diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index bc3b16eb5b..b25a945202 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp @@ -6,11 +6,12 @@ namespace FileSys { -OffsetVfsFile::OffsetVfsFile(std::unique_ptr&& file_, u64 offset_, u64 size_) - : file(std::move(file_)), offset(offset_), size(size_) {} +OffsetVfsFile::OffsetVfsFile(std::shared_ptr file_, u64 size_, u64 offset_, + const std::string& name_) + : file(file_), offset(offset_), size(size_), name(name_) {} std::string OffsetVfsFile::GetName() const { - return file->GetName(); + return name.empty() ? file->GetName() : name; } u64 OffsetVfsFile::GetSize() const { @@ -76,6 +77,10 @@ bool OffsetVfsFile::Rename(const std::string& name) { return file->Rename(name); } +size_t OffsetVfsFile::GetOffset() const { + return offset; +} + size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const { return std::max(std::min(size - r_offset, r_size), 0ull); } diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index 58d59448ea..a3ef0bde33 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -9,7 +9,8 @@ namespace FileSys { struct OffsetVfsFile : public VfsFile { - OffsetVfsFile(std::unique_ptr&& file, size_t offset, size_t size); + OffsetVfsFile(std::shared_ptr file, size_t size, size_t offset = 0, + const std::string& new_name = ""); std::string GetName() const override; size_t GetSize() const override; @@ -27,12 +28,15 @@ struct OffsetVfsFile : public VfsFile { bool Rename(const std::string& name) override; + size_t GetOffset() const; + private: size_t TrimToFit(size_t r_size, size_t r_offset) const; - std::unique_ptr file; + std::shared_ptr file; size_t offset; size_t size; + std::string name; }; } // namespace FileSys