diff options
| author | 2018-07-18 21:07:11 -0400 | |
|---|---|---|
| committer | 2018-07-18 18:07:11 -0700 | |
| commit | 29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef (patch) | |
| tree | 3202e2ce55ab6387a4ca366a509eccdd963434c3 /src/core/hle | |
| parent | Merge pull request #683 from DarkLordZach/touch (diff) | |
| download | yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.gz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.tar.xz yuzu-29aff8d5ab46c8d0199aa4bfa7eeff5d4fa2d7ef.zip | |
Virtual Filesystem 2: Electric Boogaloo (#676)
* Virtual Filesystem
* Fix delete bug and documentate
* Review fixes + other stuff
* Fix puyo regression
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/filesystem.cpp | 209 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/filesystem.h | 110 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 177 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.h | 2 |
5 files changed, 383 insertions, 116 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 0f0ab1e6a..97ef07bf9 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <cinttypes> | 5 | #include <cinttypes> |
| 6 | #include <stack> | 6 | #include <stack> |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/file_sys/filesystem.h" | ||
| 9 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 11 | #include "core/hle/kernel/process.h" | 10 | #include "core/hle/kernel/process.h" |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 902256757..ec528ef40 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -2,17 +2,204 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <boost/container/flat_map.hpp> | 5 | #pragma optimize("", off) |
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 6 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "core/core.h" | ||
| 7 | #include "core/file_sys/errors.h" | 10 | #include "core/file_sys/errors.h" |
| 8 | #include "core/file_sys/filesystem.h" | ||
| 9 | #include "core/file_sys/savedata_factory.h" | 11 | #include "core/file_sys/savedata_factory.h" |
| 10 | #include "core/file_sys/sdmc_factory.h" | 12 | #include "core/file_sys/sdmc_factory.h" |
| 13 | #include "core/file_sys/vfs.h" | ||
| 14 | #include "core/file_sys/vfs_offset.h" | ||
| 15 | #include "core/file_sys/vfs_real.h" | ||
| 11 | #include "core/hle/service/filesystem/filesystem.h" | 16 | #include "core/hle/service/filesystem/filesystem.h" |
| 12 | #include "core/hle/service/filesystem/fsp_srv.h" | 17 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 13 | 18 | ||
| 14 | namespace Service::FileSystem { | 19 | namespace Service::FileSystem { |
| 15 | 20 | ||
| 21 | // Size of emulated sd card free space, reported in bytes. | ||
| 22 | // Just using 32GB because thats reasonable | ||
| 23 | // TODO(DarkLordZach): Eventually make this configurable in settings. | ||
| 24 | constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; | ||
| 25 | |||
| 26 | static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, | ||
| 27 | const std::string& dir_name) { | ||
| 28 | if (dir_name == "." || dir_name == "" || dir_name == "/" || dir_name == "\\") | ||
| 29 | return base; | ||
| 30 | |||
| 31 | return base->GetDirectoryRelative(dir_name); | ||
| 32 | } | ||
| 33 | |||
| 34 | VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_) | ||
| 35 | : backing(backing_) {} | ||
| 36 | |||
| 37 | std::string VfsDirectoryServiceWrapper::GetName() const { | ||
| 38 | return backing->GetName(); | ||
| 39 | } | ||
| 40 | |||
| 41 | ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const { | ||
| 42 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | ||
| 43 | auto file = dir->CreateFile(FileUtil::GetFilename(path)); | ||
| 44 | if (file == nullptr) { | ||
| 45 | // TODO(DarkLordZach): Find a better error code for this | ||
| 46 | return ResultCode(-1); | ||
| 47 | } | ||
| 48 | if (!file->Resize(size)) { | ||
| 49 | // TODO(DarkLordZach): Find a better error code for this | ||
| 50 | return ResultCode(-1); | ||
| 51 | } | ||
| 52 | return RESULT_SUCCESS; | ||
| 53 | } | ||
| 54 | |||
| 55 | ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const { | ||
| 56 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | ||
| 57 | if (path == "/" || path == "\\") { | ||
| 58 | // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... | ||
| 59 | return RESULT_SUCCESS; | ||
| 60 | } | ||
| 61 | if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) | ||
| 62 | return FileSys::ERROR_PATH_NOT_FOUND; | ||
| 63 | if (!backing->DeleteFile(FileUtil::GetFilename(path))) { | ||
| 64 | // TODO(DarkLordZach): Find a better error code for this | ||
| 65 | return ResultCode(-1); | ||
| 66 | } | ||
| 67 | return RESULT_SUCCESS; | ||
| 68 | } | ||
| 69 | |||
| 70 | ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const { | ||
| 71 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | ||
| 72 | if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty()) | ||
| 73 | dir = backing; | ||
| 74 | auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path)); | ||
| 75 | if (new_dir == nullptr) { | ||
| 76 | // TODO(DarkLordZach): Find a better error code for this | ||
| 77 | return ResultCode(-1); | ||
| 78 | } | ||
| 79 | return RESULT_SUCCESS; | ||
| 80 | } | ||
| 81 | |||
| 82 | ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const { | ||
| 83 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | ||
| 84 | if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { | ||
| 85 | // TODO(DarkLordZach): Find a better error code for this | ||
| 86 | return ResultCode(-1); | ||
| 87 | } | ||
| 88 | return RESULT_SUCCESS; | ||
| 89 | } | ||
| 90 | |||
| 91 | ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const { | ||
| 92 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | ||
| 93 | if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { | ||
| 94 | // TODO(DarkLordZach): Find a better error code for this | ||
| 95 | return ResultCode(-1); | ||
| 96 | } | ||
| 97 | return RESULT_SUCCESS; | ||
| 98 | } | ||
| 99 | |||
| 100 | ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, | ||
| 101 | const std::string& dest_path) const { | ||
| 102 | auto src = backing->GetFileRelative(src_path); | ||
| 103 | if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { | ||
| 104 | // Use more-optimized vfs implementation rename. | ||
| 105 | if (src == nullptr) | ||
| 106 | return FileSys::ERROR_PATH_NOT_FOUND; | ||
| 107 | if (!src->Rename(FileUtil::GetFilename(dest_path))) { | ||
| 108 | // TODO(DarkLordZach): Find a better error code for this | ||
| 109 | return ResultCode(-1); | ||
| 110 | } | ||
| 111 | return RESULT_SUCCESS; | ||
| 112 | } | ||
| 113 | |||
| 114 | // Move by hand -- TODO(DarkLordZach): Optimize | ||
| 115 | auto c_res = CreateFile(dest_path, src->GetSize()); | ||
| 116 | if (c_res != RESULT_SUCCESS) | ||
| 117 | return c_res; | ||
| 118 | |||
| 119 | auto dest = backing->GetFileRelative(dest_path); | ||
| 120 | ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found."); | ||
| 121 | |||
| 122 | ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(), | ||
| 123 | "Could not write all of the bytes but everything else has succeded."); | ||
| 124 | |||
| 125 | if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) { | ||
| 126 | // TODO(DarkLordZach): Find a better error code for this | ||
| 127 | return ResultCode(-1); | ||
| 128 | } | ||
| 129 | |||
| 130 | return RESULT_SUCCESS; | ||
| 131 | } | ||
| 132 | |||
| 133 | ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, | ||
| 134 | const std::string& dest_path) const { | ||
| 135 | auto src = GetDirectoryRelativeWrapped(backing, src_path); | ||
| 136 | if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { | ||
| 137 | // Use more-optimized vfs implementation rename. | ||
| 138 | if (src == nullptr) | ||
| 139 | return FileSys::ERROR_PATH_NOT_FOUND; | ||
| 140 | if (!src->Rename(FileUtil::GetFilename(dest_path))) { | ||
| 141 | // TODO(DarkLordZach): Find a better error code for this | ||
| 142 | return ResultCode(-1); | ||
| 143 | } | ||
| 144 | return RESULT_SUCCESS; | ||
| 145 | } | ||
| 146 | |||
| 147 | // TODO(DarkLordZach): Implement renaming across the tree (move). | ||
| 148 | ASSERT_MSG(false, | ||
| 149 | "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs " | ||
| 150 | "don't match -- UNIMPLEMENTED", | ||
| 151 | src_path, dest_path); | ||
| 152 | |||
| 153 | // TODO(DarkLordZach): Find a better error code for this | ||
| 154 | return ResultCode(-1); | ||
| 155 | } | ||
| 156 | |||
| 157 | ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path, | ||
| 158 | FileSys::Mode mode) const { | ||
| 159 | auto npath = path; | ||
| 160 | while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\')) | ||
| 161 | npath = npath.substr(1); | ||
| 162 | auto file = backing->GetFileRelative(npath); | ||
| 163 | if (file == nullptr) | ||
| 164 | return FileSys::ERROR_PATH_NOT_FOUND; | ||
| 165 | |||
| 166 | if (mode == FileSys::Mode::Append) { | ||
| 167 | return MakeResult<FileSys::VirtualFile>( | ||
| 168 | std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize())); | ||
| 169 | } | ||
| 170 | |||
| 171 | return MakeResult<FileSys::VirtualFile>(file); | ||
| 172 | } | ||
| 173 | |||
| 174 | ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) { | ||
| 175 | auto dir = GetDirectoryRelativeWrapped(backing, path); | ||
| 176 | if (dir == nullptr) { | ||
| 177 | // TODO(DarkLordZach): Find a better error code for this | ||
| 178 | return ResultCode(-1); | ||
| 179 | } | ||
| 180 | return MakeResult(dir); | ||
| 181 | } | ||
| 182 | |||
| 183 | u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const { | ||
| 184 | if (backing->IsWritable()) | ||
| 185 | return EMULATED_SD_REPORTED_SIZE; | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( | ||
| 191 | const std::string& path) const { | ||
| 192 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | ||
| 193 | if (dir == nullptr) | ||
| 194 | return FileSys::ERROR_PATH_NOT_FOUND; | ||
| 195 | auto filename = FileUtil::GetFilename(path); | ||
| 196 | if (dir->GetFile(filename) != nullptr) | ||
| 197 | return MakeResult(FileSys::EntryType::File); | ||
| 198 | if (dir->GetSubdirectory(filename) != nullptr) | ||
| 199 | return MakeResult(FileSys::EntryType::Directory); | ||
| 200 | return FileSys::ERROR_PATH_NOT_FOUND; | ||
| 201 | } | ||
| 202 | |||
| 16 | /** | 203 | /** |
| 17 | * Map of registered file systems, identified by type. Once an file system is registered here, it | 204 | * Map of registered file systems, identified by type. Once an file system is registered here, it |
| 18 | * is never removed until UnregisterFileSystems is called. | 205 | * is never removed until UnregisterFileSystems is called. |
| @@ -42,7 +229,7 @@ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { | |||
| 42 | return RESULT_SUCCESS; | 229 | return RESULT_SUCCESS; |
| 43 | } | 230 | } |
| 44 | 231 | ||
| 45 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) { | 232 | ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id) { |
| 46 | LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id); | 233 | LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}", title_id); |
| 47 | 234 | ||
| 48 | if (romfs_factory == nullptr) { | 235 | if (romfs_factory == nullptr) { |
| @@ -53,19 +240,19 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id) { | |||
| 53 | return romfs_factory->Open(title_id); | 240 | return romfs_factory->Open(title_id); |
| 54 | } | 241 | } |
| 55 | 242 | ||
| 56 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData( | 243 | ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, |
| 57 | FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct) { | 244 | FileSys::SaveDataDescriptor save_struct) { |
| 58 | LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", | 245 | LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", |
| 59 | static_cast<u8>(space), SaveStructDebugInfo(save_struct)); | 246 | static_cast<u8>(space), save_struct.DebugInfo()); |
| 60 | 247 | ||
| 61 | if (save_data_factory == nullptr) { | 248 | if (save_data_factory == nullptr) { |
| 62 | return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound); | 249 | return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); |
| 63 | } | 250 | } |
| 64 | 251 | ||
| 65 | return save_data_factory->Open(space, save_struct); | 252 | return save_data_factory->Open(space, save_struct); |
| 66 | } | 253 | } |
| 67 | 254 | ||
| 68 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC() { | 255 | ResultVal<FileSys::VirtualDir> OpenSDMC() { |
| 69 | LOG_TRACE(Service_FS, "Opening SDMC"); | 256 | LOG_TRACE(Service_FS, "Opening SDMC"); |
| 70 | 257 | ||
| 71 | if (sdmc_factory == nullptr) { | 258 | if (sdmc_factory == nullptr) { |
| @@ -80,8 +267,10 @@ void RegisterFileSystems() { | |||
| 80 | save_data_factory = nullptr; | 267 | save_data_factory = nullptr; |
| 81 | sdmc_factory = nullptr; | 268 | sdmc_factory = nullptr; |
| 82 | 269 | ||
| 83 | std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | 270 | auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>( |
| 84 | std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); | 271 | FileUtil::GetUserPath(D_NAND_IDX), FileSys::Mode::Write); |
| 272 | auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>( | ||
| 273 | FileUtil::GetUserPath(D_SDMC_IDX), FileSys::Mode::Write); | ||
| 85 | 274 | ||
| 86 | auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); | 275 | auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); |
| 87 | save_data_factory = std::move(savedata); | 276 | save_data_factory = std::move(savedata); |
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 45272d326..d4483daa5 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -6,15 +6,13 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/file_sys/directory.h" | ||
| 10 | #include "core/file_sys/mode.h" | ||
| 9 | #include "core/file_sys/romfs_factory.h" | 11 | #include "core/file_sys/romfs_factory.h" |
| 10 | #include "core/file_sys/savedata_factory.h" | 12 | #include "core/file_sys/savedata_factory.h" |
| 11 | #include "core/file_sys/sdmc_factory.h" | 13 | #include "core/file_sys/sdmc_factory.h" |
| 12 | #include "core/hle/result.h" | 14 | #include "core/hle/result.h" |
| 13 | 15 | ||
| 14 | namespace FileSys { | ||
| 15 | class FileSystemBackend; | ||
| 16 | } // namespace FileSys | ||
| 17 | |||
| 18 | namespace Service { | 16 | namespace Service { |
| 19 | 17 | ||
| 20 | namespace SM { | 18 | namespace SM { |
| @@ -29,11 +27,10 @@ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); | |||
| 29 | 27 | ||
| 30 | // TODO(DarkLordZach): BIS Filesystem | 28 | // TODO(DarkLordZach): BIS Filesystem |
| 31 | // ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); | 29 | // ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); |
| 32 | 30 | ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id); | |
| 33 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenRomFS(u64 title_id); | 31 | ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, |
| 34 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSaveData( | 32 | FileSys::SaveDataDescriptor save_struct); |
| 35 | FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct); | 33 | ResultVal<FileSys::VirtualDir> OpenSDMC(); |
| 36 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC(); | ||
| 37 | 34 | ||
| 38 | // TODO(DarkLordZach): BIS Filesystem | 35 | // TODO(DarkLordZach): BIS Filesystem |
| 39 | // ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS(); | 36 | // ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS(); |
| @@ -41,5 +38,100 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenSDMC(); | |||
| 41 | /// Registers all Filesystem services with the specified service manager. | 38 | /// Registers all Filesystem services with the specified service manager. |
| 42 | void InstallInterfaces(SM::ServiceManager& service_manager); | 39 | void InstallInterfaces(SM::ServiceManager& service_manager); |
| 43 | 40 | ||
| 41 | // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of | ||
| 42 | // pointers and booleans. This makes using a VfsDirectory with switch services much easier and | ||
| 43 | // avoids repetitive code. | ||
| 44 | class VfsDirectoryServiceWrapper { | ||
| 45 | public: | ||
| 46 | explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) | ||
| 50 | */ | ||
| 51 | std::string GetName() const; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Create a file specified by its path | ||
| 55 | * @param path Path relative to the Archive | ||
| 56 | * @param size The size of the new file, filled with zeroes | ||
| 57 | * @return Result of the operation | ||
| 58 | */ | ||
| 59 | ResultCode CreateFile(const std::string& path, u64 size) const; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Delete a file specified by its path | ||
| 63 | * @param path Path relative to the archive | ||
| 64 | * @return Result of the operation | ||
| 65 | */ | ||
| 66 | ResultCode DeleteFile(const std::string& path) const; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Create a directory specified by its path | ||
| 70 | * @param path Path relative to the archive | ||
| 71 | * @return Result of the operation | ||
| 72 | */ | ||
| 73 | ResultCode CreateDirectory(const std::string& path) const; | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Delete a directory specified by its path | ||
| 77 | * @param path Path relative to the archive | ||
| 78 | * @return Result of the operation | ||
| 79 | */ | ||
| 80 | ResultCode DeleteDirectory(const std::string& path) const; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Delete a directory specified by its path and anything under it | ||
| 84 | * @param path Path relative to the archive | ||
| 85 | * @return Result of the operation | ||
| 86 | */ | ||
| 87 | ResultCode DeleteDirectoryRecursively(const std::string& path) const; | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Rename a File specified by its path | ||
| 91 | * @param src_path Source path relative to the archive | ||
| 92 | * @param dest_path Destination path relative to the archive | ||
| 93 | * @return Result of the operation | ||
| 94 | */ | ||
| 95 | ResultCode RenameFile(const std::string& src_path, const std::string& dest_path) const; | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Rename a Directory specified by its path | ||
| 99 | * @param src_path Source path relative to the archive | ||
| 100 | * @param dest_path Destination path relative to the archive | ||
| 101 | * @return Result of the operation | ||
| 102 | */ | ||
| 103 | ResultCode RenameDirectory(const std::string& src_path, const std::string& dest_path) const; | ||
| 104 | |||
| 105 | /** | ||
| 106 | * Open a file specified by its path, using the specified mode | ||
| 107 | * @param path Path relative to the archive | ||
| 108 | * @param mode Mode to open the file with | ||
| 109 | * @return Opened file, or error code | ||
| 110 | */ | ||
| 111 | ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const; | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Open a directory specified by its path | ||
| 115 | * @param path Path relative to the archive | ||
| 116 | * @return Opened directory, or error code | ||
| 117 | */ | ||
| 118 | ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path); | ||
| 119 | |||
| 120 | /** | ||
| 121 | * Get the free space | ||
| 122 | * @return The number of free bytes in the archive | ||
| 123 | */ | ||
| 124 | u64 GetFreeSpaceSize() const; | ||
| 125 | |||
| 126 | /** | ||
| 127 | * Get the type of the specified path | ||
| 128 | * @return The type of the specified path or error code | ||
| 129 | */ | ||
| 130 | ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const; | ||
| 131 | |||
| 132 | private: | ||
| 133 | FileSys::VirtualDir backing; | ||
| 134 | }; | ||
| 135 | |||
| 44 | } // namespace FileSystem | 136 | } // namespace FileSystem |
| 45 | } // namespace Service | 137 | } // namespace Service |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 22d3e645d..1b003bd84 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -8,11 +8,7 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/file_sys/directory.h" | 9 | #include "core/file_sys/directory.h" |
| 10 | #include "core/file_sys/errors.h" | 10 | #include "core/file_sys/errors.h" |
| 11 | #include "core/file_sys/filesystem.h" | ||
| 12 | #include "core/file_sys/storage.h" | ||
| 13 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| 14 | #include "core/hle/kernel/client_port.h" | ||
| 15 | #include "core/hle/kernel/client_session.h" | ||
| 16 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 17 | #include "core/hle/service/filesystem/filesystem.h" | 13 | #include "core/hle/service/filesystem/filesystem.h" |
| 18 | #include "core/hle/service/filesystem/fsp_srv.h" | 14 | #include "core/hle/service/filesystem/fsp_srv.h" |
| @@ -25,13 +21,13 @@ enum class StorageId : u8 { | |||
| 25 | GameCard = 2, | 21 | GameCard = 2, |
| 26 | NandSystem = 3, | 22 | NandSystem = 3, |
| 27 | NandUser = 4, | 23 | NandUser = 4, |
| 28 | SdCard = 5 | 24 | SdCard = 5, |
| 29 | }; | 25 | }; |
| 30 | 26 | ||
| 31 | class IStorage final : public ServiceFramework<IStorage> { | 27 | class IStorage final : public ServiceFramework<IStorage> { |
| 32 | public: | 28 | public: |
| 33 | IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend) | 29 | IStorage(FileSys::VirtualFile backend_) |
| 34 | : ServiceFramework("IStorage"), backend(std::move(backend)) { | 30 | : ServiceFramework("IStorage"), backend(std::move(backend_)) { |
| 35 | static const FunctionInfo functions[] = { | 31 | static const FunctionInfo functions[] = { |
| 36 | {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, | 32 | {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, |
| 37 | {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"}, | 33 | {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"}, |
| @@ -40,7 +36,7 @@ public: | |||
| 40 | } | 36 | } |
| 41 | 37 | ||
| 42 | private: | 38 | private: |
| 43 | std::unique_ptr<FileSys::StorageBackend> backend; | 39 | FileSys::VirtualFile backend; |
| 44 | 40 | ||
| 45 | void Read(Kernel::HLERequestContext& ctx) { | 41 | void Read(Kernel::HLERequestContext& ctx) { |
| 46 | IPC::RequestParser rp{ctx}; | 42 | IPC::RequestParser rp{ctx}; |
| @@ -62,14 +58,7 @@ private: | |||
| 62 | } | 58 | } |
| 63 | 59 | ||
| 64 | // Read the data from the Storage backend | 60 | // Read the data from the Storage backend |
| 65 | std::vector<u8> output(length); | 61 | std::vector<u8> output = backend->ReadBytes(length, offset); |
| 66 | ResultVal<size_t> res = backend->Read(offset, length, output.data()); | ||
| 67 | if (res.Failed()) { | ||
| 68 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 69 | rb.Push(res.Code()); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | |||
| 73 | // Write the data to memory | 62 | // Write the data to memory |
| 74 | ctx.WriteBuffer(output); | 63 | ctx.WriteBuffer(output); |
| 75 | 64 | ||
| @@ -80,8 +69,8 @@ private: | |||
| 80 | 69 | ||
| 81 | class IFile final : public ServiceFramework<IFile> { | 70 | class IFile final : public ServiceFramework<IFile> { |
| 82 | public: | 71 | public: |
| 83 | explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend) | 72 | explicit IFile(FileSys::VirtualFile backend_) |
| 84 | : ServiceFramework("IFile"), backend(std::move(backend)) { | 73 | : ServiceFramework("IFile"), backend(std::move(backend_)) { |
| 85 | static const FunctionInfo functions[] = { | 74 | static const FunctionInfo functions[] = { |
| 86 | {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, | 75 | {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, |
| 87 | {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, | 76 | {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, |
| @@ -91,7 +80,7 @@ public: | |||
| 91 | } | 80 | } |
| 92 | 81 | ||
| 93 | private: | 82 | private: |
| 94 | std::unique_ptr<FileSys::StorageBackend> backend; | 83 | FileSys::VirtualFile backend; |
| 95 | 84 | ||
| 96 | void Read(Kernel::HLERequestContext& ctx) { | 85 | void Read(Kernel::HLERequestContext& ctx) { |
| 97 | IPC::RequestParser rp{ctx}; | 86 | IPC::RequestParser rp{ctx}; |
| @@ -114,20 +103,14 @@ private: | |||
| 114 | } | 103 | } |
| 115 | 104 | ||
| 116 | // Read the data from the Storage backend | 105 | // Read the data from the Storage backend |
| 117 | std::vector<u8> output(length); | 106 | std::vector<u8> output = backend->ReadBytes(length, offset); |
| 118 | ResultVal<size_t> res = backend->Read(offset, length, output.data()); | ||
| 119 | if (res.Failed()) { | ||
| 120 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 121 | rb.Push(res.Code()); | ||
| 122 | return; | ||
| 123 | } | ||
| 124 | 107 | ||
| 125 | // Write the data to memory | 108 | // Write the data to memory |
| 126 | ctx.WriteBuffer(output); | 109 | ctx.WriteBuffer(output); |
| 127 | 110 | ||
| 128 | IPC::ResponseBuilder rb{ctx, 4}; | 111 | IPC::ResponseBuilder rb{ctx, 4}; |
| 129 | rb.Push(RESULT_SUCCESS); | 112 | rb.Push(RESULT_SUCCESS); |
| 130 | rb.Push(static_cast<u64>(*res)); | 113 | rb.Push(static_cast<u64>(output.size())); |
| 131 | } | 114 | } |
| 132 | 115 | ||
| 133 | void Write(Kernel::HLERequestContext& ctx) { | 116 | void Write(Kernel::HLERequestContext& ctx) { |
| @@ -150,14 +133,21 @@ private: | |||
| 150 | return; | 133 | return; |
| 151 | } | 134 | } |
| 152 | 135 | ||
| 153 | // Write the data to the Storage backend | ||
| 154 | std::vector<u8> data = ctx.ReadBuffer(); | 136 | std::vector<u8> data = ctx.ReadBuffer(); |
| 155 | ResultVal<size_t> res = backend->Write(offset, length, true, data.data()); | 137 | std::vector<u8> actual_data(length); |
| 156 | if (res.Failed()) { | 138 | |
| 157 | IPC::ResponseBuilder rb{ctx, 2}; | 139 | ASSERT_MSG( |
| 158 | rb.Push(res.Code()); | 140 | data.size() <= length, |
| 159 | return; | 141 | "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", |
| 160 | } | 142 | length, data.size()); |
| 143 | |||
| 144 | std::copy(data.begin(), data.end(), actual_data.begin()); | ||
| 145 | // Write the data to the Storage backend | ||
| 146 | auto written = backend->WriteBytes(data, offset); | ||
| 147 | |||
| 148 | ASSERT_MSG(written == length, | ||
| 149 | "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, | ||
| 150 | written); | ||
| 161 | 151 | ||
| 162 | IPC::ResponseBuilder rb{ctx, 2}; | 152 | IPC::ResponseBuilder rb{ctx, 2}; |
| 163 | rb.Push(RESULT_SUCCESS); | 153 | rb.Push(RESULT_SUCCESS); |
| @@ -165,7 +155,8 @@ private: | |||
| 165 | 155 | ||
| 166 | void Flush(Kernel::HLERequestContext& ctx) { | 156 | void Flush(Kernel::HLERequestContext& ctx) { |
| 167 | LOG_DEBUG(Service_FS, "called"); | 157 | LOG_DEBUG(Service_FS, "called"); |
| 168 | backend->Flush(); | 158 | |
| 159 | // Exists for SDK compatibiltity -- No need to flush file. | ||
| 169 | 160 | ||
| 170 | IPC::ResponseBuilder rb{ctx, 2}; | 161 | IPC::ResponseBuilder rb{ctx, 2}; |
| 171 | rb.Push(RESULT_SUCCESS); | 162 | rb.Push(RESULT_SUCCESS); |
| @@ -174,7 +165,7 @@ private: | |||
| 174 | void SetSize(Kernel::HLERequestContext& ctx) { | 165 | void SetSize(Kernel::HLERequestContext& ctx) { |
| 175 | IPC::RequestParser rp{ctx}; | 166 | IPC::RequestParser rp{ctx}; |
| 176 | const u64 size = rp.Pop<u64>(); | 167 | const u64 size = rp.Pop<u64>(); |
| 177 | backend->SetSize(size); | 168 | backend->Resize(size); |
| 178 | LOG_DEBUG(Service_FS, "called, size={}", size); | 169 | LOG_DEBUG(Service_FS, "called, size={}", size); |
| 179 | 170 | ||
| 180 | IPC::ResponseBuilder rb{ctx, 2}; | 171 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -191,19 +182,39 @@ private: | |||
| 191 | } | 182 | } |
| 192 | }; | 183 | }; |
| 193 | 184 | ||
| 185 | template <typename T> | ||
| 186 | static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, | ||
| 187 | FileSys::EntryType type) { | ||
| 188 | for (const auto& new_entry : new_data) { | ||
| 189 | FileSys::Entry entry; | ||
| 190 | entry.filename[0] = '\0'; | ||
| 191 | std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); | ||
| 192 | entry.type = type; | ||
| 193 | entry.file_size = new_entry->GetSize(); | ||
| 194 | entries.emplace_back(std::move(entry)); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 194 | class IDirectory final : public ServiceFramework<IDirectory> { | 198 | class IDirectory final : public ServiceFramework<IDirectory> { |
| 195 | public: | 199 | public: |
| 196 | explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend) | 200 | explicit IDirectory(FileSys::VirtualDir backend_) |
| 197 | : ServiceFramework("IDirectory"), backend(std::move(backend)) { | 201 | : ServiceFramework("IDirectory"), backend(std::move(backend_)) { |
| 198 | static const FunctionInfo functions[] = { | 202 | static const FunctionInfo functions[] = { |
| 199 | {0, &IDirectory::Read, "Read"}, | 203 | {0, &IDirectory::Read, "Read"}, |
| 200 | {1, &IDirectory::GetEntryCount, "GetEntryCount"}, | 204 | {1, &IDirectory::GetEntryCount, "GetEntryCount"}, |
| 201 | }; | 205 | }; |
| 202 | RegisterHandlers(functions); | 206 | RegisterHandlers(functions); |
| 207 | |||
| 208 | // TODO(DarkLordZach): Verify that this is the correct behavior. | ||
| 209 | // Build entry index now to save time later. | ||
| 210 | BuildEntryIndex(entries, backend->GetFiles(), FileSys::File); | ||
| 211 | BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::Directory); | ||
| 203 | } | 212 | } |
| 204 | 213 | ||
| 205 | private: | 214 | private: |
| 206 | std::unique_ptr<FileSys::DirectoryBackend> backend; | 215 | FileSys::VirtualDir backend; |
| 216 | std::vector<FileSys::Entry> entries; | ||
| 217 | u64 next_entry_index = 0; | ||
| 207 | 218 | ||
| 208 | void Read(Kernel::HLERequestContext& ctx) { | 219 | void Read(Kernel::HLERequestContext& ctx) { |
| 209 | IPC::RequestParser rp{ctx}; | 220 | IPC::RequestParser rp{ctx}; |
| @@ -214,26 +225,31 @@ private: | |||
| 214 | // Calculate how many entries we can fit in the output buffer | 225 | // Calculate how many entries we can fit in the output buffer |
| 215 | u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); | 226 | u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); |
| 216 | 227 | ||
| 228 | // Cap at total number of entries. | ||
| 229 | u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); | ||
| 230 | |||
| 217 | // Read the data from the Directory backend | 231 | // Read the data from the Directory backend |
| 218 | std::vector<FileSys::Entry> entries(count_entries); | 232 | std::vector<FileSys::Entry> entry_data(entries.begin() + next_entry_index, |
| 219 | u64 read_entries = backend->Read(count_entries, entries.data()); | 233 | entries.begin() + next_entry_index + actual_entries); |
| 234 | |||
| 235 | next_entry_index += actual_entries; | ||
| 220 | 236 | ||
| 221 | // Convert the data into a byte array | 237 | // Convert the data into a byte array |
| 222 | std::vector<u8> output(entries.size() * sizeof(FileSys::Entry)); | 238 | std::vector<u8> output(entry_data.size() * sizeof(FileSys::Entry)); |
| 223 | std::memcpy(output.data(), entries.data(), output.size()); | 239 | std::memcpy(output.data(), entry_data.data(), output.size()); |
| 224 | 240 | ||
| 225 | // Write the data to memory | 241 | // Write the data to memory |
| 226 | ctx.WriteBuffer(output); | 242 | ctx.WriteBuffer(output); |
| 227 | 243 | ||
| 228 | IPC::ResponseBuilder rb{ctx, 4}; | 244 | IPC::ResponseBuilder rb{ctx, 4}; |
| 229 | rb.Push(RESULT_SUCCESS); | 245 | rb.Push(RESULT_SUCCESS); |
| 230 | rb.Push(read_entries); | 246 | rb.Push(actual_entries); |
| 231 | } | 247 | } |
| 232 | 248 | ||
| 233 | void GetEntryCount(Kernel::HLERequestContext& ctx) { | 249 | void GetEntryCount(Kernel::HLERequestContext& ctx) { |
| 234 | LOG_DEBUG(Service_FS, "called"); | 250 | LOG_DEBUG(Service_FS, "called"); |
| 235 | 251 | ||
| 236 | u64 count = backend->GetEntryCount(); | 252 | u64 count = entries.size() - next_entry_index; |
| 237 | 253 | ||
| 238 | IPC::ResponseBuilder rb{ctx, 4}; | 254 | IPC::ResponseBuilder rb{ctx, 4}; |
| 239 | rb.Push(RESULT_SUCCESS); | 255 | rb.Push(RESULT_SUCCESS); |
| @@ -243,7 +259,7 @@ private: | |||
| 243 | 259 | ||
| 244 | class IFileSystem final : public ServiceFramework<IFileSystem> { | 260 | class IFileSystem final : public ServiceFramework<IFileSystem> { |
| 245 | public: | 261 | public: |
| 246 | explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) | 262 | explicit IFileSystem(FileSys::VirtualDir backend) |
| 247 | : ServiceFramework("IFileSystem"), backend(std::move(backend)) { | 263 | : ServiceFramework("IFileSystem"), backend(std::move(backend)) { |
| 248 | static const FunctionInfo functions[] = { | 264 | static const FunctionInfo functions[] = { |
| 249 | {0, &IFileSystem::CreateFile, "CreateFile"}, | 265 | {0, &IFileSystem::CreateFile, "CreateFile"}, |
| @@ -278,7 +294,7 @@ public: | |||
| 278 | LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); | 294 | LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); |
| 279 | 295 | ||
| 280 | IPC::ResponseBuilder rb{ctx, 2}; | 296 | IPC::ResponseBuilder rb{ctx, 2}; |
| 281 | rb.Push(backend->CreateFile(name, size)); | 297 | rb.Push(backend.CreateFile(name, size)); |
| 282 | } | 298 | } |
| 283 | 299 | ||
| 284 | void DeleteFile(Kernel::HLERequestContext& ctx) { | 300 | void DeleteFile(Kernel::HLERequestContext& ctx) { |
| @@ -290,7 +306,7 @@ public: | |||
| 290 | LOG_DEBUG(Service_FS, "called file {}", name); | 306 | LOG_DEBUG(Service_FS, "called file {}", name); |
| 291 | 307 | ||
| 292 | IPC::ResponseBuilder rb{ctx, 2}; | 308 | IPC::ResponseBuilder rb{ctx, 2}; |
| 293 | rb.Push(backend->DeleteFile(name)); | 309 | rb.Push(backend.DeleteFile(name)); |
| 294 | } | 310 | } |
| 295 | 311 | ||
| 296 | void CreateDirectory(Kernel::HLERequestContext& ctx) { | 312 | void CreateDirectory(Kernel::HLERequestContext& ctx) { |
| @@ -302,7 +318,7 @@ public: | |||
| 302 | LOG_DEBUG(Service_FS, "called directory {}", name); | 318 | LOG_DEBUG(Service_FS, "called directory {}", name); |
| 303 | 319 | ||
| 304 | IPC::ResponseBuilder rb{ctx, 2}; | 320 | IPC::ResponseBuilder rb{ctx, 2}; |
| 305 | rb.Push(backend->CreateDirectory(name)); | 321 | rb.Push(backend.CreateDirectory(name)); |
| 306 | } | 322 | } |
| 307 | 323 | ||
| 308 | void RenameFile(Kernel::HLERequestContext& ctx) { | 324 | void RenameFile(Kernel::HLERequestContext& ctx) { |
| @@ -320,7 +336,7 @@ public: | |||
| 320 | LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); | 336 | LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); |
| 321 | 337 | ||
| 322 | IPC::ResponseBuilder rb{ctx, 2}; | 338 | IPC::ResponseBuilder rb{ctx, 2}; |
| 323 | rb.Push(backend->RenameFile(src_name, dst_name)); | 339 | rb.Push(backend.RenameFile(src_name, dst_name)); |
| 324 | } | 340 | } |
| 325 | 341 | ||
| 326 | void OpenFile(Kernel::HLERequestContext& ctx) { | 342 | void OpenFile(Kernel::HLERequestContext& ctx) { |
| @@ -333,14 +349,14 @@ public: | |||
| 333 | 349 | ||
| 334 | LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); | 350 | LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); |
| 335 | 351 | ||
| 336 | auto result = backend->OpenFile(name, mode); | 352 | auto result = backend.OpenFile(name, mode); |
| 337 | if (result.Failed()) { | 353 | if (result.Failed()) { |
| 338 | IPC::ResponseBuilder rb{ctx, 2}; | 354 | IPC::ResponseBuilder rb{ctx, 2}; |
| 339 | rb.Push(result.Code()); | 355 | rb.Push(result.Code()); |
| 340 | return; | 356 | return; |
| 341 | } | 357 | } |
| 342 | 358 | ||
| 343 | auto file = std::move(result.Unwrap()); | 359 | IFile file(result.Unwrap()); |
| 344 | 360 | ||
| 345 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 361 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 346 | rb.Push(RESULT_SUCCESS); | 362 | rb.Push(RESULT_SUCCESS); |
| @@ -358,14 +374,14 @@ public: | |||
| 358 | 374 | ||
| 359 | LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); | 375 | LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); |
| 360 | 376 | ||
| 361 | auto result = backend->OpenDirectory(name); | 377 | auto result = backend.OpenDirectory(name); |
| 362 | if (result.Failed()) { | 378 | if (result.Failed()) { |
| 363 | IPC::ResponseBuilder rb{ctx, 2}; | 379 | IPC::ResponseBuilder rb{ctx, 2}; |
| 364 | rb.Push(result.Code()); | 380 | rb.Push(result.Code()); |
| 365 | return; | 381 | return; |
| 366 | } | 382 | } |
| 367 | 383 | ||
| 368 | auto directory = std::move(result.Unwrap()); | 384 | IDirectory directory(result.Unwrap()); |
| 369 | 385 | ||
| 370 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 386 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 371 | rb.Push(RESULT_SUCCESS); | 387 | rb.Push(RESULT_SUCCESS); |
| @@ -380,7 +396,7 @@ public: | |||
| 380 | 396 | ||
| 381 | LOG_DEBUG(Service_FS, "called file {}", name); | 397 | LOG_DEBUG(Service_FS, "called file {}", name); |
| 382 | 398 | ||
| 383 | auto result = backend->GetEntryType(name); | 399 | auto result = backend.GetEntryType(name); |
| 384 | if (result.Failed()) { | 400 | if (result.Failed()) { |
| 385 | IPC::ResponseBuilder rb{ctx, 2}; | 401 | IPC::ResponseBuilder rb{ctx, 2}; |
| 386 | rb.Push(result.Code()); | 402 | rb.Push(result.Code()); |
| @@ -400,7 +416,7 @@ public: | |||
| 400 | } | 416 | } |
| 401 | 417 | ||
| 402 | private: | 418 | private: |
| 403 | std::unique_ptr<FileSys::FileSystemBackend> backend; | 419 | VfsDirectoryServiceWrapper backend; |
| 404 | }; | 420 | }; |
| 405 | 421 | ||
| 406 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | 422 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { |
| @@ -536,17 +552,19 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { | |||
| 536 | LOG_INFO(Service_FS, "called with unknown={:08X}", unk); | 552 | LOG_INFO(Service_FS, "called with unknown={:08X}", unk); |
| 537 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); | 553 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); |
| 538 | 554 | ||
| 539 | auto filesystem = OpenSaveData(space_id, save_struct); | 555 | auto dir = OpenSaveData(space_id, save_struct); |
| 540 | 556 | ||
| 541 | if (filesystem.Failed()) { | 557 | if (dir.Failed()) { |
| 542 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 558 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 543 | rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::SaveDataNotFound)); | 559 | rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); |
| 544 | return; | 560 | return; |
| 545 | } | 561 | } |
| 546 | 562 | ||
| 563 | IFileSystem filesystem(std::move(dir.Unwrap())); | ||
| 564 | |||
| 547 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 565 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 548 | rb.Push(RESULT_SUCCESS); | 566 | rb.Push(RESULT_SUCCESS); |
| 549 | rb.PushIpcInterface<IFileSystem>(std::move(filesystem.Unwrap())); | 567 | rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); |
| 550 | } | 568 | } |
| 551 | 569 | ||
| 552 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 570 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { |
| @@ -569,18 +587,11 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | |||
| 569 | return; | 587 | return; |
| 570 | } | 588 | } |
| 571 | 589 | ||
| 572 | auto storage = romfs.Unwrap()->OpenFile({}, {}); | 590 | IStorage storage(std::move(romfs.Unwrap())); |
| 573 | |||
| 574 | if (storage.Failed()) { | ||
| 575 | LOG_CRITICAL(Service_FS, "no storage interface available!"); | ||
| 576 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 577 | rb.Push(storage.Code()); | ||
| 578 | return; | ||
| 579 | } | ||
| 580 | 591 | ||
| 581 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 592 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 582 | rb.Push(RESULT_SUCCESS); | 593 | rb.Push(RESULT_SUCCESS); |
| 583 | rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap())); | 594 | rb.PushIpcInterface<IStorage>(std::move(storage)); |
| 584 | } | 595 | } |
| 585 | 596 | ||
| 586 | void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { | 597 | void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { |
| @@ -591,33 +602,9 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { | |||
| 591 | 602 | ||
| 592 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", | 603 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", |
| 593 | static_cast<u8>(storage_id), title_id); | 604 | static_cast<u8>(storage_id), title_id); |
| 594 | if (title_id != Core::System::GetInstance().CurrentProcess()->program_id) { | ||
| 595 | LOG_CRITICAL( | ||
| 596 | Service_FS, | ||
| 597 | "Attempting to access RomFS of another title id (current={:016X}, requested={:016X}).", | ||
| 598 | Core::System::GetInstance().CurrentProcess()->program_id, title_id); | ||
| 599 | } | ||
| 600 | 605 | ||
| 601 | auto romfs = OpenRomFS(title_id); | 606 | IPC::ResponseBuilder rb{ctx, 2}; |
| 602 | if (romfs.Failed()) { | 607 | rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); |
| 603 | LOG_CRITICAL(Service_FS, "no file system interface available!"); | ||
| 604 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 605 | rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::RomFSNotFound)); | ||
| 606 | return; | ||
| 607 | } | ||
| 608 | |||
| 609 | auto storage = romfs.Unwrap()->OpenFile({}, {}); | ||
| 610 | |||
| 611 | if (storage.Failed()) { | ||
| 612 | LOG_CRITICAL(Service_FS, "no storage interface available!"); | ||
| 613 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 614 | rb.Push(storage.Code()); | ||
| 615 | return; | ||
| 616 | } | ||
| 617 | |||
| 618 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 619 | rb.Push(RESULT_SUCCESS); | ||
| 620 | rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap())); | ||
| 621 | } | 608 | } |
| 622 | 609 | ||
| 623 | } // namespace Service::FileSystem | 610 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4653eee4e..07f99c93d 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -27,7 +27,7 @@ private: | |||
| 27 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 27 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 28 | void OpenRomStorage(Kernel::HLERequestContext& ctx); | 28 | void OpenRomStorage(Kernel::HLERequestContext& ctx); |
| 29 | 29 | ||
| 30 | std::unique_ptr<FileSys::FileSystemBackend> romfs; | 30 | FileSys::VirtualFile romfs; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | } // namespace Service::FileSystem | 33 | } // namespace Service::FileSystem |