From 589b6427909dfc7a4b5ee1a64cb86d38d459b0f3 Mon Sep 17 00:00:00 2001 From: wwylele Date: Tue, 29 Nov 2016 00:52:11 +0200 Subject: [PATCH] FileSys: Implement OtherSaveData --- src/core/CMakeLists.txt | 2 + src/core/file_sys/archive_other_savedata.cpp | 145 +++++++++++++++++++ src/core/file_sys/archive_other_savedata.h | 52 +++++++ src/core/file_sys/errors.h | 3 + src/core/hle/result.h | 1 + src/core/hle/service/fs/archive.cpp | 9 ++ src/core/hle/service/fs/archive.h | 2 + 7 files changed, 214 insertions(+) create mode 100644 src/core/file_sys/archive_other_savedata.cpp create mode 100644 src/core/file_sys/archive_other_savedata.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3f762ed52..8ce141e6a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -18,6 +18,7 @@ set(SRCS file_sys/archive_backend.cpp 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 @@ -164,6 +165,7 @@ set(HEADERS file_sys/archive_backend.h 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 diff --git a/src/core/file_sys/archive_other_savedata.cpp b/src/core/file_sys/archive_other_savedata.cpp new file mode 100644 index 000000000..d3cf080da --- /dev/null +++ b/src/core/file_sys/archive_other_savedata.cpp @@ -0,0 +1,145 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "core/file_sys/archive_other_savedata.h" +#include "core/file_sys/errors.h" +#include "core/hle/kernel/process.h" +#include "core/hle/service/fs/archive.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +// TODO(wwylele): The storage info in exheader should be checked before accessing these archives + +using Service::FS::MediaType; + +namespace { + +template +ResultVal> ParsePath(const Path& path, T program_id_reader) { + if (path.GetType() != Binary) { + LOG_ERROR(Service_FS, "Wrong path type %d", static_cast(path.GetType())); + return ERROR_INVALID_PATH; + } + + std::vector vec_data = path.AsBinary(); + + if (vec_data.size() != 12) { + LOG_ERROR(Service_FS, "Wrong path length %zu", vec_data.size()); + return ERROR_INVALID_PATH; + } + + const u32* data = reinterpret_cast(vec_data.data()); + auto media_type = static_cast(data[0]); + + if (media_type != MediaType::SDMC && media_type != MediaType::GameCard) { + LOG_ERROR(Service_FS, "Unsupported media type %u", static_cast(media_type)); + + // Note: this is strange, but the error code was verified with a real 3DS + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + + return MakeResult>(media_type, program_id_reader(data)); +} + +ResultVal> ParsePathPermitted(const Path& path) { + return ParsePath(path, + [](const u32* data) -> u64 { return (data[1] << 8) | 0x0004000000000000ULL; }); +} + +ResultVal> ParsePathGeneral(const Path& path) { + return ParsePath( + path, [](const u32* data) -> u64 { return data[1] | (static_cast(data[2]) << 32); }); +} + +} // namespace + +ArchiveFactory_OtherSaveDataPermitted::ArchiveFactory_OtherSaveDataPermitted( + std::shared_ptr sd_savedata) + : sd_savedata_source(sd_savedata) {} + +ResultVal> ArchiveFactory_OtherSaveDataPermitted::Open( + const Path& path) { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->Open(program_id); +} + +ResultCode ArchiveFactory_OtherSaveDataPermitted::Format( + const Path& path, const FileSys::ArchiveFormatInfo& format_info) { + LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive."); + return ERROR_INVALID_PATH; +} + +ResultVal ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo( + const Path& path) const { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->GetFormatInfo(program_id); +} + +ArchiveFactory_OtherSaveDataGeneral::ArchiveFactory_OtherSaveDataGeneral( + std::shared_ptr sd_savedata) + : sd_savedata_source(sd_savedata) {} + +ResultVal> ArchiveFactory_OtherSaveDataGeneral::Open( + const Path& path) { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->Open(program_id); +} + +ResultCode ArchiveFactory_OtherSaveDataGeneral::Format( + const Path& path, const FileSys::ArchiveFormatInfo& format_info) { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->Format(program_id, format_info); +} + +ResultVal ArchiveFactory_OtherSaveDataGeneral::GetFormatInfo( + const Path& path) const { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->GetFormatInfo(program_id); +} + +} // namespace FileSys diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h new file mode 100644 index 000000000..d80725158 --- /dev/null +++ b/src/core/file_sys/archive_other_savedata.h @@ -0,0 +1,52 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/archive_source_sd_savedata.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/// File system interface to the OtherSaveDataPermitted archive +class ArchiveFactory_OtherSaveDataPermitted final : public ArchiveFactory { +public: + explicit ArchiveFactory_OtherSaveDataPermitted( + std::shared_ptr sd_savedata_source); + + std::string GetName() const override { + return "OtherSaveDataPermitted"; + } + + ResultVal> Open(const Path& path) override; + ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; + ResultVal GetFormatInfo(const Path& path) const override; + +private: + std::string mount_point; + std::shared_ptr sd_savedata_source; +}; + +/// File system interface to the OtherSaveDataGeneral archive +class ArchiveFactory_OtherSaveDataGeneral final : public ArchiveFactory { +public: + explicit ArchiveFactory_OtherSaveDataGeneral( + std::shared_ptr sd_savedata_source); + + std::string GetName() const override { + return "OtherSaveDataGeneral"; + } + + ResultVal> Open(const Path& path) override; + ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; + ResultVal GetFormatInfo(const Path& path) const override; + +private: + std::string mount_point; + std::shared_ptr sd_savedata_source; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index fd1b07df0..4d5f62b08 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h @@ -36,5 +36,8 @@ const ResultCode ERROR_ALREADY_EXISTS(ErrorDescription::FS_AlreadyExists, ErrorM ErrorSummary::NothingHappened, ErrorLevel::Status); const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status); +const ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrorDescription::FS_GameCardNotInserted, + ErrorModule::FS, ErrorSummary::NotFound, + ErrorLevel::Status); } // namespace FileSys diff --git a/src/core/hle/result.h b/src/core/hle/result.h index f7356f9d8..8d29117a8 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -22,6 +22,7 @@ enum class ErrorDescription : u32 { FS_ArchiveNotMounted = 101, FS_FileNotFound = 112, FS_PathNotFound = 113, + FS_GameCardNotInserted = 141, FS_NotFound = 120, FS_FileAlreadyExists = 180, FS_DirectoryAlreadyExists = 185, diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index a067e9262..bef75f5df 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -16,6 +16,7 @@ #include "core/file_sys/archive_backend.h" #include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/archive_ncch.h" +#include "core/file_sys/archive_other_savedata.h" #include "core/file_sys/archive_savedata.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/archive_sdmcwriteonly.h" @@ -538,6 +539,14 @@ void RegisterArchiveTypes() { auto sd_savedata_source = std::make_shared(sdmc_directory); auto savedata_factory = std::make_unique(sd_savedata_source); RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); + auto other_savedata_permitted_factory = + std::make_unique(sd_savedata_source); + RegisterArchiveType(std::move(other_savedata_permitted_factory), + ArchiveIdCode::OtherSaveDataPermitted); + auto other_savedata_general_factory = + std::make_unique(sd_savedata_source); + RegisterArchiveType(std::move(other_savedata_general_factory), + ArchiveIdCode::OtherSaveDataGeneral); auto extsavedata_factory = std::make_unique(sdmc_directory, false); diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index d0220db17..87089bd92 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -34,6 +34,8 @@ enum class ArchiveIdCode : u32 { SDMC = 0x00000009, SDMCWriteOnly = 0x0000000A, NCCH = 0x2345678A, + OtherSaveDataGeneral = 0x567890B2, + OtherSaveDataPermitted = 0x567890B4, }; /// Media types for the archives