diff options
Diffstat (limited to 'src/core/file_sys')
| -rw-r--r-- | src/core/file_sys/archive_extsavedata.cpp | 245 | ||||
| -rw-r--r-- | src/core/file_sys/archive_extsavedata.h | 89 | ||||
| -rw-r--r-- | src/core/file_sys/archive_ncch.cpp | 114 | ||||
| -rw-r--r-- | src/core/file_sys/archive_ncch.h | 34 | ||||
| -rw-r--r-- | src/core/file_sys/archive_other_savedata.cpp | 145 | ||||
| -rw-r--r-- | src/core/file_sys/archive_other_savedata.h | 52 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.cpp | 33 | ||||
| -rw-r--r-- | src/core/file_sys/archive_savedata.h | 33 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.cpp | 379 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmc.h | 66 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmcwriteonly.cpp | 70 | ||||
| -rw-r--r-- | src/core/file_sys/archive_sdmcwriteonly.h | 57 | ||||
| -rw-r--r-- | src/core/file_sys/archive_selfncch.cpp | 297 | ||||
| -rw-r--r-- | src/core/file_sys/archive_selfncch.h | 54 | ||||
| -rw-r--r-- | src/core/file_sys/archive_source_sd_savedata.cpp | 97 | ||||
| -rw-r--r-- | src/core/file_sys/archive_source_sd_savedata.h | 32 | ||||
| -rw-r--r-- | src/core/file_sys/archive_systemsavedata.cpp | 77 | ||||
| -rw-r--r-- | src/core/file_sys/archive_systemsavedata.h | 61 |
18 files changed, 0 insertions, 1935 deletions
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp deleted file mode 100644 index 4867c9d17..000000000 --- a/src/core/file_sys/archive_extsavedata.cpp +++ /dev/null | |||
| @@ -1,245 +0,0 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/file_util.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "common/string_util.h" | ||
| 12 | #include "core/file_sys/archive_extsavedata.h" | ||
| 13 | #include "core/file_sys/disk_archive.h" | ||
| 14 | #include "core/file_sys/errors.h" | ||
| 15 | #include "core/file_sys/path_parser.h" | ||
| 16 | #include "core/file_sys/savedata_archive.h" | ||
| 17 | #include "core/hle/service/fs/archive.h" | ||
| 18 | |||
| 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 20 | // FileSys namespace | ||
| 21 | |||
| 22 | namespace FileSys { | ||
| 23 | |||
| 24 | /** | ||
| 25 | * A modified version of DiskFile for fixed-size file used by ExtSaveData | ||
| 26 | * The file size can't be changed by SetSize or Write. | ||
| 27 | */ | ||
| 28 | class FixSizeDiskFile : public DiskFile { | ||
| 29 | public: | ||
| 30 | FixSizeDiskFile(FileUtil::IOFile&& file, const Mode& mode) : DiskFile(std::move(file), mode) { | ||
| 31 | size = GetSize(); | ||
| 32 | } | ||
| 33 | |||
| 34 | bool SetSize(u64 size) const override { | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | |||
| 38 | ResultVal<size_t> Write(u64 offset, size_t length, bool flush, | ||
| 39 | const u8* buffer) const override { | ||
| 40 | if (offset > size) { | ||
| 41 | return ERR_WRITE_BEYOND_END; | ||
| 42 | } else if (offset == size) { | ||
| 43 | return MakeResult<size_t>(0); | ||
| 44 | } | ||
| 45 | |||
| 46 | if (offset + length > size) { | ||
| 47 | length = size - offset; | ||
| 48 | } | ||
| 49 | |||
| 50 | return DiskFile::Write(offset, length, flush, buffer); | ||
| 51 | } | ||
| 52 | |||
| 53 | private: | ||
| 54 | u64 size{}; | ||
| 55 | }; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Archive backend for general extsave data archive type. | ||
| 59 | * The behaviour of ExtSaveDataArchive is almost the same as SaveDataArchive, except for | ||
| 60 | * - file size can't be changed once created (thus creating zero-size file and openning with create | ||
| 61 | * flag are prohibited); | ||
| 62 | * - always open a file with read+write permission. | ||
| 63 | */ | ||
| 64 | class ExtSaveDataArchive : public SaveDataArchive { | ||
| 65 | public: | ||
| 66 | explicit ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {} | ||
| 67 | |||
| 68 | std::string GetName() const override { | ||
| 69 | return "ExtSaveDataArchive: " + mount_point; | ||
| 70 | } | ||
| 71 | |||
| 72 | ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, | ||
| 73 | const Mode& mode) const override { | ||
| 74 | LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); | ||
| 75 | |||
| 76 | const PathParser path_parser(path); | ||
| 77 | |||
| 78 | if (!path_parser.IsValid()) { | ||
| 79 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 80 | return ERROR_INVALID_PATH; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (mode.hex == 0) { | ||
| 84 | LOG_ERROR(Service_FS, "Empty open mode"); | ||
| 85 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 86 | } | ||
| 87 | |||
| 88 | if (mode.create_flag) { | ||
| 89 | LOG_ERROR(Service_FS, "Create flag is not supported"); | ||
| 90 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 91 | } | ||
| 92 | |||
| 93 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 94 | |||
| 95 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 96 | case PathParser::InvalidMountPoint: | ||
| 97 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 98 | return ERROR_FILE_NOT_FOUND; | ||
| 99 | case PathParser::PathNotFound: | ||
| 100 | LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); | ||
| 101 | return ERROR_PATH_NOT_FOUND; | ||
| 102 | case PathParser::FileInPath: | ||
| 103 | case PathParser::DirectoryFound: | ||
| 104 | LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str()); | ||
| 105 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; | ||
| 106 | case PathParser::NotFound: | ||
| 107 | LOG_ERROR(Service_FS, "%s not found", full_path.c_str()); | ||
| 108 | return ERROR_FILE_NOT_FOUND; | ||
| 109 | case PathParser::FileFound: | ||
| 110 | break; // Expected 'success' case | ||
| 111 | } | ||
| 112 | |||
| 113 | FileUtil::IOFile file(full_path, "r+b"); | ||
| 114 | if (!file.IsOpen()) { | ||
| 115 | LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); | ||
| 116 | return ERROR_FILE_NOT_FOUND; | ||
| 117 | } | ||
| 118 | |||
| 119 | Mode rwmode; | ||
| 120 | rwmode.write_flag.Assign(1); | ||
| 121 | rwmode.read_flag.Assign(1); | ||
| 122 | auto disk_file = std::make_unique<FixSizeDiskFile>(std::move(file), rwmode); | ||
| 123 | return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file)); | ||
| 124 | } | ||
| 125 | |||
| 126 | ResultCode CreateFile(const Path& path, u64 size) const override { | ||
| 127 | if (size == 0) { | ||
| 128 | LOG_ERROR(Service_FS, "Zero-size file is not supported"); | ||
| 129 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 130 | } | ||
| 131 | return SaveDataArchive::CreateFile(path, size); | ||
| 132 | } | ||
| 133 | }; | ||
| 134 | |||
| 135 | std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) { | ||
| 136 | std::vector<u8> vec_data = path.AsBinary(); | ||
| 137 | const u32* data = reinterpret_cast<const u32*>(vec_data.data()); | ||
| 138 | u32 save_low = data[1]; | ||
| 139 | u32 save_high = data[2]; | ||
| 140 | return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_high, save_low); | ||
| 141 | } | ||
| 142 | |||
| 143 | std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { | ||
| 144 | if (shared) | ||
| 145 | return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID); | ||
| 146 | |||
| 147 | return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), SYSTEM_ID, | ||
| 148 | SDCARD_ID); | ||
| 149 | } | ||
| 150 | |||
| 151 | Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { | ||
| 152 | std::vector<u8> binary_path; | ||
| 153 | binary_path.reserve(12); | ||
| 154 | |||
| 155 | // Append each word byte by byte | ||
| 156 | |||
| 157 | // The first word is the media type | ||
| 158 | for (unsigned i = 0; i < 4; ++i) | ||
| 159 | binary_path.push_back((media_type >> (8 * i)) & 0xFF); | ||
| 160 | |||
| 161 | // Next is the low word | ||
| 162 | for (unsigned i = 0; i < 4; ++i) | ||
| 163 | binary_path.push_back((low >> (8 * i)) & 0xFF); | ||
| 164 | |||
| 165 | // Next is the high word | ||
| 166 | for (unsigned i = 0; i < 4; ++i) | ||
| 167 | binary_path.push_back((high >> (8 * i)) & 0xFF); | ||
| 168 | |||
| 169 | return {binary_path}; | ||
| 170 | } | ||
| 171 | |||
| 172 | ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, | ||
| 173 | bool shared) | ||
| 174 | : shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) { | ||
| 175 | LOG_DEBUG(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); | ||
| 176 | } | ||
| 177 | |||
| 178 | bool ArchiveFactory_ExtSaveData::Initialize() { | ||
| 179 | if (!FileUtil::CreateFullPath(mount_point)) { | ||
| 180 | LOG_ERROR(Service_FS, "Unable to create ExtSaveData base path."); | ||
| 181 | return false; | ||
| 182 | } | ||
| 183 | |||
| 184 | return true; | ||
| 185 | } | ||
| 186 | |||
| 187 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { | ||
| 188 | std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/"; | ||
| 189 | if (!FileUtil::Exists(fullpath)) { | ||
| 190 | // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData. | ||
| 191 | // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist. | ||
| 192 | if (!shared) { | ||
| 193 | return ERR_NOT_FOUND_INVALID_STATE; | ||
| 194 | } else { | ||
| 195 | return ERR_NOT_FORMATTED; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | auto archive = std::make_unique<ExtSaveDataArchive>(fullpath); | ||
| 199 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 200 | } | ||
| 201 | |||
| 202 | ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, | ||
| 203 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 204 | // These folders are always created with the ExtSaveData | ||
| 205 | std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; | ||
| 206 | std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; | ||
| 207 | FileUtil::CreateFullPath(user_path); | ||
| 208 | FileUtil::CreateFullPath(boss_path); | ||
| 209 | |||
| 210 | // Write the format metadata | ||
| 211 | std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; | ||
| 212 | FileUtil::IOFile file(metadata_path, "wb"); | ||
| 213 | |||
| 214 | if (!file.IsOpen()) { | ||
| 215 | // TODO(Subv): Find the correct error code | ||
| 216 | return ResultCode(-1); | ||
| 217 | } | ||
| 218 | |||
| 219 | file.WriteBytes(&format_info, sizeof(format_info)); | ||
| 220 | return RESULT_SUCCESS; | ||
| 221 | } | ||
| 222 | |||
| 223 | ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const { | ||
| 224 | std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata"; | ||
| 225 | FileUtil::IOFile file(metadata_path, "rb"); | ||
| 226 | |||
| 227 | if (!file.IsOpen()) { | ||
| 228 | LOG_ERROR(Service_FS, "Could not open metadata information for archive"); | ||
| 229 | // TODO(Subv): Verify error code | ||
| 230 | return ERR_NOT_FORMATTED; | ||
| 231 | } | ||
| 232 | |||
| 233 | ArchiveFormatInfo info = {}; | ||
| 234 | file.ReadBytes(&info, sizeof(info)); | ||
| 235 | return MakeResult<ArchiveFormatInfo>(info); | ||
| 236 | } | ||
| 237 | |||
| 238 | void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data, | ||
| 239 | size_t icon_size) { | ||
| 240 | std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path); | ||
| 241 | FileUtil::IOFile icon_file(game_path + "icon", "wb"); | ||
| 242 | icon_file.WriteBytes(icon_data, icon_size); | ||
| 243 | } | ||
| 244 | |||
| 245 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h deleted file mode 100644 index f705ade1c..000000000 --- a/src/core/file_sys/archive_extsavedata.h +++ /dev/null | |||
| @@ -1,89 +0,0 @@ | |||
| 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/archive_backend.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | /// File system interface to the ExtSaveData archive | ||
| 19 | class ArchiveFactory_ExtSaveData final : public ArchiveFactory { | ||
| 20 | public: | ||
| 21 | ArchiveFactory_ExtSaveData(const std::string& mount_point, bool shared); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Initialize the archive. | ||
| 25 | * @return true if it initialized successfully | ||
| 26 | */ | ||
| 27 | bool Initialize(); | ||
| 28 | |||
| 29 | std::string GetName() const override { | ||
| 30 | return "ExtSaveData"; | ||
| 31 | } | ||
| 32 | |||
| 33 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 34 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 35 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 36 | |||
| 37 | const std::string& GetMountPoint() const { | ||
| 38 | return mount_point; | ||
| 39 | } | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Writes the SMDH icon of the ExtSaveData to file | ||
| 43 | * @param path Path of this ExtSaveData | ||
| 44 | * @param icon_data Binary data of the icon | ||
| 45 | * @param icon_size Size of the icon data | ||
| 46 | */ | ||
| 47 | void WriteIcon(const Path& path, const u8* icon_data, size_t icon_size); | ||
| 48 | |||
| 49 | private: | ||
| 50 | bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData | ||
| 51 | /// archive | ||
| 52 | |||
| 53 | /** | ||
| 54 | * This holds the full directory path for this archive, it is only set after a successful call | ||
| 55 | * to Open, this is formed as `<base extsavedatapath>/<type>/<high>/<low>`. | ||
| 56 | * See GetExtSaveDataPath for the code that extracts this data from an archive path. | ||
| 57 | */ | ||
| 58 | std::string mount_point; | ||
| 59 | }; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Constructs a path to the concrete ExtData archive in the host filesystem based on the | ||
| 63 | * input Path and base mount point. | ||
| 64 | * @param mount_point The base mount point of the ExtSaveData archives. | ||
| 65 | * @param path The path that identifies the requested concrete ExtSaveData archive. | ||
| 66 | * @returns The complete path to the specified extdata archive in the host filesystem | ||
| 67 | */ | ||
| 68 | std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path); | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Constructs a path to the base folder to hold concrete ExtSaveData archives in the host file | ||
| 72 | * system. | ||
| 73 | * @param mount_point The base folder where this folder resides, ie. SDMC or NAND. | ||
| 74 | * @param shared Whether this ExtSaveData container is for SharedExtSaveDatas or not. | ||
| 75 | * @returns The path to the base ExtSaveData archives' folder in the host file system | ||
| 76 | */ | ||
| 77 | std::string GetExtDataContainerPath(const std::string& mount_point, bool shared); | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Constructs a FileSys::Path object that refers to the ExtData archive identified by | ||
| 81 | * the specified media type, high save id and low save id. | ||
| 82 | * @param media_type The media type where the archive is located (NAND / SDMC) | ||
| 83 | * @param high The high word of the save id for the archive | ||
| 84 | * @param low The low word of the save id for the archive | ||
| 85 | * @returns A FileSys::Path to the wanted archive | ||
| 86 | */ | ||
| 87 | Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low); | ||
| 88 | |||
| 89 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp deleted file mode 100644 index e8c5be983..000000000 --- a/src/core/file_sys/archive_ncch.cpp +++ /dev/null | |||
| @@ -1,114 +0,0 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/file_util.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "common/string_util.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/file_sys/archive_ncch.h" | ||
| 14 | #include "core/file_sys/errors.h" | ||
| 15 | #include "core/file_sys/ivfc_archive.h" | ||
| 16 | #include "core/file_sys/ncch_container.h" | ||
| 17 | #include "core/file_sys/title_metadata.h" | ||
| 18 | #include "core/hle/service/fs/archive.h" | ||
| 19 | #include "core/loader/loader.h" | ||
| 20 | |||
| 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 22 | // FileSys namespace | ||
| 23 | |||
| 24 | namespace FileSys { | ||
| 25 | |||
| 26 | static std::string GetNCCHContainerPath(const std::string& nand_directory) { | ||
| 27 | return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID); | ||
| 28 | } | ||
| 29 | |||
| 30 | static std::string GetNCCHPath(const std::string& mount_point, u32 high, u32 low) { | ||
| 31 | u32 content_id = 0; | ||
| 32 | |||
| 33 | // TODO(shinyquagsire23): Title database should be doing this path lookup | ||
| 34 | std::string content_path = | ||
| 35 | Common::StringFromFormat("%s%08x/%08x/content/", mount_point.c_str(), high, low); | ||
| 36 | std::string tmd_path = content_path + "00000000.tmd"; | ||
| 37 | TitleMetadata tmd(tmd_path); | ||
| 38 | if (tmd.Load() == Loader::ResultStatus::Success) { | ||
| 39 | content_id = tmd.GetBootContentID(); | ||
| 40 | } | ||
| 41 | |||
| 42 | return Common::StringFromFormat("%s%08x.app", content_path.c_str(), content_id); | ||
| 43 | } | ||
| 44 | |||
| 45 | ArchiveFactory_NCCH::ArchiveFactory_NCCH(const std::string& nand_directory) | ||
| 46 | : mount_point(GetNCCHContainerPath(nand_directory)) {} | ||
| 47 | |||
| 48 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) { | ||
| 49 | auto vec = path.AsBinary(); | ||
| 50 | const u32* data = reinterpret_cast<u32*>(vec.data()); | ||
| 51 | u32 high = data[1]; | ||
| 52 | u32 low = data[0]; | ||
| 53 | std::string file_path = GetNCCHPath(mount_point, high, low); | ||
| 54 | |||
| 55 | std::shared_ptr<FileUtil::IOFile> romfs_file; | ||
| 56 | u64 romfs_offset = 0; | ||
| 57 | u64 romfs_size = 0; | ||
| 58 | auto ncch_container = NCCHContainer(file_path); | ||
| 59 | |||
| 60 | if (ncch_container.ReadRomFS(romfs_file, romfs_offset, romfs_size) != | ||
| 61 | Loader::ResultStatus::Success) { | ||
| 62 | // High Title ID of the archive: The category (https://3dbrew.org/wiki/Title_list). | ||
| 63 | constexpr u32 shared_data_archive = 0x0004009B; | ||
| 64 | constexpr u32 system_data_archive = 0x000400DB; | ||
| 65 | |||
| 66 | // Low Title IDs. | ||
| 67 | constexpr u32 mii_data = 0x00010202; | ||
| 68 | constexpr u32 region_manifest = 0x00010402; | ||
| 69 | constexpr u32 ng_word_list = 0x00010302; | ||
| 70 | |||
| 71 | LOG_DEBUG(Service_FS, "Full Path: %s. Category: 0x%X. Path: 0x%X.", path.DebugStr().c_str(), | ||
| 72 | high, low); | ||
| 73 | |||
| 74 | if (high == shared_data_archive) { | ||
| 75 | if (low == mii_data) { | ||
| 76 | LOG_ERROR(Service_FS, "Failed to get a handle for shared data archive: Mii data. "); | ||
| 77 | Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles, | ||
| 78 | "Mii data"); | ||
| 79 | } else if (low == region_manifest) { | ||
| 80 | LOG_ERROR(Service_FS, | ||
| 81 | "Failed to get a handle for shared data archive: region manifest."); | ||
| 82 | Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles, | ||
| 83 | "Region manifest"); | ||
| 84 | } | ||
| 85 | } else if (high == system_data_archive) { | ||
| 86 | if (low == ng_word_list) { | ||
| 87 | LOG_ERROR(Service_FS, | ||
| 88 | "Failed to get a handle for system data archive: NG bad word list."); | ||
| 89 | Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles, | ||
| 90 | "NG bad word list"); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | return ERROR_NOT_FOUND; | ||
| 94 | } | ||
| 95 | |||
| 96 | auto archive = std::make_unique<IVFCArchive>(romfs_file, romfs_offset, romfs_size); | ||
| 97 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 98 | } | ||
| 99 | |||
| 100 | ResultCode ArchiveFactory_NCCH::Format(const Path& path, | ||
| 101 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 102 | LOG_ERROR(Service_FS, "Attempted to format a NCCH archive."); | ||
| 103 | // TODO: Verify error code | ||
| 104 | return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, | ||
| 105 | ErrorLevel::Permanent); | ||
| 106 | } | ||
| 107 | |||
| 108 | ResultVal<ArchiveFormatInfo> ArchiveFactory_NCCH::GetFormatInfo(const Path& path) const { | ||
| 109 | // TODO(Subv): Implement | ||
| 110 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||
| 111 | return ResultCode(-1); | ||
| 112 | } | ||
| 113 | |||
| 114 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h deleted file mode 100644 index 753b91f96..000000000 --- a/src/core/file_sys/archive_ncch.h +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "core/file_sys/archive_backend.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the NCCH archive | ||
| 18 | class ArchiveFactory_NCCH final : public ArchiveFactory { | ||
| 19 | public: | ||
| 20 | explicit ArchiveFactory_NCCH(const std::string& mount_point); | ||
| 21 | |||
| 22 | std::string GetName() const override { | ||
| 23 | return "NCCH"; | ||
| 24 | } | ||
| 25 | |||
| 26 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 27 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 28 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | std::string mount_point; | ||
| 32 | }; | ||
| 33 | |||
| 34 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_other_savedata.cpp b/src/core/file_sys/archive_other_savedata.cpp deleted file mode 100644 index d3cf080da..000000000 --- a/src/core/file_sys/archive_other_savedata.cpp +++ /dev/null | |||
| @@ -1,145 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <tuple> | ||
| 6 | #include "core/file_sys/archive_other_savedata.h" | ||
| 7 | #include "core/file_sys/errors.h" | ||
| 8 | #include "core/hle/kernel/process.h" | ||
| 9 | #include "core/hle/service/fs/archive.h" | ||
| 10 | |||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 12 | // FileSys namespace | ||
| 13 | |||
| 14 | namespace FileSys { | ||
| 15 | |||
| 16 | // TODO(wwylele): The storage info in exheader should be checked before accessing these archives | ||
| 17 | |||
| 18 | using Service::FS::MediaType; | ||
| 19 | |||
| 20 | namespace { | ||
| 21 | |||
| 22 | template <typename T> | ||
| 23 | ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_reader) { | ||
| 24 | if (path.GetType() != Binary) { | ||
| 25 | LOG_ERROR(Service_FS, "Wrong path type %d", static_cast<int>(path.GetType())); | ||
| 26 | return ERROR_INVALID_PATH; | ||
| 27 | } | ||
| 28 | |||
| 29 | std::vector<u8> vec_data = path.AsBinary(); | ||
| 30 | |||
| 31 | if (vec_data.size() != 12) { | ||
| 32 | LOG_ERROR(Service_FS, "Wrong path length %zu", vec_data.size()); | ||
| 33 | return ERROR_INVALID_PATH; | ||
| 34 | } | ||
| 35 | |||
| 36 | const u32* data = reinterpret_cast<const u32*>(vec_data.data()); | ||
| 37 | auto media_type = static_cast<MediaType>(data[0]); | ||
| 38 | |||
| 39 | if (media_type != MediaType::SDMC && media_type != MediaType::GameCard) { | ||
| 40 | LOG_ERROR(Service_FS, "Unsupported media type %u", static_cast<u32>(media_type)); | ||
| 41 | |||
| 42 | // Note: this is strange, but the error code was verified with a real 3DS | ||
| 43 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 44 | } | ||
| 45 | |||
| 46 | return MakeResult<std::tuple<MediaType, u64>>(media_type, program_id_reader(data)); | ||
| 47 | } | ||
| 48 | |||
| 49 | ResultVal<std::tuple<MediaType, u64>> ParsePathPermitted(const Path& path) { | ||
| 50 | return ParsePath(path, | ||
| 51 | [](const u32* data) -> u64 { return (data[1] << 8) | 0x0004000000000000ULL; }); | ||
| 52 | } | ||
| 53 | |||
| 54 | ResultVal<std::tuple<MediaType, u64>> ParsePathGeneral(const Path& path) { | ||
| 55 | return ParsePath( | ||
| 56 | path, [](const u32* data) -> u64 { return data[1] | (static_cast<u64>(data[2]) << 32); }); | ||
| 57 | } | ||
| 58 | |||
| 59 | } // namespace | ||
| 60 | |||
| 61 | ArchiveFactory_OtherSaveDataPermitted::ArchiveFactory_OtherSaveDataPermitted( | ||
| 62 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata) | ||
| 63 | : sd_savedata_source(sd_savedata) {} | ||
| 64 | |||
| 65 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataPermitted::Open( | ||
| 66 | const Path& path) { | ||
| 67 | MediaType media_type; | ||
| 68 | u64 program_id; | ||
| 69 | CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); | ||
| 70 | |||
| 71 | if (media_type == MediaType::GameCard) { | ||
| 72 | LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); | ||
| 73 | return ERROR_GAMECARD_NOT_INSERTED; | ||
| 74 | } | ||
| 75 | |||
| 76 | return sd_savedata_source->Open(program_id); | ||
| 77 | } | ||
| 78 | |||
| 79 | ResultCode ArchiveFactory_OtherSaveDataPermitted::Format( | ||
| 80 | const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||
| 81 | LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive."); | ||
| 82 | return ERROR_INVALID_PATH; | ||
| 83 | } | ||
| 84 | |||
| 85 | ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo( | ||
| 86 | const Path& path) const { | ||
| 87 | MediaType media_type; | ||
| 88 | u64 program_id; | ||
| 89 | CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); | ||
| 90 | |||
| 91 | if (media_type == MediaType::GameCard) { | ||
| 92 | LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); | ||
| 93 | return ERROR_GAMECARD_NOT_INSERTED; | ||
| 94 | } | ||
| 95 | |||
| 96 | return sd_savedata_source->GetFormatInfo(program_id); | ||
| 97 | } | ||
| 98 | |||
| 99 | ArchiveFactory_OtherSaveDataGeneral::ArchiveFactory_OtherSaveDataGeneral( | ||
| 100 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata) | ||
| 101 | : sd_savedata_source(sd_savedata) {} | ||
| 102 | |||
| 103 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataGeneral::Open( | ||
| 104 | const Path& path) { | ||
| 105 | MediaType media_type; | ||
| 106 | u64 program_id; | ||
| 107 | CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); | ||
| 108 | |||
| 109 | if (media_type == MediaType::GameCard) { | ||
| 110 | LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); | ||
| 111 | return ERROR_GAMECARD_NOT_INSERTED; | ||
| 112 | } | ||
| 113 | |||
| 114 | return sd_savedata_source->Open(program_id); | ||
| 115 | } | ||
| 116 | |||
| 117 | ResultCode ArchiveFactory_OtherSaveDataGeneral::Format( | ||
| 118 | const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | ||
| 119 | MediaType media_type; | ||
| 120 | u64 program_id; | ||
| 121 | CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); | ||
| 122 | |||
| 123 | if (media_type == MediaType::GameCard) { | ||
| 124 | LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); | ||
| 125 | return ERROR_GAMECARD_NOT_INSERTED; | ||
| 126 | } | ||
| 127 | |||
| 128 | return sd_savedata_source->Format(program_id, format_info); | ||
| 129 | } | ||
| 130 | |||
| 131 | ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataGeneral::GetFormatInfo( | ||
| 132 | const Path& path) const { | ||
| 133 | MediaType media_type; | ||
| 134 | u64 program_id; | ||
| 135 | CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); | ||
| 136 | |||
| 137 | if (media_type == MediaType::GameCard) { | ||
| 138 | LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); | ||
| 139 | return ERROR_GAMECARD_NOT_INSERTED; | ||
| 140 | } | ||
| 141 | |||
| 142 | return sd_savedata_source->GetFormatInfo(program_id); | ||
| 143 | } | ||
| 144 | |||
| 145 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h deleted file mode 100644 index d80725158..000000000 --- a/src/core/file_sys/archive_other_savedata.h +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | // Copyright 2016 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 "core/file_sys/archive_source_sd_savedata.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // FileSys namespace | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | /// File system interface to the OtherSaveDataPermitted archive | ||
| 15 | class ArchiveFactory_OtherSaveDataPermitted final : public ArchiveFactory { | ||
| 16 | public: | ||
| 17 | explicit ArchiveFactory_OtherSaveDataPermitted( | ||
| 18 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source); | ||
| 19 | |||
| 20 | std::string GetName() const override { | ||
| 21 | return "OtherSaveDataPermitted"; | ||
| 22 | } | ||
| 23 | |||
| 24 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 25 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 26 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 27 | |||
| 28 | private: | ||
| 29 | std::string mount_point; | ||
| 30 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source; | ||
| 31 | }; | ||
| 32 | |||
| 33 | /// File system interface to the OtherSaveDataGeneral archive | ||
| 34 | class ArchiveFactory_OtherSaveDataGeneral final : public ArchiveFactory { | ||
| 35 | public: | ||
| 36 | explicit ArchiveFactory_OtherSaveDataGeneral( | ||
| 37 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source); | ||
| 38 | |||
| 39 | std::string GetName() const override { | ||
| 40 | return "OtherSaveDataGeneral"; | ||
| 41 | } | ||
| 42 | |||
| 43 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 44 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 45 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 46 | |||
| 47 | private: | ||
| 48 | std::string mount_point; | ||
| 49 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source; | ||
| 50 | }; | ||
| 51 | |||
| 52 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp deleted file mode 100644 index 67076c73f..000000000 --- a/src/core/file_sys/archive_savedata.cpp +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 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 "core/file_sys/archive_savedata.h" | ||
| 6 | #include "core/hle/kernel/process.h" | ||
| 7 | |||
| 8 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 9 | // FileSys namespace | ||
| 10 | |||
| 11 | namespace FileSys { | ||
| 12 | |||
| 13 | ArchiveFactory_SaveData::ArchiveFactory_SaveData( | ||
| 14 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata) | ||
| 15 | : sd_savedata_source(sd_savedata) {} | ||
| 16 | |||
| 17 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { | ||
| 18 | UNIMPLEMENTED(); | ||
| 19 | return {}; //sd_savedata_source->Open(Kernel::g_current_process->codeset->program_id); | ||
| 20 | } | ||
| 21 | |||
| 22 | ResultCode ArchiveFactory_SaveData::Format(const Path& path, | ||
| 23 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 24 | UNIMPLEMENTED(); | ||
| 25 | return RESULT_SUCCESS; //sd_savedata_source->Format(Kernel::g_current_process->codeset->program_id, format_info); | ||
| 26 | } | ||
| 27 | |||
| 28 | ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const { | ||
| 29 | UNIMPLEMENTED(); | ||
| 30 | return {}; //sd_savedata_source->GetFormatInfo(Kernel::g_current_process->codeset->program_id); | ||
| 31 | } | ||
| 32 | |||
| 33 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h deleted file mode 100644 index 41aa6f189..000000000 --- a/src/core/file_sys/archive_savedata.h +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 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 "core/file_sys/archive_source_sd_savedata.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // FileSys namespace | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | /// File system interface to the SaveData archive | ||
| 15 | class ArchiveFactory_SaveData final : public ArchiveFactory { | ||
| 16 | public: | ||
| 17 | explicit ArchiveFactory_SaveData(std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source); | ||
| 18 | |||
| 19 | std::string GetName() const override { | ||
| 20 | return "SaveData"; | ||
| 21 | } | ||
| 22 | |||
| 23 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 24 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 25 | |||
| 26 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 27 | |||
| 28 | private: | ||
| 29 | std::string mount_point; | ||
| 30 | std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source; | ||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp deleted file mode 100644 index fe3dce5d4..000000000 --- a/src/core/file_sys/archive_sdmc.cpp +++ /dev/null | |||
| @@ -1,379 +0,0 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <memory> | ||
| 7 | #include "common/file_util.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/file_sys/archive_sdmc.h" | ||
| 10 | #include "core/file_sys/disk_archive.h" | ||
| 11 | #include "core/file_sys/errors.h" | ||
| 12 | #include "core/file_sys/path_parser.h" | ||
| 13 | #include "core/settings.h" | ||
| 14 | |||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 16 | // FileSys namespace | ||
| 17 | |||
| 18 | namespace FileSys { | ||
| 19 | |||
| 20 | ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFile(const Path& path, | ||
| 21 | const Mode& mode) const { | ||
| 22 | Mode modified_mode; | ||
| 23 | modified_mode.hex = mode.hex; | ||
| 24 | |||
| 25 | // SDMC archive always opens a file with at least read permission | ||
| 26 | modified_mode.read_flag.Assign(1); | ||
| 27 | |||
| 28 | return OpenFileBase(path, modified_mode); | ||
| 29 | } | ||
| 30 | |||
| 31 | ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFileBase(const Path& path, | ||
| 32 | const Mode& mode) const { | ||
| 33 | LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); | ||
| 34 | |||
| 35 | const PathParser path_parser(path); | ||
| 36 | |||
| 37 | if (!path_parser.IsValid()) { | ||
| 38 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 39 | return ERROR_INVALID_PATH; | ||
| 40 | } | ||
| 41 | |||
| 42 | if (mode.hex == 0) { | ||
| 43 | LOG_ERROR(Service_FS, "Empty open mode"); | ||
| 44 | return ERROR_INVALID_OPEN_FLAGS; | ||
| 45 | } | ||
| 46 | |||
| 47 | if (mode.create_flag && !mode.write_flag) { | ||
| 48 | LOG_ERROR(Service_FS, "Create flag set but write flag not set"); | ||
| 49 | return ERROR_INVALID_OPEN_FLAGS; | ||
| 50 | } | ||
| 51 | |||
| 52 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 53 | |||
| 54 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 55 | case PathParser::InvalidMountPoint: | ||
| 56 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 57 | return ERROR_NOT_FOUND; | ||
| 58 | case PathParser::PathNotFound: | ||
| 59 | case PathParser::FileInPath: | ||
| 60 | LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); | ||
| 61 | return ERROR_NOT_FOUND; | ||
| 62 | case PathParser::DirectoryFound: | ||
| 63 | LOG_ERROR(Service_FS, "%s is not a file", full_path.c_str()); | ||
| 64 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC; | ||
| 65 | case PathParser::NotFound: | ||
| 66 | if (!mode.create_flag) { | ||
| 67 | LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", | ||
| 68 | full_path.c_str()); | ||
| 69 | return ERROR_NOT_FOUND; | ||
| 70 | } else { | ||
| 71 | // Create the file | ||
| 72 | FileUtil::CreateEmptyFile(full_path); | ||
| 73 | } | ||
| 74 | break; | ||
| 75 | case PathParser::FileFound: | ||
| 76 | break; // Expected 'success' case | ||
| 77 | } | ||
| 78 | |||
| 79 | FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb"); | ||
| 80 | if (!file.IsOpen()) { | ||
| 81 | LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); | ||
| 82 | return ERROR_NOT_FOUND; | ||
| 83 | } | ||
| 84 | |||
| 85 | auto disk_file = std::make_unique<DiskFile>(std::move(file), mode); | ||
| 86 | return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file)); | ||
| 87 | } | ||
| 88 | |||
| 89 | ResultCode SDMCArchive::DeleteFile(const Path& path) const { | ||
| 90 | const PathParser path_parser(path); | ||
| 91 | |||
| 92 | if (!path_parser.IsValid()) { | ||
| 93 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 94 | return ERROR_INVALID_PATH; | ||
| 95 | } | ||
| 96 | |||
| 97 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 98 | |||
| 99 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 100 | case PathParser::InvalidMountPoint: | ||
| 101 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 102 | return ERROR_NOT_FOUND; | ||
| 103 | case PathParser::PathNotFound: | ||
| 104 | case PathParser::FileInPath: | ||
| 105 | case PathParser::NotFound: | ||
| 106 | LOG_ERROR(Service_FS, "%s not found", full_path.c_str()); | ||
| 107 | return ERROR_NOT_FOUND; | ||
| 108 | case PathParser::DirectoryFound: | ||
| 109 | LOG_ERROR(Service_FS, "%s is not a file", full_path.c_str()); | ||
| 110 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC; | ||
| 111 | case PathParser::FileFound: | ||
| 112 | break; // Expected 'success' case | ||
| 113 | } | ||
| 114 | |||
| 115 | if (FileUtil::Delete(full_path)) { | ||
| 116 | return RESULT_SUCCESS; | ||
| 117 | } | ||
| 118 | |||
| 119 | LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str()); | ||
| 120 | return ERROR_NOT_FOUND; | ||
| 121 | } | ||
| 122 | |||
| 123 | ResultCode SDMCArchive::RenameFile(const Path& src_path, const Path& dest_path) const { | ||
| 124 | const PathParser path_parser_src(src_path); | ||
| 125 | |||
| 126 | // TODO: Verify these return codes with HW | ||
| 127 | if (!path_parser_src.IsValid()) { | ||
| 128 | LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); | ||
| 129 | return ERROR_INVALID_PATH; | ||
| 130 | } | ||
| 131 | |||
| 132 | const PathParser path_parser_dest(dest_path); | ||
| 133 | |||
| 134 | if (!path_parser_dest.IsValid()) { | ||
| 135 | LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); | ||
| 136 | return ERROR_INVALID_PATH; | ||
| 137 | } | ||
| 138 | |||
| 139 | const auto src_path_full = path_parser_src.BuildHostPath(mount_point); | ||
| 140 | const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); | ||
| 141 | |||
| 142 | if (FileUtil::Rename(src_path_full, dest_path_full)) { | ||
| 143 | return RESULT_SUCCESS; | ||
| 144 | } | ||
| 145 | |||
| 146 | // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't | ||
| 147 | // exist or similar. Verify. | ||
| 148 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 149 | ErrorSummary::NothingHappened, ErrorLevel::Status); | ||
| 150 | } | ||
| 151 | |||
| 152 | template <typename T> | ||
| 153 | static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point, | ||
| 154 | T deleter) { | ||
| 155 | const PathParser path_parser(path); | ||
| 156 | |||
| 157 | if (!path_parser.IsValid()) { | ||
| 158 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 159 | return ERROR_INVALID_PATH; | ||
| 160 | } | ||
| 161 | |||
| 162 | if (path_parser.IsRootDirectory()) | ||
| 163 | return ERROR_NOT_FOUND; | ||
| 164 | |||
| 165 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 166 | |||
| 167 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 168 | case PathParser::InvalidMountPoint: | ||
| 169 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 170 | return ERROR_NOT_FOUND; | ||
| 171 | case PathParser::PathNotFound: | ||
| 172 | case PathParser::NotFound: | ||
| 173 | LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); | ||
| 174 | return ERROR_NOT_FOUND; | ||
| 175 | case PathParser::FileInPath: | ||
| 176 | case PathParser::FileFound: | ||
| 177 | LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); | ||
| 178 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC; | ||
| 179 | case PathParser::DirectoryFound: | ||
| 180 | break; // Expected 'success' case | ||
| 181 | } | ||
| 182 | |||
| 183 | if (deleter(full_path)) { | ||
| 184 | return RESULT_SUCCESS; | ||
| 185 | } | ||
| 186 | |||
| 187 | LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str()); | ||
| 188 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC; | ||
| 189 | } | ||
| 190 | |||
| 191 | ResultCode SDMCArchive::DeleteDirectory(const Path& path) const { | ||
| 192 | return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir); | ||
| 193 | } | ||
| 194 | |||
| 195 | ResultCode SDMCArchive::DeleteDirectoryRecursively(const Path& path) const { | ||
| 196 | return DeleteDirectoryHelper( | ||
| 197 | path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); }); | ||
| 198 | } | ||
| 199 | |||
| 200 | ResultCode SDMCArchive::CreateFile(const FileSys::Path& path, u64 size) const { | ||
| 201 | const PathParser path_parser(path); | ||
| 202 | |||
| 203 | if (!path_parser.IsValid()) { | ||
| 204 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 205 | return ERROR_INVALID_PATH; | ||
| 206 | } | ||
| 207 | |||
| 208 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 209 | |||
| 210 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 211 | case PathParser::InvalidMountPoint: | ||
| 212 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 213 | return ERROR_NOT_FOUND; | ||
| 214 | case PathParser::PathNotFound: | ||
| 215 | case PathParser::FileInPath: | ||
| 216 | LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); | ||
| 217 | return ERROR_NOT_FOUND; | ||
| 218 | case PathParser::DirectoryFound: | ||
| 219 | LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); | ||
| 220 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC; | ||
| 221 | case PathParser::FileFound: | ||
| 222 | LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); | ||
| 223 | return ERROR_ALREADY_EXISTS; | ||
| 224 | case PathParser::NotFound: | ||
| 225 | break; // Expected 'success' case | ||
| 226 | } | ||
| 227 | |||
| 228 | if (size == 0) { | ||
| 229 | FileUtil::CreateEmptyFile(full_path); | ||
| 230 | return RESULT_SUCCESS; | ||
| 231 | } | ||
| 232 | |||
| 233 | FileUtil::IOFile file(full_path, "wb"); | ||
| 234 | // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) | ||
| 235 | // We do this by seeking to the right size, then writing a single null byte. | ||
| 236 | if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) { | ||
| 237 | return RESULT_SUCCESS; | ||
| 238 | } | ||
| 239 | |||
| 240 | LOG_ERROR(Service_FS, "Too large file"); | ||
| 241 | return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, | ||
| 242 | ErrorLevel::Info); | ||
| 243 | } | ||
| 244 | |||
| 245 | ResultCode SDMCArchive::CreateDirectory(const Path& path) const { | ||
| 246 | const PathParser path_parser(path); | ||
| 247 | |||
| 248 | if (!path_parser.IsValid()) { | ||
| 249 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 250 | return ERROR_INVALID_PATH; | ||
| 251 | } | ||
| 252 | |||
| 253 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 254 | |||
| 255 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 256 | case PathParser::InvalidMountPoint: | ||
| 257 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 258 | return ERROR_NOT_FOUND; | ||
| 259 | case PathParser::PathNotFound: | ||
| 260 | case PathParser::FileInPath: | ||
| 261 | LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); | ||
| 262 | return ERROR_NOT_FOUND; | ||
| 263 | case PathParser::DirectoryFound: | ||
| 264 | case PathParser::FileFound: | ||
| 265 | LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); | ||
| 266 | return ERROR_ALREADY_EXISTS; | ||
| 267 | case PathParser::NotFound: | ||
| 268 | break; // Expected 'success' case | ||
| 269 | } | ||
| 270 | |||
| 271 | if (FileUtil::CreateDir(mount_point + path.AsString())) { | ||
| 272 | return RESULT_SUCCESS; | ||
| 273 | } | ||
| 274 | |||
| 275 | LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str()); | ||
| 276 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled, | ||
| 277 | ErrorLevel::Status); | ||
| 278 | } | ||
| 279 | |||
| 280 | ResultCode SDMCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { | ||
| 281 | const PathParser path_parser_src(src_path); | ||
| 282 | |||
| 283 | // TODO: Verify these return codes with HW | ||
| 284 | if (!path_parser_src.IsValid()) { | ||
| 285 | LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); | ||
| 286 | return ERROR_INVALID_PATH; | ||
| 287 | } | ||
| 288 | |||
| 289 | const PathParser path_parser_dest(dest_path); | ||
| 290 | |||
| 291 | if (!path_parser_dest.IsValid()) { | ||
| 292 | LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); | ||
| 293 | return ERROR_INVALID_PATH; | ||
| 294 | } | ||
| 295 | |||
| 296 | const auto src_path_full = path_parser_src.BuildHostPath(mount_point); | ||
| 297 | const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); | ||
| 298 | |||
| 299 | if (FileUtil::Rename(src_path_full, dest_path_full)) { | ||
| 300 | return RESULT_SUCCESS; | ||
| 301 | } | ||
| 302 | |||
| 303 | // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't | ||
| 304 | // exist or similar. Verify. | ||
| 305 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 306 | ErrorSummary::NothingHappened, ErrorLevel::Status); | ||
| 307 | } | ||
| 308 | |||
| 309 | ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Path& path) const { | ||
| 310 | const PathParser path_parser(path); | ||
| 311 | |||
| 312 | if (!path_parser.IsValid()) { | ||
| 313 | LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); | ||
| 314 | return ERROR_INVALID_PATH; | ||
| 315 | } | ||
| 316 | |||
| 317 | const auto full_path = path_parser.BuildHostPath(mount_point); | ||
| 318 | |||
| 319 | switch (path_parser.GetHostStatus(mount_point)) { | ||
| 320 | case PathParser::InvalidMountPoint: | ||
| 321 | LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); | ||
| 322 | return ERROR_NOT_FOUND; | ||
| 323 | case PathParser::PathNotFound: | ||
| 324 | case PathParser::NotFound: | ||
| 325 | case PathParser::FileFound: | ||
| 326 | LOG_ERROR(Service_FS, "%s not found", full_path.c_str()); | ||
| 327 | return ERROR_NOT_FOUND; | ||
| 328 | case PathParser::FileInPath: | ||
| 329 | LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); | ||
| 330 | return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC; | ||
| 331 | case PathParser::DirectoryFound: | ||
| 332 | break; // Expected 'success' case | ||
| 333 | } | ||
| 334 | |||
| 335 | auto directory = std::make_unique<DiskDirectory>(full_path); | ||
| 336 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory)); | ||
| 337 | } | ||
| 338 | |||
| 339 | u64 SDMCArchive::GetFreeBytes() const { | ||
| 340 | // TODO: Stubbed to return 1GiB | ||
| 341 | return 1024 * 1024 * 1024; | ||
| 342 | } | ||
| 343 | |||
| 344 | ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory) | ||
| 345 | : sdmc_directory(sdmc_directory) { | ||
| 346 | LOG_DEBUG(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str()); | ||
| 347 | } | ||
| 348 | |||
| 349 | bool ArchiveFactory_SDMC::Initialize() { | ||
| 350 | if (!Settings::values.use_virtual_sd) { | ||
| 351 | LOG_WARNING(Service_FS, "SDMC disabled by config."); | ||
| 352 | return false; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (!FileUtil::CreateFullPath(sdmc_directory)) { | ||
| 356 | LOG_ERROR(Service_FS, "Unable to create SDMC path."); | ||
| 357 | return false; | ||
| 358 | } | ||
| 359 | |||
| 360 | return true; | ||
| 361 | } | ||
| 362 | |||
| 363 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path) { | ||
| 364 | auto archive = std::make_unique<SDMCArchive>(sdmc_directory); | ||
| 365 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 366 | } | ||
| 367 | |||
| 368 | ResultCode ArchiveFactory_SDMC::Format(const Path& path, | ||
| 369 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 370 | // This is kind of an undesirable operation, so let's just ignore it. :) | ||
| 371 | return RESULT_SUCCESS; | ||
| 372 | } | ||
| 373 | |||
| 374 | ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path) const { | ||
| 375 | // TODO(Subv): Implement | ||
| 376 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||
| 377 | return ResultCode(-1); | ||
| 378 | } | ||
| 379 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h deleted file mode 100644 index f6c70bfcc..000000000 --- a/src/core/file_sys/archive_sdmc.h +++ /dev/null | |||
| @@ -1,66 +0,0 @@ | |||
| 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "core/file_sys/archive_backend.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// Archive backend for SDMC archive | ||
| 18 | class SDMCArchive : public ArchiveBackend { | ||
| 19 | public: | ||
| 20 | explicit SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {} | ||
| 21 | |||
| 22 | std::string GetName() const override { | ||
| 23 | return "SDMCArchive: " + mount_point; | ||
| 24 | } | ||
| 25 | |||
| 26 | ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, | ||
| 27 | const Mode& mode) const override; | ||
| 28 | ResultCode DeleteFile(const Path& path) const override; | ||
| 29 | ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; | ||
| 30 | ResultCode DeleteDirectory(const Path& path) const override; | ||
| 31 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; | ||
| 32 | ResultCode CreateFile(const Path& path, u64 size) const override; | ||
| 33 | ResultCode CreateDirectory(const Path& path) const override; | ||
| 34 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | ||
| 35 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; | ||
| 36 | u64 GetFreeBytes() const override; | ||
| 37 | |||
| 38 | protected: | ||
| 39 | ResultVal<std::unique_ptr<FileBackend>> OpenFileBase(const Path& path, const Mode& mode) const; | ||
| 40 | std::string mount_point; | ||
| 41 | }; | ||
| 42 | |||
| 43 | /// File system interface to the SDMC archive | ||
| 44 | class ArchiveFactory_SDMC final : public ArchiveFactory { | ||
| 45 | public: | ||
| 46 | explicit ArchiveFactory_SDMC(const std::string& mount_point); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Initialize the archive. | ||
| 50 | * @return true if it initialized successfully | ||
| 51 | */ | ||
| 52 | bool Initialize(); | ||
| 53 | |||
| 54 | std::string GetName() const override { | ||
| 55 | return "SDMC"; | ||
| 56 | } | ||
| 57 | |||
| 58 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 59 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 60 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 61 | |||
| 62 | private: | ||
| 63 | std::string sdmc_directory; | ||
| 64 | }; | ||
| 65 | |||
| 66 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp deleted file mode 100644 index 244aef48a..000000000 --- a/src/core/file_sys/archive_sdmcwriteonly.cpp +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include "common/file_util.h" | ||
| 7 | #include "core/file_sys/archive_sdmcwriteonly.h" | ||
| 8 | #include "core/file_sys/directory_backend.h" | ||
| 9 | #include "core/file_sys/errors.h" | ||
| 10 | #include "core/file_sys/file_backend.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | ResultVal<std::unique_ptr<FileBackend>> SDMCWriteOnlyArchive::OpenFile(const Path& path, | ||
| 19 | const Mode& mode) const { | ||
| 20 | if (mode.read_flag) { | ||
| 21 | LOG_ERROR(Service_FS, "Read flag is not supported"); | ||
| 22 | return ERROR_INVALID_READ_FLAG; | ||
| 23 | } | ||
| 24 | return SDMCArchive::OpenFileBase(path, mode); | ||
| 25 | } | ||
| 26 | |||
| 27 | ResultVal<std::unique_ptr<DirectoryBackend>> SDMCWriteOnlyArchive::OpenDirectory( | ||
| 28 | const Path& path) const { | ||
| 29 | LOG_ERROR(Service_FS, "Not supported"); | ||
| 30 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 31 | } | ||
| 32 | |||
| 33 | ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point) | ||
| 34 | : sdmc_directory(mount_point) { | ||
| 35 | LOG_DEBUG(Service_FS, "Directory %s set as SDMCWriteOnly.", sdmc_directory.c_str()); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool ArchiveFactory_SDMCWriteOnly::Initialize() { | ||
| 39 | if (!Settings::values.use_virtual_sd) { | ||
| 40 | LOG_WARNING(Service_FS, "SDMC disabled by config."); | ||
| 41 | return false; | ||
| 42 | } | ||
| 43 | |||
| 44 | if (!FileUtil::CreateFullPath(sdmc_directory)) { | ||
| 45 | LOG_ERROR(Service_FS, "Unable to create SDMC path."); | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | return true; | ||
| 50 | } | ||
| 51 | |||
| 52 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMCWriteOnly::Open(const Path& path) { | ||
| 53 | auto archive = std::make_unique<SDMCWriteOnlyArchive>(sdmc_directory); | ||
| 54 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 55 | } | ||
| 56 | |||
| 57 | ResultCode ArchiveFactory_SDMCWriteOnly::Format(const Path& path, | ||
| 58 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 59 | // TODO(wwylele): hwtest this | ||
| 60 | LOG_ERROR(Service_FS, "Attempted to format a SDMC write-only archive."); | ||
| 61 | return ResultCode(-1); | ||
| 62 | } | ||
| 63 | |||
| 64 | ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const Path& path) const { | ||
| 65 | // TODO(Subv): Implement | ||
| 66 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||
| 67 | return ResultCode(-1); | ||
| 68 | } | ||
| 69 | |||
| 70 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h deleted file mode 100644 index 9cd38d96f..000000000 --- a/src/core/file_sys/archive_sdmcwriteonly.h +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | // Copyright 2016 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 "core/file_sys/archive_sdmc.h" | ||
| 8 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 10 | // FileSys namespace | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Archive backend for SDMC write-only archive. | ||
| 16 | * The behaviour of SDMCWriteOnlyArchive is almost the same as SDMCArchive, except for | ||
| 17 | * - OpenDirectory is unsupported; | ||
| 18 | * - OpenFile with read flag is unsupported. | ||
| 19 | */ | ||
| 20 | class SDMCWriteOnlyArchive : public SDMCArchive { | ||
| 21 | public: | ||
| 22 | explicit SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {} | ||
| 23 | |||
| 24 | std::string GetName() const override { | ||
| 25 | return "SDMCWriteOnlyArchive: " + mount_point; | ||
| 26 | } | ||
| 27 | |||
| 28 | ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, | ||
| 29 | const Mode& mode) const override; | ||
| 30 | |||
| 31 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; | ||
| 32 | }; | ||
| 33 | |||
| 34 | /// File system interface to the SDMC write-only archive | ||
| 35 | class ArchiveFactory_SDMCWriteOnly final : public ArchiveFactory { | ||
| 36 | public: | ||
| 37 | explicit ArchiveFactory_SDMCWriteOnly(const std::string& mount_point); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Initialize the archive. | ||
| 41 | * @return true if it initialized successfully | ||
| 42 | */ | ||
| 43 | bool Initialize(); | ||
| 44 | |||
| 45 | std::string GetName() const override { | ||
| 46 | return "SDMCWriteOnly"; | ||
| 47 | } | ||
| 48 | |||
| 49 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 50 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 51 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 52 | |||
| 53 | private: | ||
| 54 | std::string sdmc_directory; | ||
| 55 | }; | ||
| 56 | |||
| 57 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp deleted file mode 100644 index 3222000cf..000000000 --- a/src/core/file_sys/archive_selfncch.cpp +++ /dev/null | |||
| @@ -1,297 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <cinttypes> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/file_sys/archive_selfncch.h" | ||
| 11 | #include "core/file_sys/errors.h" | ||
| 12 | #include "core/file_sys/ivfc_archive.h" | ||
| 13 | #include "core/hle/kernel/process.h" | ||
| 14 | |||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 16 | // FileSys namespace | ||
| 17 | |||
| 18 | namespace FileSys { | ||
| 19 | |||
| 20 | enum class SelfNCCHFilePathType : u32 { | ||
| 21 | RomFS = 0, | ||
| 22 | Code = 1, // This is not supported by SelfNCCHArchive but by archive 0x2345678E | ||
| 23 | ExeFS = 2, | ||
| 24 | UpdateRomFS = 5, // This is presumably for accessing the RomFS of the update patch. | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct SelfNCCHFilePath { | ||
| 28 | u32_le type; | ||
| 29 | std::array<char, 8> exefs_filename; | ||
| 30 | }; | ||
| 31 | static_assert(sizeof(SelfNCCHFilePath) == 12, "NCCHFilePath has wrong size!"); | ||
| 32 | |||
| 33 | // A read-only file created from a block of data. It only allows you to read the entire file at | ||
| 34 | // once, in a single read operation. | ||
| 35 | class ExeFSSectionFile final : public FileBackend { | ||
| 36 | public: | ||
| 37 | explicit ExeFSSectionFile(std::shared_ptr<std::vector<u8>> data_) : data(std::move(data_)) {} | ||
| 38 | |||
| 39 | ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override { | ||
| 40 | if (offset != 0) { | ||
| 41 | LOG_ERROR(Service_FS, "offset must be zero!"); | ||
| 42 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 43 | } | ||
| 44 | |||
| 45 | if (length != data->size()) { | ||
| 46 | LOG_ERROR(Service_FS, "size must match the file size!"); | ||
| 47 | return ERROR_INCORRECT_EXEFS_READ_SIZE; | ||
| 48 | } | ||
| 49 | |||
| 50 | std::memcpy(buffer, data->data(), data->size()); | ||
| 51 | return MakeResult<size_t>(data->size()); | ||
| 52 | } | ||
| 53 | |||
| 54 | ResultVal<size_t> Write(u64 offset, size_t length, bool flush, | ||
| 55 | const u8* buffer) const override { | ||
| 56 | LOG_ERROR(Service_FS, "The file is read-only!"); | ||
| 57 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 58 | } | ||
| 59 | |||
| 60 | u64 GetSize() const override { | ||
| 61 | return data->size(); | ||
| 62 | } | ||
| 63 | |||
| 64 | bool SetSize(u64 size) const override { | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | |||
| 68 | bool Close() const override { | ||
| 69 | return true; | ||
| 70 | } | ||
| 71 | |||
| 72 | void Flush() const override {} | ||
| 73 | |||
| 74 | private: | ||
| 75 | std::shared_ptr<std::vector<u8>> data; | ||
| 76 | }; | ||
| 77 | |||
| 78 | // SelfNCCHArchive represents the running application itself. From this archive the application can | ||
| 79 | // open RomFS and ExeFS, excluding the .code section. | ||
| 80 | class SelfNCCHArchive final : public ArchiveBackend { | ||
| 81 | public: | ||
| 82 | explicit SelfNCCHArchive(const NCCHData& ncch_data_) : ncch_data(ncch_data_) {} | ||
| 83 | |||
| 84 | std::string GetName() const override { | ||
| 85 | return "SelfNCCHArchive"; | ||
| 86 | } | ||
| 87 | |||
| 88 | ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode&) const override { | ||
| 89 | // Note: SelfNCCHArchive doesn't check the open mode. | ||
| 90 | |||
| 91 | if (path.GetType() != LowPathType::Binary) { | ||
| 92 | LOG_ERROR(Service_FS, "Path need to be Binary"); | ||
| 93 | return ERROR_INVALID_PATH; | ||
| 94 | } | ||
| 95 | |||
| 96 | std::vector<u8> binary = path.AsBinary(); | ||
| 97 | if (binary.size() != sizeof(SelfNCCHFilePath)) { | ||
| 98 | LOG_ERROR(Service_FS, "Wrong path size %zu", binary.size()); | ||
| 99 | return ERROR_INVALID_PATH; | ||
| 100 | } | ||
| 101 | |||
| 102 | SelfNCCHFilePath file_path; | ||
| 103 | std::memcpy(&file_path, binary.data(), sizeof(SelfNCCHFilePath)); | ||
| 104 | |||
| 105 | switch (static_cast<SelfNCCHFilePathType>(file_path.type)) { | ||
| 106 | case SelfNCCHFilePathType::UpdateRomFS: | ||
| 107 | return OpenUpdateRomFS(); | ||
| 108 | |||
| 109 | case SelfNCCHFilePathType::RomFS: | ||
| 110 | return OpenRomFS(); | ||
| 111 | |||
| 112 | case SelfNCCHFilePathType::Code: | ||
| 113 | LOG_ERROR(Service_FS, "Reading the code section is not supported!"); | ||
| 114 | return ERROR_COMMAND_NOT_ALLOWED; | ||
| 115 | |||
| 116 | case SelfNCCHFilePathType::ExeFS: { | ||
| 117 | const auto& raw = file_path.exefs_filename; | ||
| 118 | auto end = std::find(raw.begin(), raw.end(), '\0'); | ||
| 119 | std::string filename(raw.begin(), end); | ||
| 120 | return OpenExeFS(filename); | ||
| 121 | } | ||
| 122 | default: | ||
| 123 | LOG_ERROR(Service_FS, "Unknown file type %u!", static_cast<u32>(file_path.type)); | ||
| 124 | return ERROR_INVALID_PATH; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | ResultCode DeleteFile(const Path& path) const override { | ||
| 129 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 130 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 131 | } | ||
| 132 | |||
| 133 | ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override { | ||
| 134 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 135 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 136 | } | ||
| 137 | |||
| 138 | ResultCode DeleteDirectory(const Path& path) const override { | ||
| 139 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 140 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 141 | } | ||
| 142 | |||
| 143 | ResultCode DeleteDirectoryRecursively(const Path& path) const override { | ||
| 144 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 145 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 146 | } | ||
| 147 | |||
| 148 | ResultCode CreateFile(const Path& path, u64 size) const override { | ||
| 149 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 150 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 151 | } | ||
| 152 | |||
| 153 | ResultCode CreateDirectory(const Path& path) const override { | ||
| 154 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 155 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 156 | } | ||
| 157 | |||
| 158 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override { | ||
| 159 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 160 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 161 | } | ||
| 162 | |||
| 163 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override { | ||
| 164 | LOG_ERROR(Service_FS, "Unsupported"); | ||
| 165 | return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||
| 166 | } | ||
| 167 | |||
| 168 | u64 GetFreeBytes() const override { | ||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | private: | ||
| 173 | ResultVal<std::unique_ptr<FileBackend>> OpenRomFS() const { | ||
| 174 | if (ncch_data.romfs_file) { | ||
| 175 | return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>( | ||
| 176 | ncch_data.romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size)); | ||
| 177 | } else { | ||
| 178 | LOG_INFO(Service_FS, "Unable to read RomFS"); | ||
| 179 | return ERROR_ROMFS_NOT_FOUND; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | ResultVal<std::unique_ptr<FileBackend>> OpenUpdateRomFS() const { | ||
| 184 | if (ncch_data.update_romfs_file) { | ||
| 185 | return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>( | ||
| 186 | ncch_data.update_romfs_file, ncch_data.update_romfs_offset, | ||
| 187 | ncch_data.update_romfs_size)); | ||
| 188 | } else { | ||
| 189 | LOG_INFO(Service_FS, "Unable to read update RomFS"); | ||
| 190 | return ERROR_ROMFS_NOT_FOUND; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | ResultVal<std::unique_ptr<FileBackend>> OpenExeFS(const std::string& filename) const { | ||
| 195 | if (filename == "icon") { | ||
| 196 | if (ncch_data.icon) { | ||
| 197 | return MakeResult<std::unique_ptr<FileBackend>>( | ||
| 198 | std::make_unique<ExeFSSectionFile>(ncch_data.icon)); | ||
| 199 | } | ||
| 200 | |||
| 201 | LOG_WARNING(Service_FS, "Unable to read icon"); | ||
| 202 | return ERROR_EXEFS_SECTION_NOT_FOUND; | ||
| 203 | } | ||
| 204 | |||
| 205 | if (filename == "logo") { | ||
| 206 | if (ncch_data.logo) { | ||
| 207 | return MakeResult<std::unique_ptr<FileBackend>>( | ||
| 208 | std::make_unique<ExeFSSectionFile>(ncch_data.logo)); | ||
| 209 | } | ||
| 210 | |||
| 211 | LOG_WARNING(Service_FS, "Unable to read logo"); | ||
| 212 | return ERROR_EXEFS_SECTION_NOT_FOUND; | ||
| 213 | } | ||
| 214 | |||
| 215 | if (filename == "banner") { | ||
| 216 | if (ncch_data.banner) { | ||
| 217 | return MakeResult<std::unique_ptr<FileBackend>>( | ||
| 218 | std::make_unique<ExeFSSectionFile>(ncch_data.banner)); | ||
| 219 | } | ||
| 220 | |||
| 221 | LOG_WARNING(Service_FS, "Unable to read banner"); | ||
| 222 | return ERROR_EXEFS_SECTION_NOT_FOUND; | ||
| 223 | } | ||
| 224 | |||
| 225 | LOG_ERROR(Service_FS, "Unknown ExeFS section %s!", filename.c_str()); | ||
| 226 | return ERROR_INVALID_PATH; | ||
| 227 | } | ||
| 228 | |||
| 229 | NCCHData ncch_data; | ||
| 230 | }; | ||
| 231 | |||
| 232 | void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) { | ||
| 233 | u64 program_id = 0; | ||
| 234 | if (app_loader.ReadProgramId(program_id) != Loader::ResultStatus::Success) { | ||
| 235 | LOG_WARNING( | ||
| 236 | Service_FS, | ||
| 237 | "Could not read program id when registering with SelfNCCH, this might be a 3dsx file"); | ||
| 238 | } | ||
| 239 | |||
| 240 | LOG_DEBUG(Service_FS, "Registering program %016" PRIX64 " with the SelfNCCH archive factory", | ||
| 241 | program_id); | ||
| 242 | |||
| 243 | if (ncch_data.find(program_id) != ncch_data.end()) { | ||
| 244 | LOG_WARNING(Service_FS, "Registering program %016" PRIX64 | ||
| 245 | " with SelfNCCH will override existing mapping", | ||
| 246 | program_id); | ||
| 247 | } | ||
| 248 | |||
| 249 | NCCHData& data = ncch_data[program_id]; | ||
| 250 | |||
| 251 | std::shared_ptr<FileUtil::IOFile> romfs_file_; | ||
| 252 | if (Loader::ResultStatus::Success == | ||
| 253 | app_loader.ReadRomFS(romfs_file_, data.romfs_offset, data.romfs_size)) { | ||
| 254 | |||
| 255 | data.romfs_file = std::move(romfs_file_); | ||
| 256 | } | ||
| 257 | |||
| 258 | std::shared_ptr<FileUtil::IOFile> update_romfs_file; | ||
| 259 | if (Loader::ResultStatus::Success == | ||
| 260 | app_loader.ReadUpdateRomFS(update_romfs_file, data.update_romfs_offset, | ||
| 261 | data.update_romfs_size)) { | ||
| 262 | |||
| 263 | data.update_romfs_file = std::move(update_romfs_file); | ||
| 264 | } | ||
| 265 | |||
| 266 | std::vector<u8> buffer; | ||
| 267 | |||
| 268 | if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer)) | ||
| 269 | data.icon = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||
| 270 | |||
| 271 | buffer.clear(); | ||
| 272 | if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer)) | ||
| 273 | data.logo = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||
| 274 | |||
| 275 | buffer.clear(); | ||
| 276 | if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer)) | ||
| 277 | data.banner = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||
| 278 | } | ||
| 279 | |||
| 280 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) { | ||
| 281 | //auto archive = std::make_unique<SelfNCCHArchive>( | ||
| 282 | // ncch_data[Kernel::g_current_process->codeset->program_id]); | ||
| 283 | //return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 284 | return {}; | ||
| 285 | } | ||
| 286 | |||
| 287 | ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) { | ||
| 288 | LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive."); | ||
| 289 | return ERROR_INVALID_PATH; | ||
| 290 | } | ||
| 291 | |||
| 292 | ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&) const { | ||
| 293 | LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive"); | ||
| 294 | return ERROR_INVALID_PATH; | ||
| 295 | } | ||
| 296 | |||
| 297 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h deleted file mode 100644 index 0d6d6766e..000000000 --- a/src/core/file_sys/archive_selfncch.h +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | // Copyright 2017 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | #include <unordered_map> | ||
| 10 | #include <vector> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "core/file_sys/archive_backend.h" | ||
| 13 | #include "core/hle/result.h" | ||
| 14 | #include "core/loader/loader.h" | ||
| 15 | |||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 17 | // FileSys namespace | ||
| 18 | |||
| 19 | namespace FileSys { | ||
| 20 | |||
| 21 | struct NCCHData { | ||
| 22 | std::shared_ptr<std::vector<u8>> icon; | ||
| 23 | std::shared_ptr<std::vector<u8>> logo; | ||
| 24 | std::shared_ptr<std::vector<u8>> banner; | ||
| 25 | std::shared_ptr<FileUtil::IOFile> romfs_file; | ||
| 26 | u64 romfs_offset = 0; | ||
| 27 | u64 romfs_size = 0; | ||
| 28 | |||
| 29 | std::shared_ptr<FileUtil::IOFile> update_romfs_file; | ||
| 30 | u64 update_romfs_offset = 0; | ||
| 31 | u64 update_romfs_size = 0; | ||
| 32 | }; | ||
| 33 | |||
| 34 | /// File system interface to the SelfNCCH archive | ||
| 35 | class ArchiveFactory_SelfNCCH final : public ArchiveFactory { | ||
| 36 | public: | ||
| 37 | ArchiveFactory_SelfNCCH() = default; | ||
| 38 | |||
| 39 | /// Registers a loaded application so that we can open its SelfNCCH archive when requested. | ||
| 40 | void Register(Loader::AppLoader& app_loader); | ||
| 41 | |||
| 42 | std::string GetName() const override { | ||
| 43 | return "SelfNCCH"; | ||
| 44 | } | ||
| 45 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 46 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 47 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 48 | |||
| 49 | private: | ||
| 50 | /// Mapping of ProgramId -> NCCHData | ||
| 51 | std::unordered_map<u64, NCCHData> ncch_data; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp deleted file mode 100644 index a7e331724..000000000 --- a/src/core/file_sys/archive_source_sd_savedata.cpp +++ /dev/null | |||
| @@ -1,97 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/file_util.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | #include "core/file_sys/archive_source_sd_savedata.h" | ||
| 9 | #include "core/file_sys/errors.h" | ||
| 10 | #include "core/file_sys/savedata_archive.h" | ||
| 11 | #include "core/hle/service/fs/archive.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | namespace { | ||
| 19 | |||
| 20 | std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { | ||
| 21 | return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), | ||
| 22 | SYSTEM_ID, SDCARD_ID); | ||
| 23 | } | ||
| 24 | |||
| 25 | std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) { | ||
| 26 | u32 high = static_cast<u32>(program_id >> 32); | ||
| 27 | u32 low = static_cast<u32>(program_id & 0xFFFFFFFF); | ||
| 28 | return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, | ||
| 29 | low); | ||
| 30 | } | ||
| 31 | |||
| 32 | std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) { | ||
| 33 | u32 high = static_cast<u32>(program_id >> 32); | ||
| 34 | u32 low = static_cast<u32>(program_id & 0xFFFFFFFF); | ||
| 35 | return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(), | ||
| 36 | high, low); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace | ||
| 40 | |||
| 41 | ArchiveSource_SDSaveData::ArchiveSource_SDSaveData(const std::string& sdmc_directory) | ||
| 42 | : mount_point(GetSaveDataContainerPath(sdmc_directory)) { | ||
| 43 | LOG_DEBUG(Service_FS, "Directory %s set as SaveData.", mount_point.c_str()); | ||
| 44 | } | ||
| 45 | |||
| 46 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 program_id) { | ||
| 47 | std::string concrete_mount_point = GetSaveDataPath(mount_point, program_id); | ||
| 48 | if (!FileUtil::Exists(concrete_mount_point)) { | ||
| 49 | // When a SaveData archive is created for the first time, it is not yet formatted and the | ||
| 50 | // save file/directory structure expected by the game has not yet been initialized. | ||
| 51 | // Returning the NotFormatted error code will signal the game to provision the SaveData | ||
| 52 | // archive with the files and folders that it expects. | ||
| 53 | return ERR_NOT_FORMATTED; | ||
| 54 | } | ||
| 55 | |||
| 56 | auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point)); | ||
| 57 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 58 | } | ||
| 59 | |||
| 60 | ResultCode ArchiveSource_SDSaveData::Format(u64 program_id, | ||
| 61 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 62 | std::string concrete_mount_point = GetSaveDataPath(mount_point, program_id); | ||
| 63 | FileUtil::DeleteDirRecursively(concrete_mount_point); | ||
| 64 | FileUtil::CreateFullPath(concrete_mount_point); | ||
| 65 | |||
| 66 | // Write the format metadata | ||
| 67 | std::string metadata_path = GetSaveDataMetadataPath(mount_point, program_id); | ||
| 68 | FileUtil::IOFile file(metadata_path, "wb"); | ||
| 69 | |||
| 70 | if (file.IsOpen()) { | ||
| 71 | file.WriteBytes(&format_info, sizeof(format_info)); | ||
| 72 | return RESULT_SUCCESS; | ||
| 73 | } | ||
| 74 | return RESULT_SUCCESS; | ||
| 75 | } | ||
| 76 | |||
| 77 | ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program_id) const { | ||
| 78 | std::string metadata_path = GetSaveDataMetadataPath(mount_point, program_id); | ||
| 79 | FileUtil::IOFile file(metadata_path, "rb"); | ||
| 80 | |||
| 81 | if (!file.IsOpen()) { | ||
| 82 | LOG_ERROR(Service_FS, "Could not open metadata information for archive"); | ||
| 83 | // TODO(Subv): Verify error code | ||
| 84 | return ERR_NOT_FORMATTED; | ||
| 85 | } | ||
| 86 | |||
| 87 | ArchiveFormatInfo info = {}; | ||
| 88 | file.ReadBytes(&info, sizeof(info)); | ||
| 89 | return MakeResult<ArchiveFormatInfo>(info); | ||
| 90 | } | ||
| 91 | |||
| 92 | std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point, | ||
| 93 | u64 program_id) { | ||
| 94 | return GetSaveDataPath(GetSaveDataContainerPath(mount_point), program_id); | ||
| 95 | } | ||
| 96 | |||
| 97 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h deleted file mode 100644 index b5fe43cc1..000000000 --- a/src/core/file_sys/archive_source_sd_savedata.h +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2016 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "core/file_sys/archive_backend.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// A common source of SD save data archive | ||
| 18 | class ArchiveSource_SDSaveData { | ||
| 19 | public: | ||
| 20 | explicit ArchiveSource_SDSaveData(const std::string& mount_point); | ||
| 21 | |||
| 22 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(u64 program_id); | ||
| 23 | ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info); | ||
| 24 | ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const; | ||
| 25 | |||
| 26 | static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id); | ||
| 27 | |||
| 28 | private: | ||
| 29 | std::string mount_point; | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp deleted file mode 100644 index 81423bffd..000000000 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ /dev/null | |||
| @@ -1,77 +0,0 @@ | |||
| 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 <algorithm> | ||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/file_util.h" | ||
| 10 | #include "common/string_util.h" | ||
| 11 | #include "core/file_sys/archive_systemsavedata.h" | ||
| 12 | #include "core/file_sys/errors.h" | ||
| 13 | #include "core/file_sys/savedata_archive.h" | ||
| 14 | #include "core/hle/service/fs/archive.h" | ||
| 15 | |||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 17 | // FileSys namespace | ||
| 18 | |||
| 19 | namespace FileSys { | ||
| 20 | |||
| 21 | std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) { | ||
| 22 | std::vector<u8> vec_data = path.AsBinary(); | ||
| 23 | const u32* data = reinterpret_cast<const u32*>(vec_data.data()); | ||
| 24 | u32 save_low = data[1]; | ||
| 25 | u32 save_high = data[0]; | ||
| 26 | return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_low, save_high); | ||
| 27 | } | ||
| 28 | |||
| 29 | std::string GetSystemSaveDataContainerPath(const std::string& mount_point) { | ||
| 30 | return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID); | ||
| 31 | } | ||
| 32 | |||
| 33 | Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) { | ||
| 34 | std::vector<u8> binary_path; | ||
| 35 | binary_path.reserve(8); | ||
| 36 | |||
| 37 | // Append each word byte by byte | ||
| 38 | |||
| 39 | // First is the high word | ||
| 40 | for (unsigned i = 0; i < 4; ++i) | ||
| 41 | binary_path.push_back((high >> (8 * i)) & 0xFF); | ||
| 42 | |||
| 43 | // Next is the low word | ||
| 44 | for (unsigned i = 0; i < 4; ++i) | ||
| 45 | binary_path.push_back((low >> (8 * i)) & 0xFF); | ||
| 46 | |||
| 47 | return {binary_path}; | ||
| 48 | } | ||
| 49 | |||
| 50 | ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path) | ||
| 51 | : base_path(GetSystemSaveDataContainerPath(nand_path)) {} | ||
| 52 | |||
| 53 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(const Path& path) { | ||
| 54 | std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||
| 55 | if (!FileUtil::Exists(fullpath)) { | ||
| 56 | // TODO(Subv): Check error code, this one is probably wrong | ||
| 57 | return ERR_NOT_FORMATTED; | ||
| 58 | } | ||
| 59 | auto archive = std::make_unique<SaveDataArchive>(fullpath); | ||
| 60 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||
| 61 | } | ||
| 62 | |||
| 63 | ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, | ||
| 64 | const FileSys::ArchiveFormatInfo& format_info) { | ||
| 65 | std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||
| 66 | FileUtil::DeleteDirRecursively(fullpath); | ||
| 67 | FileUtil::CreateFullPath(fullpath); | ||
| 68 | return RESULT_SUCCESS; | ||
| 69 | } | ||
| 70 | |||
| 71 | ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path) const { | ||
| 72 | // TODO(Subv): Implement | ||
| 73 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||
| 74 | return ResultCode(-1); | ||
| 75 | } | ||
| 76 | |||
| 77 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h deleted file mode 100644 index 52eb6c630..000000000 --- a/src/core/file_sys/archive_systemsavedata.h +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/archive_backend.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | /// File system interface to the SystemSaveData archive | ||
| 19 | class ArchiveFactory_SystemSaveData final : public ArchiveFactory { | ||
| 20 | public: | ||
| 21 | explicit ArchiveFactory_SystemSaveData(const std::string& mount_point); | ||
| 22 | |||
| 23 | ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||
| 24 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||
| 25 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 26 | |||
| 27 | std::string GetName() const override { | ||
| 28 | return "SystemSaveData"; | ||
| 29 | } | ||
| 30 | |||
| 31 | private: | ||
| 32 | std::string base_path; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Constructs a path to the concrete SystemSaveData archive in the host filesystem based on the | ||
| 37 | * input Path and base mount point. | ||
| 38 | * @param mount_point The base mount point of the SystemSaveData archives. | ||
| 39 | * @param path The path that identifies the requested concrete SystemSaveData archive. | ||
| 40 | * @returns The complete path to the specified SystemSaveData archive in the host filesystem | ||
| 41 | */ | ||
| 42 | std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path); | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Constructs a path to the base folder to hold concrete SystemSaveData archives in the host file | ||
| 46 | * system. | ||
| 47 | * @param mount_point The base folder where this folder resides, ie. SDMC or NAND. | ||
| 48 | * @returns The path to the base SystemSaveData archives' folder in the host file system | ||
| 49 | */ | ||
| 50 | std::string GetSystemSaveDataContainerPath(const std::string& mount_point); | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Constructs a FileSys::Path object that refers to the SystemSaveData archive identified by | ||
| 54 | * the specified high save id and low save id. | ||
| 55 | * @param high The high word of the save id for the archive | ||
| 56 | * @param low The low word of the save id for the archive | ||
| 57 | * @returns A FileSys::Path to the wanted archive | ||
| 58 | */ | ||
| 59 | Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low); | ||
| 60 | |||
| 61 | } // namespace FileSys | ||