diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1bc536075..6ad04d19d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -7,6 +7,8 @@ add_library(core STATIC core_timing.cpp core_timing.h file_sys/directory.h + file_sys/disk_filesystem.cpp + file_sys/disk_filesystem.h file_sys/errors.h file_sys/filesystem.cpp file_sys/filesystem.h @@ -18,6 +20,8 @@ add_library(core STATIC file_sys/romfs_factory.h file_sys/romfs_filesystem.cpp file_sys/romfs_filesystem.h + file_sys/savedata_factory.cpp + file_sys/savedata_factory.h file_sys/storage.h frontend/emu_window.cpp frontend/emu_window.h diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp new file mode 100644 index 000000000..be7574fdb --- /dev/null +++ b/src/core/file_sys/disk_filesystem.cpp @@ -0,0 +1,147 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/file_sys/disk_filesystem.h" + +namespace FileSys { + +std::string Disk_FileSystem::GetName() const { + return "Disk"; +} + +ResultVal> Disk_FileSystem::OpenFile(const std::string& path, + Mode mode) const { + ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); + + std::string full_path = base_directory + path; + auto file = std::make_shared(full_path, mode == Mode::Read ? "rb" : "wb"); + + if (!file->IsOpen()) { + // TODO(Subv): Find out the correct error code. + return ResultCode(-1); + } + + return MakeResult>( + std::make_unique(std::move(file))); +} + +ResultCode Disk_FileSystem::DeleteFile(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(bunnei): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + std::string full_path = base_directory + path; + 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"); + // TODO(Subv): Find out the correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + +ResultVal> Disk_FileSystem::OpenDirectory( + const Path& path) const { + return MakeResult>(std::make_unique()); +} + +u64 Disk_FileSystem::GetFreeSpaceSize() const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return 0; +} + +ResultVal Disk_FileSystem::GetEntryType(const std::string& path) const { + std::string full_path = base_directory + path; + if (!FileUtil::Exists(full_path)) { + // TODO(Subv): Find out what this actually means + return ResultCode(ErrorModule::FS, 1); + } + + // TODO(Subv): Find out the EntryType values + UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); +} + +ResultVal Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { + LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); + file->Seek(offset, SEEK_SET); + return MakeResult(file->ReadBytes(buffer, length)); +} + +ResultVal Disk_Storage::Write(const u64 offset, const size_t length, const bool flush, + const u8* buffer) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + file->Seek(offset, SEEK_SET); + size_t written = file->WriteBytes(buffer, length); + if (flush) { + file->Flush(); + } + return MakeResult(written); +} + +u64 Disk_Storage::GetSize() const { + return file->GetSize(); +} + +bool Disk_Storage::SetSize(const u64 size) const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return false; +} + +u32 Disk_Directory::Read(const u32 count, Entry* entries) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return 0; +} + +bool Disk_Directory::Close() const { + LOG_WARNING(Service_FS, "(STUBBED) called"); + return true; +} + +} // namespace FileSys diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h new file mode 100644 index 000000000..53767b949 --- /dev/null +++ b/src/core/file_sys/disk_filesystem.h @@ -0,0 +1,66 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#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" + +namespace FileSys { + +class Disk_FileSystem : public FileSystemBackend { +public: + explicit Disk_FileSystem(std::string base_directory) + : base_directory(std::move(base_directory)) {} + + std::string GetName() const override; + + ResultVal> OpenFile(const std::string& path, + 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 std::string& 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 GetFreeSpaceSize() const override; + ResultVal GetEntryType(const std::string& path) const override; + +protected: + std::string base_directory; +}; + +class Disk_Storage : public StorageBackend { +public: + Disk_Storage(std::shared_ptr file) : file(std::move(file)) {} + + ResultVal Read(u64 offset, size_t length, u8* buffer) const override; + ResultVal 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 file; +}; + +class Disk_Directory : public DirectoryBackend { +public: + u32 Read(const u32 count, Entry* entries) override; + bool Close() const override; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 02705506b..df4e66a0b 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -27,11 +27,14 @@ enum LowPathType : u32 { Wchar = 4, }; -union Mode { - u32 hex; - BitField<0, 1, u32> read_flag; - BitField<1, 1, u32> write_flag; - BitField<2, 1, u32> create_flag; +enum EntryType : u32 { + Directory = 0, + File = 1, +}; + +enum class Mode : u32 { + Read = 1, + Write = 2, }; class Path { @@ -86,7 +89,7 @@ public: * @param size The size of the new file, filled with zeroes * @return Result of the operation */ - virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; + virtual ResultCode CreateFile(const std::string& path, u64 size) const = 0; /** * Delete a file specified by its path @@ -138,8 +141,8 @@ public: * @param mode Mode to open the file with * @return Opened file, or error code */ - virtual ResultVal> OpenFile(const Path& path, - const Mode& mode) const = 0; + virtual ResultVal> OpenFile(const std::string& path, + Mode mode) const = 0; /** * Open a directory specified by its path @@ -153,6 +156,12 @@ public: * @return The number of free bytes in the archive */ virtual u64 GetFreeSpaceSize() const = 0; + + /** + * Get the type of the specified path + * @return The type of the specified path or error code + */ + virtual ResultVal GetEntryType(const std::string& path) const = 0; }; class FileSystemFactory : NonCopyable { diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index ca1463d7c..f1f9b4d04 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -14,8 +14,8 @@ std::string RomFS_FileSystem::GetName() const { return "RomFS"; } -ResultVal> RomFS_FileSystem::OpenFile(const Path& path, - const Mode& mode) const { +ResultVal> RomFS_FileSystem::OpenFile(const std::string& path, + Mode mode) const { return MakeResult>( std::make_unique(romfs_file, data_offset, data_size)); } @@ -48,7 +48,7 @@ ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const return ResultCode(-1); } -ResultCode RomFS_FileSystem::CreateFile(const Path& path, u64 size) const { +ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const { LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code @@ -79,6 +79,12 @@ u64 RomFS_FileSystem::GetFreeSpaceSize() const { return 0; } +ResultVal RomFS_FileSystem::GetEntryType(const std::string& path) const { + LOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path %s).", path.c_str()); + // TODO(wwylele): Use correct error code + return ResultCode(-1); +} + ResultVal RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); romfs_file->Seek(data_offset + offset, SEEK_SET); diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index 900ea567a..cedd70645 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -29,17 +29,18 @@ public: std::string GetName() const override; - ResultVal> OpenFile(const Path& path, - const Mode& mode) const override; + ResultVal> OpenFile(const std::string& path, + 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 CreateFile(const std::string& 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 GetFreeSpaceSize() const override; + ResultVal GetEntryType(const std::string& path) const override; protected: std::shared_ptr romfs_file; diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp new file mode 100644 index 000000000..0df754e7c --- /dev/null +++ b/src/core/file_sys/savedata_factory.cpp @@ -0,0 +1,41 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/file_sys/disk_filesystem.h" +#include "core/file_sys/savedata_factory.h" + +namespace FileSys { + +SaveData_Factory::SaveData_Factory(std::string nand_directory) + : nand_directory(std::move(nand_directory)) {} + +ResultVal> SaveData_Factory::Open(const Path& path) { + // TODO(Subv): Somehow obtain these values. + u64 title_id = 0; + u32 user = 0; + std::string save_directory = Common::StringFromFormat("%ssave/%016" PRIX64 "/%08X", + nand_directory.c_str(), title_id, user); + auto archive = std::make_unique(save_directory); + return MakeResult>(std::move(archive)); +} + +ResultCode SaveData_Factory::Format(const Path& path, + const FileSys::ArchiveFormatInfo& format_info) { + LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +ResultVal SaveData_Factory::GetFormatInfo(const Path& path) const { + LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +} // namespace FileSys diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h new file mode 100644 index 000000000..726743fde --- /dev/null +++ b/src/core/file_sys/savedata_factory.h @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/hle/result.h" + +namespace FileSys { + +/// File system interface to the SaveData archive +class SaveData_Factory final : public FileSystemFactory { +public: + explicit SaveData_Factory(std::string nand_directory); + + std::string GetName() const override { + return "SaveData_Factory"; + } + 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 nand_directory; +}; + +} // namespace FileSys diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 4b47548fd..32752aea5 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -3,7 +3,9 @@ // Refer to the license.txt file included. #include +#include "common/file_util.h" #include "core/file_sys/filesystem.h" +#include "core/file_sys/savedata_factory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_srv.h" @@ -41,12 +43,17 @@ ResultVal> OpenFileSystem(Type type, return itr->second->Open(path); } -void UnregisterFileSystems() { +void RegisterFileSystems() { filesystem_map.clear(); + + std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); + + auto savedata = std::make_unique(std::move(nand_directory)); + RegisterFileSystem(std::move(savedata), Type::SaveData); } void InstallInterfaces(SM::ServiceManager& service_manager) { - UnregisterFileSystems(); + RegisterFileSystems(); std::make_shared()->InstallAsService(service_manager); } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index a674c9493..80f318676 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -25,6 +25,7 @@ namespace FileSystem { /// Supported FileSystem types enum class Type { RomFS = 1, + SaveData = 2, }; /**