summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authorGravatar bunnei2018-07-07 20:24:51 -0700
committerGravatar bunnei2018-07-07 20:24:51 -0700
commit913896cbd99e414c325c9d47a987376ed6d9fffd (patch)
treeb660920a49f538f0ee00486c50a0d153d53c423d /src/core/hle
parentMerge pull request #632 from FearlessTobi/add-discord-link (diff)
downloadyuzu-913896cbd99e414c325c9d47a987376ed6d9fffd.tar.gz
yuzu-913896cbd99e414c325c9d47a987376ed6d9fffd.tar.xz
yuzu-913896cbd99e414c325c9d47a987376ed6d9fffd.zip
Revert "Virtual Filesystem (#597)"
This reverts commit 77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2.
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp225
-rw-r--r--src/core/hle/service/filesystem/filesystem.h133
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp114
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h2
5 files changed, 71 insertions, 405 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 7bb13c735..a871b3eaa 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -621,7 +621,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
621 IPC::ResponseBuilder rb{ctx, 4}; 621 IPC::ResponseBuilder rb{ctx, 4};
622 622
623 FileSys::Path unused; 623 FileSys::Path unused;
624 auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData); 624 auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused);
625 if (savedata.Failed()) { 625 if (savedata.Failed()) {
626 // Create the save data and return an error indicating that the operation was performed. 626 // Create the save data and return an error indicating that the operation was performed.
627 FileSystem::FormatFileSystem(FileSystem::Type::SaveData); 627 FileSystem::FormatFileSystem(FileSystem::Type::SaveData);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 25810c165..f58b518b6 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -2,221 +2,36 @@
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#include <boost/container/flat_map.hpp>
6#include "common/assert.h"
7#include "common/common_paths.h"
8#include "common/file_util.h" 6#include "common/file_util.h"
9#include "core/core.h"
10#include "core/file_sys/errors.h"
11#include "core/file_sys/filesystem.h" 7#include "core/file_sys/filesystem.h"
12#include "core/file_sys/vfs.h" 8#include "core/file_sys/savedata_factory.h"
13#include "core/file_sys/vfs_offset.h" 9#include "core/file_sys/sdmc_factory.h"
14#include "core/file_sys/vfs_real.h"
15#include "core/hle/kernel/process.h"
16#include "core/hle/service/filesystem/filesystem.h" 10#include "core/hle/service/filesystem/filesystem.h"
17#include "core/hle/service/filesystem/fsp_srv.h" 11#include "core/hle/service/filesystem/fsp_srv.h"
18 12
19namespace Service::FileSystem { 13namespace Service::FileSystem {
20 14
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.
24constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
25
26static 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
34VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_)
35 : backing(backing_) {}
36
37std::string VfsDirectoryServiceWrapper::GetName() const {
38 return backing->GetName();
39}
40
41ResultCode 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 return ResultCode(-1);
46 if (!file->Resize(size))
47 return ResultCode(-1);
48 return RESULT_SUCCESS;
49}
50
51ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const {
52 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
53 if (!backing->DeleteFile(FileUtil::GetFilename(path)))
54 return ResultCode(-1);
55 return RESULT_SUCCESS;
56}
57
58ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const {
59 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
60 if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty())
61 dir = backing;
62 auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path));
63 if (new_dir == nullptr)
64 return ResultCode(-1);
65 return RESULT_SUCCESS;
66}
67
68ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const {
69 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
70 if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path)))
71 return ResultCode(-1);
72 return RESULT_SUCCESS;
73}
74
75ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const {
76 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
77 if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path)))
78 return ResultCode(-1);
79 return RESULT_SUCCESS;
80}
81
82ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path,
83 const std::string& dest_path) const {
84 auto src = backing->GetFileRelative(src_path);
85 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
86 // Use more-optimized vfs implementation rename.
87 if (src == nullptr)
88 return FileSys::ERROR_PATH_NOT_FOUND;
89 if (!src->Rename(FileUtil::GetFilename(dest_path)))
90 return ResultCode(-1);
91 return RESULT_SUCCESS;
92 }
93
94 // Move by hand -- TODO(DarkLordZach): Optimize
95 auto c_res = CreateFile(dest_path, src->GetSize());
96 if (c_res != RESULT_SUCCESS)
97 return c_res;
98
99 auto dest = backing->GetFileRelative(dest_path);
100 ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found.");
101
102 ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
103 "Could not write all of the bytes but everything else has succeded.");
104
105 if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path)))
106 return ResultCode(-1);
107
108 return RESULT_SUCCESS;
109}
110
111ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path,
112 const std::string& dest_path) const {
113 auto src = GetDirectoryRelativeWrapped(backing, src_path);
114 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
115 // Use more-optimized vfs implementation rename.
116 if (src == nullptr)
117 return FileSys::ERROR_PATH_NOT_FOUND;
118 if (!src->Rename(FileUtil::GetFilename(dest_path)))
119 return ResultCode(-1);
120 return RESULT_SUCCESS;
121 }
122
123 // TODO(DarkLordZach): Implement renaming across the tree (move).
124 ASSERT_MSG(false,
125 "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs "
126 "don't match -- UNIMPLEMENTED",
127 src_path, dest_path);
128
129 return ResultCode(-1);
130}
131
132ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path,
133 FileSys::Mode mode) const {
134 auto file = backing->GetFileRelative(path);
135 if (file == nullptr)
136 return FileSys::ERROR_PATH_NOT_FOUND;
137
138 if ((static_cast<u32>(mode) & static_cast<u32>(FileSys::Mode::Append)) != 0) {
139 return MakeResult<FileSys::VirtualFile>(
140 std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()));
141 }
142
143 return MakeResult<FileSys::VirtualFile>(file);
144}
145
146ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) {
147 auto dir = GetDirectoryRelativeWrapped(backing, path);
148 if (dir == nullptr)
149 return ResultCode(-1);
150 return MakeResult(dir);
151}
152
153u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
154 if (backing->IsWritable())
155 return EMULATED_SD_REPORTED_SIZE;
156
157 return 0;
158}
159
160ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
161 const std::string& path) const {
162 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
163 if (dir == nullptr)
164 return ResultCode(-1);
165 auto filename = FileUtil::GetFilename(path);
166 if (dir->GetFile(filename) != nullptr)
167 return MakeResult(FileSys::EntryType::File);
168 if (dir->GetSubdirectory(filename) != nullptr)
169 return MakeResult(FileSys::EntryType::Directory);
170 return ResultCode(-1);
171}
172
173// A deferred filesystem for nand save data.
174// This must be deferred because the directory is dependent on title id, which is not set at
175// registration time.
176struct SaveDataDeferredFilesystem : DeferredFilesystem {
177protected:
178 FileSys::VirtualDir CreateFilesystem() override {
179 u64 title_id = Core::CurrentProcess()->program_id;
180 // TODO(DarkLordZach): Users
181 u32 user_id = 0;
182 std::string nand_directory = fmt::format(
183 "{}save/{:016X}/{:08X}/", FileUtil::GetUserPath(D_NAND_IDX), title_id, user_id);
184
185 auto savedata =
186 std::make_shared<FileSys::RealVfsDirectory>(nand_directory, FileSys::Mode::Write);
187 return savedata;
188 }
189};
190
191/** 15/**
192 * Map of registered file systems, identified by type. Once an file system is registered here, it 16 * Map of registered file systems, identified by type. Once an file system is registered here, it
193 * is never removed until UnregisterFileSystems is called. 17 * is never removed until UnregisterFileSystems is called.
194 */ 18 */
195static boost::container::flat_map<Type, std::unique_ptr<DeferredFilesystem>> filesystem_map; 19static boost::container::flat_map<Type, std::unique_ptr<FileSys::FileSystemFactory>> filesystem_map;
196static FileSys::VirtualFile filesystem_romfs = nullptr;
197 20
198ResultCode RegisterFileSystem(std::unique_ptr<DeferredFilesystem>&& factory, Type type) { 21ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type) {
199 auto result = filesystem_map.emplace(type, std::move(factory)); 22 auto result = filesystem_map.emplace(type, std::move(factory));
200 23
201 bool inserted = result.second; 24 bool inserted = result.second;
202 ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); 25 ASSERT_MSG(inserted, "Tried to register more than one system with same id code");
203 26
204 auto& filesystem = result.first->second; 27 auto& filesystem = result.first->second;
205 LOG_DEBUG(Service_FS, "Registered file system with id code 0x{:08X}", static_cast<u32>(type));
206 return RESULT_SUCCESS;
207}
208
209ResultCode RegisterRomFS(FileSys::VirtualFile filesystem) {
210 ASSERT_MSG(filesystem_romfs == nullptr,
211 "Tried to register more than one system with same id code");
212
213 filesystem_romfs = filesystem;
214 LOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", filesystem->GetName(), 28 LOG_DEBUG(Service_FS, "Registered file system {} with id code 0x{:08X}", filesystem->GetName(),
215 static_cast<u32>(Type::RomFS)); 29 static_cast<u32>(type));
216 return RESULT_SUCCESS; 30 return RESULT_SUCCESS;
217} 31}
218 32
219ResultVal<FileSys::VirtualDir> OpenFileSystem(Type type) { 33ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
34 FileSys::Path& path) {
220 LOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type)); 35 LOG_TRACE(Service_FS, "Opening FileSystem with type={}", static_cast<u32>(type));
221 36
222 auto itr = filesystem_map.find(type); 37 auto itr = filesystem_map.find(type);
@@ -225,13 +40,7 @@ ResultVal<FileSys::VirtualDir> OpenFileSystem(Type type) {
225 return ResultCode(-1); 40 return ResultCode(-1);
226 } 41 }
227 42
228 return MakeResult(itr->second->Get()); 43 return itr->second->Open(path);
229}
230
231ResultVal<FileSys::VirtualFile> OpenRomFS() {
232 if (filesystem_romfs == nullptr)
233 return ResultCode(-1);
234 return MakeResult(filesystem_romfs);
235} 44}
236 45
237ResultCode FormatFileSystem(Type type) { 46ResultCode FormatFileSystem(Type type) {
@@ -243,21 +52,21 @@ ResultCode FormatFileSystem(Type type) {
243 return ResultCode(-1); 52 return ResultCode(-1);
244 } 53 }
245 54
246 return itr->second->Get()->GetParentDirectory()->DeleteSubdirectory( 55 FileSys::Path unused;
247 itr->second->Get()->GetName()) 56 return itr->second->Format(unused);
248 ? RESULT_SUCCESS
249 : ResultCode(-1);
250} 57}
251 58
252void RegisterFileSystems() { 59void RegisterFileSystems() {
253 filesystem_map.clear(); 60 filesystem_map.clear();
254 filesystem_romfs = nullptr;
255 61
62 std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
256 std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX); 63 std::string sd_directory = FileUtil::GetUserPath(D_SDMC_IDX);
257 auto sdcard = std::make_shared<FileSys::RealVfsDirectory>(sd_directory, FileSys::Mode::Write);
258 RegisterFileSystem(std::make_unique<DeferredFilesystem>(sdcard), Type::SDMC);
259 64
260 RegisterFileSystem(std::make_unique<SaveDataDeferredFilesystem>(), Type::SaveData); 65 auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory));
66 RegisterFileSystem(std::move(savedata), Type::SaveData);
67
68 auto sdcard = std::make_unique<FileSys::SDMC_Factory>(std::move(sd_directory));
69 RegisterFileSystem(std::move(sdcard), Type::SDMC);
261} 70}
262 71
263void InstallInterfaces(SM::ServiceManager& service_manager) { 72void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index d3de797f1..56d26146e 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -6,8 +6,6 @@
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/filesystem.h"
10#include "core/file_sys/vfs.h"
11#include "core/hle/result.h" 9#include "core/hle/result.h"
12 10
13namespace FileSys { 11namespace FileSys {
@@ -31,136 +29,12 @@ enum class Type {
31 SDMC = 3, 29 SDMC = 3,
32}; 30};
33 31
34// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
35// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
36// avoids repetitive code.
37class VfsDirectoryServiceWrapper {
38public:
39 explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing);
40
41 /**
42 * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
43 */
44 std::string GetName() const;
45
46 /**
47 * Create a file specified by its path
48 * @param path Path relative to the Archive
49 * @param size The size of the new file, filled with zeroes
50 * @return Result of the operation
51 */
52 ResultCode CreateFile(const std::string& path, u64 size) const;
53
54 /**
55 * Delete a file specified by its path
56 * @param path Path relative to the archive
57 * @return Result of the operation
58 */
59 ResultCode DeleteFile(const std::string& path) const;
60
61 /**
62 * Create a directory specified by its path
63 * @param path Path relative to the archive
64 * @return Result of the operation
65 */
66 ResultCode CreateDirectory(const std::string& path) const;
67
68 /**
69 * Delete a directory specified by its path
70 * @param path Path relative to the archive
71 * @return Result of the operation
72 */
73 ResultCode DeleteDirectory(const std::string& path) const;
74
75 /**
76 * Delete a directory specified by its path and anything under it
77 * @param path Path relative to the archive
78 * @return Result of the operation
79 */
80 ResultCode DeleteDirectoryRecursively(const std::string& path) const;
81
82 /**
83 * Rename a File specified by its path
84 * @param src_path Source path relative to the archive
85 * @param dest_path Destination path relative to the archive
86 * @return Result of the operation
87 */
88 ResultCode RenameFile(const std::string& src_path, const std::string& dest_path) const;
89
90 /**
91 * Rename a Directory specified by its path
92 * @param src_path Source path relative to the archive
93 * @param dest_path Destination path relative to the archive
94 * @return Result of the operation
95 */
96 ResultCode RenameDirectory(const std::string& src_path, const std::string& dest_path) const;
97
98 /**
99 * Open a file specified by its path, using the specified mode
100 * @param path Path relative to the archive
101 * @param mode Mode to open the file with
102 * @return Opened file, or error code
103 */
104 ResultVal<FileSys::VirtualFile> OpenFile(const std::string& path, FileSys::Mode mode) const;
105
106 /**
107 * Open a directory specified by its path
108 * @param path Path relative to the archive
109 * @return Opened directory, or error code
110 */
111 ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
112
113 /**
114 * Get the free space
115 * @return The number of free bytes in the archive
116 */
117 u64 GetFreeSpaceSize() const;
118
119 /**
120 * Get the type of the specified path
121 * @return The type of the specified path or error code
122 */
123 ResultVal<FileSys::EntryType> GetEntryType(const std::string& path) const;
124
125private:
126 FileSys::VirtualDir backing;
127};
128
129// A class that deferres the creation of a filesystem until a later time.
130// This is useful if construction depends on a variable not known when the filesystem is registered.
131// Construct this with a filesystem (VirtualDir) to avoid the deferrence feature or override the
132// CreateFilesystem method which will be called on first use.
133struct DeferredFilesystem {
134 DeferredFilesystem() = default;
135
136 explicit DeferredFilesystem(FileSys::VirtualDir vfs_directory) : fs(std::move(vfs_directory)) {}
137
138 FileSys::VirtualDir Get() {
139 if (fs == nullptr)
140 fs = CreateFilesystem();
141
142 return fs;
143 }
144
145 virtual ~DeferredFilesystem() = default;
146
147protected:
148 virtual FileSys::VirtualDir CreateFilesystem() {
149 return fs;
150 }
151
152private:
153 FileSys::VirtualDir fs;
154};
155
156/** 32/**
157 * Registers a FileSystem, instances of which can later be opened using its IdCode. 33 * Registers a FileSystem, instances of which can later be opened using its IdCode.
158 * @param factory FileSystem backend interface to use 34 * @param factory FileSystem backend interface to use
159 * @param type Type used to access this type of FileSystem 35 * @param type Type used to access this type of FileSystem
160 */ 36 */
161ResultCode RegisterFileSystem(std::unique_ptr<DeferredFilesystem>&& fs, Type type); 37ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& factory, Type type);
162
163ResultCode RegisterRomFS(FileSys::VirtualFile fs);
164 38
165/** 39/**
166 * Opens a file system 40 * Opens a file system
@@ -168,9 +42,8 @@ ResultCode RegisterRomFS(FileSys::VirtualFile fs);
168 * @param path Path to the file system, used with Binary paths 42 * @param path Path to the file system, used with Binary paths
169 * @return FileSys::FileSystemBackend interface to the file system 43 * @return FileSys::FileSystemBackend interface to the file system
170 */ 44 */
171ResultVal<FileSys::VirtualDir> OpenFileSystem(Type type); 45ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type,
172 46 FileSys::Path& path);
173ResultVal<FileSys::VirtualFile> OpenRomFS();
174 47
175/** 48/**
176 * Formats a file system 49 * Formats a file system
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 26e8a8c88..216bfea0a 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -19,8 +19,8 @@ namespace Service::FileSystem {
19 19
20class IStorage final : public ServiceFramework<IStorage> { 20class IStorage final : public ServiceFramework<IStorage> {
21public: 21public:
22 IStorage(FileSys::VirtualFile backend_) 22 IStorage(std::unique_ptr<FileSys::StorageBackend>&& backend)
23 : ServiceFramework("IStorage"), backend(std::move(backend_)) { 23 : ServiceFramework("IStorage"), backend(std::move(backend)) {
24 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
25 {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, 25 {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"},
26 {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"}, 26 {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"},
@@ -29,7 +29,7 @@ public:
29 } 29 }
30 30
31private: 31private:
32 FileSys::VirtualFile backend; 32 std::unique_ptr<FileSys::StorageBackend> backend;
33 33
34 void Read(Kernel::HLERequestContext& ctx) { 34 void Read(Kernel::HLERequestContext& ctx) {
35 IPC::RequestParser rp{ctx}; 35 IPC::RequestParser rp{ctx};
@@ -51,8 +51,8 @@ private:
51 } 51 }
52 52
53 // Read the data from the Storage backend 53 // Read the data from the Storage backend
54 std::vector<u8> output = backend->ReadBytes(length, offset); 54 std::vector<u8> output(length);
55 auto res = MakeResult<size_t>(output.size()); 55 ResultVal<size_t> res = backend->Read(offset, length, output.data());
56 if (res.Failed()) { 56 if (res.Failed()) {
57 IPC::ResponseBuilder rb{ctx, 2}; 57 IPC::ResponseBuilder rb{ctx, 2};
58 rb.Push(res.Code()); 58 rb.Push(res.Code());
@@ -69,8 +69,8 @@ private:
69 69
70class IFile final : public ServiceFramework<IFile> { 70class IFile final : public ServiceFramework<IFile> {
71public: 71public:
72 explicit IFile(FileSys::VirtualFile backend_) 72 explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend)
73 : ServiceFramework("IFile"), backend(std::move(backend_)) { 73 : ServiceFramework("IFile"), backend(std::move(backend)) {
74 static const FunctionInfo functions[] = { 74 static const FunctionInfo functions[] = {
75 {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, 75 {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
76 {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, 76 {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
@@ -80,7 +80,7 @@ public:
80 } 80 }
81 81
82private: 82private:
83 FileSys::VirtualFile backend; 83 std::unique_ptr<FileSys::StorageBackend> backend;
84 84
85 void Read(Kernel::HLERequestContext& ctx) { 85 void Read(Kernel::HLERequestContext& ctx) {
86 IPC::RequestParser rp{ctx}; 86 IPC::RequestParser rp{ctx};
@@ -103,8 +103,8 @@ private:
103 } 103 }
104 104
105 // Read the data from the Storage backend 105 // Read the data from the Storage backend
106 std::vector<u8> output = backend->ReadBytes(length, offset); 106 std::vector<u8> output(length);
107 auto res = MakeResult<size_t>(output.size()); 107 ResultVal<size_t> res = backend->Read(offset, length, output.data());
108 if (res.Failed()) { 108 if (res.Failed()) {
109 IPC::ResponseBuilder rb{ctx, 2}; 109 IPC::ResponseBuilder rb{ctx, 2};
110 rb.Push(res.Code()); 110 rb.Push(res.Code());
@@ -139,10 +139,9 @@ private:
139 return; 139 return;
140 } 140 }
141 141
142 std::vector<u8> data = ctx.ReadBuffer();
143 data.resize(length);
144 // Write the data to the Storage backend 142 // Write the data to the Storage backend
145 auto res = MakeResult<size_t>(backend->WriteBytes(data, offset)); 143 std::vector<u8> data = ctx.ReadBuffer();
144 ResultVal<size_t> res = backend->Write(offset, length, true, data.data());
146 if (res.Failed()) { 145 if (res.Failed()) {
147 IPC::ResponseBuilder rb{ctx, 2}; 146 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(res.Code()); 147 rb.Push(res.Code());
@@ -155,8 +154,7 @@ private:
155 154
156 void Flush(Kernel::HLERequestContext& ctx) { 155 void Flush(Kernel::HLERequestContext& ctx) {
157 LOG_DEBUG(Service_FS, "called"); 156 LOG_DEBUG(Service_FS, "called");
158 157 backend->Flush();
159 // Exists for SDK compatibiltity -- No need to flush file.
160 158
161 IPC::ResponseBuilder rb{ctx, 2}; 159 IPC::ResponseBuilder rb{ctx, 2};
162 rb.Push(RESULT_SUCCESS); 160 rb.Push(RESULT_SUCCESS);
@@ -165,7 +163,7 @@ private:
165 void SetSize(Kernel::HLERequestContext& ctx) { 163 void SetSize(Kernel::HLERequestContext& ctx) {
166 IPC::RequestParser rp{ctx}; 164 IPC::RequestParser rp{ctx};
167 const u64 size = rp.Pop<u64>(); 165 const u64 size = rp.Pop<u64>();
168 backend->Resize(size); 166 backend->SetSize(size);
169 LOG_DEBUG(Service_FS, "called, size={}", size); 167 LOG_DEBUG(Service_FS, "called, size={}", size);
170 168
171 IPC::ResponseBuilder rb{ctx, 2}; 169 IPC::ResponseBuilder rb{ctx, 2};
@@ -182,38 +180,19 @@ private:
182 } 180 }
183}; 181};
184 182
185template <typename T>
186static 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
198class IDirectory final : public ServiceFramework<IDirectory> { 183class IDirectory final : public ServiceFramework<IDirectory> {
199public: 184public:
200 explicit IDirectory(FileSys::VirtualDir backend_) 185 explicit IDirectory(std::unique_ptr<FileSys::DirectoryBackend>&& backend)
201 : ServiceFramework("IDirectory"), backend(std::move(backend_)) { 186 : ServiceFramework("IDirectory"), backend(std::move(backend)) {
202 static const FunctionInfo functions[] = { 187 static const FunctionInfo functions[] = {
203 {0, &IDirectory::Read, "Read"}, 188 {0, &IDirectory::Read, "Read"},
204 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 189 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
205 }; 190 };
206 RegisterHandlers(functions); 191 RegisterHandlers(functions);
207
208 // Build entry index now to save time later.
209 BuildEntryIndex(entries, backend->GetFiles(), FileSys::File);
210 BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::Directory);
211 } 192 }
212 193
213private: 194private:
214 FileSys::VirtualDir backend; 195 std::unique_ptr<FileSys::DirectoryBackend> backend;
215 std::vector<FileSys::Entry> entries;
216 u64 next_entry_index = 0;
217 196
218 void Read(Kernel::HLERequestContext& ctx) { 197 void Read(Kernel::HLERequestContext& ctx) {
219 IPC::RequestParser rp{ctx}; 198 IPC::RequestParser rp{ctx};
@@ -224,31 +203,26 @@ private:
224 // Calculate how many entries we can fit in the output buffer 203 // Calculate how many entries we can fit in the output buffer
225 u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); 204 u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
226 205
227 // Cap at total number of entries.
228 u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
229
230 // Read the data from the Directory backend 206 // Read the data from the Directory backend
231 std::vector<FileSys::Entry> entry_data(entries.begin() + next_entry_index, 207 std::vector<FileSys::Entry> entries(count_entries);
232 entries.begin() + next_entry_index + actual_entries); 208 u64 read_entries = backend->Read(count_entries, entries.data());
233
234 next_entry_index += actual_entries;
235 209
236 // Convert the data into a byte array 210 // Convert the data into a byte array
237 std::vector<u8> output(entry_data.size() * sizeof(FileSys::Entry)); 211 std::vector<u8> output(entries.size() * sizeof(FileSys::Entry));
238 std::memcpy(output.data(), entry_data.data(), output.size()); 212 std::memcpy(output.data(), entries.data(), output.size());
239 213
240 // Write the data to memory 214 // Write the data to memory
241 ctx.WriteBuffer(output); 215 ctx.WriteBuffer(output);
242 216
243 IPC::ResponseBuilder rb{ctx, 4}; 217 IPC::ResponseBuilder rb{ctx, 4};
244 rb.Push(RESULT_SUCCESS); 218 rb.Push(RESULT_SUCCESS);
245 rb.Push(actual_entries); 219 rb.Push(read_entries);
246 } 220 }
247 221
248 void GetEntryCount(Kernel::HLERequestContext& ctx) { 222 void GetEntryCount(Kernel::HLERequestContext& ctx) {
249 LOG_DEBUG(Service_FS, "called"); 223 LOG_DEBUG(Service_FS, "called");
250 224
251 u64 count = entries.size() - next_entry_index; 225 u64 count = backend->GetEntryCount();
252 226
253 IPC::ResponseBuilder rb{ctx, 4}; 227 IPC::ResponseBuilder rb{ctx, 4};
254 rb.Push(RESULT_SUCCESS); 228 rb.Push(RESULT_SUCCESS);
@@ -258,7 +232,7 @@ private:
258 232
259class IFileSystem final : public ServiceFramework<IFileSystem> { 233class IFileSystem final : public ServiceFramework<IFileSystem> {
260public: 234public:
261 explicit IFileSystem(FileSys::VirtualDir backend) 235 explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend)
262 : ServiceFramework("IFileSystem"), backend(std::move(backend)) { 236 : ServiceFramework("IFileSystem"), backend(std::move(backend)) {
263 static const FunctionInfo functions[] = { 237 static const FunctionInfo functions[] = {
264 {0, &IFileSystem::CreateFile, "CreateFile"}, 238 {0, &IFileSystem::CreateFile, "CreateFile"},
@@ -293,7 +267,7 @@ public:
293 LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); 267 LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size);
294 268
295 IPC::ResponseBuilder rb{ctx, 2}; 269 IPC::ResponseBuilder rb{ctx, 2};
296 rb.Push(backend.CreateFile(name, size)); 270 rb.Push(backend->CreateFile(name, size));
297 } 271 }
298 272
299 void DeleteFile(Kernel::HLERequestContext& ctx) { 273 void DeleteFile(Kernel::HLERequestContext& ctx) {
@@ -305,7 +279,7 @@ public:
305 LOG_DEBUG(Service_FS, "called file {}", name); 279 LOG_DEBUG(Service_FS, "called file {}", name);
306 280
307 IPC::ResponseBuilder rb{ctx, 2}; 281 IPC::ResponseBuilder rb{ctx, 2};
308 rb.Push(backend.DeleteFile(name)); 282 rb.Push(backend->DeleteFile(name));
309 } 283 }
310 284
311 void CreateDirectory(Kernel::HLERequestContext& ctx) { 285 void CreateDirectory(Kernel::HLERequestContext& ctx) {
@@ -317,7 +291,7 @@ public:
317 LOG_DEBUG(Service_FS, "called directory {}", name); 291 LOG_DEBUG(Service_FS, "called directory {}", name);
318 292
319 IPC::ResponseBuilder rb{ctx, 2}; 293 IPC::ResponseBuilder rb{ctx, 2};
320 rb.Push(backend.CreateDirectory(name)); 294 rb.Push(backend->CreateDirectory(name));
321 } 295 }
322 296
323 void RenameFile(Kernel::HLERequestContext& ctx) { 297 void RenameFile(Kernel::HLERequestContext& ctx) {
@@ -335,7 +309,7 @@ public:
335 LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); 309 LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name);
336 310
337 IPC::ResponseBuilder rb{ctx, 2}; 311 IPC::ResponseBuilder rb{ctx, 2};
338 rb.Push(backend.RenameFile(src_name, dst_name)); 312 rb.Push(backend->RenameFile(src_name, dst_name));
339 } 313 }
340 314
341 void OpenFile(Kernel::HLERequestContext& ctx) { 315 void OpenFile(Kernel::HLERequestContext& ctx) {
@@ -348,14 +322,14 @@ public:
348 322
349 LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); 323 LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode));
350 324
351 auto result = backend.OpenFile(name, mode); 325 auto result = backend->OpenFile(name, mode);
352 if (result.Failed()) { 326 if (result.Failed()) {
353 IPC::ResponseBuilder rb{ctx, 2}; 327 IPC::ResponseBuilder rb{ctx, 2};
354 rb.Push(result.Code()); 328 rb.Push(result.Code());
355 return; 329 return;
356 } 330 }
357 331
358 IFile file(result.Unwrap()); 332 auto file = std::move(result.Unwrap());
359 333
360 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 334 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
361 rb.Push(RESULT_SUCCESS); 335 rb.Push(RESULT_SUCCESS);
@@ -373,14 +347,14 @@ public:
373 347
374 LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); 348 LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags);
375 349
376 auto result = backend.OpenDirectory(name); 350 auto result = backend->OpenDirectory(name);
377 if (result.Failed()) { 351 if (result.Failed()) {
378 IPC::ResponseBuilder rb{ctx, 2}; 352 IPC::ResponseBuilder rb{ctx, 2};
379 rb.Push(result.Code()); 353 rb.Push(result.Code());
380 return; 354 return;
381 } 355 }
382 356
383 IDirectory directory(result.Unwrap()); 357 auto directory = std::move(result.Unwrap());
384 358
385 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 359 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
386 rb.Push(RESULT_SUCCESS); 360 rb.Push(RESULT_SUCCESS);
@@ -395,7 +369,7 @@ public:
395 369
396 LOG_DEBUG(Service_FS, "called file {}", name); 370 LOG_DEBUG(Service_FS, "called file {}", name);
397 371
398 auto result = backend.GetEntryType(name); 372 auto result = backend->GetEntryType(name);
399 if (result.Failed()) { 373 if (result.Failed()) {
400 IPC::ResponseBuilder rb{ctx, 2}; 374 IPC::ResponseBuilder rb{ctx, 2};
401 rb.Push(result.Code()); 375 rb.Push(result.Code());
@@ -415,7 +389,7 @@ public:
415 } 389 }
416 390
417private: 391private:
418 VfsDirectoryServiceWrapper backend; 392 std::unique_ptr<FileSys::FileSystemBackend> backend;
419}; 393};
420 394
421FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { 395FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
@@ -516,7 +490,8 @@ void FSP_SRV::TryLoadRomFS() {
516 if (romfs) { 490 if (romfs) {
517 return; 491 return;
518 } 492 }
519 auto res = OpenRomFS(); 493 FileSys::Path unused;
494 auto res = OpenFileSystem(Type::RomFS, unused);
520 if (res.Succeeded()) { 495 if (res.Succeeded()) {
521 romfs = std::move(res.Unwrap()); 496 romfs = std::move(res.Unwrap());
522 } 497 }
@@ -532,7 +507,8 @@ void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) {
532void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { 507void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) {
533 LOG_DEBUG(Service_FS, "called"); 508 LOG_DEBUG(Service_FS, "called");
534 509
535 IFileSystem filesystem(OpenFileSystem(Type::SDMC).Unwrap()); 510 FileSys::Path unused;
511 auto filesystem = OpenFileSystem(Type::SDMC, unused).Unwrap();
536 512
537 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 513 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
538 rb.Push(RESULT_SUCCESS); 514 rb.Push(RESULT_SUCCESS);
@@ -555,7 +531,8 @@ void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) {
555void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { 531void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
556 LOG_WARNING(Service_FS, "(STUBBED) called"); 532 LOG_WARNING(Service_FS, "(STUBBED) called");
557 533
558 IFileSystem filesystem(OpenFileSystem(Type::SaveData).Unwrap()); 534 FileSys::Path unused;
535 auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap();
559 536
560 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 537 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
561 rb.Push(RESULT_SUCCESS); 538 rb.Push(RESULT_SUCCESS);
@@ -582,11 +559,18 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
582 return; 559 return;
583 } 560 }
584 561
585 IStorage storage(romfs); 562 // Attempt to open a StorageBackend interface to the RomFS
563 auto storage = romfs->OpenFile({}, {});
564 if (storage.Failed()) {
565 LOG_CRITICAL(Service_FS, "no storage interface available!");
566 IPC::ResponseBuilder rb{ctx, 2};
567 rb.Push(storage.Code());
568 return;
569 }
586 570
587 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 571 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
588 rb.Push(RESULT_SUCCESS); 572 rb.Push(RESULT_SUCCESS);
589 rb.PushIpcInterface<IStorage>(std::move(storage)); 573 rb.PushIpcInterface<IStorage>(std::move(storage.Unwrap()));
590} 574}
591 575
592void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { 576void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index b1ef6397f..acb78fac1 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -29,7 +29,7 @@ private:
29 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 29 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
30 void OpenRomStorage(Kernel::HLERequestContext& ctx); 30 void OpenRomStorage(Kernel::HLERequestContext& ctx);
31 31
32 FileSys::VirtualFile romfs; 32 std::unique_ptr<FileSys::FileSystemBackend> romfs;
33}; 33};
34 34
35} // namespace Service::FileSystem 35} // namespace Service::FileSystem