More Overhaul
This commit is contained in:
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
|
#include "core/file_sys/vfs_offset.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "vfs_offset.h"
|
|
||||||
|
|
||||||
// Media offsets in headers are stored divided by 512. Mult. by this to get real offset.
|
// Media offsets in headers are stored divided by 512. Mult. by this to get real offset.
|
||||||
constexpr u64 MEDIA_OFFSET_MULTIPLIER = 0x200;
|
constexpr u64 MEDIA_OFFSET_MULTIPLIER = 0x200;
|
||||||
@@ -14,18 +14,18 @@ constexpr u64 SECTION_HEADER_SIZE = 0x200;
|
|||||||
constexpr u64 SECTION_HEADER_OFFSET = 0x400;
|
constexpr u64 SECTION_HEADER_OFFSET = 0x400;
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
enum class NcaSectionFilesystemType : u8 { PFS0 = 0x2, ROMFS = 0x3 };
|
enum class NCASectionFilesystemType : u8 { PFS0 = 0x2, ROMFS = 0x3 };
|
||||||
|
|
||||||
struct NcaSectionHeaderBlock {
|
struct NCASectionHeaderBlock {
|
||||||
INSERT_PADDING_BYTES(3);
|
INSERT_PADDING_BYTES(3);
|
||||||
NcaSectionFilesystemType filesystem_type;
|
NCASectionFilesystemType filesystem_type;
|
||||||
u8 crypto_type;
|
u8 crypto_type;
|
||||||
INSERT_PADDING_BYTES(3);
|
INSERT_PADDING_BYTES(3);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NcaSectionHeaderBlock) == 0x8, "NcaSectionHeaderBlock has incorrect size.");
|
static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
|
||||||
|
|
||||||
struct Pfs0Superblock {
|
struct PFS0Superblock {
|
||||||
NcaSectionHeaderBlock header_block;
|
NCASectionHeaderBlock header_block;
|
||||||
std::array<u8, 0x20> hash;
|
std::array<u8, 0x20> hash;
|
||||||
u32_le size;
|
u32_le size;
|
||||||
INSERT_PADDING_BYTES(4);
|
INSERT_PADDING_BYTES(4);
|
||||||
@@ -35,40 +35,39 @@ struct Pfs0Superblock {
|
|||||||
u64_le pfs0_size;
|
u64_le pfs0_size;
|
||||||
INSERT_PADDING_BYTES(432);
|
INSERT_PADDING_BYTES(432);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Pfs0Superblock) == 0x200, "Pfs0Superblock has incorrect size.");
|
static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size.");
|
||||||
|
|
||||||
Loader::ResultStatus Nca::Load(v_file file_) {
|
NCA::NCA(v_file file_) : file(file_) {
|
||||||
file = std::move(file_);
|
if (sizeof(NCAHeader) != file->ReadObject(&header))
|
||||||
|
|
||||||
if (sizeof(NcaHeader) != file->ReadObject(&header))
|
|
||||||
NGLOG_CRITICAL(Loader, "File reader errored out during header read.");
|
NGLOG_CRITICAL(Loader, "File reader errored out during header read.");
|
||||||
|
|
||||||
if (!IsValidNca(header))
|
if (!IsValidNCA(header)) {
|
||||||
return Loader::ResultStatus::ErrorInvalidFormat;
|
status = Loader::ResultStatus::ErrorInvalidFormat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int number_sections =
|
int number_sections =
|
||||||
std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
|
std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
|
||||||
[](NcaSectionTableEntry entry) { return entry.media_offset > 0; });
|
[](NCASectionTableEntry entry) { return entry.media_offset > 0; });
|
||||||
|
|
||||||
for (int i = 0; i < number_sections; ++i) {
|
for (int i = 0; i < number_sections; ++i) {
|
||||||
// Seek to beginning of this section.
|
// Seek to beginning of this section.
|
||||||
NcaSectionHeaderBlock block{};
|
NCASectionHeaderBlock block{};
|
||||||
if (sizeof(NcaSectionHeaderBlock) !=
|
if (sizeof(NCASectionHeaderBlock) !=
|
||||||
file->ReadObject(&block, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
|
file->ReadObject(&block, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
|
||||||
NGLOG_CRITICAL(Loader, "File reader errored out during header read.");
|
NGLOG_CRITICAL(Loader, "File reader errored out during header read.");
|
||||||
|
|
||||||
if (block.filesystem_type == NcaSectionFilesystemType::ROMFS) {
|
if (block.filesystem_type == NCASectionFilesystemType::ROMFS) {
|
||||||
const size_t romfs_offset =
|
const size_t romfs_offset =
|
||||||
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER;
|
header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER;
|
||||||
const size_t romfs_size =
|
const size_t romfs_size =
|
||||||
header.section_tables[i].media_end_offset * MEDIA_OFFSET_MULTIPLIER - romfs_offset;
|
header.section_tables[i].media_end_offset * MEDIA_OFFSET_MULTIPLIER - romfs_offset;
|
||||||
entries.emplace_back(std::make_shared<RomFs>(
|
files.emplace_back(std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset));
|
||||||
std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset)));
|
romfs = files.back();
|
||||||
romfs = entries.back();
|
} else if (block.filesystem_type == NCASectionFilesystemType::PFS0) {
|
||||||
} else if (block.filesystem_type == NcaSectionFilesystemType::PFS0) {
|
PFS0Superblock sb{};
|
||||||
Pfs0Superblock sb{};
|
|
||||||
// Seek back to beginning of this section.
|
// Seek back to beginning of this section.
|
||||||
if (sizeof(Pfs0Superblock) !=
|
if (sizeof(PFS0Superblock) !=
|
||||||
file->ReadObject(&sb, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
|
file->ReadObject(&sb, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
|
||||||
NGLOG_CRITICAL(Loader, "File reader errored out during header read.");
|
NGLOG_CRITICAL(Loader, "File reader errored out during header read.");
|
||||||
|
|
||||||
@@ -77,50 +76,63 @@ Loader::ResultStatus Nca::Load(v_file file_) {
|
|||||||
sb.pfs0_header_offset;
|
sb.pfs0_header_offset;
|
||||||
u64 size = MEDIA_OFFSET_MULTIPLIER * (header.section_tables[i].media_end_offset -
|
u64 size = MEDIA_OFFSET_MULTIPLIER * (header.section_tables[i].media_end_offset -
|
||||||
header.section_tables[i].media_offset);
|
header.section_tables[i].media_offset);
|
||||||
FileSys::PartitionFilesystem npfs{};
|
auto npfs = std::make_shared<PartitionFilesystem>(
|
||||||
Loader::ResultStatus status =
|
std::make_shared<OffsetVfsFile>(file, size, offset));
|
||||||
npfs.Load(std::make_shared<OffsetVfsFile>(file, size, offset));
|
|
||||||
|
|
||||||
if (status == Loader::ResultStatus::Success) {
|
if (npfs->GetStatus() == Loader::ResultStatus::Success) {
|
||||||
entries.emplace_back(npfs);
|
dirs.emplace_back(npfs);
|
||||||
if (IsDirectoryExeFs(entries.back()))
|
if (IsDirectoryExeFS(dirs.back()))
|
||||||
exefs = entries.back();
|
exefs = dirs.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Loader::ResultStatus::Success;
|
status = Loader::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> Nca::GetFiles() const {
|
Loader::ResultStatus NCA::GetStatus() const {
|
||||||
return {};
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> Nca::GetSubdirectories() const {
|
std::vector<std::shared_ptr<VfsFile>> NCA::GetFiles() const {
|
||||||
return entries;
|
if (status != Loader::ResultStatus::Success)
|
||||||
|
return {};
|
||||||
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Nca::GetName() const {
|
std::vector<std::shared_ptr<VfsDirectory>> NCA::GetSubdirectories() const {
|
||||||
|
if (status != Loader::ResultStatus::Success)
|
||||||
|
return {};
|
||||||
|
return dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NCA::GetName() const {
|
||||||
return file->GetName();
|
return file->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VfsDirectory> Nca::GetParentDirectory() const {
|
std::shared_ptr<VfsDirectory> NCA::GetParentDirectory() const {
|
||||||
return file->GetContainingDirectory();
|
return file->GetContainingDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaContentType Nca::GetType() const {
|
NCAContentType NCA::GetType() const {
|
||||||
return header.content_type;
|
return header.content_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Nca::GetTitleId() const {
|
u64 NCA::GetTitleId() const {
|
||||||
|
if (status != Loader::ResultStatus::Success)
|
||||||
|
return {};
|
||||||
return header.title_id;
|
return header.title_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
v_dir Nca::GetRomFs() const {
|
v_file NCA::GetRomFS() const {
|
||||||
return romfs;
|
return romfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
v_dir Nca::GetExeFs() const {
|
v_dir NCA::GetExeFS() const {
|
||||||
return exefs;
|
return exefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NCA::ReplaceFileWithSubdirectory(v_file file, v_dir dir) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|||||||
@@ -11,21 +11,21 @@
|
|||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
enum class NcaContentType : u8 { Program = 0, Meta = 1, Control = 2, Manual = 3, Data = 4 };
|
enum class NCAContentType : u8 { Program = 0, Meta = 1, Control = 2, Manual = 3, Data = 4 };
|
||||||
|
|
||||||
struct NcaSectionTableEntry {
|
struct NCASectionTableEntry {
|
||||||
u32_le media_offset;
|
u32_le media_offset;
|
||||||
u32_le media_end_offset;
|
u32_le media_end_offset;
|
||||||
INSERT_PADDING_BYTES(0x8);
|
INSERT_PADDING_BYTES(0x8);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NcaSectionTableEntry) == 0x10, "NcaSectionTableEntry has incorrect size.");
|
static_assert(sizeof(NCASectionTableEntry) == 0x10, "NCASectionTableEntry has incorrect size.");
|
||||||
|
|
||||||
struct NcaHeader {
|
struct NCAHeader {
|
||||||
std::array<u8, 0x100> rsa_signature_1;
|
std::array<u8, 0x100> rsa_signature_1;
|
||||||
std::array<u8, 0x100> rsa_signature_2;
|
std::array<u8, 0x100> rsa_signature_2;
|
||||||
u32_le magic;
|
u32_le magic;
|
||||||
u8 is_system;
|
u8 is_system;
|
||||||
NcaContentType content_type;
|
NCAContentType content_type;
|
||||||
u8 crypto_type;
|
u8 crypto_type;
|
||||||
u8 key_index;
|
u8 key_index;
|
||||||
u64_le size;
|
u64_le size;
|
||||||
@@ -35,46 +35,52 @@ struct NcaHeader {
|
|||||||
u8 crypto_type_2;
|
u8 crypto_type_2;
|
||||||
INSERT_PADDING_BYTES(15);
|
INSERT_PADDING_BYTES(15);
|
||||||
std::array<u8, 0x10> rights_id;
|
std::array<u8, 0x10> rights_id;
|
||||||
std::array<NcaSectionTableEntry, 0x4> section_tables;
|
std::array<NCASectionTableEntry, 0x4> section_tables;
|
||||||
std::array<std::array<u8, 0x20>, 0x4> hash_tables;
|
std::array<std::array<u8, 0x20>, 0x4> hash_tables;
|
||||||
std::array<std::array<u8, 0x10>, 0x4> key_area;
|
std::array<std::array<u8, 0x10>, 0x4> key_area;
|
||||||
INSERT_PADDING_BYTES(0xC0);
|
INSERT_PADDING_BYTES(0xC0);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NcaHeader) == 0x400, "NcaHeader has incorrect size.");
|
static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size.");
|
||||||
|
|
||||||
static bool IsDirectoryExeFs(std::shared_ptr<FileSys::VfsDirectory> pfs) {
|
static bool IsDirectoryExeFS(std::shared_ptr<FileSys::VfsDirectory> pfs) {
|
||||||
// According to switchbrew, an exefs must only contain these two files:
|
// According to switchbrew, an exefs must only contain these two files:
|
||||||
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.ndpm") != nullptr;
|
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.ndpm") != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsValidNca(const NcaHeader& header) {
|
static bool IsValidNCA(const NCAHeader& header) {
|
||||||
return header.magic == Common::MakeMagic('N', 'C', 'A', '2') ||
|
return header.magic == Common::MakeMagic('N', 'C', 'A', '2') ||
|
||||||
header.magic == Common::MakeMagic('N', 'C', 'A', '3');
|
header.magic == Common::MakeMagic('N', 'C', 'A', '3');
|
||||||
}
|
}
|
||||||
|
|
||||||
class Nca : public ReadOnlyVfsDirectory {
|
class NCA : public ReadOnlyVfsDirectory {
|
||||||
std::vector<v_dir> entries;
|
std::vector<v_dir> dirs{};
|
||||||
std::vector<u64> entry_offset;
|
std::vector<v_file> files{};
|
||||||
|
|
||||||
v_dir romfs = nullptr;
|
v_file romfs = nullptr;
|
||||||
v_dir exefs = nullptr;
|
v_dir exefs = nullptr;
|
||||||
v_file file;
|
v_file file;
|
||||||
|
|
||||||
NcaHeader header{};
|
NCAHeader header{};
|
||||||
|
|
||||||
|
Loader::ResultStatus status{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Loader::ResultStatus Load(v_file file);
|
explicit NCA(v_file file);
|
||||||
|
Loader::ResultStatus GetStatus() const;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
|
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
|
||||||
|
|
||||||
NcaContentType GetType() const;
|
NCAContentType GetType() const;
|
||||||
u64 GetTitleId() const;
|
u64 GetTitleId() const;
|
||||||
|
|
||||||
v_dir GetRomFs() const;
|
v_file GetRomFS() const;
|
||||||
v_dir GetExeFs() const;
|
v_dir GetExeFS() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ReplaceFileWithSubdirectory(v_file file, v_dir dir) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|||||||
@@ -66,44 +66,4 @@ private:
|
|||||||
std::u16string u16str;
|
std::u16string u16str;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parameters of the archive, as specified in the Create or Format call.
|
|
||||||
struct ArchiveFormatInfo {
|
|
||||||
u32_le total_size; ///< The pre-defined size of the archive.
|
|
||||||
u32_le number_directories; ///< The pre-defined number of directories in the archive.
|
|
||||||
u32_le number_files; ///< The pre-defined number of files in the archive.
|
|
||||||
u8 duplicate_data; ///< Whether the archive should duplicate the data.
|
|
||||||
};
|
|
||||||
static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
|
|
||||||
|
|
||||||
class FileSystemFactory : NonCopyable {
|
|
||||||
public:
|
|
||||||
virtual ~FileSystemFactory() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
|
|
||||||
*/
|
|
||||||
virtual std::string GetName() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to open the archive of this type with the specified path
|
|
||||||
* @param path Path to the archive
|
|
||||||
* @return An ArchiveBackend corresponding operating specified archive path.
|
|
||||||
*/
|
|
||||||
virtual ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the archive contents and then re-creates the base folder
|
|
||||||
* @param path Path to the archive
|
|
||||||
* @return ResultCode of the operation, 0 on success
|
|
||||||
*/
|
|
||||||
virtual ResultCode Format(const Path& path) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the format info about the archive with the specified path
|
|
||||||
* @param path Path to the archive
|
|
||||||
* @return Format information about the archive or error code
|
|
||||||
*/
|
|
||||||
virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|||||||
@@ -11,20 +11,25 @@
|
|||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
Loader::ResultStatus PartitionFilesystem::Load(std::shared_ptr<VfsFile> file) {
|
PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
|
||||||
// At least be as large as the header
|
// At least be as large as the header
|
||||||
if (file->GetSize() < sizeof(Header))
|
if (file->GetSize() < sizeof(Header)) {
|
||||||
return Loader::ResultStatus::Error;
|
status = Loader::ResultStatus::Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// For cartridges, HFSs can get very large, so we need to calculate the size up to
|
// 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.
|
// the actual content itself instead of just blindly reading in the entire file.
|
||||||
Header pfs_header;
|
Header pfs_header;
|
||||||
if (!file->ReadObject(&pfs_header))
|
if (!file->ReadObject(&pfs_header)) {
|
||||||
return Loader::ResultStatus::Error;
|
status = Loader::ResultStatus::Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
|
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
|
||||||
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
|
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
|
||||||
return Loader::ResultStatus::ErrorInvalidFormat;
|
status = Loader::ResultStatus::ErrorInvalidFormat;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
|
bool is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
|
||||||
@@ -36,17 +41,22 @@ Loader::ResultStatus PartitionFilesystem::Load(std::shared_ptr<VfsFile> file) {
|
|||||||
// Actually read in now...
|
// Actually read in now...
|
||||||
std::vector<u8> file_data = file->ReadBytes(metadata_size);
|
std::vector<u8> file_data = file->ReadBytes(metadata_size);
|
||||||
|
|
||||||
if (file_data.size() != metadata_size)
|
if (file_data.size() != metadata_size) {
|
||||||
return Loader::ResultStatus::Error;
|
status = Loader::ResultStatus::Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t total_size = file_data.size();
|
size_t total_size = file_data.size();
|
||||||
if (total_size < sizeof(Header))
|
if (total_size < sizeof(Header)) {
|
||||||
return Loader::ResultStatus::Error;
|
status = Loader::ResultStatus::Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&pfs_header, &file_data, sizeof(Header));
|
memcpy(&pfs_header, &file_data, sizeof(Header));
|
||||||
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
|
if (pfs_header.magic != Common::MakeMagic('H', 'F', 'S', '0') &&
|
||||||
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
|
pfs_header.magic != Common::MakeMagic('P', 'F', 'S', '0')) {
|
||||||
return Loader::ResultStatus::ErrorInvalidFormat;
|
status = Loader::ResultStatus::ErrorInvalidFormat;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
|
is_hfs = pfs_header.magic == Common::MakeMagic('H', 'F', 'S', '0');
|
||||||
@@ -65,7 +75,11 @@ Loader::ResultStatus PartitionFilesystem::Load(std::shared_ptr<VfsFile> file) {
|
|||||||
std::make_shared<OffsetVfsFile>(file, entry.size, content_offset + entry.offset, name));
|
std::make_shared<OffsetVfsFile>(file, entry.size, content_offset + entry.offset, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Loader::ResultStatus::Success;
|
status = Loader::ResultStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader::ResultStatus PartitionFilesystem::GetStatus() const {
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const {
|
std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const {
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ namespace FileSys {
|
|||||||
*/
|
*/
|
||||||
class PartitionFilesystem : public ReadOnlyVfsDirectory {
|
class PartitionFilesystem : public ReadOnlyVfsDirectory {
|
||||||
public:
|
public:
|
||||||
Loader::ResultStatus Load(std::shared_ptr<VfsFile> file);
|
explicit PartitionFilesystem(std::shared_ptr<VfsFile> file);
|
||||||
|
Loader::ResultStatus GetStatus() const;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||||
@@ -72,6 +73,8 @@ private:
|
|||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
Loader::ResultStatus status;
|
||||||
|
|
||||||
Header pfs_header;
|
Header pfs_header;
|
||||||
bool is_hfs;
|
bool is_hfs;
|
||||||
size_t content_offset;
|
size_t content_offset;
|
||||||
|
|||||||
@@ -14,13 +14,19 @@ Loader::ResultStatus ProgramMetadata::Load(v_file file) {
|
|||||||
if (total_size < sizeof(Header))
|
if (total_size < sizeof(Header))
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
|
||||||
if (sizeof(Header) != file->ReadObject(&npdm_header))
|
// TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
|
||||||
|
std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
|
||||||
|
if (sizeof(Header) != npdm_header_data.size())
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
|
||||||
|
|
||||||
|
std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
|
||||||
|
if (sizeof(AcidHeader) != acid_header_data.size())
|
||||||
|
return Loader::ResultStatus::Error;
|
||||||
|
std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
|
||||||
|
|
||||||
if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
|
if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset))
|
|
||||||
return Loader::ResultStatus::Error;
|
|
||||||
|
|
||||||
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
|
if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public:
|
|||||||
void Print() const;
|
void Print() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// TODO(DarkLordZach): BitField is not trivially copyable.
|
||||||
struct Header {
|
struct Header {
|
||||||
std::array<char, 4> magic;
|
std::array<char, 4> magic;
|
||||||
std::array<u8, 8> reserved;
|
std::array<u8, 8> reserved;
|
||||||
@@ -77,6 +78,7 @@ private:
|
|||||||
|
|
||||||
static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
|
static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
|
||||||
|
|
||||||
|
// TODO(DarkLordZach): BitField is not trivially copyable.
|
||||||
struct AcidHeader {
|
struct AcidHeader {
|
||||||
std::array<u8, 0x100> signature;
|
std::array<u8, 0x100> signature;
|
||||||
std::array<u8, 0x100> nca_modulus;
|
std::array<u8, 0x100> nca_modulus;
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
// Copyright 2018 yuzu emulator team
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "core/file_sys/romfs_filesystem.h"
|
|
||||||
|
|
||||||
namespace FileSys {
|
|
||||||
|
|
||||||
std::string RomFS_FileSystem::GetName() const {
|
|
||||||
return "RomFS";
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const std::string& path,
|
|
||||||
Mode mode) const {
|
|
||||||
return MakeResult<std::unique_ptr<StorageBackend>>(
|
|
||||||
std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size));
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::DeleteFile(const std::string& path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive ({}).", GetName());
|
|
||||||
// TODO(bunnei): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::RenameFile(const std::string& src_path,
|
|
||||||
const std::string& dest_path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", GetName());
|
|
||||||
// TODO(wwylele): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).",
|
|
||||||
GetName());
|
|
||||||
// TODO(wwylele): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive ({}).",
|
|
||||||
GetName());
|
|
||||||
// TODO(wwylele): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive ({}).", GetName());
|
|
||||||
// TODO(bunnei): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::CreateDirectory(const std::string& path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive ({}).",
|
|
||||||
GetName());
|
|
||||||
// TODO(wwylele): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive ({}).", GetName());
|
|
||||||
// TODO(wwylele): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> RomFS_FileSystem::OpenDirectory(
|
|
||||||
const std::string& path) const {
|
|
||||||
LOG_WARNING(Service_FS, "Opening Directory in a ROMFS archive");
|
|
||||||
return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<ROMFSDirectory>());
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 RomFS_FileSystem::GetFreeSpaceSize() const {
|
|
||||||
LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<FileSys::EntryType> RomFS_FileSystem::GetEntryType(const std::string& path) const {
|
|
||||||
LOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path {}).", path);
|
|
||||||
// TODO(wwylele): Use correct error code
|
|
||||||
return ResultCode(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
|
|
||||||
LOG_TRACE(Service_FS, "called offset={}, length={}", offset, length);
|
|
||||||
romfs_file->Seek(data_offset + offset, SEEK_SET);
|
|
||||||
size_t read_length = (size_t)std::min((u64)length, data_size - offset);
|
|
||||||
|
|
||||||
return MakeResult<size_t>(romfs_file->ReadBytes(buffer, read_length));
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<size_t> RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush,
|
|
||||||
const u8* buffer) const {
|
|
||||||
LOG_ERROR(Service_FS, "Attempted to write to ROMFS file");
|
|
||||||
// TODO(Subv): Find error code
|
|
||||||
return MakeResult<size_t>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 RomFS_Storage::GetSize() const {
|
|
||||||
return data_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RomFS_Storage::SetSize(const u64 size) const {
|
|
||||||
LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace FileSys
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
// Copyright 2018 yuzu emulator team
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/file_util.h"
|
|
||||||
#include "core/file_sys/directory.h"
|
|
||||||
#include "core/file_sys/filesystem.h"
|
|
||||||
#include "core/file_sys/storage.h"
|
|
||||||
#include "core/hle/result.h"
|
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
|
||||||
|
|
||||||
namespace FileSys {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which implements an interface to deal with Switch .istorage ROMFS images used in some
|
|
||||||
* archives This should be subclassed by concrete archive types, which will provide the input data
|
|
||||||
* (load the raw ROMFS archive) and override any required methods
|
|
||||||
*/
|
|
||||||
class RomFS_FileSystem : public FileSystemBackend {
|
|
||||||
public:
|
|
||||||
RomFS_FileSystem(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
|
|
||||||
: romfs_file(file), data_offset(offset), data_size(size) {}
|
|
||||||
|
|
||||||
std::string GetName() const override;
|
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path,
|
|
||||||
Mode mode) const override;
|
|
||||||
ResultCode DeleteFile(const std::string& path) const override;
|
|
||||||
ResultCode RenameFile(const std::string& src_path, const std::string& dest_path) const override;
|
|
||||||
ResultCode DeleteDirectory(const Path& path) const override;
|
|
||||||
ResultCode DeleteDirectoryRecursively(const Path& path) const override;
|
|
||||||
ResultCode CreateFile(const std::string& path, u64 size) const override;
|
|
||||||
ResultCode CreateDirectory(const std::string& path) const override;
|
|
||||||
ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
|
|
||||||
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(
|
|
||||||
const std::string& path) const override;
|
|
||||||
u64 GetFreeSpaceSize() const override;
|
|
||||||
ResultVal<EntryType> GetEntryType(const std::string& path) const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
|
||||||
u64 data_offset;
|
|
||||||
u64 data_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RomFS_Storage : public StorageBackend {
|
|
||||||
public:
|
|
||||||
RomFS_Storage(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
|
|
||||||
: romfs_file(file), data_offset(offset), data_size(size) {}
|
|
||||||
|
|
||||||
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;
|
|
||||||
u64 GetSize() const override;
|
|
||||||
bool SetSize(u64 size) const override;
|
|
||||||
bool Close() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void Flush() const override {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
|
||||||
u64 data_offset;
|
|
||||||
u64 data_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ROMFSDirectory : public DirectoryBackend {
|
|
||||||
public:
|
|
||||||
u64 Read(const u64 count, Entry* entries) override {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u64 GetEntryCount() const override {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bool Close() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace FileSys
|
|
||||||
@@ -125,4 +125,16 @@ bool RealVfsDirectory::Rename(const std::string& name) {
|
|||||||
return FileUtil::Rename(path.string(), (path / name).string());
|
return FileUtil::Rename(path.string(), (path / name).string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RealVfsDirectory::ReplaceFileWithSubdirectory(v_file file, v_dir dir) {
|
||||||
|
auto iter = std::find(files.begin(), files.end(), file);
|
||||||
|
if (iter == files.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
files[iter - files.begin()] = files.back();
|
||||||
|
files.pop_back();
|
||||||
|
|
||||||
|
subdirectories.emplace_back(dir);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ struct RealVfsDirectory : public VfsDirectory {
|
|||||||
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||||
bool IsWritable() const override;
|
bool IsWritable() const override;
|
||||||
bool IsReadable() const override;
|
bool IsReadable() const override;
|
||||||
bool IsRoot() const override;
|
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
|
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
|
||||||
std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override;
|
std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override;
|
||||||
@@ -45,6 +44,9 @@ struct RealVfsDirectory : public VfsDirectory {
|
|||||||
bool DeleteFile(const std::string& name) override;
|
bool DeleteFile(const std::string& name) override;
|
||||||
bool Rename(const std::string& name) override;
|
bool Rename(const std::string& name) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ReplaceFileWithSubdirectory(v_file file, v_dir dir) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
filesystem::path path;
|
filesystem::path path;
|
||||||
filesystem::perms perms;
|
filesystem::perms perms;
|
||||||
|
|||||||
@@ -5,21 +5,26 @@
|
|||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "core/file_sys/filesystem.h"
|
#include "core/file_sys/filesystem.h"
|
||||||
#include "core/file_sys/savedata_factory.h"
|
#include "core/file_sys/vfs.h"
|
||||||
#include "core/file_sys/sdmc_factory.h"
|
#include "core/file_sys/vfs_real.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
namespace Service::FileSystem {
|
||||||
|
|
||||||
|
ResultVal<v_file> OpenRomFS() {
|
||||||
|
return romfs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of registered file systems, identified by type. Once an file system is registered here, it
|
* Map of registered file systems, identified by type. Once an file system is registered here, it
|
||||||
* is never removed until UnregisterFileSystems is called.
|
* is never removed until UnregisterFileSystems is called.
|
||||||
*/
|
*/
|
||||||
static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map;
|
static boost::container::flat_map<Type, v_dir> filesystem_map;
|
||||||
|
static v_file filesystem_romfs;
|
||||||
|
|
||||||
ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) {
|
ResultCode RegisterFileSystem(v_dir factory, Type type) {
|
||||||
auto result = filesystem_map.emplace(type, std::move(factory));
|
auto result = filesystem_map.emplace(type, factory);
|
||||||
|
|
||||||
bool inserted = result.second;
|
bool inserted = result.second;
|
||||||
ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
|
ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
|
||||||
@@ -30,9 +35,18 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
|
ResultCode RegisterRomFS(v_file filesystem) {
|
||||||
FileSys::Path& path) {
|
bool inserted = filesystem_romfs == nullptr;
|
||||||
LOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type));
|
ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
|
||||||
|
|
||||||
|
filesystem_romfs = filesystem;
|
||||||
|
NGLOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}",
|
||||||
|
filesystem->GetName(), static_cast<u32>(Type::RomFS));
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultVal<v_dir> OpenFileSystem(Type type) {
|
||||||
|
NGLOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type));
|
||||||
|
|
||||||
auto itr = filesystem_map.find(type);
|
auto itr = filesystem_map.find(type);
|
||||||
if (itr == filesystem_map.end()) {
|
if (itr == filesystem_map.end()) {
|
||||||
@@ -40,7 +54,7 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
|
|||||||
return ResultCode(-1);
|
return ResultCode(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return itr->second->Open(path);
|
return MakeResult(itr->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode FormatFileSystem(Type type) {
|
ResultCode FormatFileSystem(Type type) {
|
||||||
@@ -52,8 +66,9 @@ ResultCode FormatFileSystem(Type type) {
|
|||||||
return ResultCode(-1);
|
return ResultCode(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSys::Path unused;
|
return itr->second->GetParentDirectory()->DeleteSubdirectory(itr->second->GetName())
|
||||||
return itr->second->Format(unused);
|
? RESULT_SUCCESS
|
||||||
|
: ResultCode(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterFileSystems() {
|
void RegisterFileSystems() {
|
||||||
@@ -62,10 +77,11 @@ void RegisterFileSystems() {
|
|||||||
std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
|
std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
|
||||||
std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
|
std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
|
||||||
|
|
||||||
auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory));
|
auto savedata =
|
||||||
|
std::make_unique<FileSys::RealVfsDirectory>(nand_directory, filesystem::perms::all);
|
||||||
RegisterFileSystem(std::move(savedata), Type::SaveData);
|
RegisterFileSystem(std::move(savedata), Type::SaveData);
|
||||||
|
|
||||||
auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory));
|
auto sdcard = std::make_unique<FileSys::RealVfsDirectory>(sd_directory, filesystem::perms::all);
|
||||||
RegisterFileSystem(std::move(sdcard), Type::SDMC);
|
RegisterFileSystem(std::move(sdcard), Type::SDMC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/file_sys/vfs.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
@@ -29,12 +30,109 @@ enum class Type {
|
|||||||
SDMC = 3,
|
SDMC = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VfsDirectoryServiceWrapper {
|
||||||
|
v_dir backing;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VfsDirectoryServiceWrapper(v_dir backing);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
|
||||||
|
*/
|
||||||
|
std::string GetName() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a file specified by its path
|
||||||
|
* @param path Path relative to the Archive
|
||||||
|
* @param size The size of the new file, filled with zeroes
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode CreateFile(const std::string& path, u64 size) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a file specified by its path
|
||||||
|
* @param path Path relative to the archive
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode DeleteFile(const std::string& path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a directory specified by its path
|
||||||
|
* @param path Path relative to the archive
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode CreateDirectory(const std::string& path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a directory specified by its path
|
||||||
|
* @param path Path relative to the archive
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode DeleteDirectory(const std::string& path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a directory specified by its path and anything under it
|
||||||
|
* @param path Path relative to the archive
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode DeleteDirectoryRecursively(const std::string& path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a File specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode RenameFile(const std::string& src_path, const std::string& dest_path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a Directory specified by its path
|
||||||
|
* @param src_path Source path relative to the archive
|
||||||
|
* @param dest_path Destination path relative to the archive
|
||||||
|
* @return Result of the operation
|
||||||
|
*/
|
||||||
|
ResultCode RenameDirectory(const std::string& src_path, const std::string& dest_path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a file specified by its path, using the specified mode
|
||||||
|
* @param path Path relative to the archive
|
||||||
|
* @param mode Mode to open the file with
|
||||||
|
* @return Opened file, or error code
|
||||||
|
*/
|
||||||
|
ResultVal<v_file> OpenFile(const std::string& path, FileSys::Mode mode) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a directory specified by its path
|
||||||
|
* @param path Path relative to the archive
|
||||||
|
* @return Opened directory, or error code
|
||||||
|
*/
|
||||||
|
ResultVal<v_dir> OpenDirectory(const std::string& path) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the free space
|
||||||
|
* @return The number of free bytes in the archive
|
||||||
|
*/
|
||||||
|
u64 GetFreeSpaceSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of the specified path
|
||||||
|
* @return The type of the specified path or error code
|
||||||
|
*/
|
||||||
|
ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VfsFileServiceWrapper {
|
||||||
|
v_file backing;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a FileSystem, instances of which can later be opened using its IdCode.
|
* Registers a FileSystem, instances of which can later be opened using its IdCode.
|
||||||
* @param factory FileSystem backend interface to use
|
* @param factory FileSystem backend interface to use
|
||||||
* @param type Type used to access this type of FileSystem
|
* @param type Type used to access this type of FileSystem
|
||||||
*/
|
*/
|
||||||
ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type);
|
ResultCode RegisterFileSystem(v_dir fs, Type type);
|
||||||
|
|
||||||
|
ResultCode RegisterRomFS(v_file fs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a file system
|
* Opens a file system
|
||||||
@@ -42,8 +140,9 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact
|
|||||||
* @param path Path to the file system, used with Binary paths
|
* @param path Path to the file system, used with Binary paths
|
||||||
* @return FileSys::FileSystemBackend interface to the file system
|
* @return FileSys::FileSystemBackend interface to the file system
|
||||||
*/
|
*/
|
||||||
ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
|
ResultVal<v_dir> OpenFileSystem(Type type);
|
||||||
FileSys::Path& path);
|
|
||||||
|
ResultVal<v_file> OpenRomFS();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a file system
|
* Formats a file system
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ namespace Service::FileSystem {
|
|||||||
|
|
||||||
class IStorage final : public ServiceFramework<IStorage> {
|
class IStorage final : public ServiceFramework<IStorage> {
|
||||||
public:
|
public:
|
||||||
IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend)
|
IStorage(v_file backend_) : ServiceFramework("IStorage"), backend(backend_) {
|
||||||
: ServiceFramework("IStorage"), backend(std::move(backend)) {
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
|
{0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
|
||||||
{3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"},
|
{3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"},
|
||||||
@@ -29,7 +28,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<FileSys::StorageBackend> backend;
|
v_file backend;
|
||||||
|
|
||||||
void Read(Kernel::HLERequestContext& ctx) {
|
void Read(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
@@ -51,8 +50,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the data from the Storage backend
|
// Read the data from the Storage backend
|
||||||
std::vector<u8> output(length);
|
std::vector<u8> output = backend->ReadBytes(length, offset);
|
||||||
ResultVal<size_t> res = backend->Read(offset, length, output.data());
|
auto res = MakeResult<size_t>(output.size());
|
||||||
if (res.Failed()) {
|
if (res.Failed()) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(res.Code());
|
rb.Push(res.Code());
|
||||||
@@ -69,8 +68,7 @@ private:
|
|||||||
|
|
||||||
class IFile final : public ServiceFramework<IFile> {
|
class IFile final : public ServiceFramework<IFile> {
|
||||||
public:
|
public:
|
||||||
explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend)
|
explicit IFile(v_file backend_) : ServiceFramework("IFile"), backend(backend_) {
|
||||||
: ServiceFramework("IFile"), backend(std::move(backend)) {
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
|
{0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
|
||||||
{2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
|
{2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
|
||||||
@@ -80,7 +78,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<FileSys::StorageBackend> backend;
|
v_file backend;
|
||||||
|
|
||||||
void Read(Kernel::HLERequestContext& ctx) {
|
void Read(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
@@ -103,8 +101,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the data from the Storage backend
|
// Read the data from the Storage backend
|
||||||
std::vector<u8> output(length);
|
std::vector<u8> output = backend->ReadBytes(length, offset);
|
||||||
ResultVal<size_t> res = backend->Read(offset, length, output.data());
|
auto res = MakeResult<size_t>(output.size());
|
||||||
if (res.Failed()) {
|
if (res.Failed()) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(res.Code());
|
rb.Push(res.Code());
|
||||||
@@ -140,8 +138,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the data to the Storage backend
|
// Write the data to the Storage backend
|
||||||
std::vector<u8> data = ctx.ReadBuffer();
|
auto res = MakeResult<size_t>(backend->WriteBytes(ctx.ReadBuffer(), length, offset));
|
||||||
ResultVal<size_t> res = backend->Write(offset, length, true, data.data());
|
|
||||||
if (res.Failed()) {
|
if (res.Failed()) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(res.Code());
|
rb.Push(res.Code());
|
||||||
@@ -153,8 +150,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Flush(Kernel::HLERequestContext& ctx) {
|
void Flush(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_FS, "called");
|
NGLOG_DEBUG(Service_FS, "called");
|
||||||
backend->Flush();
|
|
||||||
|
// Exists for SDK compatibiltity -- No need to flush file.
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
@@ -163,7 +161,7 @@ private:
|
|||||||
void SetSize(Kernel::HLERequestContext& ctx) {
|
void SetSize(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 size = rp.Pop<u64>();
|
const u64 size = rp.Pop<u64>();
|
||||||
backend->SetSize(size);
|
backend->Resize(size);
|
||||||
LOG_DEBUG(Service_FS, "called, size={}", size);
|
LOG_DEBUG(Service_FS, "called, size={}", size);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@@ -232,7 +230,7 @@ private:
|
|||||||
|
|
||||||
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
||||||
public:
|
public:
|
||||||
explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend)
|
explicit IFileSystem(v_dir backend)
|
||||||
: ServiceFramework("IFileSystem"), backend(std::move(backend)) {
|
: ServiceFramework("IFileSystem"), backend(std::move(backend)) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IFileSystem::CreateFile, "CreateFile"},
|
{0, &IFileSystem::CreateFile, "CreateFile"},
|
||||||
@@ -267,7 +265,12 @@ public:
|
|||||||
LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
|
LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(backend->CreateFile(name, size));
|
auto b1 = backend->CreateFile(name);
|
||||||
|
if (b1 == nullptr) {
|
||||||
|
}
|
||||||
|
auto b2 = b1->Res
|
||||||
|
|
||||||
|
rb.Push(? RESULT_SUCCESS : ResultCode(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteFile(Kernel::HLERequestContext& ctx) {
|
void DeleteFile(Kernel::HLERequestContext& ctx) {
|
||||||
@@ -291,7 +294,8 @@ public:
|
|||||||
LOG_DEBUG(Service_FS, "called directory {}", name);
|
LOG_DEBUG(Service_FS, "called directory {}", name);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(backend->CreateDirectory(name));
|
auto dir = backend->CreateSubdirectory(name);
|
||||||
|
rb.Push(dir == nullptr ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenameFile(Kernel::HLERequestContext& ctx) {
|
void RenameFile(Kernel::HLERequestContext& ctx) {
|
||||||
@@ -389,7 +393,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<FileSys::FileSystemBackend> backend;
|
v_dir backend;
|
||||||
};
|
};
|
||||||
|
|
||||||
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||||
@@ -490,10 +494,9 @@ void FSP_SRV::TryLoadRomFS() {
|
|||||||
if (romfs) {
|
if (romfs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FileSys::Path unused;
|
auto res = OpenRomFS();
|
||||||
auto res = OpenFileSystem(Type::RomFS, unused);
|
|
||||||
if (res.Succeeded()) {
|
if (res.Succeeded()) {
|
||||||
romfs = std::move(res.Unwrap());
|
romfs = res.Unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,8 +510,7 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
|
|||||||
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
|
void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_FS, "called");
|
LOG_DEBUG(Service_FS, "called");
|
||||||
|
|
||||||
FileSys::Path unused;
|
auto filesystem = OpenFileSystem(Type::SDMC).Unwrap();
|
||||||
auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap();
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
@@ -559,15 +561,6 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to open a StorageBackend interface to the RomFS
|
|
||||||
auto storage = romfs->OpenFile({}, {});
|
|
||||||
if (storage.Failed()) {
|
|
||||||
LOG_CRITICAL(Service_FS, "no storage interface available!");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(storage.Code());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
|
rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ private:
|
|||||||
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
|
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
|
||||||
void OpenRomStorage(Kernel::HLERequestContext& ctx);
|
void OpenRomStorage(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
std::unique_ptr<FileSys::FileSystemBackend> romfs;
|
v_file romfs;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::FileSystem
|
} // namespace Service::FileSystem
|
||||||
|
|||||||
@@ -4,12 +4,10 @@
|
|||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_paths.h"
|
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/romfs_factory.h"
|
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
@@ -51,7 +49,7 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(v_file
|
|||||||
: AppLoader(file) {}
|
: AppLoader(file) {}
|
||||||
|
|
||||||
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(v_file file) {
|
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(v_file file) {
|
||||||
if (FileSys::IsDirectoryExeFs(file->GetContainingDirectory())) {
|
if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) {
|
||||||
return FileType::DeconstructedRomDirectory;
|
return FileType::DeconstructedRomDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,26 +108,19 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// TODO(DarkLordZach): Identify RomFS if its a subdirectory.
|
// TODO(DarkLordZach): Identify RomFS if its a subdirectory.
|
||||||
romfs = std::make_shared<RomFs>((romfs_iter == dir->GetFiles().end()) ? nullptr : *romfs_iter);
|
romfs = (romfs_iter == dir->GetFiles().end()) ? nullptr : *romfs_iter;
|
||||||
|
|
||||||
// Register the RomFS if a ".romfs" file was found
|
|
||||||
if (romfs != nullptr) {
|
|
||||||
Service::FileSystem::RegisterFileSystem(std::make_unique<FileSys::RomFS_Factory>(*this),
|
|
||||||
Service::FileSystem::Type::RomFS);
|
|
||||||
}
|
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(v_dir& dir) {
|
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(v_file& file) {
|
||||||
|
if (romfs == nullptr) {
|
||||||
if (filepath_romfs.empty()) {
|
|
||||||
LOG_DEBUG(Loader, "No RomFS available");
|
LOG_DEBUG(Loader, "No RomFS available");
|
||||||
return ResultStatus::ErrorNotUsed;
|
return ResultStatus::ErrorNotUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = romfs;
|
file = romfs;
|
||||||
|
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ public:
|
|||||||
|
|
||||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||||
|
|
||||||
ResultStatus ReadRomFS(v_dir& dir) override;
|
ResultStatus ReadRomFS(v_file& file) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
v_dir romfs;
|
v_file romfs;
|
||||||
FileSys::ProgramMetadata metadata;
|
FileSys::ProgramMetadata metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ public:
|
|||||||
* @param file The file containing the RomFS
|
* @param file The file containing the RomFS
|
||||||
* @return ResultStatus result of function
|
* @return ResultStatus result of function
|
||||||
*/
|
*/
|
||||||
virtual ResultStatus ReadRomFS(v_dir& dir) {
|
virtual ResultStatus ReadRomFS(v_file& dir) {
|
||||||
return ResultStatus::ErrorNotImplemented;
|
return ResultStatus::ErrorNotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ public:
|
|||||||
* @param file The file containing the RomFS
|
* @param file The file containing the RomFS
|
||||||
* @return ResultStatus result of function
|
* @return ResultStatus result of function
|
||||||
*/
|
*/
|
||||||
virtual ResultStatus ReadUpdateRomFS(v_dir& file) {
|
virtual ResultStatus ReadUpdateRomFS(v_file& file) {
|
||||||
return ResultStatus::ErrorNotImplemented;
|
return ResultStatus::ErrorNotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,11 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/swap.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/program_metadata.h"
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/file_sys/romfs_factory.h"
|
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
@@ -21,15 +18,15 @@
|
|||||||
|
|
||||||
namespace Loader {
|
namespace Loader {
|
||||||
|
|
||||||
AppLoader_NCA::AppLoader_NCA(v_file file) : AppLoader(std::move(file)) {}
|
AppLoader_NCA::AppLoader_NCA(v_file file) : AppLoader(file) {}
|
||||||
|
|
||||||
FileType AppLoader_NCA::IdentifyType(v_file file) {
|
FileType AppLoader_NCA::IdentifyType(v_file file) {
|
||||||
// TODO(DarkLordZach): Assuming everything is decrypted. Add crypto support.
|
// TODO(DarkLordZach): Assuming everything is decrypted. Add crypto support.
|
||||||
FileSys::NcaHeader header{};
|
FileSys::NCAHeader header{};
|
||||||
if (sizeof(FileSys::NcaHeader) != file->ReadObject(&header))
|
if (sizeof(FileSys::NCAHeader) != file->ReadObject(&header))
|
||||||
return FileType::Error;
|
return FileType::Error;
|
||||||
|
|
||||||
if (IsValidNca(header) && header.content_type == FileSys::NcaContentType::Program)
|
if (IsValidNCA(header) && header.content_type == FileSys::NCAContentType::Program)
|
||||||
return FileType::NCA;
|
return FileType::NCA;
|
||||||
|
|
||||||
return FileType::Error;
|
return FileType::Error;
|
||||||
@@ -40,16 +37,16 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
|||||||
return ResultStatus::ErrorAlreadyLoaded;
|
return ResultStatus::ErrorAlreadyLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
nca = std::make_unique<FileSys::Nca>();
|
nca = std::make_unique<FileSys::NCA>(file);
|
||||||
ResultStatus result = nca->Load(file);
|
ResultStatus result = nca->GetStatus();
|
||||||
if (result != ResultStatus::Success) {
|
if (result != ResultStatus::Success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nca->GetType() != FileSys::NcaContentType::Program)
|
if (nca->GetType() != FileSys::NCAContentType::Program)
|
||||||
return ResultStatus::ErrorInvalidFormat;
|
return ResultStatus::ErrorInvalidFormat;
|
||||||
|
|
||||||
auto exefs = nca->GetExeFs();
|
auto exefs = nca->GetExeFS();
|
||||||
|
|
||||||
if (exefs == nullptr)
|
if (exefs == nullptr)
|
||||||
return ResultStatus::ErrorInvalidFormat;
|
return ResultStatus::ErrorInvalidFormat;
|
||||||
@@ -85,23 +82,19 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
|
|||||||
process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
|
process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
|
||||||
metadata.GetMainThreadStackSize());
|
metadata.GetMainThreadStackSize());
|
||||||
|
|
||||||
if (nca->GetRomFs() != nullptr)
|
|
||||||
Service::FileSystem::RegisterFileSystem(std::make_unique<FileSys::RomFS_Factory>(*this),
|
|
||||||
Service::FileSystem::Type::RomFS);
|
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NCA::ReadRomFS(v_dir& dir) {
|
ResultStatus AppLoader_NCA::ReadRomFS(v_file& file) {
|
||||||
const auto romfs = nca->GetRomFs();
|
const auto romfs = nca->GetRomFS();
|
||||||
|
|
||||||
if (romfs == nullptr) {
|
if (romfs == nullptr) {
|
||||||
NGLOG_DEBUG(Loader, "No RomFS available");
|
NGLOG_DEBUG(Loader, "No RomFS available");
|
||||||
return ResultStatus::ErrorNotUsed;
|
return ResultStatus::ErrorNotUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = romfs;
|
file = romfs;
|
||||||
|
|
||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/file_sys/partition_filesystem.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/program_metadata.h"
|
#include "core/file_sys/program_metadata.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
@@ -31,14 +31,14 @@ public:
|
|||||||
|
|
||||||
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
|
||||||
|
|
||||||
ResultStatus ReadRomFS(v_dir& dir) override;
|
ResultStatus ReadRomFS(v_file& file) override;
|
||||||
|
|
||||||
~AppLoader_NCA();
|
~AppLoader_NCA();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileSys::ProgramMetadata metadata;
|
FileSys::ProgramMetadata metadata;
|
||||||
|
|
||||||
std::unique_ptr<FileSys::Nca> nca;
|
std::unique_ptr<FileSys::NCA> nca;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ struct NsoHeader {
|
|||||||
std::array<u32_le, 3> segments_compressed_size;
|
std::array<u32_le, 3> segments_compressed_size;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
|
static_assert(sizeof(NsoHeader) == 0x6c, "NsoHeader has incorrect size.");
|
||||||
|
static_assert(std::is_trivially_copyable<NsoHeader>::value, "NsoHeader isn't trivially copyable.");
|
||||||
|
|
||||||
struct ModHeader {
|
struct ModHeader {
|
||||||
u32_le magic;
|
u32_le magic;
|
||||||
@@ -99,7 +100,7 @@ VAddr AppLoader_NSO::LoadModule(v_file file, VAddr load_base) {
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
NsoHeader nso_header{};
|
NsoHeader nso_header{};
|
||||||
if (sizeof(NsoHeader) != file->ReadObject(&file))
|
if (sizeof(NsoHeader) != file->ReadObject(&nso_header))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0'))
|
if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0'))
|
||||||
|
|||||||
Reference in New Issue
Block a user