summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/file_sys/archive_romfs.cpp43
-rw-r--r--src/core/file_sys/archive_selfncch.cpp257
-rw-r--r--src/core/file_sys/archive_selfncch.h (renamed from src/core/file_sys/archive_romfs.h)23
-rw-r--r--src/core/file_sys/errors.h10
-rw-r--r--src/core/hle/result.h4
-rw-r--r--src/core/hle/service/fs/archive.h2
-rw-r--r--src/core/loader/3dsx.cpp6
-rw-r--r--src/core/loader/ncch.cpp6
9 files changed, 295 insertions, 60 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index b178914dd..8c2438831 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -20,10 +20,10 @@ set(SRCS
file_sys/archive_extsavedata.cpp
file_sys/archive_ncch.cpp
file_sys/archive_other_savedata.cpp
- file_sys/archive_romfs.cpp
file_sys/archive_savedata.cpp
file_sys/archive_sdmc.cpp
file_sys/archive_sdmcwriteonly.cpp
+ file_sys/archive_selfncch.cpp
file_sys/archive_source_sd_savedata.cpp
file_sys/archive_systemsavedata.cpp
file_sys/disk_archive.cpp
@@ -197,10 +197,10 @@ set(HEADERS
file_sys/archive_extsavedata.h
file_sys/archive_ncch.h
file_sys/archive_other_savedata.h
- file_sys/archive_romfs.h
file_sys/archive_savedata.h
file_sys/archive_sdmc.h
file_sys/archive_sdmcwriteonly.h
+ file_sys/archive_selfncch.h
file_sys/archive_source_sd_savedata.h
file_sys/archive_systemsavedata.h
file_sys/directory_backend.h
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
deleted file mode 100644
index 6c99ca5b4..000000000
--- a/src/core/file_sys/archive_romfs.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include <memory>
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "core/file_sys/archive_romfs.h"
-#include "core/file_sys/ivfc_archive.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// FileSys namespace
-
-namespace FileSys {
-
-ArchiveFactory_RomFS::ArchiveFactory_RomFS(Loader::AppLoader& app_loader) {
- // Load the RomFS from the app
- if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
- LOG_ERROR(Service_FS, "Unable to read RomFS!");
- }
-}
-
-ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) {
- auto archive = std::make_unique<IVFCArchive>(romfs_file, data_offset, data_size);
- return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
-}
-
-ResultCode ArchiveFactory_RomFS::Format(const Path& path,
- const FileSys::ArchiveFormatInfo& format_info) {
- LOG_ERROR(Service_FS, "Attempted to format a RomFS archive.");
- // TODO: Verify error code
- return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported,
- ErrorLevel::Permanent);
-}
-
-ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const {
- // TODO(Subv): Implement
- LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
- return ResultCode(-1);
-}
-
-} // namespace FileSys
diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp
new file mode 100644
index 000000000..298a37a44
--- /dev/null
+++ b/src/core/file_sys/archive_selfncch.cpp
@@ -0,0 +1,257 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/swap.h"
+#include "core/file_sys/archive_selfncch.h"
+#include "core/file_sys/errors.h"
+#include "core/file_sys/ivfc_archive.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+enum class SelfNCCHFilePathType : u32 {
+ RomFS = 0,
+ Code = 1, // This is not supported by SelfNCCHArchive but by archive 0x2345678E
+ ExeFS = 2,
+ UpdateRomFS = 5, // This is presumably for accessing the RomFS of the update patch.
+};
+
+struct SelfNCCHFilePath {
+ u32_le type;
+ std::array<char, 8> exefs_filename;
+};
+static_assert(sizeof(SelfNCCHFilePath) == 12, "NCCHFilePath has wrong size!");
+
+// A read-only file created from a block of data. It only allows you to read the entire file at
+// once, in a single read operation.
+class ExeFSSectionFile final : public FileBackend {
+public:
+ explicit ExeFSSectionFile(std::shared_ptr<std::vector<u8>> data_) : data(std::move(data_)) {}
+
+ ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override {
+ if (offset != 0) {
+ LOG_ERROR(Service_FS, "offset must be zero!");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ if (length != data->size()) {
+ LOG_ERROR(Service_FS, "size must match the file size!");
+ return ERROR_INCORRECT_EXEFS_READ_SIZE;
+ }
+
+ std::memcpy(buffer, data->data(), data->size());
+ return MakeResult<size_t>(data->size());
+ }
+
+ ResultVal<size_t> Write(u64 offset, size_t length, bool flush,
+ const u8* buffer) const override {
+ LOG_ERROR(Service_FS, "The file is read-only!");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ u64 GetSize() const override {
+ return data->size();
+ }
+
+ bool SetSize(u64 size) const override {
+ return false;
+ }
+
+ bool Close() const override {
+ return true;
+ }
+
+ void Flush() const override {}
+
+private:
+ std::shared_ptr<std::vector<u8>> data;
+};
+
+// SelfNCCHArchive represents the running application itself. From this archive the application can
+// open RomFS and ExeFS, excluding the .code section.
+class SelfNCCHArchive final : public ArchiveBackend {
+public:
+ explicit SelfNCCHArchive(const NCCHData& ncch_data_) : ncch_data(ncch_data_) {}
+
+ std::string GetName() const override {
+ return "SelfNCCHArchive";
+ }
+
+ ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode&) const override {
+ // Note: SelfNCCHArchive doesn't check the open mode.
+
+ if (path.GetType() != LowPathType::Binary) {
+ LOG_ERROR(Service_FS, "Path need to be Binary");
+ return ERROR_INVALID_PATH;
+ }
+
+ std::vector<u8> binary = path.AsBinary();
+ if (binary.size() != sizeof(SelfNCCHFilePath)) {
+ LOG_ERROR(Service_FS, "Wrong path size %zu", binary.size());
+ return ERROR_INVALID_PATH;
+ }
+
+ SelfNCCHFilePath file_path;
+ std::memcpy(&file_path, binary.data(), sizeof(SelfNCCHFilePath));
+
+ switch (static_cast<SelfNCCHFilePathType>(file_path.type)) {
+ case SelfNCCHFilePathType::UpdateRomFS:
+ LOG_WARNING(Service_FS, "(STUBBED) open update RomFS");
+ return OpenRomFS();
+
+ case SelfNCCHFilePathType::RomFS:
+ return OpenRomFS();
+
+ case SelfNCCHFilePathType::Code:
+ LOG_ERROR(Service_FS, "Reading the code section is not supported!");
+ return ERROR_COMMAND_NOT_ALLOWED;
+
+ case SelfNCCHFilePathType::ExeFS: {
+ const auto& raw = file_path.exefs_filename;
+ auto end = std::find(raw.begin(), raw.end(), '\0');
+ std::string filename(raw.begin(), end);
+ return OpenExeFS(filename);
+ }
+ default:
+ LOG_ERROR(Service_FS, "Unknown file type %u!", static_cast<u32>(file_path.type));
+ return ERROR_INVALID_PATH;
+ }
+ }
+
+ ResultCode DeleteFile(const Path& path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultCode DeleteDirectory(const Path& path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultCode DeleteDirectoryRecursively(const Path& path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultCode CreateFile(const Path& path, u64 size) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultCode CreateDirectory(const Path& path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override {
+ LOG_ERROR(Service_FS, "Unsupported");
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ u64 GetFreeBytes() const override {
+ return 0;
+ }
+
+private:
+ ResultVal<std::unique_ptr<FileBackend>> OpenRomFS() const {
+ if (ncch_data.romfs_file) {
+ return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>(
+ ncch_data.romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size));
+ } else {
+ LOG_INFO(Service_FS, "Unable to read RomFS");
+ return ERROR_ROMFS_NOT_FOUND;
+ }
+ }
+
+ ResultVal<std::unique_ptr<FileBackend>> OpenExeFS(const std::string& filename) const {
+ if (filename == "icon") {
+ if (ncch_data.icon) {
+ return MakeResult<std::unique_ptr<FileBackend>>(
+ std::make_unique<ExeFSSectionFile>(ncch_data.icon));
+ }
+
+ LOG_WARNING(Service_FS, "Unable to read icon");
+ return ERROR_EXEFS_SECTION_NOT_FOUND;
+ }
+
+ if (filename == "logo") {
+ if (ncch_data.logo) {
+ return MakeResult<std::unique_ptr<FileBackend>>(
+ std::make_unique<ExeFSSectionFile>(ncch_data.logo));
+ }
+
+ LOG_WARNING(Service_FS, "Unable to read logo");
+ return ERROR_EXEFS_SECTION_NOT_FOUND;
+ }
+
+ if (filename == "banner") {
+ if (ncch_data.banner) {
+ return MakeResult<std::unique_ptr<FileBackend>>(
+ std::make_unique<ExeFSSectionFile>(ncch_data.banner));
+ }
+
+ LOG_WARNING(Service_FS, "Unable to read banner");
+ return ERROR_EXEFS_SECTION_NOT_FOUND;
+ }
+
+ LOG_ERROR(Service_FS, "Unknown ExeFS section %s!", filename.c_str());
+ return ERROR_INVALID_PATH;
+ }
+
+ NCCHData ncch_data;
+};
+
+ArchiveFactory_SelfNCCH::ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader) {
+ std::shared_ptr<FileUtil::IOFile> romfs_file_;
+ if (Loader::ResultStatus::Success ==
+ app_loader.ReadRomFS(romfs_file_, ncch_data.romfs_offset, ncch_data.romfs_size)) {
+
+ ncch_data.romfs_file = std::move(romfs_file_);
+ }
+
+ std::vector<u8> buffer;
+
+ if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer))
+ ncch_data.icon = std::make_shared<std::vector<u8>>(std::move(buffer));
+
+ buffer.clear();
+ if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer))
+ ncch_data.logo = std::make_shared<std::vector<u8>>(std::move(buffer));
+
+ buffer.clear();
+ if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer))
+ ncch_data.banner = std::make_shared<std::vector<u8>>(std::move(buffer));
+}
+
+ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) {
+ auto archive = std::make_unique<SelfNCCHArchive>(ncch_data);
+ return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
+}
+
+ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) {
+ LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive.");
+ return ERROR_INVALID_PATH;
+}
+
+ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&) const {
+ LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive");
+ return ERROR_INVALID_PATH;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_selfncch.h
index 1eaf99b54..f1b971296 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_selfncch.h
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -17,22 +17,29 @@
namespace FileSys {
-/// File system interface to the RomFS archive
-class ArchiveFactory_RomFS final : public ArchiveFactory {
+struct NCCHData {
+ std::shared_ptr<std::vector<u8>> icon;
+ std::shared_ptr<std::vector<u8>> logo;
+ std::shared_ptr<std::vector<u8>> banner;
+ std::shared_ptr<FileUtil::IOFile> romfs_file;
+ u64 romfs_offset = 0;
+ u64 romfs_size = 0;
+};
+
+/// File system interface to the SelfNCCH archive
+class ArchiveFactory_SelfNCCH final : public ArchiveFactory {
public:
- explicit ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
+ explicit ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader);
std::string GetName() const override {
- return "RomFS";
+ return "SelfNCCH";
}
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
private:
- std::shared_ptr<FileUtil::IOFile> romfs_file;
- u64 data_offset;
- u64 data_size;
+ NCCHData ncch_data;
};
} // namespace FileSys
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index 4d5f62b08..9fc8d753b 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -39,5 +39,15 @@ const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpt
const ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrorDescription::FS_GameCardNotInserted,
ErrorModule::FS, ErrorSummary::NotFound,
ErrorLevel::Status);
+const ResultCode ERROR_INCORRECT_EXEFS_READ_SIZE(ErrorDescription::FS_IncorrectExeFSReadSize,
+ ErrorModule::FS, ErrorSummary::NotSupported,
+ ErrorLevel::Usage);
+const ResultCode ERROR_ROMFS_NOT_FOUND(ErrorDescription::FS_RomFSNotFound, ErrorModule::FS,
+ ErrorSummary::NotFound, ErrorLevel::Status);
+const ResultCode ERROR_COMMAND_NOT_ALLOWED(ErrorDescription::FS_CommandNotAllowed, ErrorModule::FS,
+ ErrorSummary::WrongArgument, ErrorLevel::Permanent);
+const ResultCode ERROR_EXEFS_SECTION_NOT_FOUND(ErrorDescription::FS_ExeFSSectionNotFound,
+ ErrorModule::FS, ErrorSummary::NotFound,
+ ErrorLevel::Status);
} // namespace FileSys
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 53864a3a7..cfefbbc64 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -20,6 +20,7 @@ enum class ErrorDescription : u32 {
OS_InvalidBufferDescriptor = 48,
MaxConnectionsReached = 52,
WrongAddress = 53,
+ FS_RomFSNotFound = 100,
FS_ArchiveNotMounted = 101,
FS_FileNotFound = 112,
FS_PathNotFound = 113,
@@ -35,10 +36,13 @@ enum class ErrorDescription : u32 {
OutofRangeOrMisalignedAddress =
513, // TODO(purpasmart): Check if this name fits its actual usage
GPU_FirstInitialization = 519,
+ FS_ExeFSSectionNotFound = 567,
+ FS_CommandNotAllowed = 630,
FS_InvalidReadFlag = 700,
FS_InvalidPath = 702,
FS_WriteBeyondEnd = 705,
FS_UnsupportedOpenFlags = 760,
+ FS_IncorrectExeFSReadSize = 761,
FS_UnexpectedFileOrDirectory = 770,
InvalidSection = 1000,
TooLarge = 1001,
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 519c1f3a9..2ea956e0b 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -26,7 +26,7 @@ namespace FS {
/// Supported archive types
enum class ArchiveIdCode : u32 {
- RomFS = 0x00000003,
+ SelfNCCH = 0x00000003,
SaveData = 0x00000004,
ExtSaveData = 0x00000006,
SharedExtSaveData = 0x00000007,
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 09266e8b0..74e336487 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -5,7 +5,7 @@
#include <algorithm>
#include <vector>
#include "common/logging/log.h"
-#include "core/file_sys/archive_romfs.h"
+#include "core/file_sys/archive_selfncch.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/fs/archive.h"
@@ -277,8 +277,8 @@ ResultStatus AppLoader_THREEDSX::Load() {
Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
- Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this),
- Service::FS::ArchiveIdCode::RomFS);
+ Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this),
+ Service::FS::ArchiveIdCode::SelfNCCH);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 5df33f6d2..98b8259d9 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -8,7 +8,7 @@
#include "common/logging/log.h"
#include "common/string_util.h"
#include "common/swap.h"
-#include "core/file_sys/archive_romfs.h"
+#include "core/file_sys/archive_selfncch.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/cfg/cfg.h"
@@ -342,8 +342,8 @@ ResultStatus AppLoader_NCCH::Load() {
if (ResultStatus::Success != result)
return result;
- Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this),
- Service::FS::ArchiveIdCode::RomFS);
+ Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this),
+ Service::FS::ArchiveIdCode::SelfNCCH);
ParseRegionLockoutInfo();