From 4dd8a831bd5ea32108db837754289ab42a2fa6ca Mon Sep 17 00:00:00 2001 From: wwylele Date: Fri, 14 Oct 2016 15:29:09 +0800 Subject: FileSys: make Archive interfaces return error code and make the mode parameter a reference since it is a BitField union --- src/core/hle/service/fs/archive.cpp | 41 ++++++++----------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 7f9696bfb..891d7bc84 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -338,17 +338,11 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, return ERR_INVALID_ARCHIVE_HANDLE; if (src_archive == dest_archive) { - if (src_archive->RenameFile(src_path, dest_path)) - return RESULT_SUCCESS; + return src_archive->RenameFile(src_path, dest_path); } else { // TODO: Implement renaming across archives return UnimplementedFunction(ErrorModule::FS); } - - // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't - // exist or similar. Verify. - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::NothingHappened, ErrorLevel::Status); } ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { @@ -356,10 +350,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; - if (archive->DeleteDirectory(path)) - return RESULT_SUCCESS; - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::Canceled, ErrorLevel::Status); + return archive->DeleteDirectory(path); } ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, @@ -368,10 +359,7 @@ ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; - if (archive->DeleteDirectoryRecursively(path)) - return RESULT_SUCCESS; - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::Canceled, ErrorLevel::Status); + return archive->DeleteDirectoryRecursively(path); } ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, @@ -388,10 +376,7 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; - if (archive->CreateDirectory(path)) - return RESULT_SUCCESS; - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::Canceled, ErrorLevel::Status); + return archive->CreateDirectory(path); } ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, @@ -404,17 +389,11 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, return ERR_INVALID_ARCHIVE_HANDLE; if (src_archive == dest_archive) { - if (src_archive->RenameDirectory(src_path, dest_path)) - return RESULT_SUCCESS; + return src_archive->RenameDirectory(src_path, dest_path); } else { // TODO: Implement renaming across archives return UnimplementedFunction(ErrorModule::FS); } - - // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't - // exist or similar. Verify. - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::NothingHappened, ErrorLevel::Status); } ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, @@ -423,13 +402,11 @@ ResultVal> OpenDirectoryFromArchive(ArchiveHandle a if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; - std::unique_ptr backend = archive->OpenDirectory(path); - if (backend == nullptr) { - return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, - ErrorLevel::Permanent); - } + auto backend = archive->OpenDirectory(path); + if (backend.Failed()) + return backend.Code(); - auto directory = Kernel::SharedPtr(new Directory(std::move(backend), path)); + auto directory = Kernel::SharedPtr(new Directory(backend.MoveFrom(), path)); return MakeResult>(std::move(directory)); } -- cgit v1.2.3 From 7166fdc49072d987d04e681de4d9e1558ba75c63 Mon Sep 17 00:00:00 2001 From: wwylele Date: Mon, 17 Oct 2016 14:54:48 +0800 Subject: FileSys: add SaveDataArchive The error checking of SaveDataArchive is completely different from DiskArchive, so it has to be a new class instead of a subclass of DiskArchive. --- src/core/CMakeLists.txt | 2 + src/core/file_sys/archive_savedata.cpp | 4 +- src/core/file_sys/archive_systemsavedata.cpp | 4 +- src/core/file_sys/errors.h | 29 +++ src/core/file_sys/savedata_archive.cpp | 283 +++++++++++++++++++++++++++ src/core/file_sys/savedata_archive.h | 43 ++++ src/core/hle/result.h | 7 + 7 files changed, 368 insertions(+), 4 deletions(-) create mode 100644 src/core/file_sys/errors.h create mode 100644 src/core/file_sys/savedata_archive.cpp create mode 100644 src/core/file_sys/savedata_archive.h (limited to 'src/core/hle') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ae9e8dcea..63a402ad0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -25,6 +25,7 @@ set(SRCS file_sys/disk_archive.cpp file_sys/ivfc_archive.cpp file_sys/path_parser.cpp + file_sys/savedata_archive.cpp gdbstub/gdbstub.cpp hle/config_mem.cpp hle/hle.cpp @@ -170,6 +171,7 @@ set(HEADERS file_sys/file_backend.h file_sys/ivfc_archive.h file_sys/path_parser.h + file_sys/savedata_archive.h gdbstub/gdbstub.h hle/config_mem.h hle/function_wrappers.h diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index 6711035ec..ecb44a215 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp @@ -9,7 +9,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/archive_savedata.h" -#include "core/file_sys/disk_archive.h" +#include "core/file_sys/savedata_archive.h" #include "core/hle/kernel/process.h" #include "core/hle/service/fs/archive.h" @@ -54,7 +54,7 @@ ResultVal> ArchiveFactory_SaveData::Open(const P ErrorSummary::InvalidState, ErrorLevel::Status); } - auto archive = std::make_unique(std::move(concrete_mount_point)); + auto archive = std::make_unique(std::move(concrete_mount_point)); return MakeResult>(std::move(archive)); } diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 48ebc0ed4..54e7793e0 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp @@ -9,7 +9,7 @@ #include "common/file_util.h" #include "common/string_util.h" #include "core/file_sys/archive_systemsavedata.h" -#include "core/file_sys/disk_archive.h" +#include "core/file_sys/savedata_archive.h" #include "core/hle/service/fs/archive.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -56,7 +56,7 @@ ResultVal> ArchiveFactory_SystemSaveData::Open(c return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status); } - auto archive = std::make_unique(fullpath); + auto archive = std::make_unique(fullpath); return MakeResult>(std::move(archive)); } diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h new file mode 100644 index 000000000..da7e82642 --- /dev/null +++ b/src/core/file_sys/errors.h @@ -0,0 +1,29 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/result.h" + +namespace FileSys { + +const ResultCode ERROR_INVALID_PATH(ErrorDescription::FS_InvalidPath, ErrorModule::FS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); +const ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrorDescription::FS_UnsupportedOpenFlags, + ErrorModule::FS, ErrorSummary::NotSupported, + ErrorLevel::Usage); +const ResultCode ERROR_FILE_NOT_FOUND(ErrorDescription::FS_FileNotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Status); +const ResultCode ERROR_PATH_NOT_FOUND(ErrorDescription::FS_PathNotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Status); +const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrorDescription::FS_UnexpectedFileOrDirectory, + ErrorModule::FS, ErrorSummary::NotSupported, + ErrorLevel::Usage); +const ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrorDescription::FS_DirectoryAlreadyExists, + ErrorModule::FS, ErrorSummary::NothingHappened, + ErrorLevel::Status); +const ResultCode ERROR_FILE_ALREADY_EXISTS(ErrorDescription::FS_FileAlreadyExists, ErrorModule::FS, + ErrorSummary::NothingHappened, ErrorLevel::Status); +const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS, + ErrorSummary::Canceled, ErrorLevel::Status); + +} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp new file mode 100644 index 000000000..f2e6a06bc --- /dev/null +++ b/src/core/file_sys/savedata_archive.cpp @@ -0,0 +1,283 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/file_util.h" +#include "core/file_sys/disk_archive.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/path_parser.h" +#include "core/file_sys/savedata_archive.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +ResultVal> SaveDataArchive::OpenFile(const Path& path, + const Mode& mode) const { + LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); + + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + if (mode.hex == 0) { + LOG_ERROR(Service_FS, "Empty open mode"); + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + + if (mode.create_flag && !mode.write_flag) { + LOG_ERROR(Service_FS, "Create flag set but write flag not set"); + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_FILE_NOT_FOUND; + case PathParser::PathNotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + case PathParser::DirectoryFound: + LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str()); + return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; + case PathParser::NotFound: + if (!mode.create_flag) { + LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", + full_path.c_str()); + return ERROR_FILE_NOT_FOUND; + } else { + // Create the file + FileUtil::CreateEmptyFile(full_path); + } + break; + } + + FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb"); + if (!file.IsOpen()) { + LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); + return ERROR_FILE_NOT_FOUND; + } + + auto disk_file = std::make_unique(std::move(file), mode); + return MakeResult>(std::move(disk_file)); +} + +ResultCode SaveDataArchive::DeleteFile(const Path& path) const { + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_FILE_NOT_FOUND; + case PathParser::PathNotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + case PathParser::DirectoryFound: + case PathParser::NotFound: + LOG_ERROR(Service_FS, "File not found %s", full_path.c_str()); + return ERROR_FILE_NOT_FOUND; + } + + if (FileUtil::Delete(full_path)) { + return RESULT_SUCCESS; + } + + LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str()); + return ERROR_FILE_NOT_FOUND; +} + +ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const { + if (FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString())) { + return RESULT_SUCCESS; + } + + // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't + // exist or similar. Verify. + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::NothingHappened, ErrorLevel::Status); +} + +template +static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point, + T deleter) { + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + if (path_parser.IsRootDirectory()) + return ERROR_DIRECTORY_NOT_EMPTY; + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::PathNotFound: + case PathParser::NotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + case PathParser::FileFound: + LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str()); + return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; + } + + if (deleter(full_path)) { + return RESULT_SUCCESS; + } + + LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str()); + return ERROR_DIRECTORY_NOT_EMPTY; +} + +ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const { + return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir); +} + +ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const { + return DeleteDirectoryHelper( + path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); }); +} + +ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const { + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_FILE_NOT_FOUND; + case PathParser::PathNotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); + return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; + case PathParser::DirectoryFound: + case PathParser::FileFound: + LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); + return ERROR_FILE_ALREADY_EXISTS; + } + + if (size == 0) { + FileUtil::CreateEmptyFile(full_path); + return RESULT_SUCCESS; + } + + FileUtil::IOFile file(full_path, "wb"); + // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) + // We do this by seeking to the right size, then writing a single null byte. + if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) { + return RESULT_SUCCESS; + } + + LOG_ERROR(Service_FS, "Too large file"); + return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, + ErrorLevel::Info); +} + +ResultCode SaveDataArchive::CreateDirectory(const Path& path) const { + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_FILE_NOT_FOUND; + case PathParser::PathNotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); + return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; + case PathParser::DirectoryFound: + case PathParser::FileFound: + LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); + return ERROR_DIRECTORY_ALREADY_EXISTS; + } + + if (FileUtil::CreateDir(mount_point + path.AsString())) { + return RESULT_SUCCESS; + } + + LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str()); + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled, + ErrorLevel::Status); +} + +ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { + if (FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString())) + return RESULT_SUCCESS; + + // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't + // exist or similar. Verify. + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::NothingHappened, ErrorLevel::Status); +} + +ResultVal> SaveDataArchive::OpenDirectory( + const Path& path) const { + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_FILE_NOT_FOUND; + case PathParser::PathNotFound: + case PathParser::NotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + case PathParser::FileFound: + LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); + return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; + } + + auto directory = std::make_unique(full_path); + return MakeResult>(std::move(directory)); +} + +u64 SaveDataArchive::GetFreeBytes() const { + // TODO: Stubbed to return 1GiB + return 1024 * 1024 * 1024; +} + +} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h new file mode 100644 index 000000000..2fb6c452a --- /dev/null +++ b/src/core/file_sys/savedata_archive.h @@ -0,0 +1,43 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "core/file_sys/archive_backend.h" +#include "core/file_sys/directory_backend.h" +#include "core/file_sys/file_backend.h" +#include "core/hle/result.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/// Archive backend for general save data archive type (SaveData and SystemSaveData) +class SaveDataArchive : public ArchiveBackend { +public: + SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {} + + std::string GetName() const override { + return "SaveDataArchive: " + mount_point; + } + + ResultVal> OpenFile(const Path& path, + const Mode& mode) const override; + ResultCode DeleteFile(const Path& path) const override; + ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; + ResultCode DeleteDirectory(const Path& path) const override; + ResultCode DeleteDirectoryRecursively(const Path& path) const override; + ResultCode CreateFile(const Path& path, u64 size) const override; + ResultCode CreateDirectory(const Path& path) const override; + ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; + ResultVal> OpenDirectory(const Path& path) const override; + u64 GetFreeBytes() const override; + +protected: + std::string mount_point; +}; + +} // namespace FileSys diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 7f8d8e00d..8330894f2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -20,15 +20,22 @@ enum class ErrorDescription : u32 { OS_InvalidBufferDescriptor = 48, WrongAddress = 53, FS_ArchiveNotMounted = 101, + FS_FileNotFound = 112, + FS_PathNotFound = 113, FS_NotFound = 120, + FS_FileAlreadyExists = 180, + FS_DirectoryAlreadyExists = 185, FS_AlreadyExists = 190, FS_InvalidOpenFlags = 230, + FS_DirectoryNotEmpty = 240, FS_NotAFile = 250, FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage GPU_FirstInitialization = 519, FS_InvalidPath = 702, + FS_UnsupportedOpenFlags = 760, + FS_UnexpectedFileOrDirectory = 770, InvalidSection = 1000, TooLarge = 1001, NotAuthorized = 1002, -- cgit v1.2.3 From a879984c06baf6c4185e376dd47258bfc108dec5 Mon Sep 17 00:00:00 2001 From: wwylele Date: Mon, 17 Oct 2016 20:23:34 +0800 Subject: FileSys: add ExtSaveDataArchive ExtSaveData is more similar to SaveData, so let it be a subclass of SaveData --- src/core/file_sys/archive_extsavedata.cpp | 115 +++++++++++++++++++++++++++++- src/core/hle/result.h | 1 + 2 files changed, 115 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index e1d29efd3..e1c4931ec 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -11,6 +11,9 @@ #include "common/string_util.h" #include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/disk_archive.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/path_parser.h" +#include "core/file_sys/savedata_archive.h" #include "core/hle/service/fs/archive.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -18,6 +21,116 @@ namespace FileSys { +/** + * A modified version of DiskFile for fixed-size file used by ExtSaveData + * The file size can't be changed by SetSize or Write. + */ +class FixSizeDiskFile : public DiskFile { +public: + FixSizeDiskFile(FileUtil::IOFile&& file, const Mode& mode) : DiskFile(std::move(file), mode) { + size = GetSize(); + } + + bool SetSize(u64 size) const override { + return false; + } + + ResultVal Write(u64 offset, size_t length, bool flush, + const u8* buffer) const override { + if (offset > size) { + return ResultCode(ErrorDescription::FS_WriteBeyondEnd, ErrorModule::FS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); + } else if (offset == size) { + return MakeResult(0); + } + + if (offset + length > size) { + length = size - offset; + } + + return DiskFile::Write(offset, length, flush, buffer); + } + +private: + u64 size{}; +}; + +/** + * Archive backend for general extsave data archive type. + * The behaviour of ExtSaveDataArchive is almost the same as SaveDataArchive, except for + * - file size can't be changed once created (thus creating zero-size file and openning with create + * flag are prohibited); + * - always open a file with read+write permission. + */ +class ExtSaveDataArchive : public SaveDataArchive { +public: + ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {} + + std::string GetName() const override { + return "ExtSaveDataArchive: " + mount_point; + } + + ResultVal> OpenFile(const Path& path, + const Mode& mode) const override { + LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); + + const PathParser path_parser(path); + + if (!path_parser.IsValid()) { + LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); + return ERROR_INVALID_PATH; + } + + if (mode.hex == 0) { + LOG_ERROR(Service_FS, "Empty open mode"); + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + + if (mode.create_flag) { + LOG_ERROR(Service_FS, "Create flag is not supported"); + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + + const auto full_path = path_parser.BuildHostPath(mount_point); + + switch (path_parser.GetHostStatus(mount_point)) { + case PathParser::InvalidMountPoint: + LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); + return ERROR_FILE_NOT_FOUND; + case PathParser::PathNotFound: + LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); + return ERROR_PATH_NOT_FOUND; + case PathParser::FileInPath: + case PathParser::DirectoryFound: + LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str()); + return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; + case PathParser::NotFound: + LOG_ERROR(Service_FS, "%s not found", full_path.c_str()); + return ERROR_FILE_NOT_FOUND; + } + + FileUtil::IOFile file(full_path, "r+b"); + if (!file.IsOpen()) { + LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); + return ERROR_FILE_NOT_FOUND; + } + + Mode rwmode; + rwmode.write_flag.Assign(1); + rwmode.read_flag.Assign(1); + auto disk_file = std::make_unique(std::move(file), rwmode); + return MakeResult>(std::move(disk_file)); + } + + ResultCode CreateFile(const Path& path, u64 size) const override { + if (size == 0) { + LOG_ERROR(Service_FS, "Zero-size file is not supported"); + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + return SaveDataArchive::CreateFile(path, size); + } +}; + std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) { std::vector vec_data = path.AsBinary(); const u32* data = reinterpret_cast(vec_data.data()); @@ -84,7 +197,7 @@ ResultVal> ArchiveFactory_ExtSaveData::Open(cons ErrorSummary::InvalidState, ErrorLevel::Status); } } - auto archive = std::make_unique(fullpath); + auto archive = std::make_unique(fullpath); return MakeResult>(std::move(archive)); } diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 8330894f2..a355f970a 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -34,6 +34,7 @@ enum class ErrorDescription : u32 { 513, // TODO(purpasmart): Check if this name fits its actual usage GPU_FirstInitialization = 519, FS_InvalidPath = 702, + FS_WriteBeyondEnd = 705, FS_UnsupportedOpenFlags = 760, FS_UnexpectedFileOrDirectory = 770, InvalidSection = 1000, -- cgit v1.2.3 From 098778369962f8ec5eba6ccc91b2846c72cb0005 Mon Sep 17 00:00:00 2001 From: wwylele Date: Tue, 18 Oct 2016 17:27:51 +0800 Subject: FileSys: add SDMCWriteOnlyArchive --- src/core/CMakeLists.txt | 2 + src/core/file_sys/archive_sdmcwriteonly.cpp | 70 +++++++++++++++++++++++++++++ src/core/file_sys/archive_sdmcwriteonly.h | 57 +++++++++++++++++++++++ src/core/file_sys/errors.h | 2 + src/core/hle/result.h | 1 + src/core/hle/service/fs/archive.cpp | 8 ++++ 6 files changed, 140 insertions(+) create mode 100644 src/core/file_sys/archive_sdmcwriteonly.cpp create mode 100644 src/core/file_sys/archive_sdmcwriteonly.h (limited to 'src/core/hle') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 63a402ad0..1ecd1c431 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -21,6 +21,7 @@ set(SRCS file_sys/archive_savedata.cpp file_sys/archive_savedatacheck.cpp file_sys/archive_sdmc.cpp + file_sys/archive_sdmcwriteonly.cpp file_sys/archive_systemsavedata.cpp file_sys/disk_archive.cpp file_sys/ivfc_archive.cpp @@ -165,6 +166,7 @@ set(HEADERS file_sys/archive_savedata.h file_sys/archive_savedatacheck.h file_sys/archive_sdmc.h + file_sys/archive_sdmcwriteonly.h file_sys/archive_systemsavedata.h file_sys/directory_backend.h file_sys/disk_archive.h diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp new file mode 100644 index 000000000..64ae49b86 --- /dev/null +++ b/src/core/file_sys/archive_sdmcwriteonly.cpp @@ -0,0 +1,70 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/file_util.h" +#include "core/file_sys/archive_sdmcwriteonly.h" +#include "core/file_sys/directory_backend.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/file_backend.h" +#include "core/settings.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +ResultVal> SDMCWriteOnlyArchive::OpenFile(const Path& path, + const Mode& mode) const { + if (mode.read_flag) { + LOG_ERROR(Service_FS, "Read flag is not supported"); + return ERROR_INVALID_READ_FLAG; + } + return SDMCArchive::OpenFile(path, mode); +} + +ResultVal> SDMCWriteOnlyArchive::OpenDirectory( + const Path& path) const { + LOG_ERROR(Service_FS, "Not supported"); + return ERROR_UNSUPPORTED_OPEN_FLAGS; +} + +ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point) + : sdmc_directory(mount_point) { + LOG_INFO(Service_FS, "Directory %s set as SDMCWriteOnly.", sdmc_directory.c_str()); +} + +bool ArchiveFactory_SDMCWriteOnly::Initialize() { + if (!Settings::values.use_virtual_sd) { + LOG_WARNING(Service_FS, "SDMC disabled by config."); + return false; + } + + if (!FileUtil::CreateFullPath(sdmc_directory)) { + LOG_ERROR(Service_FS, "Unable to create SDMC path."); + return false; + } + + return true; +} + +ResultVal> ArchiveFactory_SDMCWriteOnly::Open(const Path& path) { + auto archive = std::make_unique(sdmc_directory); + return MakeResult>(std::move(archive)); +} + +ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path, + const FileSys::ArchiveFormatInfo& format_info) { + // TODO(wwylele): hwtest this + LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive."); + return ResultCode(-1); +} + +ResultVal ArchiveFactory_SDMCWriteOnly::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_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h new file mode 100644 index 000000000..ed977485a --- /dev/null +++ b/src/core/file_sys/archive_sdmcwriteonly.h @@ -0,0 +1,57 @@ +// 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_sdmc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/** + * Archive backend for SDMC write-only archive. + * The behaviour of SDMCWriteOnlyArchive is almost the same as SDMCArchive, except for + * - OpenDirectory is unsupported; + * - OpenFile with read flag is unsupported. + */ +class SDMCWriteOnlyArchive : public SDMCArchive { +public: + SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {} + + std::string GetName() const override { + return "SDMCWriteOnlyArchive: " + mount_point; + } + + ResultVal> OpenFile(const Path& path, + const Mode& mode) const override; + + ResultVal> OpenDirectory(const Path& path) const override; +}; + +/// File system interface to the SDMC write-only archive +class ArchiveFactory_SDMCWriteOnly final : public ArchiveFactory { +public: + ArchiveFactory_SDMCWriteOnly(const std::string& mount_point); + + /** + * Initialize the archive. + * @return true if it initialized successfully + */ + bool Initialize(); + + std::string GetName() const override { + return "SDMCWriteOnly"; + } + + 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 sdmc_directory; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index f9299364c..fd1b07df0 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h @@ -13,6 +13,8 @@ const ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrorDescription::FS_UnsupportedOp ErrorLevel::Usage); const ResultCode ERROR_INVALID_OPEN_FLAGS(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status); +const ResultCode ERROR_INVALID_READ_FLAG(ErrorDescription::FS_InvalidReadFlag, ErrorModule::FS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); const ResultCode ERROR_FILE_NOT_FOUND(ErrorDescription::FS_FileNotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status); const ResultCode ERROR_PATH_NOT_FOUND(ErrorDescription::FS_PathNotFound, ErrorModule::FS, diff --git a/src/core/hle/result.h b/src/core/hle/result.h index a355f970a..f7356f9d8 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -33,6 +33,7 @@ enum class ErrorDescription : u32 { OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage GPU_FirstInitialization = 519, + FS_InvalidReadFlag = 700, FS_InvalidPath = 702, FS_WriteBeyondEnd = 705, FS_UnsupportedOpenFlags = 760, diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 891d7bc84..62cf2c249 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -18,6 +18,7 @@ #include "core/file_sys/archive_savedata.h" #include "core/file_sys/archive_savedatacheck.h" #include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/archive_sdmcwriteonly.h" #include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/file_sys/file_backend.h" @@ -526,6 +527,13 @@ void RegisterArchiveTypes() { LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); + auto sdmcwo_factory = std::make_unique(sdmc_directory); + if (sdmcwo_factory->Initialize()) + RegisterArchiveType(std::move(sdmcwo_factory), ArchiveIdCode::SDMCWriteOnly); + else + LOG_ERROR(Service_FS, "Can't instantiate SDMCWriteOnly archive with path %s", + sdmc_directory.c_str()); + // Create the SaveData archive auto savedata_factory = std::make_unique(sdmc_directory); RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); -- cgit v1.2.3 From 5c6e13a171cd5952732895bba645f375ae38d775 Mon Sep 17 00:00:00 2001 From: wwylele Date: Thu, 20 Oct 2016 09:43:43 +0800 Subject: PTM & CFG: use the correct path and error code according to the new FileSys policy --- src/core/hle/service/cfg/cfg.cpp | 9 +++++---- src/core/hle/service/ptm/ptm.cpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 24eee6903..849dab707 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -359,7 +359,7 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* da } ResultCode DeleteConfigNANDSaveFile() { - FileSys::Path path("config"); + FileSys::Path path("/config"); return Service::FS::DeleteFileFromArchive(cfg_system_save_data_archive, path); } @@ -368,7 +368,7 @@ ResultCode UpdateConfigNANDSavegame() { mode.write_flag.Assign(1); mode.create_flag.Assign(1); - FileSys::Path path("config"); + FileSys::Path path("/config"); auto config_result = Service::FS::OpenFileFromArchive(cfg_system_save_data_archive, path, mode); ASSERT_MSG(config_result.Succeeded(), "could not open file"); @@ -382,8 +382,9 @@ ResultCode UpdateConfigNANDSavegame() { ResultCode FormatConfig() { ResultCode res = DeleteConfigNANDSaveFile(); // The delete command fails if the file doesn't exist, so we have to check that too - if (!res.IsSuccess() && res.description != ErrorDescription::FS_NotFound) + if (!res.IsSuccess() && res.description != ErrorDescription::FS_FileNotFound) { return res; + } // Delete the old data cfg_config_file_buffer.fill(0); // Create the header @@ -504,7 +505,7 @@ ResultCode LoadConfigNANDSaveFile() { cfg_system_save_data_archive = *archive_result; - FileSys::Path config_path("config"); + FileSys::Path config_path("/config"); FileSys::Mode open_mode = {}; open_mode.read_flag.Assign(1); diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 6e6b63329..cc859c14c 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -128,7 +128,7 @@ void Init() { Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); - FileSys::Path gamecoin_path("gamecoin.dat"); + FileSys::Path gamecoin_path("/gamecoin.dat"); FileSys::Mode open_mode = {}; open_mode.write_flag.Assign(1); open_mode.create_flag.Assign(1); -- cgit v1.2.3 From d7d6975af0971f5a07d489bdef522ca121bb30ec Mon Sep 17 00:00:00 2001 From: wwylele Date: Fri, 21 Oct 2016 22:10:55 +0800 Subject: FileSys: rename SaveDataCheck archive to NCCH archive According to the observation from game and 3dbrew "Used for accessing general NCCH data" --- src/core/CMakeLists.txt | 4 +- src/core/file_sys/archive_ncch.cpp | 62 +++++++++++++++++++++++++++++ src/core/file_sys/archive_ncch.h | 34 ++++++++++++++++ src/core/file_sys/archive_savedatacheck.cpp | 62 ----------------------------- src/core/file_sys/archive_savedatacheck.h | 34 ---------------- src/core/hle/service/fs/archive.cpp | 9 ++--- src/core/hle/service/fs/archive.h | 2 +- 7 files changed, 103 insertions(+), 104 deletions(-) create mode 100644 src/core/file_sys/archive_ncch.cpp create mode 100644 src/core/file_sys/archive_ncch.h delete mode 100644 src/core/file_sys/archive_savedatacheck.cpp delete mode 100644 src/core/file_sys/archive_savedatacheck.h (limited to 'src/core/hle') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1ecd1c431..299f1f261 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -17,9 +17,9 @@ set(SRCS core_timing.cpp file_sys/archive_backend.cpp file_sys/archive_extsavedata.cpp + file_sys/archive_ncch.cpp file_sys/archive_romfs.cpp file_sys/archive_savedata.cpp - file_sys/archive_savedatacheck.cpp file_sys/archive_sdmc.cpp file_sys/archive_sdmcwriteonly.cpp file_sys/archive_systemsavedata.cpp @@ -162,9 +162,9 @@ set(HEADERS core_timing.h file_sys/archive_backend.h file_sys/archive_extsavedata.h + file_sys/archive_ncch.h file_sys/archive_romfs.h file_sys/archive_savedata.h - file_sys/archive_savedatacheck.h file_sys/archive_sdmc.h file_sys/archive_sdmcwriteonly.h file_sys/archive_systemsavedata.h diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp new file mode 100644 index 000000000..6f1aadfc3 --- /dev/null +++ b/src/core/file_sys/archive_ncch.cpp @@ -0,0 +1,62 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include "common/common_types.h" +#include "common/file_util.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/file_sys/archive_ncch.h" +#include "core/file_sys/ivfc_archive.h" +#include "core/hle/service/fs/archive.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +static std::string GetNCCHContainerPath(const std::string& nand_directory) { + return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID.c_str()); +} + +static std::string GetNCCHPath(const std::string& mount_point, u32 high, u32 low) { + return Common::StringFromFormat("%s%08x/%08x/content/00000000.app.romfs", mount_point.c_str(), + high, low); +} + +ArchiveFactory_NCCH::ArchiveFactory_NCCH(const std::string& nand_directory) + : mount_point(GetNCCHContainerPath(nand_directory)) {} + +ResultVal> ArchiveFactory_NCCH::Open(const Path& path) { + auto vec = path.AsBinary(); + const u32* data = reinterpret_cast(vec.data()); + std::string file_path = GetNCCHPath(mount_point, data[1], data[0]); + auto file = std::make_shared(file_path, "rb"); + + if (!file->IsOpen()) { + return ResultCode(-1); // TODO(Subv): Find the right error code + } + auto size = file->GetSize(); + + auto archive = std::make_unique(file, 0, size); + return MakeResult>(std::move(archive)); +} + +ResultCode ArchiveFactory_NCCH::Format(const Path& path, + const FileSys::ArchiveFormatInfo& format_info) { + LOG_ERROR(Service_FS, "Attempted to format a NCCH archive."); + // TODO: Verify error code + return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, + ErrorLevel::Permanent); +} + +ResultVal ArchiveFactory_NCCH::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_ncch.h b/src/core/file_sys/archive_ncch.h new file mode 100644 index 000000000..66b8ce75d --- /dev/null +++ b/src/core/file_sys/archive_ncch.h @@ -0,0 +1,34 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "core/file_sys/archive_backend.h" +#include "core/hle/result.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/// File system interface to the NCCH archive +class ArchiveFactory_NCCH final : public ArchiveFactory { +public: + ArchiveFactory_NCCH(const std::string& mount_point); + + std::string GetName() const override { + return "NCCH"; + } + + 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; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp deleted file mode 100644 index 6c4542b7d..000000000 --- a/src/core/file_sys/archive_savedatacheck.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include "common/common_types.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "common/string_util.h" -#include "core/file_sys/archive_savedatacheck.h" -#include "core/file_sys/ivfc_archive.h" -#include "core/hle/service/fs/archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -static std::string GetSaveDataCheckContainerPath(const std::string& nand_directory) { - return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID.c_str()); -} - -static std::string GetSaveDataCheckPath(const std::string& mount_point, u32 high, u32 low) { - return Common::StringFromFormat("%s%08x/%08x/content/00000000.app.romfs", mount_point.c_str(), - high, low); -} - -ArchiveFactory_SaveDataCheck::ArchiveFactory_SaveDataCheck(const std::string& nand_directory) - : mount_point(GetSaveDataCheckContainerPath(nand_directory)) {} - -ResultVal> ArchiveFactory_SaveDataCheck::Open(const Path& path) { - auto vec = path.AsBinary(); - const u32* data = reinterpret_cast(vec.data()); - std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); - auto file = std::make_shared(file_path, "rb"); - - if (!file->IsOpen()) { - return ResultCode(-1); // TODO(Subv): Find the right error code - } - auto size = file->GetSize(); - - auto archive = std::make_unique(file, 0, size); - return MakeResult>(std::move(archive)); -} - -ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path, - const FileSys::ArchiveFormatInfo& format_info) { - LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive."); - // TODO: Verify error code - return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, - ErrorLevel::Permanent); -} - -ResultVal ArchiveFactory_SaveDataCheck::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_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h deleted file mode 100644 index e9cafbed9..000000000 --- a/src/core/file_sys/archive_savedatacheck.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "core/file_sys/archive_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -/// File system interface to the SaveDataCheck archive -class ArchiveFactory_SaveDataCheck final : public ArchiveFactory { -public: - ArchiveFactory_SaveDataCheck(const std::string& mount_point); - - std::string GetName() const override { - return "SaveDataCheck"; - } - - 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; -}; - -} // namespace FileSys diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 62cf2c249..4c29784e8 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -15,8 +15,8 @@ #include "common/logging/log.h" #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_savedata.h" -#include "core/file_sys/archive_savedatacheck.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/archive_sdmcwriteonly.h" #include "core/file_sys/archive_systemsavedata.h" @@ -554,10 +554,9 @@ void RegisterArchiveTypes() { LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", sharedextsavedata_factory->GetMountPoint().c_str()); - // Create the SaveDataCheck archive, basically a small variation of the RomFS archive - auto savedatacheck_factory = - std::make_unique(nand_directory); - RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::SaveDataCheck); + // Create the NCCH archive, basically a small variation of the RomFS archive + auto savedatacheck_factory = std::make_unique(nand_directory); + RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::NCCH); auto systemsavedata_factory = std::make_unique(nand_directory); diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 41a76285c..21ed9717b 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -33,7 +33,7 @@ enum class ArchiveIdCode : u32 { SystemSaveData = 0x00000008, SDMC = 0x00000009, SDMCWriteOnly = 0x0000000A, - SaveDataCheck = 0x2345678A, + NCCH = 0x2345678A, }; /// Media types for the archives -- cgit v1.2.3