summaryrefslogtreecommitdiff
path: root/src/core/hle/service/filesystem
diff options
context:
space:
mode:
authorGravatar FearlessTobi2024-01-05 05:23:58 +0100
committerGravatar Liam2024-01-25 16:40:42 -0500
commit06fb7f90da0b465e723a562134c12b513aa77dff (patch)
treea256bbe22aa4c2a6704f41eb22b3d2cfba0fed72 /src/core/hle/service/filesystem
parentMerge pull request #12759 from liamwhite/mp-misc (diff)
downloadyuzu-06fb7f90da0b465e723a562134c12b513aa77dff.tar.gz
yuzu-06fb7f90da0b465e723a562134c12b513aa77dff.tar.xz
yuzu-06fb7f90da0b465e723a562134c12b513aa77dff.zip
fs: Move fsp_srv subclasses to separate files
fs: Move additional files to the fsp directory
Diffstat (limited to 'src/core/hle/service/filesystem')
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp6
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.cpp79
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.h27
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.cpp127
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.h26
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp262
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h38
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp62
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_ldr.cpp (renamed from src/core/hle/service/filesystem/fsp_ldr.cpp)2
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_ldr.h (renamed from src/core/hle/service/filesystem/fsp_ldr.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_pr.cpp (renamed from src/core/hle/service/filesystem/fsp_pr.cpp)2
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_pr.h (renamed from src/core/hle/service/filesystem/fsp_pr.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp (renamed from src/core/hle/service/filesystem/fsp_srv.cpp)540
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h (renamed from src/core/hle/service/filesystem/fsp_srv.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_util.h22
16 files changed, 676 insertions, 540 deletions
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index ca6d8d607..ab4974ac5 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -21,9 +21,9 @@
21#include "core/file_sys/vfs.h" 21#include "core/file_sys/vfs.h"
22#include "core/file_sys/vfs_offset.h" 22#include "core/file_sys/vfs_offset.h"
23#include "core/hle/service/filesystem/filesystem.h" 23#include "core/hle/service/filesystem/filesystem.h"
24#include "core/hle/service/filesystem/fsp_ldr.h" 24#include "core/hle/service/filesystem/fsp/fsp_ldr.h"
25#include "core/hle/service/filesystem/fsp_pr.h" 25#include "core/hle/service/filesystem/fsp/fsp_pr.h"
26#include "core/hle/service/filesystem/fsp_srv.h" 26#include "core/hle/service/filesystem/fsp/fsp_srv.h"
27#include "core/hle/service/filesystem/romfs_controller.h" 27#include "core/hle/service/filesystem/romfs_controller.h"
28#include "core/hle/service/filesystem/save_data_controller.h" 28#include "core/hle/service/filesystem/save_data_controller.h"
29#include "core/hle/service/server_manager.h" 29#include "core/hle/service/server_manager.h"
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
new file mode 100644
index 000000000..62512ad0f
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -0,0 +1,79 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/savedata_factory.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::FileSystem {
9
10template <typename T>
11static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
12 FileSys::EntryType type) {
13 entries.reserve(entries.size() + new_data.size());
14
15 for (const auto& new_entry : new_data) {
16 auto name = new_entry->GetName();
17
18 if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) {
19 continue;
20 }
21
22 entries.emplace_back(name, type,
23 type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
24 }
25}
26
27IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode)
28 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
29 static const FunctionInfo functions[] = {
30 {0, &IDirectory::Read, "Read"},
31 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
32 };
33 RegisterHandlers(functions);
34
35 // TODO(DarkLordZach): Verify that this is the correct behavior.
36 // Build entry index now to save time later.
37 if (True(mode & OpenDirectoryMode::Directory)) {
38 BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
39 }
40 if (True(mode & OpenDirectoryMode::File)) {
41 BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
42 }
43}
44
45void IDirectory::Read(HLERequestContext& ctx) {
46 LOG_DEBUG(Service_FS, "called.");
47
48 // Calculate how many entries we can fit in the output buffer
49 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>();
50
51 // Cap at total number of entries.
52 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
53
54 // Determine data start and end
55 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
56 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
57 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
58
59 next_entry_index += actual_entries;
60
61 // Write the data to memory
62 ctx.WriteBuffer(begin, range_size);
63
64 IPC::ResponseBuilder rb{ctx, 4};
65 rb.Push(ResultSuccess);
66 rb.Push(actual_entries);
67}
68
69void IDirectory::GetEntryCount(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_FS, "called");
71
72 u64 count = entries.size() - next_entry_index;
73
74 IPC::ResponseBuilder rb{ctx, 4};
75 rb.Push(ResultSuccess);
76 rb.Push(count);
77}
78
79} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
new file mode 100644
index 000000000..2a28ee496
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs.h"
7#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp_util.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class IDirectory final : public ServiceFramework<IDirectory> {
14public:
15 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
16 OpenDirectoryMode mode);
17
18private:
19 FileSys::VirtualDir backend;
20 std::vector<FileSys::Entry> entries;
21 u64 next_entry_index = 0;
22
23 void Read(HLERequestContext& ctx);
24 void GetEntryCount(HLERequestContext& ctx);
25};
26
27} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
new file mode 100644
index 000000000..7e0c90a89
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -0,0 +1,127 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/errors.h"
5#include "core/hle/service/filesystem/fsp/fs_i_file.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::FileSystem {
9
10IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = {
13 {0, &IFile::Read, "Read"},
14 {1, &IFile::Write, "Write"},
15 {2, &IFile::Flush, "Flush"},
16 {3, &IFile::SetSize, "SetSize"},
17 {4, &IFile::GetSize, "GetSize"},
18 {5, nullptr, "OperateRange"},
19 {6, nullptr, "OperateRangeWithBuffer"},
20 };
21 RegisterHandlers(functions);
22}
23
24void IFile::Read(HLERequestContext& ctx) {
25 IPC::RequestParser rp{ctx};
26 const u64 option = rp.Pop<u64>();
27 const s64 offset = rp.Pop<s64>();
28 const s64 length = rp.Pop<s64>();
29
30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
31
32 // Error checking
33 if (length < 0) {
34 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
35 IPC::ResponseBuilder rb{ctx, 2};
36 rb.Push(FileSys::ERROR_INVALID_SIZE);
37 return;
38 }
39 if (offset < 0) {
40 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
41 IPC::ResponseBuilder rb{ctx, 2};
42 rb.Push(FileSys::ERROR_INVALID_OFFSET);
43 return;
44 }
45
46 // Read the data from the Storage backend
47 std::vector<u8> output = backend->ReadBytes(length, offset);
48
49 // Write the data to memory
50 ctx.WriteBuffer(output);
51
52 IPC::ResponseBuilder rb{ctx, 4};
53 rb.Push(ResultSuccess);
54 rb.Push(static_cast<u64>(output.size()));
55}
56
57void IFile::Write(HLERequestContext& ctx) {
58 IPC::RequestParser rp{ctx};
59 const u64 option = rp.Pop<u64>();
60 const s64 offset = rp.Pop<s64>();
61 const s64 length = rp.Pop<s64>();
62
63 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
64
65 // Error checking
66 if (length < 0) {
67 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(FileSys::ERROR_INVALID_SIZE);
70 return;
71 }
72 if (offset < 0) {
73 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(FileSys::ERROR_INVALID_OFFSET);
76 return;
77 }
78
79 const auto data = ctx.ReadBuffer();
80
81 ASSERT_MSG(static_cast<s64>(data.size()) <= length,
82 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
83 length, data.size());
84
85 // Write the data to the Storage backend
86 const auto write_size =
87 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
88 const std::size_t written = backend->Write(data.data(), write_size, offset);
89
90 ASSERT_MSG(static_cast<s64>(written) == length,
91 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
92 written);
93
94 IPC::ResponseBuilder rb{ctx, 2};
95 rb.Push(ResultSuccess);
96}
97
98void IFile::Flush(HLERequestContext& ctx) {
99 LOG_DEBUG(Service_FS, "called");
100
101 // Exists for SDK compatibiltity -- No need to flush file.
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105}
106
107void IFile::SetSize(HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109 const u64 size = rp.Pop<u64>();
110 LOG_DEBUG(Service_FS, "called, size={}", size);
111
112 backend->Resize(size);
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116}
117
118void IFile::GetSize(HLERequestContext& ctx) {
119 const u64 size = backend->GetSize();
120 LOG_DEBUG(Service_FS, "called, size={}", size);
121
122 IPC::ResponseBuilder rb{ctx, 4};
123 rb.Push(ResultSuccess);
124 rb.Push<u64>(size);
125}
126
127} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h
new file mode 100644
index 000000000..a7eb1a1e9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs.h"
7#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h"
9
10namespace Service::FileSystem {
11
12class IFile final : public ServiceFramework<IFile> {
13public:
14 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_);
15
16private:
17 FileSys::VirtualFile backend;
18
19 void Read(HLERequestContext& ctx);
20 void Write(HLERequestContext& ctx);
21 void Flush(HLERequestContext& ctx);
22 void SetSize(HLERequestContext& ctx);
23 void GetSize(HLERequestContext& ctx);
24};
25
26} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
new file mode 100644
index 000000000..3e72101a4
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -0,0 +1,262 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_file.h"
7#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
8#include "core/hle/service/ipc_helpers.h"
9
10namespace Service::FileSystem {
11
12IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
13 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)},
14 size{std::move(size_)} {
15 static const FunctionInfo functions[] = {
16 {0, &IFileSystem::CreateFile, "CreateFile"},
17 {1, &IFileSystem::DeleteFile, "DeleteFile"},
18 {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
19 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
20 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
21 {5, &IFileSystem::RenameFile, "RenameFile"},
22 {6, nullptr, "RenameDirectory"},
23 {7, &IFileSystem::GetEntryType, "GetEntryType"},
24 {8, &IFileSystem::OpenFile, "OpenFile"},
25 {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
26 {10, &IFileSystem::Commit, "Commit"},
27 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
28 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
29 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
30 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
31 {15, nullptr, "QueryEntry"},
32 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
33 };
34 RegisterHandlers(functions);
35}
36
37void IFileSystem::CreateFile(HLERequestContext& ctx) {
38 IPC::RequestParser rp{ctx};
39
40 const auto file_buffer = ctx.ReadBuffer();
41 const std::string name = Common::StringFromBuffer(file_buffer);
42
43 const u64 file_mode = rp.Pop<u64>();
44 const u32 file_size = rp.Pop<u32>();
45
46 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
47 file_size);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(backend.CreateFile(name, file_size));
51}
52
53void IFileSystem::DeleteFile(HLERequestContext& ctx) {
54 const auto file_buffer = ctx.ReadBuffer();
55 const std::string name = Common::StringFromBuffer(file_buffer);
56
57 LOG_DEBUG(Service_FS, "called. file={}", name);
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(backend.DeleteFile(name));
61}
62
63void IFileSystem::CreateDirectory(HLERequestContext& ctx) {
64 const auto file_buffer = ctx.ReadBuffer();
65 const std::string name = Common::StringFromBuffer(file_buffer);
66
67 LOG_DEBUG(Service_FS, "called. directory={}", name);
68
69 IPC::ResponseBuilder rb{ctx, 2};
70 rb.Push(backend.CreateDirectory(name));
71}
72
73void IFileSystem::DeleteDirectory(HLERequestContext& ctx) {
74 const auto file_buffer = ctx.ReadBuffer();
75 const std::string name = Common::StringFromBuffer(file_buffer);
76
77 LOG_DEBUG(Service_FS, "called. directory={}", name);
78
79 IPC::ResponseBuilder rb{ctx, 2};
80 rb.Push(backend.DeleteDirectory(name));
81}
82
83void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) {
84 const auto file_buffer = ctx.ReadBuffer();
85 const std::string name = Common::StringFromBuffer(file_buffer);
86
87 LOG_DEBUG(Service_FS, "called. directory={}", name);
88
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(backend.DeleteDirectoryRecursively(name));
91}
92
93void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) {
94 const auto file_buffer = ctx.ReadBuffer();
95 const std::string name = Common::StringFromBuffer(file_buffer);
96
97 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
98
99 IPC::ResponseBuilder rb{ctx, 2};
100 rb.Push(backend.CleanDirectoryRecursively(name));
101}
102
103void IFileSystem::RenameFile(HLERequestContext& ctx) {
104 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
105 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
106
107 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
108
109 IPC::ResponseBuilder rb{ctx, 2};
110 rb.Push(backend.RenameFile(src_name, dst_name));
111}
112
113void IFileSystem::OpenFile(HLERequestContext& ctx) {
114 IPC::RequestParser rp{ctx};
115
116 const auto file_buffer = ctx.ReadBuffer();
117 const std::string name = Common::StringFromBuffer(file_buffer);
118
119 const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
120
121 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
122
123 FileSys::VirtualFile vfs_file{};
124 auto result = backend.OpenFile(&vfs_file, name, mode);
125 if (result != ResultSuccess) {
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(result);
128 return;
129 }
130
131 auto file = std::make_shared<IFile>(system, vfs_file);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(ResultSuccess);
135 rb.PushIpcInterface<IFile>(std::move(file));
136}
137
138void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140
141 const auto file_buffer = ctx.ReadBuffer();
142 const std::string name = Common::StringFromBuffer(file_buffer);
143 const auto mode = rp.PopRaw<OpenDirectoryMode>();
144
145 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
146
147 FileSys::VirtualDir vfs_dir{};
148 auto result = backend.OpenDirectory(&vfs_dir, name);
149 if (result != ResultSuccess) {
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(result);
152 return;
153 }
154
155 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158 rb.Push(ResultSuccess);
159 rb.PushIpcInterface<IDirectory>(std::move(directory));
160}
161
162void IFileSystem::GetEntryType(HLERequestContext& ctx) {
163 const auto file_buffer = ctx.ReadBuffer();
164 const std::string name = Common::StringFromBuffer(file_buffer);
165
166 LOG_DEBUG(Service_FS, "called. file={}", name);
167
168 FileSys::EntryType vfs_entry_type{};
169 auto result = backend.GetEntryType(&vfs_entry_type, name);
170 if (result != ResultSuccess) {
171 IPC::ResponseBuilder rb{ctx, 2};
172 rb.Push(result);
173 return;
174 }
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
179}
180
181void IFileSystem::Commit(HLERequestContext& ctx) {
182 LOG_WARNING(Service_FS, "(STUBBED) called");
183
184 IPC::ResponseBuilder rb{ctx, 2};
185 rb.Push(ResultSuccess);
186}
187
188void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) {
189 LOG_DEBUG(Service_FS, "called");
190
191 IPC::ResponseBuilder rb{ctx, 4};
192 rb.Push(ResultSuccess);
193 rb.Push(size.get_free_size());
194}
195
196void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) {
197 LOG_DEBUG(Service_FS, "called");
198
199 IPC::ResponseBuilder rb{ctx, 4};
200 rb.Push(ResultSuccess);
201 rb.Push(size.get_total_size());
202}
203
204void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) {
205 const auto file_buffer = ctx.ReadBuffer();
206 const std::string name = Common::StringFromBuffer(file_buffer);
207
208 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
209
210 FileSys::FileTimeStampRaw vfs_timestamp{};
211 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
212 if (result != ResultSuccess) {
213 IPC::ResponseBuilder rb{ctx, 2};
214 rb.Push(result);
215 return;
216 }
217
218 IPC::ResponseBuilder rb{ctx, 10};
219 rb.Push(ResultSuccess);
220 rb.PushRaw(vfs_timestamp);
221}
222
223void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) {
224 LOG_WARNING(Service_FS, "(STUBBED) called");
225
226 struct FileSystemAttribute {
227 u8 dir_entry_name_length_max_defined;
228 u8 file_entry_name_length_max_defined;
229 u8 dir_path_name_length_max_defined;
230 u8 file_path_name_length_max_defined;
231 INSERT_PADDING_BYTES_NOINIT(0x5);
232 u8 utf16_dir_entry_name_length_max_defined;
233 u8 utf16_file_entry_name_length_max_defined;
234 u8 utf16_dir_path_name_length_max_defined;
235 u8 utf16_file_path_name_length_max_defined;
236 INSERT_PADDING_BYTES_NOINIT(0x18);
237 s32 dir_entry_name_length_max;
238 s32 file_entry_name_length_max;
239 s32 dir_path_name_length_max;
240 s32 file_path_name_length_max;
241 INSERT_PADDING_WORDS_NOINIT(0x5);
242 s32 utf16_dir_entry_name_length_max;
243 s32 utf16_file_entry_name_length_max;
244 s32 utf16_dir_path_name_length_max;
245 s32 utf16_file_path_name_length_max;
246 INSERT_PADDING_WORDS_NOINIT(0x18);
247 INSERT_PADDING_WORDS_NOINIT(0x1);
248 };
249 static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
250
251 FileSystemAttribute savedata_attribute{};
252 savedata_attribute.dir_entry_name_length_max_defined = true;
253 savedata_attribute.file_entry_name_length_max_defined = true;
254 savedata_attribute.dir_entry_name_length_max = 0x40;
255 savedata_attribute.file_entry_name_length_max = 0x40;
256
257 IPC::ResponseBuilder rb{ctx, 50};
258 rb.Push(ResultSuccess);
259 rb.PushRaw(savedata_attribute);
260}
261
262} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
new file mode 100644
index 000000000..c9e94c911
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs.h"
7#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp/fsp_util.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class IFileSystem final : public ServiceFramework<IFileSystem> {
14public:
15 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_);
16
17 void CreateFile(HLERequestContext& ctx);
18 void DeleteFile(HLERequestContext& ctx);
19 void CreateDirectory(HLERequestContext& ctx);
20 void DeleteDirectory(HLERequestContext& ctx);
21 void DeleteDirectoryRecursively(HLERequestContext& ctx);
22 void CleanDirectoryRecursively(HLERequestContext& ctx);
23 void RenameFile(HLERequestContext& ctx);
24 void OpenFile(HLERequestContext& ctx);
25 void OpenDirectory(HLERequestContext& ctx);
26 void GetEntryType(HLERequestContext& ctx);
27 void Commit(HLERequestContext& ctx);
28 void GetFreeSpaceSize(HLERequestContext& ctx);
29 void GetTotalSpaceSize(HLERequestContext& ctx);
30 void GetFileTimeStampRaw(HLERequestContext& ctx);
31 void GetFileSystemAttribute(HLERequestContext& ctx);
32
33private:
34 VfsDirectoryServiceWrapper backend;
35 SizeGetter size;
36};
37
38} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
new file mode 100644
index 000000000..9fe36f31a
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -0,0 +1,62 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/file_sys/errors.h"
5#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::FileSystem {
9
10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = {
13 {0, &IStorage::Read, "Read"},
14 {1, nullptr, "Write"},
15 {2, nullptr, "Flush"},
16 {3, nullptr, "SetSize"},
17 {4, &IStorage::GetSize, "GetSize"},
18 {5, nullptr, "OperateRange"},
19 };
20 RegisterHandlers(functions);
21}
22
23void IStorage::Read(HLERequestContext& ctx) {
24 IPC::RequestParser rp{ctx};
25 const s64 offset = rp.Pop<s64>();
26 const s64 length = rp.Pop<s64>();
27
28 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
29
30 // Error checking
31 if (length < 0) {
32 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
33 IPC::ResponseBuilder rb{ctx, 2};
34 rb.Push(FileSys::ERROR_INVALID_SIZE);
35 return;
36 }
37 if (offset < 0) {
38 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(FileSys::ERROR_INVALID_OFFSET);
41 return;
42 }
43
44 // Read the data from the Storage backend
45 std::vector<u8> output = backend->ReadBytes(length, offset);
46 // Write the data to memory
47 ctx.WriteBuffer(output);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(ResultSuccess);
51}
52
53void IStorage::GetSize(HLERequestContext& ctx) {
54 const u64 size = backend->GetSize();
55 LOG_DEBUG(Service_FS, "called, size={}", size);
56
57 IPC::ResponseBuilder rb{ctx, 4};
58 rb.Push(ResultSuccess);
59 rb.Push<u64>(size);
60}
61
62} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
new file mode 100644
index 000000000..48d059874
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs.h"
7#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h"
9
10namespace Service::FileSystem {
11
12class IStorage final : public ServiceFramework<IStorage> {
13public:
14 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_);
15
16private:
17 FileSys::VirtualFile backend;
18
19 void Read(HLERequestContext& ctx);
20 void GetSize(HLERequestContext& ctx);
21};
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp
index 1e3366e71..8ee733f47 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/filesystem/fsp_ldr.h" 4#include "core/hle/service/filesystem/fsp/fsp_ldr.h"
5 5
6namespace Service::FileSystem { 6namespace Service::FileSystem {
7 7
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp/fsp_ldr.h
index 358739a87..358739a87 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.h
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp
index 4ffc31977..7c03ebaea 100644
--- a/src/core/hle/service/filesystem/fsp_pr.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/filesystem/fsp_pr.h" 4#include "core/hle/service/filesystem/fsp/fsp_pr.h"
5 5
6namespace Service::FileSystem { 6namespace Service::FileSystem {
7 7
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp/fsp_pr.h
index bd4e0a730..bd4e0a730 100644
--- a/src/core/hle/service/filesystem/fsp_pr.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_pr.h
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index a2397bec4..85ab75517 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -26,7 +26,9 @@
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs.h"
27#include "core/hle/result.h" 27#include "core/hle/result.h"
28#include "core/hle/service/filesystem/filesystem.h" 28#include "core/hle/service/filesystem/filesystem.h"
29#include "core/hle/service/filesystem/fsp_srv.h" 29#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
30#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
31#include "core/hle/service/filesystem/fsp/fsp_srv.h"
30#include "core/hle/service/filesystem/romfs_controller.h" 32#include "core/hle/service/filesystem/romfs_controller.h"
31#include "core/hle/service/filesystem/save_data_controller.h" 33#include "core/hle/service/filesystem/save_data_controller.h"
32#include "core/hle/service/hle_ipc.h" 34#include "core/hle/service/hle_ipc.h"
@@ -34,19 +36,6 @@
34#include "core/reporter.h" 36#include "core/reporter.h"
35 37
36namespace Service::FileSystem { 38namespace Service::FileSystem {
37
38struct SizeGetter {
39 std::function<u64()> get_free_size;
40 std::function<u64()> get_total_size;
41
42 static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
43 return {
44 [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
45 [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
46 };
47 }
48};
49
50enum class FileSystemType : u8 { 39enum class FileSystemType : u8 {
51 Invalid0 = 0, 40 Invalid0 = 0,
52 Invalid1 = 1, 41 Invalid1 = 1,
@@ -58,532 +47,13 @@ enum class FileSystemType : u8 {
58 ApplicationPackage = 7, 47 ApplicationPackage = 7,
59}; 48};
60 49
61class IStorage final : public ServiceFramework<IStorage> {
62public:
63 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
64 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
65 static const FunctionInfo functions[] = {
66 {0, &IStorage::Read, "Read"},
67 {1, nullptr, "Write"},
68 {2, nullptr, "Flush"},
69 {3, nullptr, "SetSize"},
70 {4, &IStorage::GetSize, "GetSize"},
71 {5, nullptr, "OperateRange"},
72 };
73 RegisterHandlers(functions);
74 }
75
76private:
77 FileSys::VirtualFile backend;
78
79 void Read(HLERequestContext& ctx) {
80 IPC::RequestParser rp{ctx};
81 const s64 offset = rp.Pop<s64>();
82 const s64 length = rp.Pop<s64>();
83
84 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
85
86 // Error checking
87 if (length < 0) {
88 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(FileSys::ERROR_INVALID_SIZE);
91 return;
92 }
93 if (offset < 0) {
94 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
95 IPC::ResponseBuilder rb{ctx, 2};
96 rb.Push(FileSys::ERROR_INVALID_OFFSET);
97 return;
98 }
99
100 // Read the data from the Storage backend
101 std::vector<u8> output = backend->ReadBytes(length, offset);
102 // Write the data to memory
103 ctx.WriteBuffer(output);
104
105 IPC::ResponseBuilder rb{ctx, 2};
106 rb.Push(ResultSuccess);
107 }
108
109 void GetSize(HLERequestContext& ctx) {
110 const u64 size = backend->GetSize();
111 LOG_DEBUG(Service_FS, "called, size={}", size);
112
113 IPC::ResponseBuilder rb{ctx, 4};
114 rb.Push(ResultSuccess);
115 rb.Push<u64>(size);
116 }
117};
118
119class IFile final : public ServiceFramework<IFile> {
120public:
121 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
122 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
123 static const FunctionInfo functions[] = {
124 {0, &IFile::Read, "Read"},
125 {1, &IFile::Write, "Write"},
126 {2, &IFile::Flush, "Flush"},
127 {3, &IFile::SetSize, "SetSize"},
128 {4, &IFile::GetSize, "GetSize"},
129 {5, nullptr, "OperateRange"},
130 {6, nullptr, "OperateRangeWithBuffer"},
131 };
132 RegisterHandlers(functions);
133 }
134
135private:
136 FileSys::VirtualFile backend;
137
138 void Read(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140 const u64 option = rp.Pop<u64>();
141 const s64 offset = rp.Pop<s64>();
142 const s64 length = rp.Pop<s64>();
143
144 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
145 length);
146
147 // Error checking
148 if (length < 0) {
149 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(FileSys::ERROR_INVALID_SIZE);
152 return;
153 }
154 if (offset < 0) {
155 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
156 IPC::ResponseBuilder rb{ctx, 2};
157 rb.Push(FileSys::ERROR_INVALID_OFFSET);
158 return;
159 }
160
161 // Read the data from the Storage backend
162 std::vector<u8> output = backend->ReadBytes(length, offset);
163
164 // Write the data to memory
165 ctx.WriteBuffer(output);
166
167 IPC::ResponseBuilder rb{ctx, 4};
168 rb.Push(ResultSuccess);
169 rb.Push(static_cast<u64>(output.size()));
170 }
171
172 void Write(HLERequestContext& ctx) {
173 IPC::RequestParser rp{ctx};
174 const u64 option = rp.Pop<u64>();
175 const s64 offset = rp.Pop<s64>();
176 const s64 length = rp.Pop<s64>();
177
178 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
179 length);
180
181 // Error checking
182 if (length < 0) {
183 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
184 IPC::ResponseBuilder rb{ctx, 2};
185 rb.Push(FileSys::ERROR_INVALID_SIZE);
186 return;
187 }
188 if (offset < 0) {
189 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
190 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(FileSys::ERROR_INVALID_OFFSET);
192 return;
193 }
194
195 const auto data = ctx.ReadBuffer();
196
197 ASSERT_MSG(
198 static_cast<s64>(data.size()) <= length,
199 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
200 length, data.size());
201
202 // Write the data to the Storage backend
203 const auto write_size =
204 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
205 const std::size_t written = backend->Write(data.data(), write_size, offset);
206
207 ASSERT_MSG(static_cast<s64>(written) == length,
208 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
209 written);
210
211 IPC::ResponseBuilder rb{ctx, 2};
212 rb.Push(ResultSuccess);
213 }
214
215 void Flush(HLERequestContext& ctx) {
216 LOG_DEBUG(Service_FS, "called");
217
218 // Exists for SDK compatibiltity -- No need to flush file.
219
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(ResultSuccess);
222 }
223
224 void SetSize(HLERequestContext& ctx) {
225 IPC::RequestParser rp{ctx};
226 const u64 size = rp.Pop<u64>();
227 LOG_DEBUG(Service_FS, "called, size={}", size);
228
229 backend->Resize(size);
230
231 IPC::ResponseBuilder rb{ctx, 2};
232 rb.Push(ResultSuccess);
233 }
234
235 void GetSize(HLERequestContext& ctx) {
236 const u64 size = backend->GetSize();
237 LOG_DEBUG(Service_FS, "called, size={}", size);
238
239 IPC::ResponseBuilder rb{ctx, 4};
240 rb.Push(ResultSuccess);
241 rb.Push<u64>(size);
242 }
243};
244
245template <typename T>
246static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
247 FileSys::EntryType type) {
248 entries.reserve(entries.size() + new_data.size());
249
250 for (const auto& new_entry : new_data) {
251 auto name = new_entry->GetName();
252
253 if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) {
254 continue;
255 }
256
257 entries.emplace_back(name, type,
258 type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
259 }
260}
261
262class IDirectory final : public ServiceFramework<IDirectory> {
263public:
264 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode)
265 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
266 static const FunctionInfo functions[] = {
267 {0, &IDirectory::Read, "Read"},
268 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
269 };
270 RegisterHandlers(functions);
271
272 // TODO(DarkLordZach): Verify that this is the correct behavior.
273 // Build entry index now to save time later.
274 if (True(mode & OpenDirectoryMode::Directory)) {
275 BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
276 }
277 if (True(mode & OpenDirectoryMode::File)) {
278 BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
279 }
280 }
281
282private:
283 FileSys::VirtualDir backend;
284 std::vector<FileSys::Entry> entries;
285 u64 next_entry_index = 0;
286
287 void Read(HLERequestContext& ctx) {
288 LOG_DEBUG(Service_FS, "called.");
289
290 // Calculate how many entries we can fit in the output buffer
291 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>();
292
293 // Cap at total number of entries.
294 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
295
296 // Determine data start and end
297 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
298 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
299 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
300
301 next_entry_index += actual_entries;
302
303 // Write the data to memory
304 ctx.WriteBuffer(begin, range_size);
305
306 IPC::ResponseBuilder rb{ctx, 4};
307 rb.Push(ResultSuccess);
308 rb.Push(actual_entries);
309 }
310
311 void GetEntryCount(HLERequestContext& ctx) {
312 LOG_DEBUG(Service_FS, "called");
313
314 u64 count = entries.size() - next_entry_index;
315
316 IPC::ResponseBuilder rb{ctx, 4};
317 rb.Push(ResultSuccess);
318 rb.Push(count);
319 }
320};
321
322class IFileSystem final : public ServiceFramework<IFileSystem> {
323public:
324 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
325 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
326 size_)} {
327 static const FunctionInfo functions[] = {
328 {0, &IFileSystem::CreateFile, "CreateFile"},
329 {1, &IFileSystem::DeleteFile, "DeleteFile"},
330 {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
331 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
332 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
333 {5, &IFileSystem::RenameFile, "RenameFile"},
334 {6, nullptr, "RenameDirectory"},
335 {7, &IFileSystem::GetEntryType, "GetEntryType"},
336 {8, &IFileSystem::OpenFile, "OpenFile"},
337 {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
338 {10, &IFileSystem::Commit, "Commit"},
339 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
340 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
341 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
342 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
343 {15, nullptr, "QueryEntry"},
344 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
345 };
346 RegisterHandlers(functions);
347 }
348
349 void CreateFile(HLERequestContext& ctx) {
350 IPC::RequestParser rp{ctx};
351
352 const auto file_buffer = ctx.ReadBuffer();
353 const std::string name = Common::StringFromBuffer(file_buffer);
354
355 const u64 file_mode = rp.Pop<u64>();
356 const u32 file_size = rp.Pop<u32>();
357
358 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
359 file_size);
360
361 IPC::ResponseBuilder rb{ctx, 2};
362 rb.Push(backend.CreateFile(name, file_size));
363 }
364
365 void DeleteFile(HLERequestContext& ctx) {
366 const auto file_buffer = ctx.ReadBuffer();
367 const std::string name = Common::StringFromBuffer(file_buffer);
368
369 LOG_DEBUG(Service_FS, "called. file={}", name);
370
371 IPC::ResponseBuilder rb{ctx, 2};
372 rb.Push(backend.DeleteFile(name));
373 }
374
375 void CreateDirectory(HLERequestContext& ctx) {
376 const auto file_buffer = ctx.ReadBuffer();
377 const std::string name = Common::StringFromBuffer(file_buffer);
378
379 LOG_DEBUG(Service_FS, "called. directory={}", name);
380
381 IPC::ResponseBuilder rb{ctx, 2};
382 rb.Push(backend.CreateDirectory(name));
383 }
384
385 void DeleteDirectory(HLERequestContext& ctx) {
386 const auto file_buffer = ctx.ReadBuffer();
387 const std::string name = Common::StringFromBuffer(file_buffer);
388
389 LOG_DEBUG(Service_FS, "called. directory={}", name);
390
391 IPC::ResponseBuilder rb{ctx, 2};
392 rb.Push(backend.DeleteDirectory(name));
393 }
394
395 void DeleteDirectoryRecursively(HLERequestContext& ctx) {
396 const auto file_buffer = ctx.ReadBuffer();
397 const std::string name = Common::StringFromBuffer(file_buffer);
398
399 LOG_DEBUG(Service_FS, "called. directory={}", name);
400
401 IPC::ResponseBuilder rb{ctx, 2};
402 rb.Push(backend.DeleteDirectoryRecursively(name));
403 }
404
405 void CleanDirectoryRecursively(HLERequestContext& ctx) {
406 const auto file_buffer = ctx.ReadBuffer();
407 const std::string name = Common::StringFromBuffer(file_buffer);
408
409 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
410
411 IPC::ResponseBuilder rb{ctx, 2};
412 rb.Push(backend.CleanDirectoryRecursively(name));
413 }
414
415 void RenameFile(HLERequestContext& ctx) {
416 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
417 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
418
419 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
420
421 IPC::ResponseBuilder rb{ctx, 2};
422 rb.Push(backend.RenameFile(src_name, dst_name));
423 }
424
425 void OpenFile(HLERequestContext& ctx) {
426 IPC::RequestParser rp{ctx};
427
428 const auto file_buffer = ctx.ReadBuffer();
429 const std::string name = Common::StringFromBuffer(file_buffer);
430
431 const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
432
433 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
434
435 FileSys::VirtualFile vfs_file{};
436 auto result = backend.OpenFile(&vfs_file, name, mode);
437 if (result != ResultSuccess) {
438 IPC::ResponseBuilder rb{ctx, 2};
439 rb.Push(result);
440 return;
441 }
442
443 auto file = std::make_shared<IFile>(system, vfs_file);
444
445 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
446 rb.Push(ResultSuccess);
447 rb.PushIpcInterface<IFile>(std::move(file));
448 }
449
450 void OpenDirectory(HLERequestContext& ctx) {
451 IPC::RequestParser rp{ctx};
452
453 const auto file_buffer = ctx.ReadBuffer();
454 const std::string name = Common::StringFromBuffer(file_buffer);
455 const auto mode = rp.PopRaw<OpenDirectoryMode>();
456
457 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
458
459 FileSys::VirtualDir vfs_dir{};
460 auto result = backend.OpenDirectory(&vfs_dir, name);
461 if (result != ResultSuccess) {
462 IPC::ResponseBuilder rb{ctx, 2};
463 rb.Push(result);
464 return;
465 }
466
467 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
468
469 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
470 rb.Push(ResultSuccess);
471 rb.PushIpcInterface<IDirectory>(std::move(directory));
472 }
473
474 void GetEntryType(HLERequestContext& ctx) {
475 const auto file_buffer = ctx.ReadBuffer();
476 const std::string name = Common::StringFromBuffer(file_buffer);
477
478 LOG_DEBUG(Service_FS, "called. file={}", name);
479
480 FileSys::EntryType vfs_entry_type{};
481 auto result = backend.GetEntryType(&vfs_entry_type, name);
482 if (result != ResultSuccess) {
483 IPC::ResponseBuilder rb{ctx, 2};
484 rb.Push(result);
485 return;
486 }
487
488 IPC::ResponseBuilder rb{ctx, 3};
489 rb.Push(ResultSuccess);
490 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
491 }
492
493 void Commit(HLERequestContext& ctx) {
494 LOG_WARNING(Service_FS, "(STUBBED) called");
495
496 IPC::ResponseBuilder rb{ctx, 2};
497 rb.Push(ResultSuccess);
498 }
499
500 void GetFreeSpaceSize(HLERequestContext& ctx) {
501 LOG_DEBUG(Service_FS, "called");
502
503 IPC::ResponseBuilder rb{ctx, 4};
504 rb.Push(ResultSuccess);
505 rb.Push(size.get_free_size());
506 }
507
508 void GetTotalSpaceSize(HLERequestContext& ctx) {
509 LOG_DEBUG(Service_FS, "called");
510
511 IPC::ResponseBuilder rb{ctx, 4};
512 rb.Push(ResultSuccess);
513 rb.Push(size.get_total_size());
514 }
515
516 void GetFileTimeStampRaw(HLERequestContext& ctx) {
517 const auto file_buffer = ctx.ReadBuffer();
518 const std::string name = Common::StringFromBuffer(file_buffer);
519
520 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
521
522 FileSys::FileTimeStampRaw vfs_timestamp{};
523 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
524 if (result != ResultSuccess) {
525 IPC::ResponseBuilder rb{ctx, 2};
526 rb.Push(result);
527 return;
528 }
529
530 IPC::ResponseBuilder rb{ctx, 10};
531 rb.Push(ResultSuccess);
532 rb.PushRaw(vfs_timestamp);
533 }
534
535 void GetFileSystemAttribute(HLERequestContext& ctx) {
536 LOG_WARNING(Service_FS, "(STUBBED) called");
537
538 struct FileSystemAttribute {
539 u8 dir_entry_name_length_max_defined;
540 u8 file_entry_name_length_max_defined;
541 u8 dir_path_name_length_max_defined;
542 u8 file_path_name_length_max_defined;
543 INSERT_PADDING_BYTES_NOINIT(0x5);
544 u8 utf16_dir_entry_name_length_max_defined;
545 u8 utf16_file_entry_name_length_max_defined;
546 u8 utf16_dir_path_name_length_max_defined;
547 u8 utf16_file_path_name_length_max_defined;
548 INSERT_PADDING_BYTES_NOINIT(0x18);
549 s32 dir_entry_name_length_max;
550 s32 file_entry_name_length_max;
551 s32 dir_path_name_length_max;
552 s32 file_path_name_length_max;
553 INSERT_PADDING_WORDS_NOINIT(0x5);
554 s32 utf16_dir_entry_name_length_max;
555 s32 utf16_file_entry_name_length_max;
556 s32 utf16_dir_path_name_length_max;
557 s32 utf16_file_path_name_length_max;
558 INSERT_PADDING_WORDS_NOINIT(0x18);
559 INSERT_PADDING_WORDS_NOINIT(0x1);
560 };
561 static_assert(sizeof(FileSystemAttribute) == 0xc0,
562 "FileSystemAttribute has incorrect size");
563
564 FileSystemAttribute savedata_attribute{};
565 savedata_attribute.dir_entry_name_length_max_defined = true;
566 savedata_attribute.file_entry_name_length_max_defined = true;
567 savedata_attribute.dir_entry_name_length_max = 0x40;
568 savedata_attribute.file_entry_name_length_max = 0x40;
569
570 IPC::ResponseBuilder rb{ctx, 50};
571 rb.Push(ResultSuccess);
572 rb.PushRaw(savedata_attribute);
573 }
574
575private:
576 VfsDirectoryServiceWrapper backend;
577 SizeGetter size;
578};
579
580class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { 50class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
581public: 51public:
582 explicit ISaveDataInfoReader(Core::System& system_, 52 explicit ISaveDataInfoReader(Core::System& system_,
583 std::shared_ptr<SaveDataController> save_data_controller_, 53 std::shared_ptr<SaveDataController> save_data_controller_,
584 FileSys::SaveDataSpaceId space) 54 FileSys::SaveDataSpaceId space)
585 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{ 55 : ServiceFramework{system_, "ISaveDataInfoReader"},
586 save_data_controller_} { 56 save_data_controller{save_data_controller_} {
587 static const FunctionInfo functions[] = { 57 static const FunctionInfo functions[] = {
588 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, 58 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
589 }; 59 };
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 26980af99..26980af99 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_util.h
new file mode 100644
index 000000000..253f866db
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_util.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/filesystem/filesystem.h"
7
8namespace Service::FileSystem {
9
10struct SizeGetter {
11 std::function<u64()> get_free_size;
12 std::function<u64()> get_total_size;
13
14 static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
15 return {
16 [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
17 [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
18 };
19 }
20};
21
22} // namespace Service::FileSystem