diff options
Diffstat (limited to 'src/core/file_sys')
| -rw-r--r-- | src/core/file_sys/disk_filesystem.cpp | 14 | ||||
| -rw-r--r-- | src/core/file_sys/disk_filesystem.h | 7 | ||||
| -rw-r--r-- | src/core/file_sys/filesystem.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/partition_filesystem.cpp | 125 | ||||
| -rw-r--r-- | src/core/file_sys/partition_filesystem.h | 87 | ||||
| -rw-r--r-- | src/core/file_sys/romfs_filesystem.cpp | 2 | ||||
| -rw-r--r-- | src/core/file_sys/romfs_filesystem.h | 2 |
7 files changed, 227 insertions, 12 deletions
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp index 4235f3935..ca1323873 100644 --- a/src/core/file_sys/disk_filesystem.cpp +++ b/src/core/file_sys/disk_filesystem.cpp @@ -57,10 +57,14 @@ ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std:: std::make_unique<Disk_Storage>(std::move(file))); } -ResultCode Disk_FileSystem::DeleteFile(const Path& path) const { - LOG_WARNING(Service_FS, "(STUBBED) called"); - // TODO(bunnei): Use correct error code - return ResultCode(-1); +ResultCode Disk_FileSystem::DeleteFile(const std::string& path) const { + if (!FileUtil::Exists(path)) { + return ERROR_PATH_NOT_FOUND; + } + + FileUtil::Delete(path); + + return RESULT_SUCCESS; } ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const { @@ -179,7 +183,7 @@ bool Disk_Storage::SetSize(const u64 size) const { return true; } -Disk_Directory::Disk_Directory(const std::string& path) : directory() { +Disk_Directory::Disk_Directory(const std::string& path) { unsigned size = FileUtil::ScanDirectoryTree(path, directory); directory.size = size; directory.isDirectory = true; diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h index 742d7db1a..8f9e1145a 100644 --- a/src/core/file_sys/disk_filesystem.h +++ b/src/core/file_sys/disk_filesystem.h @@ -25,7 +25,7 @@ public: ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path, Mode mode) const override; - ResultCode DeleteFile(const Path& path) const override; + ResultCode DeleteFile(const std::string& path) const override; ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; ResultCode DeleteDirectory(const Path& path) const override; ResultCode DeleteDirectoryRecursively(const Path& path) const override; @@ -43,7 +43,7 @@ protected: class Disk_Storage : public StorageBackend { public: - Disk_Storage(std::shared_ptr<FileUtil::IOFile> file) : file(std::move(file)) {} + explicit Disk_Storage(std::shared_ptr<FileUtil::IOFile> file) : file(std::move(file)) {} ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override; ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; @@ -60,7 +60,7 @@ private: class Disk_Directory : public DirectoryBackend { public: - Disk_Directory(const std::string& path); + explicit Disk_Directory(const std::string& path); ~Disk_Directory() override { Close(); @@ -74,7 +74,6 @@ public: } protected: - u32 total_entries_in_directory; FileUtil::FSTEntry directory; // We need to remember the last entry we returned, so a subsequent call to Read will continue diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 399427ca2..beefcfdb2 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -97,7 +97,7 @@ public: * @param path Path relative to the archive * @return Result of the operation */ - virtual ResultCode DeleteFile(const Path& path) const = 0; + virtual ResultCode DeleteFile(const std::string& path) const = 0; /** * Create a directory specified by its path diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp new file mode 100644 index 000000000..4a58a9291 --- /dev/null +++ b/src/core/file_sys/partition_filesystem.cpp @@ -0,0 +1,125 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cinttypes> +#include <utility> +#include "common/file_util.h" +#include "common/logging/log.h" +#include "core/file_sys/partition_filesystem.h" +#include "core/loader/loader.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; + + // At least be as large as the header + if (file.GetSize() < sizeof(Header)) + return Loader::ResultStatus::Error; + + // 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))) + return Loader::ResultStatus::Error; + + bool is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 0); + size_t entry_size = is_hfs ? sizeof(HFSEntry) : sizeof(PFSEntry); + size_t metadata_size = + sizeof(Header) + (pfs_header.num_entries * entry_size) + pfs_header.strtab_size; + + // Actually read in now... + file.Seek(offset, SEEK_SET); + std::vector<u8> file_data(metadata_size); + + if (!file.ReadBytes(file_data.data(), 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 %s!", file_path.c_str()); + + return result; +} + +Loader::ResultStatus PartitionFilesystem::Load(const std::vector<u8>& file_data, size_t offset) { + size_t total_size = file_data.size() - offset; + if (total_size < sizeof(Header)) + return Loader::ResultStatus::Error; + + memcpy(&pfs_header, &file_data[offset], sizeof(Header)); + is_hfs = (memcmp(pfs_header.magic.data(), "HFS", 3) == 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<const char*>( + &file_data[strtab_offset + entry.fs_entry.strtab_offset])); + pfs_entries.push_back(std::move(entry)); + } + + content_offset = strtab_offset + pfs_header.strtab_size; + + return Loader::ResultStatus::Success; +} + +u32 PartitionFilesystem::GetNumEntries() const { + return pfs_header.num_entries; +} + +u64 PartitionFilesystem::GetEntryOffset(int index) const { + if (index > GetNumEntries()) + return 0; + + return content_offset + pfs_entries[index].fs_entry.offset; +} + +u64 PartitionFilesystem::GetEntrySize(int index) const { + if (index > GetNumEntries()) + return 0; + + return pfs_entries[index].fs_entry.size; +} + +std::string PartitionFilesystem::GetEntryName(int index) const { + if (index > GetNumEntries()) + return ""; + + return pfs_entries[index].name; +} + +u64 PartitionFilesystem::GetFileOffset(const std::string& name) const { + 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 { + 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++) { + NGLOG_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)); + } +} +} // namespace FileSys diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h new file mode 100644 index 000000000..573c90057 --- /dev/null +++ b/src/core/file_sys/partition_filesystem.h @@ -0,0 +1,87 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <string> +#include <vector> +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/swap.h" + +namespace Loader { +enum class ResultStatus; +} + +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 { +public: + Loader::ResultStatus Load(const std::string& file_path, size_t offset = 0); + Loader::ResultStatus Load(const std::vector<u8>& file_data, size_t offset = 0); + + u32 GetNumEntries() const; + u64 GetEntryOffset(int index) const; + u64 GetEntrySize(int index) const; + std::string GetEntryName(int index) const; + u64 GetFileOffset(const std::string& name) const; + u64 GetFileSize(const std::string& name) const; + + void Print() const; + +private: + struct Header { + std::array<char, 4> magic; + u32_le num_entries; + u32_le strtab_size; + INSERT_PADDING_BYTES(0x4); + }; + + static_assert(sizeof(Header) == 0x10, "PFS/HFS header structure size is wrong"); + +#pragma pack(push, 1) + struct FSEntry { + u64_le offset; + u64_le size; + u32_le strtab_offset; + }; + + static_assert(sizeof(FSEntry) == 0x14, "FS entry structure size is wrong"); + + struct PFSEntry { + FSEntry fs_entry; + INSERT_PADDING_BYTES(0x4); + }; + + static_assert(sizeof(PFSEntry) == 0x18, "PFS entry structure size is wrong"); + + struct HFSEntry { + FSEntry fs_entry; + u32_le hash_region_size; + INSERT_PADDING_BYTES(0x8); + std::array<char, 0x20> hash; + }; + + static_assert(sizeof(HFSEntry) == 0x40, "HFS entry structure size is wrong"); + +#pragma pack(pop) + + struct FileEntry { + FSEntry fs_entry; + std::string name; + }; + + Header pfs_header; + bool is_hfs; + size_t content_offset; + + std::vector<FileEntry> pfs_entries; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index 0c6cc3157..3d77e2d5f 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -20,7 +20,7 @@ ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const std: std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size)); } -ResultCode RomFS_FileSystem::DeleteFile(const Path& path) const { +ResultCode RomFS_FileSystem::DeleteFile(const std::string& path) const { LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index 3f94c04d0..1b5cac409 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -31,7 +31,7 @@ public: ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path, Mode mode) const override; - ResultCode DeleteFile(const Path& path) const override; + ResultCode DeleteFile(const std::string& path) const override; ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; ResultCode DeleteDirectory(const Path& path) const override; ResultCode DeleteDirectoryRecursively(const Path& path) const override; |
