diff options
| author | 2014-12-29 13:04:37 -0500 | |
|---|---|---|
| committer | 2014-12-29 22:29:55 -0500 | |
| commit | 2c89d4d5cd4e308b04cebb1c9bca48e12f0945da (patch) | |
| tree | ea0a85e43943ba76418f27a68572e8602dbd9839 /src/core/file_sys | |
| parent | Merge pull request #367 from bunnei/usat_ssat (diff) | |
| download | yuzu-2c89d4d5cd4e308b04cebb1c9bca48e12f0945da.tar.gz yuzu-2c89d4d5cd4e308b04cebb1c9bca48e12f0945da.tar.xz yuzu-2c89d4d5cd4e308b04cebb1c9bca48e12f0945da.zip | |
Archives: Implemented ExtSaveData and SharedExtSaveData
They will be stored in /extsavedata/SDMC and /extsavedata/NAND respectively.
Also redirect some APT_A functions to their APT_U equivalents.
Implemented the gamecoin.dat file in SharedExtSaveData in the PTM module.
Implemented formatting the savegame.
Retake a previous savegame if it exists instead of reporting them as not formatted every time a game is loaded.
Diffstat (limited to 'src/core/file_sys')
| -rw-r--r-- | src/core/file_sys/archive_backend.h | 17 | ||||
| -rw-r--r-- | src/core/file_sys/archive_extsavedata.cpp | 59 | ||||
| -rw-r--r-- | src/core/file_sys/archive_extsavedata.h | 45 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.cpp | 5 | ||||
| -rw-r--r-- | src/core/file_sys/archive_romfs.h | 6 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.cpp | 25 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.h | 19 | ||||
| -rw-r--r-- | src/core/file_sys/disk_archive.h | 7 |
8 files changed, 168 insertions, 15 deletions
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index e153917ea..1612c35c2 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -46,6 +46,9 @@ public: | |||
| 46 | Path(const char* path) : type(Char), string(path) { | 46 | Path(const char* path) : type(Char), string(path) { |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | Path(std::vector<u8> binary_data) : type(Binary), binary(std::move(binary_data)) { | ||
| 50 | } | ||
| 51 | |||
| 49 | Path(LowPathType type, u32 size, u32 pointer) : type(type) { | 52 | Path(LowPathType type, u32 size, u32 pointer) : type(type) { |
| 50 | switch (type) { | 53 | switch (type) { |
| 51 | case Binary: | 54 | case Binary: |
| @@ -175,6 +178,20 @@ public: | |||
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | /** | 180 | /** |
| 181 | * Tries to open the archive of this type with the specified path | ||
| 182 | * @param path Path to the archive | ||
| 183 | * @return ResultCode of the operation | ||
| 184 | */ | ||
| 185 | virtual ResultCode Open(const Path& path) = 0; | ||
| 186 | |||
| 187 | /** | ||
| 188 | * Deletes the archive contents and then re-creates the base folder | ||
| 189 | * @param path Path to the archive | ||
| 190 | * @return ResultCode of the operation, 0 on success | ||
| 191 | */ | ||
| 192 | virtual ResultCode Format(const Path& path) const = 0; | ||
| 193 | |||
| 194 | /** | ||
| 178 | * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) | 195 | * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) |
| 179 | */ | 196 | */ |
| 180 | virtual std::string GetName() const = 0; | 197 | virtual std::string GetName() const = 0; |
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp new file mode 100644 index 000000000..4759ef3ae --- /dev/null +++ b/src/core/file_sys/archive_extsavedata.cpp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/archive_extsavedata.h" | ||
| 11 | #include "core/file_sys/disk_archive.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | static std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) { | ||
| 20 | std::vector<u8> vec_data = path.AsBinary(); | ||
| 21 | const u32* data = reinterpret_cast<const u32*>(vec_data.data()); | ||
| 22 | u32 media_type = data[0]; | ||
| 23 | u32 save_low = data[1]; | ||
| 24 | u32 save_high = data[2]; | ||
| 25 | return Common::StringFromFormat("%s%s/%08X/%08X/", mount_point.c_str(), media_type == 0 ? "nand" : "sdmc", save_high, save_low); | ||
| 26 | } | ||
| 27 | |||
| 28 | Archive_ExtSaveData::Archive_ExtSaveData(const std::string& mount_point) | ||
| 29 | : DiskArchive(mount_point), concrete_mount_point(mount_point) { | ||
| 30 | LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", this->mount_point.c_str()); | ||
| 31 | } | ||
| 32 | |||
| 33 | bool Archive_ExtSaveData::Initialize() { | ||
| 34 | if (!FileUtil::CreateFullPath(mount_point)) { | ||
| 35 | LOG_ERROR(Service_FS, "Unable to create ExtSaveData base path."); | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | |||
| 39 | return true; | ||
| 40 | } | ||
| 41 | |||
| 42 | ResultCode Archive_ExtSaveData::Open(const Path& path) { | ||
| 43 | std::string fullpath = GetExtSaveDataPath(mount_point, path); | ||
| 44 | if (!FileUtil::Exists(fullpath)) { | ||
| 45 | // TODO(Subv): Check error code, this one is probably wrong | ||
| 46 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 47 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 48 | } | ||
| 49 | concrete_mount_point = fullpath; | ||
| 50 | return RESULT_SUCCESS; | ||
| 51 | } | ||
| 52 | |||
| 53 | ResultCode Archive_ExtSaveData::Format(const Path& path) const { | ||
| 54 | std::string fullpath = GetExtSaveDataPath(mount_point, path); | ||
| 55 | FileUtil::CreateFullPath(fullpath); | ||
| 56 | return RESULT_SUCCESS; | ||
| 57 | } | ||
| 58 | |||
| 59 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h new file mode 100644 index 000000000..a3a144799 --- /dev/null +++ b/src/core/file_sys/archive_extsavedata.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/file_sys/disk_archive.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the ExtSaveData archive | ||
| 18 | class Archive_ExtSaveData final : public DiskArchive { | ||
| 19 | public: | ||
| 20 | Archive_ExtSaveData(const std::string& mount_point); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Initialize the archive. | ||
| 24 | * @return true if it initialized successfully | ||
| 25 | */ | ||
| 26 | bool Initialize(); | ||
| 27 | |||
| 28 | ResultCode Open(const Path& path) override; | ||
| 29 | ResultCode Format(const Path& path) const override; | ||
| 30 | std::string GetName() const override { return "ExtSaveData"; } | ||
| 31 | |||
| 32 | const std::string& GetMountPoint() const override { | ||
| 33 | return concrete_mount_point; | ||
| 34 | } | ||
| 35 | |||
| 36 | protected: | ||
| 37 | /** | ||
| 38 | * This holds the full directory path for this archive, it is only set after a successful call to Open, | ||
| 39 | * this is formed as <base extsavedatapath>/<type>/<high>/<low>. | ||
| 40 | * See GetExtSaveDataPath for the code that extracts this data from an archive path. | ||
| 41 | */ | ||
| 42 | std::string concrete_mount_point; | ||
| 43 | }; | ||
| 44 | |||
| 45 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index fdaf73179..2fc3831b7 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp | |||
| @@ -62,4 +62,9 @@ std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) | |||
| 62 | return Common::make_unique<Directory_RomFS>(); | 62 | return Common::make_unique<Directory_RomFS>(); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | ResultCode Archive_RomFS::Format(const Path& path) const { | ||
| 66 | LOG_WARNING(Service_FS, "Attempted to format ROMFS."); | ||
| 67 | return UnimplementedFunction(ErrorModule::FS); | ||
| 68 | } | ||
| 69 | |||
| 65 | } // namespace FileSys | 70 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 5e918f92d..d4b1eb7f2 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h | |||
| @@ -83,6 +83,12 @@ public: | |||
| 83 | */ | 83 | */ |
| 84 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 84 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 85 | 85 | ||
| 86 | ResultCode Open(const Path& path) override { | ||
| 87 | return RESULT_SUCCESS; | ||
| 88 | } | ||
| 89 | |||
| 90 | ResultCode Format(const Path& path) const override; | ||
| 91 | |||
| 86 | private: | 92 | private: |
| 87 | friend class File_RomFS; | 93 | friend class File_RomFS; |
| 88 | 94 | ||
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index 97853567c..280d4ff5d 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp | |||
| @@ -16,18 +16,29 @@ | |||
| 16 | 16 | ||
| 17 | namespace FileSys { | 17 | namespace FileSys { |
| 18 | 18 | ||
| 19 | Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id) | 19 | Archive_SaveData::Archive_SaveData(const std::string& mount_point) |
| 20 | : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) { | 20 | : DiskArchive(mount_point) { |
| 21 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); | 21 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | bool Archive_SaveData::Initialize() { | 24 | ResultCode Archive_SaveData::Open(const Path& path) { |
| 25 | if (!FileUtil::CreateFullPath(mount_point)) { | 25 | if (concrete_mount_point.empty()) |
| 26 | LOG_ERROR(Service_FS, "Unable to create SaveData path."); | 26 | concrete_mount_point = Common::StringFromFormat("%s%016X", mount_point.c_str(), Kernel::g_program_id) + DIR_SEP; |
| 27 | return false; | 27 | if (!FileUtil::Exists(concrete_mount_point)) { |
| 28 | // When a SaveData archive is created for the first time, it is not yet formatted | ||
| 29 | // and the save file/directory structure expected by the game has not yet been initialized. | ||
| 30 | // Returning the NotFormatted error code will signal the game to provision the SaveData archive | ||
| 31 | // with the files and folders that it expects. | ||
| 32 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 33 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 28 | } | 34 | } |
| 35 | return RESULT_SUCCESS; | ||
| 36 | } | ||
| 29 | 37 | ||
| 30 | return true; | 38 | ResultCode Archive_SaveData::Format(const Path& path) const { |
| 39 | FileUtil::DeleteDirRecursively(concrete_mount_point); | ||
| 40 | FileUtil::CreateFullPath(concrete_mount_point); | ||
| 41 | return RESULT_SUCCESS; | ||
| 31 | } | 42 | } |
| 32 | 43 | ||
| 33 | } // namespace FileSys | 44 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h index 5b0ce29e6..07c7f7eff 100644 --- a/src/core/file_sys/archive_savedata.h +++ b/src/core/file_sys/archive_savedata.h | |||
| @@ -17,15 +17,20 @@ namespace FileSys { | |||
| 17 | /// File system interface to the SaveData archive | 17 | /// File system interface to the SaveData archive |
| 18 | class Archive_SaveData final : public DiskArchive { | 18 | class Archive_SaveData final : public DiskArchive { |
| 19 | public: | 19 | public: |
| 20 | Archive_SaveData(const std::string& mount_point, u64 program_id); | 20 | Archive_SaveData(const std::string& mount_point); |
| 21 | |||
| 22 | /** | ||
| 23 | * Initialize the archive. | ||
| 24 | * @return true if it initialized successfully | ||
| 25 | */ | ||
| 26 | bool Initialize(); | ||
| 27 | 21 | ||
| 28 | std::string GetName() const override { return "SaveData"; } | 22 | std::string GetName() const override { return "SaveData"; } |
| 23 | |||
| 24 | ResultCode Open(const Path& path) override; | ||
| 25 | |||
| 26 | ResultCode Format(const Path& path) const override; | ||
| 27 | |||
| 28 | const std::string& GetMountPoint() const override { | ||
| 29 | return concrete_mount_point; | ||
| 30 | } | ||
| 31 | |||
| 32 | protected: | ||
| 33 | std::string concrete_mount_point; | ||
| 29 | }; | 34 | }; |
| 30 | 35 | ||
| 31 | } // namespace FileSys | 36 | } // namespace FileSys |
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index 018ebd2ed..f18d96f5a 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -25,6 +25,7 @@ public: | |||
| 25 | DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} | 25 | DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} |
| 26 | 26 | ||
| 27 | virtual std::string GetName() const = 0; | 27 | virtual std::string GetName() const = 0; |
| 28 | virtual ResultCode Format(const Path& path) const { return RESULT_SUCCESS; } | ||
| 28 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; | 29 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; |
| 29 | bool DeleteFile(const Path& path) const override; | 30 | bool DeleteFile(const Path& path) const override; |
| 30 | bool RenameFile(const Path& src_path, const Path& dest_path) const override; | 31 | bool RenameFile(const Path& src_path, const Path& dest_path) const override; |
| @@ -34,11 +35,15 @@ public: | |||
| 34 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 35 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 35 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 36 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 36 | 37 | ||
| 38 | virtual ResultCode Open(const Path& path) override { | ||
| 39 | return RESULT_SUCCESS; | ||
| 40 | } | ||
| 41 | |||
| 37 | /** | 42 | /** |
| 38 | * Getter for the path used for this Archive | 43 | * Getter for the path used for this Archive |
| 39 | * @return Mount point of that passthrough archive | 44 | * @return Mount point of that passthrough archive |
| 40 | */ | 45 | */ |
| 41 | const std::string& GetMountPoint() const { | 46 | virtual const std::string& GetMountPoint() const { |
| 42 | return mount_point; | 47 | return mount_point; |
| 43 | } | 48 | } |
| 44 | 49 | ||