summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar David Marcec2018-08-11 10:35:47 +1000
committerGravatar David Marcec2018-08-11 10:35:47 +1000
commitb76ddb7647cbb390cce4143d91a1db171b0fa503 (patch)
treea6e2e334e82b035923c41458150604dd5fb31d65 /src/core
parentAdded IsUserRegistrationRequestPermitted (diff)
parentMerge pull request #1007 from MerryMage/dynarmic (diff)
downloadyuzu-b76ddb7647cbb390cce4143d91a1db171b0fa503.tar.gz
yuzu-b76ddb7647cbb390cce4143d91a1db171b0fa503.tar.xz
yuzu-b76ddb7647cbb390cce4143d91a1db171b0fa503.zip
Merge remote-tracking branch 'origin/master' into better-account
Diffstat (limited to 'src/core')
-rw-r--r--src/core/core.cpp8
-rw-r--r--src/core/core.h12
-rw-r--r--src/core/file_sys/card_image.cpp1
-rw-r--r--src/core/file_sys/content_archive.cpp4
-rw-r--r--src/core/file_sys/content_archive.h1
-rw-r--r--src/core/file_sys/control_metadata.h7
-rw-r--r--src/core/file_sys/directory.h12
-rw-r--r--src/core/file_sys/savedata_factory.h1
-rw-r--r--src/core/file_sys/vfs.cpp148
-rw-r--r--src/core/file_sys/vfs.h66
-rw-r--r--src/core/file_sys/vfs_real.cpp341
-rw-r--r--src/core/file_sys/vfs_real.h56
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp2
-rw-r--r--src/core/hle/kernel/hle_ipc.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp23
-rw-r--r--src/core/hle/service/am/am.cpp9
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp16
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp7
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h8
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h2
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp7
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h9
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/service.h7
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp68
-rw-r--r--src/core/loader/deconstructed_rom_directory.h7
-rw-r--r--src/core/loader/loader.cpp6
-rw-r--r--src/core/loader/loader.h10
-rw-r--r--src/core/loader/nca.cpp4
-rw-r--r--src/core/loader/nca.h2
-rw-r--r--src/core/loader/xci.cpp33
-rw-r--r--src/core/loader/xci.h5
37 files changed, 758 insertions, 148 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 085ba68d0..69c45c026 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -89,7 +89,7 @@ System::ResultStatus System::SingleStep() {
89} 89}
90 90
91System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { 91System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) {
92 app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath)); 92 app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read));
93 93
94 if (!app_loader) { 94 if (!app_loader) {
95 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 95 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
@@ -174,6 +174,10 @@ System::ResultStatus System::Init(EmuWindow& emu_window) {
174 174
175 CoreTiming::Init(); 175 CoreTiming::Init();
176 176
177 // Create a default fs if one doesn't already exist.
178 if (virtual_filesystem == nullptr)
179 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
180
177 current_process = Kernel::Process::Create("main"); 181 current_process = Kernel::Process::Create("main");
178 182
179 cpu_barrier = std::make_shared<CpuBarrier>(); 183 cpu_barrier = std::make_shared<CpuBarrier>();
@@ -186,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window) {
186 service_manager = std::make_shared<Service::SM::ServiceManager>(); 190 service_manager = std::make_shared<Service::SM::ServiceManager>();
187 191
188 Kernel::Init(); 192 Kernel::Init();
189 Service::Init(service_manager); 193 Service::Init(service_manager, virtual_filesystem);
190 GDBStub::Init(); 194 GDBStub::Init();
191 195
192 renderer = VideoCore::CreateRenderer(emu_window); 196 renderer = VideoCore::CreateRenderer(emu_window);
diff --git a/src/core/core.h b/src/core/core.h
index c8ca4b247..7cf7ea4e1 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -17,6 +17,8 @@
17#include "core/memory.h" 17#include "core/memory.h"
18#include "core/perf_stats.h" 18#include "core/perf_stats.h"
19#include "core/telemetry_session.h" 19#include "core/telemetry_session.h"
20#include "file_sys/vfs_real.h"
21#include "hle/service/filesystem/filesystem.h"
20#include "video_core/debug_utils/debug_utils.h" 22#include "video_core/debug_utils/debug_utils.h"
21#include "video_core/gpu.h" 23#include "video_core/gpu.h"
22 24
@@ -211,6 +213,14 @@ public:
211 return debug_context; 213 return debug_context;
212 } 214 }
213 215
216 void SetFilesystem(FileSys::VirtualFilesystem vfs) {
217 virtual_filesystem = std::move(vfs);
218 }
219
220 FileSys::VirtualFilesystem GetFilesystem() const {
221 return virtual_filesystem;
222 }
223
214private: 224private:
215 System(); 225 System();
216 226
@@ -225,6 +235,8 @@ private:
225 */ 235 */
226 ResultStatus Init(EmuWindow& emu_window); 236 ResultStatus Init(EmuWindow& emu_window);
227 237
238 /// RealVfsFilesystem instance
239 FileSys::VirtualFilesystem virtual_filesystem;
228 /// AppLoader used to load the current executing application 240 /// AppLoader used to load the current executing application
229 std::unique_ptr<Loader::AppLoader> app_loader; 241 std::unique_ptr<Loader::AppLoader> app_loader;
230 std::unique_ptr<VideoCore::RendererBase> renderer; 242 std::unique_ptr<VideoCore::RendererBase> renderer;
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 395eea8ae..e897d9913 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -5,6 +5,7 @@
5#include <array> 5#include <array>
6#include <string> 6#include <string>
7#include <core/loader/loader.h> 7#include <core/loader/loader.h>
8#include "common/logging/log.h"
8#include "core/file_sys/card_image.h" 9#include "core/file_sys/card_image.h"
9#include "core/file_sys/partition_filesystem.h" 10#include "core/file_sys/partition_filesystem.h"
10#include "core/file_sys/vfs_offset.h" 11#include "core/file_sys/vfs_offset.h"
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 3529166ac..d3007d981 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -170,6 +170,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
170} 170}
171 171
172NCA::NCA(VirtualFile file_) : file(std::move(file_)) { 172NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
173 if (file == nullptr) {
174 status = Loader::ResultStatus::ErrorInvalidFormat;
175 return;
176 }
173 if (sizeof(NCAHeader) != file->ReadObject(&header)) 177 if (sizeof(NCAHeader) != file->ReadObject(&header))
174 LOG_ERROR(Loader, "File reader errored out during header read."); 178 LOG_ERROR(Loader, "File reader errored out during header read.");
175 179
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index a8879d9a8..5cfd5031a 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -12,6 +12,7 @@
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/swap.h" 14#include "common/swap.h"
15#include "control_metadata.h"
15#include "core/crypto/key_manager.h" 16#include "core/crypto/key_manager.h"
16#include "core/file_sys/partition_filesystem.h" 17#include "core/file_sys/partition_filesystem.h"
17#include "core/loader/loader.h" 18#include "core/loader/loader.h"
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index cc3b745f7..6582cc240 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -62,6 +62,13 @@ enum class Language : u8 {
62 Chinese = 14, 62 Chinese = 14,
63}; 63};
64 64
65static constexpr std::array<const char*, 15> LANGUAGE_NAMES = {
66 "AmericanEnglish", "BritishEnglish", "Japanese",
67 "French", "German", "LatinAmericanSpanish",
68 "Spanish", "Italian", "Dutch",
69 "CanadianFrench", "Portugese", "Russian",
70 "Korean", "Taiwanese", "Chinese"};
71
65// A class representing the format used by NX metadata files, typically named Control.nacp. 72// A class representing the format used by NX metadata files, typically named Control.nacp.
66// These store application name, dev name, title id, and other miscellaneous data. 73// These store application name, dev name, title id, and other miscellaneous data.
67class NACP { 74class NACP {
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index 213ce1826..3759e743a 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -4,8 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <cstddef> 7#include <cstddef>
8#include <iterator>
9#include <string_view>
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
@@ -21,9 +22,14 @@ enum EntryType : u8 {
21 22
22// Structure of a directory entry, from 23// Structure of a directory entry, from
23// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry 24// http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry
24const size_t FILENAME_LENGTH = 0x300;
25struct Entry { 25struct Entry {
26 char filename[FILENAME_LENGTH]; 26 Entry(std::string_view view, EntryType entry_type, u64 entry_size)
27 : type{entry_type}, file_size{entry_size} {
28 const size_t copy_size = view.copy(filename, std::size(filename) - 1);
29 filename[copy_size] = '\0';
30 }
31
32 char filename[0x300];
27 INSERT_PADDING_BYTES(4); 33 INSERT_PADDING_BYTES(4);
28 EntryType type; 34 EntryType type;
29 INSERT_PADDING_BYTES(3); 35 INSERT_PADDING_BYTES(3);
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index e3a578c0f..f3cf50d5a 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -7,6 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h"
10#include "core/hle/result.h" 11#include "core/hle/result.h"
11 12
12namespace FileSys { 13namespace FileSys {
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index dae1c16ef..24e158962 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -4,12 +4,160 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <numeric> 6#include <numeric>
7#include <string>
8#include "common/common_paths.h"
7#include "common/file_util.h" 9#include "common/file_util.h"
8#include "common/logging/backend.h" 10#include "common/logging/backend.h"
9#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs.h"
10 12
11namespace FileSys { 13namespace FileSys {
12 14
15VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}
16
17VfsFilesystem::~VfsFilesystem() = default;
18
19std::string VfsFilesystem::GetName() const {
20 return root->GetName();
21}
22
23bool VfsFilesystem::IsReadable() const {
24 return root->IsReadable();
25}
26
27bool VfsFilesystem::IsWritable() const {
28 return root->IsWritable();
29}
30
31VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
32 const auto path = FileUtil::SanitizePath(path_);
33 if (root->GetFileRelative(path) != nullptr)
34 return VfsEntryType::File;
35 if (root->GetDirectoryRelative(path) != nullptr)
36 return VfsEntryType::Directory;
37
38 return VfsEntryType::None;
39}
40
41VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
42 const auto path = FileUtil::SanitizePath(path_);
43 return root->GetFileRelative(path);
44}
45
46VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
47 const auto path = FileUtil::SanitizePath(path_);
48 return root->CreateFileRelative(path);
49}
50
51VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
52 const auto old_path = FileUtil::SanitizePath(old_path_);
53 const auto new_path = FileUtil::SanitizePath(new_path_);
54
55 // VfsDirectory impls are only required to implement copy across the current directory.
56 if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) {
57 if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path)))
58 return nullptr;
59 return OpenFile(new_path, Mode::ReadWrite);
60 }
61
62 // Do it using RawCopy. Non-default impls are encouraged to optimize this.
63 const auto old_file = OpenFile(old_path, Mode::Read);
64 if (old_file == nullptr)
65 return nullptr;
66 auto new_file = OpenFile(new_path, Mode::Read);
67 if (new_file != nullptr)
68 return nullptr;
69 new_file = CreateFile(new_path, Mode::Write);
70 if (new_file == nullptr)
71 return nullptr;
72 if (!VfsRawCopy(old_file, new_file))
73 return nullptr;
74 return new_file;
75}
76
77VirtualFile VfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
78 const auto old_path = FileUtil::SanitizePath(old_path_);
79 const auto new_path = FileUtil::SanitizePath(new_path_);
80
81 // Again, non-default impls are highly encouraged to provide a more optimized version of this.
82 auto out = CopyFile(old_path_, new_path_);
83 if (out == nullptr)
84 return nullptr;
85 if (DeleteFile(old_path))
86 return out;
87 return nullptr;
88}
89
90bool VfsFilesystem::DeleteFile(std::string_view path_) {
91 const auto path = FileUtil::SanitizePath(path_);
92 auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
93 if (parent == nullptr)
94 return false;
95 return parent->DeleteFile(FileUtil::GetFilename(path));
96}
97
98VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
99 const auto path = FileUtil::SanitizePath(path_);
100 return root->GetDirectoryRelative(path);
101}
102
103VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
104 const auto path = FileUtil::SanitizePath(path_);
105 return root->CreateDirectoryRelative(path);
106}
107
108VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
109 const auto old_path = FileUtil::SanitizePath(old_path_);
110 const auto new_path = FileUtil::SanitizePath(new_path_);
111
112 // Non-default impls are highly encouraged to provide a more optimized version of this.
113 auto old_dir = OpenDirectory(old_path, Mode::Read);
114 if (old_dir == nullptr)
115 return nullptr;
116 auto new_dir = OpenDirectory(new_path, Mode::Read);
117 if (new_dir != nullptr)
118 return nullptr;
119 new_dir = CreateDirectory(new_path, Mode::Write);
120 if (new_dir == nullptr)
121 return nullptr;
122
123 for (const auto& file : old_dir->GetFiles()) {
124 const auto x =
125 CopyFile(old_path + DIR_SEP + file->GetName(), new_path + DIR_SEP + file->GetName());
126 if (x == nullptr)
127 return nullptr;
128 }
129
130 for (const auto& dir : old_dir->GetSubdirectories()) {
131 const auto x =
132 CopyDirectory(old_path + DIR_SEP + dir->GetName(), new_path + DIR_SEP + dir->GetName());
133 if (x == nullptr)
134 return nullptr;
135 }
136
137 return new_dir;
138}
139
140VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) {
141 const auto old_path = FileUtil::SanitizePath(old_path_);
142 const auto new_path = FileUtil::SanitizePath(new_path_);
143
144 // Non-default impls are highly encouraged to provide a more optimized version of this.
145 auto out = CopyDirectory(old_path_, new_path_);
146 if (out == nullptr)
147 return nullptr;
148 if (DeleteDirectory(old_path))
149 return out;
150 return nullptr;
151}
152
153bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
154 const auto path = FileUtil::SanitizePath(path_);
155 auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
156 if (parent == nullptr)
157 return false;
158 return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path));
159}
160
13VfsFile::~VfsFile() = default; 161VfsFile::~VfsFile() = default;
14 162
15std::string VfsFile::GetExtension() const { 163std::string VfsFile::GetExtension() const {
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index fab9e2b45..141a053ce 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -11,14 +11,74 @@
11#include <vector> 11#include <vector>
12#include "boost/optional.hpp" 12#include "boost/optional.hpp"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/file_sys/mode.h"
14 15
15namespace FileSys { 16namespace FileSys {
17
18struct VfsFilesystem;
16struct VfsFile; 19struct VfsFile;
17struct VfsDirectory; 20struct VfsDirectory;
18 21
19// Convenience typedefs to use VfsDirectory and VfsFile 22// Convenience typedefs to use Vfs* interfaces
20using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>; 23using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;
21using VirtualFile = std::shared_ptr<FileSys::VfsFile>; 24using VirtualDir = std::shared_ptr<VfsDirectory>;
25using VirtualFile = std::shared_ptr<VfsFile>;
26
27// An enumeration representing what can be at the end of a path in a VfsFilesystem
28enum class VfsEntryType {
29 None,
30 File,
31 Directory,
32};
33
34// A class representing an abstract filesystem. A default implementation given the root VirtualDir
35// is provided for convenience, but if the Vfs implementation has any additional state or
36// functionality, they will need to override.
37struct VfsFilesystem : NonCopyable {
38 VfsFilesystem(VirtualDir root);
39 virtual ~VfsFilesystem();
40
41 // Gets the friendly name for the filesystem.
42 virtual std::string GetName() const;
43
44 // Return whether or not the user has read permissions on this filesystem.
45 virtual bool IsReadable() const;
46 // Return whether or not the user has write permission on this filesystem.
47 virtual bool IsWritable() const;
48
49 // Determine if the entry at path is non-existant, a file, or a directory.
50 virtual VfsEntryType GetEntryType(std::string_view path) const;
51
52 // Opens the file with path relative to root. If it doesn't exist, returns nullptr.
53 virtual VirtualFile OpenFile(std::string_view path, Mode perms);
54 // Creates a new, empty file at path
55 virtual VirtualFile CreateFile(std::string_view path, Mode perms);
56 // Copies the file from old_path to new_path, returning the new file on success and nullptr on
57 // failure.
58 virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path);
59 // Moves the file from old_path to new_path, returning the moved file on success and nullptr on
60 // failure.
61 virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path);
62 // Deletes the file with path relative to root, returing true on success.
63 virtual bool DeleteFile(std::string_view path);
64
65 // Opens the directory with path relative to root. If it doesn't exist, returns nullptr.
66 virtual VirtualDir OpenDirectory(std::string_view path, Mode perms);
67 // Creates a new, empty directory at path
68 virtual VirtualDir CreateDirectory(std::string_view path, Mode perms);
69 // Copies the directory from old_path to new_path, returning the new directory on success and
70 // nullptr on failure.
71 virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path);
72 // Moves the directory from old_path to new_path, returning the moved directory on success and
73 // nullptr on failure.
74 virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path);
75 // Deletes the directory with path relative to root, returing true on success.
76 virtual bool DeleteDirectory(std::string_view path);
77
78protected:
79 // Root directory in default implementation.
80 VirtualDir root;
81};
22 82
23// A class representing a file in an abstract filesystem. 83// A class representing a file in an abstract filesystem.
24struct VfsFile : NonCopyable { 84struct VfsFile : NonCopyable {
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 82d54da4a..1b5919737 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -6,7 +6,7 @@
6#include <cstddef> 6#include <cstddef>
7#include <iterator> 7#include <iterator>
8#include <utility> 8#include <utility>
9 9#include "common/assert.h"
10#include "common/common_paths.h" 10#include "common/common_paths.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/file_sys/vfs_real.h" 12#include "core/file_sys/vfs_real.h"
@@ -29,6 +29,8 @@ static std::string ModeFlagsToString(Mode mode) {
29 mode_str = "a"; 29 mode_str = "a";
30 else if (mode & Mode::Write) 30 else if (mode & Mode::Write)
31 mode_str = "w"; 31 mode_str = "w";
32 else
33 UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode));
32 } 34 }
33 35
34 mode_str += "b"; 36 mode_str += "b";
@@ -36,8 +38,174 @@ static std::string ModeFlagsToString(Mode mode) {
36 return mode_str; 38 return mode_str;
37} 39}
38 40
39RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_) 41RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {}
40 : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_), 42
43std::string RealVfsFilesystem::GetName() const {
44 return "Real";
45}
46
47bool RealVfsFilesystem::IsReadable() const {
48 return true;
49}
50
51bool RealVfsFilesystem::IsWritable() const {
52 return true;
53}
54
55VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
56 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
57 if (!FileUtil::Exists(path))
58 return VfsEntryType::None;
59 if (FileUtil::IsDirectory(path))
60 return VfsEntryType::Directory;
61
62 return VfsEntryType::File;
63}
64
65VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
66 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
67 if (cache.find(path) != cache.end()) {
68 auto weak = cache[path];
69 if (!weak.expired()) {
70 return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
71 }
72 }
73
74 if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0)
75 FileUtil::CreateEmptyFile(path);
76
77 auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str());
78 cache[path] = backing;
79
80 // Cannot use make_shared as RealVfsFile constructor is private
81 return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
82}
83
84VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
85 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
86 if (!FileUtil::Exists(path) && !FileUtil::CreateEmptyFile(path))
87 return nullptr;
88 return OpenFile(path, perms);
89}
90
91VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
92 const auto old_path =
93 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
94 const auto new_path =
95 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
96
97 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
98 FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path))
99 return nullptr;
100 return OpenFile(new_path, Mode::ReadWrite);
101}
102
103VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
104 const auto old_path =
105 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
106 const auto new_path =
107 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
108
109 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
110 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
111 return nullptr;
112
113 if (cache.find(old_path) != cache.end()) {
114 auto cached = cache[old_path];
115 if (!cached.expired()) {
116 auto file = cached.lock();
117 file->Open(new_path, "r+b");
118 cache.erase(old_path);
119 cache[new_path] = file;
120 }
121 }
122 return OpenFile(new_path, Mode::ReadWrite);
123}
124
125bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
126 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
127 if (cache.find(path) != cache.end()) {
128 if (!cache[path].expired())
129 cache[path].lock()->Close();
130 cache.erase(path);
131 }
132 return FileUtil::Delete(path);
133}
134
135VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
136 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
137 // Cannot use make_shared as RealVfsDirectory constructor is private
138 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
139}
140
141VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
142 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
143 if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path))
144 return nullptr;
145 // Cannot use make_shared as RealVfsDirectory constructor is private
146 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
147}
148
149VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
150 std::string_view new_path_) {
151 const auto old_path =
152 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
153 const auto new_path =
154 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
155 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
156 !FileUtil::IsDirectory(old_path))
157 return nullptr;
158 FileUtil::CopyDir(old_path, new_path);
159 return OpenDirectory(new_path, Mode::ReadWrite);
160}
161
162VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
163 std::string_view new_path_) {
164 const auto old_path =
165 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
166 const auto new_path =
167 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
168 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
169 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
170 return nullptr;
171
172 for (auto& kv : cache) {
173 // Path in cache starts with old_path
174 if (kv.first.rfind(old_path, 0) == 0) {
175 const auto file_old_path =
176 FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault);
177 const auto file_new_path =
178 FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
179 FileUtil::DirectorySeparator::PlatformDefault);
180 auto cached = cache[file_old_path];
181 if (!cached.expired()) {
182 auto file = cached.lock();
183 file->Open(file_new_path, "r+b");
184 cache.erase(file_old_path);
185 cache[file_new_path] = file;
186 }
187 }
188 }
189
190 return OpenDirectory(new_path, Mode::ReadWrite);
191}
192
193bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
194 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
195 for (auto& kv : cache) {
196 // Path in cache starts with old_path
197 if (kv.first.rfind(path, 0) == 0) {
198 if (!cache[kv.first].expired())
199 cache[kv.first].lock()->Close();
200 cache.erase(kv.first);
201 }
202 }
203 return FileUtil::DeleteDirRecursively(path);
204}
205
206RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_,
207 const std::string& path_, Mode perms_)
208 : base(base_), backing(std::move(backing_)), path(path_),
41 parent_path(FileUtil::GetParentPath(path_)), 209 parent_path(FileUtil::GetParentPath(path_)),
42 path_components(FileUtil::SplitPathComponents(path_)), 210 path_components(FileUtil::SplitPathComponents(path_)),
43 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), 211 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
@@ -48,15 +216,15 @@ std::string RealVfsFile::GetName() const {
48} 216}
49 217
50size_t RealVfsFile::GetSize() const { 218size_t RealVfsFile::GetSize() const {
51 return backing.GetSize(); 219 return backing->GetSize();
52} 220}
53 221
54bool RealVfsFile::Resize(size_t new_size) { 222bool RealVfsFile::Resize(size_t new_size) {
55 return backing.Resize(new_size); 223 return backing->Resize(new_size);
56} 224}
57 225
58std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const { 226std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
59 return std::make_shared<RealVfsDirectory>(parent_path, perms); 227 return base.OpenDirectory(parent_path, perms);
60} 228}
61 229
62bool RealVfsFile::IsWritable() const { 230bool RealVfsFile::IsWritable() const {
@@ -68,62 +236,118 @@ bool RealVfsFile::IsReadable() const {
68} 236}
69 237
70size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { 238size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
71 if (!backing.Seek(offset, SEEK_SET)) 239 if (!backing->Seek(offset, SEEK_SET))
72 return 0; 240 return 0;
73 return backing.ReadBytes(data, length); 241 return backing->ReadBytes(data, length);
74} 242}
75 243
76size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { 244size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
77 if (!backing.Seek(offset, SEEK_SET)) 245 if (!backing->Seek(offset, SEEK_SET))
78 return 0; 246 return 0;
79 return backing.WriteBytes(data, length); 247 return backing->WriteBytes(data, length);
80} 248}
81 249
82bool RealVfsFile::Rename(std::string_view name) { 250bool RealVfsFile::Rename(std::string_view name) {
83 std::string name_str(name.begin(), name.end()); 251 return base.MoveFile(path, parent_path + DIR_SEP + std::string(name)) != nullptr;
84 const auto out = FileUtil::Rename(GetName(), name_str); 252}
253
254bool RealVfsFile::Close() {
255 return backing->Close();
256}
85 257
86 path = (parent_path + DIR_SEP).append(name); 258// TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if
87 path_components = parent_components; 259// constexpr' because there is a compile error in the branch not used.
88 path_components.push_back(std::move(name_str)); 260
89 backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str()); 261template <>
262std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
263 if (perms == Mode::Append)
264 return {};
265
266 std::vector<VirtualFile> out;
267 FileUtil::ForeachDirectoryEntry(
268 nullptr, path,
269 [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
270 const std::string full_path = directory + DIR_SEP + filename;
271 if (!FileUtil::IsDirectory(full_path))
272 out.emplace_back(base.OpenFile(full_path, perms));
273 return true;
274 });
90 275
91 return out; 276 return out;
92} 277}
93 278
94bool RealVfsFile::Close() { 279template <>
95 return backing.Close(); 280std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
281 if (perms == Mode::Append)
282 return {};
283
284 std::vector<VirtualDir> out;
285 FileUtil::ForeachDirectoryEntry(
286 nullptr, path,
287 [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
288 const std::string full_path = directory + DIR_SEP + filename;
289 if (FileUtil::IsDirectory(full_path))
290 out.emplace_back(base.OpenDirectory(full_path, perms));
291 return true;
292 });
293
294 return out;
96} 295}
97 296
98RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_) 297RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
99 : path(FileUtil::RemoveTrailingSlash(path_)), parent_path(FileUtil::GetParentPath(path)), 298 : base(base_), path(FileUtil::RemoveTrailingSlash(path_)),
299 parent_path(FileUtil::GetParentPath(path)),
100 path_components(FileUtil::SplitPathComponents(path)), 300 path_components(FileUtil::SplitPathComponents(path)),
101 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), 301 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
102 perms(perms_) { 302 perms(perms_) {
103 if (!FileUtil::Exists(path) && perms & Mode::WriteAppend) 303 if (!FileUtil::Exists(path) && perms & Mode::WriteAppend)
104 FileUtil::CreateDir(path); 304 FileUtil::CreateDir(path);
305}
105 306
106 if (perms == Mode::Append) 307std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
107 return; 308 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
309 if (!FileUtil::Exists(full_path))
310 return nullptr;
311 return base.OpenFile(full_path, perms);
312}
108 313
109 FileUtil::ForeachDirectoryEntry( 314std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
110 nullptr, path, 315 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
111 [this](u64* entries_out, const std::string& directory, const std::string& filename) { 316 if (!FileUtil::Exists(full_path))
112 std::string full_path = directory + DIR_SEP + filename; 317 return nullptr;
113 if (FileUtil::IsDirectory(full_path)) 318 return base.OpenDirectory(full_path, perms);
114 subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(full_path, perms)); 319}
115 else 320
116 files.emplace_back(std::make_shared<RealVfsFile>(full_path, perms)); 321std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const {
117 return true; 322 return GetFileRelative(name);
118 }); 323}
324
325std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const {
326 return GetDirectoryRelative(name);
327}
328
329std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
330 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
331 return base.CreateFile(full_path, perms);
332}
333
334std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
335 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
336 auto parent = std::string(FileUtil::GetParentPath(full_path));
337 return base.CreateDirectory(full_path, perms);
338}
339
340bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
341 auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name));
342 return base.DeleteDirectory(full_path);
119} 343}
120 344
121std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { 345std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
122 return files; 346 return IterateEntries<RealVfsFile, VfsFile>();
123} 347}
124 348
125std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { 349std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
126 return subdirectories; 350 return IterateEntries<RealVfsDirectory, VfsDirectory>();
127} 351}
128 352
129bool RealVfsDirectory::IsWritable() const { 353bool RealVfsDirectory::IsWritable() const {
@@ -142,57 +366,32 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
142 if (path_components.size() <= 1) 366 if (path_components.size() <= 1)
143 return nullptr; 367 return nullptr;
144 368
145 return std::make_shared<RealVfsDirectory>(parent_path, perms); 369 return base.OpenDirectory(parent_path, perms);
146} 370}
147 371
148std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) { 372std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) {
149 const std::string subdir_path = (path + DIR_SEP).append(name); 373 const std::string subdir_path = (path + DIR_SEP).append(name);
150 374 return base.CreateDirectory(subdir_path, perms);
151 if (!FileUtil::CreateDir(subdir_path)) {
152 return nullptr;
153 }
154
155 subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(subdir_path, perms));
156 return subdirectories.back();
157} 375}
158 376
159std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) { 377std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) {
160 const std::string file_path = (path + DIR_SEP).append(name); 378 const std::string file_path = (path + DIR_SEP).append(name);
161 379 return base.CreateFile(file_path, perms);
162 if (!FileUtil::CreateEmptyFile(file_path)) {
163 return nullptr;
164 }
165
166 files.emplace_back(std::make_shared<RealVfsFile>(file_path, perms));
167 return files.back();
168} 380}
169 381
170bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) { 382bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) {
171 const std::string subdir_path = (path + DIR_SEP).append(name); 383 const std::string subdir_path = (path + DIR_SEP).append(name);
172 384 return base.DeleteDirectory(subdir_path);
173 return FileUtil::DeleteDirRecursively(subdir_path);
174} 385}
175 386
176bool RealVfsDirectory::DeleteFile(std::string_view name) { 387bool RealVfsDirectory::DeleteFile(std::string_view name) {
177 const auto file = GetFile(name);
178
179 if (file == nullptr) {
180 return false;
181 }
182
183 files.erase(std::find(files.begin(), files.end(), file));
184
185 auto real_file = std::static_pointer_cast<RealVfsFile>(file);
186 real_file->Close();
187
188 const std::string file_path = (path + DIR_SEP).append(name); 388 const std::string file_path = (path + DIR_SEP).append(name);
189 return FileUtil::Delete(file_path); 389 return base.DeleteFile(file_path);
190} 390}
191 391
192bool RealVfsDirectory::Rename(std::string_view name) { 392bool RealVfsDirectory::Rename(std::string_view name) {
193 const std::string new_name = (parent_path + DIR_SEP).append(name); 393 const std::string new_name = (parent_path + DIR_SEP).append(name);
194 394 return base.MoveFile(path, new_name) != nullptr;
195 return FileUtil::Rename(path, new_name);
196} 395}
197 396
198std::string RealVfsDirectory::GetFullPath() const { 397std::string RealVfsDirectory::GetFullPath() const {
@@ -202,16 +401,6 @@ std::string RealVfsDirectory::GetFullPath() const {
202} 401}
203 402
204bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { 403bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
205 const auto iter = std::find(files.begin(), files.end(), file); 404 return false;
206 if (iter == files.end())
207 return false;
208
209 const std::ptrdiff_t offset = std::distance(files.begin(), iter);
210 files[offset] = files.back();
211 files.pop_back();
212
213 subdirectories.emplace_back(std::move(dir));
214
215 return true;
216} 405}
217} // namespace FileSys 406} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 243d58576..8a1e79ef6 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -6,18 +6,45 @@
6 6
7#include <string_view> 7#include <string_view>
8 8
9#include <boost/container/flat_map.hpp>
9#include "common/file_util.h" 10#include "common/file_util.h"
10#include "core/file_sys/mode.h" 11#include "core/file_sys/mode.h"
11#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
12 13
13namespace FileSys { 14namespace FileSys {
14 15
16class RealVfsFilesystem : public VfsFilesystem {
17public:
18 RealVfsFilesystem();
19
20 std::string GetName() const override;
21 bool IsReadable() const override;
22 bool IsWritable() const override;
23 VfsEntryType GetEntryType(std::string_view path) const override;
24 VirtualFile OpenFile(std::string_view path, Mode perms = Mode::Read) override;
25 VirtualFile CreateFile(std::string_view path, Mode perms = Mode::ReadWrite) override;
26 VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override;
27 VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override;
28 bool DeleteFile(std::string_view path) override;
29 VirtualDir OpenDirectory(std::string_view path, Mode perms = Mode::Read) override;
30 VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::ReadWrite) override;
31 VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override;
32 VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override;
33 bool DeleteDirectory(std::string_view path) override;
34
35private:
36 boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache;
37};
38
15// An implmentation of VfsFile that represents a file on the user's computer. 39// An implmentation of VfsFile that represents a file on the user's computer.
16struct RealVfsFile : public VfsFile { 40class RealVfsFile : public VfsFile {
17 friend struct RealVfsDirectory; 41 friend class RealVfsDirectory;
42 friend class RealVfsFilesystem;
18 43
19 RealVfsFile(const std::string& name, Mode perms = Mode::Read); 44 RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing,
45 const std::string& path, Mode perms = Mode::Read);
20 46
47public:
21 std::string GetName() const override; 48 std::string GetName() const override;
22 size_t GetSize() const override; 49 size_t GetSize() const override;
23 bool Resize(size_t new_size) override; 50 bool Resize(size_t new_size) override;
@@ -31,7 +58,8 @@ struct RealVfsFile : public VfsFile {
31private: 58private:
32 bool Close(); 59 bool Close();
33 60
34 FileUtil::IOFile backing; 61 RealVfsFilesystem& base;
62 std::shared_ptr<FileUtil::IOFile> backing;
35 std::string path; 63 std::string path;
36 std::string parent_path; 64 std::string parent_path;
37 std::vector<std::string> path_components; 65 std::vector<std::string> path_components;
@@ -40,9 +68,19 @@ private:
40}; 68};
41 69
42// An implementation of VfsDirectory that represents a directory on the user's computer. 70// An implementation of VfsDirectory that represents a directory on the user's computer.
43struct RealVfsDirectory : public VfsDirectory { 71class RealVfsDirectory : public VfsDirectory {
44 RealVfsDirectory(const std::string& path, Mode perms = Mode::Read); 72 friend class RealVfsFilesystem;
45 73
74 RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read);
75
76public:
77 std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
78 std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
79 std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
80 std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override;
81 std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
82 std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
83 bool DeleteSubdirectoryRecursive(std::string_view name) override;
46 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 84 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
47 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 85 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
48 bool IsWritable() const override; 86 bool IsWritable() const override;
@@ -60,13 +98,15 @@ protected:
60 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; 98 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
61 99
62private: 100private:
101 template <typename T, typename R>
102 std::vector<std::shared_ptr<R>> IterateEntries() const;
103
104 RealVfsFilesystem& base;
63 std::string path; 105 std::string path;
64 std::string parent_path; 106 std::string parent_path;
65 std::vector<std::string> path_components; 107 std::vector<std::string> path_components;
66 std::vector<std::string> parent_components; 108 std::vector<std::string> parent_components;
67 Mode perms; 109 Mode perms;
68 std::vector<std::shared_ptr<VfsFile>> files;
69 std::vector<std::shared_ptr<VfsDirectory>> subdirectories;
70}; 110};
71 111
72} // namespace FileSys 112} // namespace FileSys
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 5dd1b68d7..82a3fb5a8 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -201,7 +201,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
201 return RESULT_SUCCESS; 201 return RESULT_SUCCESS;
202} 202}
203 203
204ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { 204ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) {
205 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; 205 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
206 Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), 206 Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
207 dst_cmdbuf.size() * sizeof(u32)); 207 dst_cmdbuf.size() * sizeof(u32));
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 9ce52db24..f0d07f1b6 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -132,7 +132,7 @@ public:
132 ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, 132 ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process,
133 HandleTable& src_table); 133 HandleTable& src_table);
134 /// Writes data from this context back to the requesting process/thread. 134 /// Writes data from this context back to the requesting process/thread.
135 ResultCode WriteToOutgoingCommandBuffer(Thread& thread); 135 ResultCode WriteToOutgoingCommandBuffer(const Thread& thread);
136 136
137 u32_le GetCommand() const { 137 u32_le GetCommand() const {
138 return command; 138 return command;
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 0a6cac5b7..e74379a24 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -38,7 +38,7 @@ public:
38 {0, &IProfile::Get, "Get"}, 38 {0, &IProfile::Get, "Get"},
39 {1, &IProfile::GetBase, "GetBase"}, 39 {1, &IProfile::GetBase, "GetBase"},
40 {10, nullptr, "GetImageSize"}, 40 {10, nullptr, "GetImageSize"},
41 {11, nullptr, "LoadImage"}, 41 {11, &IProfile::LoadImage, "LoadImage"},
42 }; 42 };
43 RegisterHandlers(functions); 43 RegisterHandlers(functions);
44 } 44 }
@@ -72,6 +72,27 @@ private:
72 } 72 }
73 } 73 }
74 74
75 void LoadImage(Kernel::HLERequestContext& ctx) {
76 LOG_WARNING(Service_ACC, "(STUBBED) called");
77 // smallest jpeg https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
78 // TODO(mailwl): load actual profile image from disk, width 256px, max size 0x20000
79 const u32 jpeg_size = 107;
80 static const std::array<u8, jpeg_size> jpeg{
81 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03,
82 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04,
83 0x08, 0x06, 0x06, 0x05, 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a,
84 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f,
85 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10,
86 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x11, 0x00,
87 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01,
88 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
89 };
90 ctx.WriteBuffer(jpeg.data(), jpeg_size);
91 IPC::ResponseBuilder rb{ctx, 3};
92 rb.Push(RESULT_SUCCESS);
93 rb.Push<u32>(jpeg_size);
94 }
95
75 ProfileManager& profile_manager; 96 ProfileManager& profile_manager;
76 UUID user_id; ///< The user id this profile refers to. 97 UUID user_id; ///< The user id this profile refers to.
77}; 98};
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 9404d6b8c..762763463 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -136,7 +136,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
136 {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, 136 {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
137 {17, nullptr, "SetControllerFirmwareUpdateSection"}, 137 {17, nullptr, "SetControllerFirmwareUpdateSection"},
138 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, 138 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
139 {19, nullptr, "SetScreenShotImageOrientation"}, 139 {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"},
140 {20, nullptr, "SetDesirableKeyboardLayout"}, 140 {20, nullptr, "SetDesirableKeyboardLayout"},
141 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, 141 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
142 {41, nullptr, "IsSystemBufferSharingEnabled"}, 142 {41, nullptr, "IsSystemBufferSharingEnabled"},
@@ -254,6 +254,13 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
254 LOG_WARNING(Service_AM, "(STUBBED) called"); 254 LOG_WARNING(Service_AM, "(STUBBED) called");
255} 255}
256 256
257void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
258 IPC::ResponseBuilder rb{ctx, 2};
259 rb.Push(RESULT_SUCCESS);
260
261 LOG_WARNING(Service_AM, "(STUBBED) called");
262}
263
257void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { 264void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
258 // TODO(Subv): Find out how AM determines the display to use, for now just create the layer 265 // TODO(Subv): Find out how AM determines the display to use, for now just create the layer
259 // in the Default display. 266 // in the Default display.
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 8f4f98346..862f338ac 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -83,6 +83,7 @@ private:
83 void LockExit(Kernel::HLERequestContext& ctx); 83 void LockExit(Kernel::HLERequestContext& ctx);
84 void UnlockExit(Kernel::HLERequestContext& ctx); 84 void UnlockExit(Kernel::HLERequestContext& ctx);
85 void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); 85 void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx);
86 void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx);
86 void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); 87 void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
87 void SetScreenShotPermission(Kernel::HLERequestContext& ctx); 88 void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
88 void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); 89 void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index e17d637e4..5e416cde2 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -59,7 +59,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64
59ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { 59ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
60 std::string path(FileUtil::SanitizePath(path_)); 60 std::string path(FileUtil::SanitizePath(path_));
61 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 61 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
62 if (path == "/" || path == "\\") { 62 if (path.empty()) {
63 // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... 63 // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
64 return RESULT_SUCCESS; 64 return RESULT_SUCCESS;
65 } 65 }
@@ -281,15 +281,15 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
281 return sdmc_factory->Open(); 281 return sdmc_factory->Open();
282} 282}
283 283
284void RegisterFileSystems() { 284void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) {
285 romfs_factory = nullptr; 285 romfs_factory = nullptr;
286 save_data_factory = nullptr; 286 save_data_factory = nullptr;
287 sdmc_factory = nullptr; 287 sdmc_factory = nullptr;
288 288
289 auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>( 289 auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
290 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite); 290 FileSys::Mode::ReadWrite);
291 auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>( 291 auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
292 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite); 292 FileSys::Mode::ReadWrite);
293 293
294 auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); 294 auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
295 save_data_factory = std::move(savedata); 295 save_data_factory = std::move(savedata);
@@ -298,8 +298,8 @@ void RegisterFileSystems() {
298 sdmc_factory = std::move(sdcard); 298 sdmc_factory = std::move(sdcard);
299} 299}
300 300
301void InstallInterfaces(SM::ServiceManager& service_manager) { 301void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) {
302 RegisterFileSystems(); 302 RegisterFileSystems(vfs);
303 std::make_shared<FSP_LDR>()->InstallAsService(service_manager); 303 std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
304 std::make_shared<FSP_PR>()->InstallAsService(service_manager); 304 std::make_shared<FSP_PR>()->InstallAsService(service_manager);
305 std::make_shared<FSP_SRV>()->InstallAsService(service_manager); 305 std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index d4483daa5..462c13f20 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -36,7 +36,7 @@ ResultVal<FileSys::VirtualDir> OpenSDMC();
36// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS(); 36// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
37 37
38/// Registers all Filesystem services with the specified service manager. 38/// Registers all Filesystem services with the specified service manager.
39void InstallInterfaces(SM::ServiceManager& service_manager); 39void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs);
40 40
41// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of 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 42// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index e7ffb6bd1..1470f9017 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -193,13 +193,10 @@ private:
193template <typename T> 193template <typename T>
194static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, 194static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
195 FileSys::EntryType type) { 195 FileSys::EntryType type) {
196 entries.reserve(entries.size() + new_data.size());
197
196 for (const auto& new_entry : new_data) { 198 for (const auto& new_entry : new_data) {
197 FileSys::Entry entry; 199 entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize());
198 entry.filename[0] = '\0';
199 std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1);
200 entry.type = type;
201 entry.file_size = new_entry->GetSize();
202 entries.emplace_back(std::move(entry));
203 } 200 }
204} 201}
205 202
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 116dabedb..4cdf7f613 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -147,7 +147,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
147 } 147 }
148 params.fence_out.id = 0; 148 params.fence_out.id = 0;
149 params.fence_out.value = 0; 149 params.fence_out.value = 0;
150 std::memcpy(output.data(), &params, output.size()); 150 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
151 return 0; 151 return 0;
152} 152}
153 153
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index e8b30921a..427f4b574 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -16,19 +16,18 @@
16#include "core/hle/service/nvdrv/interface.h" 16#include "core/hle/service/nvdrv/interface.h"
17#include "core/hle/service/nvdrv/nvdrv.h" 17#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvdrv/nvmemp.h" 18#include "core/hle/service/nvdrv/nvmemp.h"
19#include "core/hle/service/nvflinger/nvflinger.h"
19 20
20namespace Service::Nvidia { 21namespace Service::Nvidia {
21 22
22std::weak_ptr<Module> nvdrv; 23void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) {
23
24void InstallInterfaces(SM::ServiceManager& service_manager) {
25 auto module_ = std::make_shared<Module>(); 24 auto module_ = std::make_shared<Module>();
26 std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); 25 std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager);
27 std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); 26 std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager);
28 std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); 27 std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager);
29 std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); 28 std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager);
30 std::make_shared<NVMEMP>()->InstallAsService(service_manager); 29 std::make_shared<NVMEMP>()->InstallAsService(service_manager);
31 nvdrv = module_; 30 nvflinger.SetNVDrvInstance(module_);
32} 31}
33 32
34Module::Module() { 33Module::Module() {
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 184f3c9fc..99eb1128a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12 12
13namespace Service::NVFlinger {
14class NVFlinger;
15}
16
13namespace Service::Nvidia { 17namespace Service::Nvidia {
14 18
15namespace Devices { 19namespace Devices {
@@ -56,8 +60,6 @@ private:
56}; 60};
57 61
58/// Registers all NVDRV services with the specified service manager. 62/// Registers all NVDRV services with the specified service manager.
59void InstallInterfaces(SM::ServiceManager& service_manager); 63void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger);
60
61extern std::weak_ptr<Module> nvdrv;
62 64
63} // namespace Service::Nvidia 65} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index adf180509..ef5713a71 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -16,7 +16,7 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
16 Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); 16 Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
17} 17}
18 18
19void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { 19void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
20 Buffer buffer{}; 20 Buffer buffer{};
21 buffer.slot = slot; 21 buffer.slot = slot;
22 buffer.igbp_buffer = igbp_buffer; 22 buffer.igbp_buffer = igbp_buffer;
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 004170538..f86e1056c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -72,7 +72,7 @@ public:
72 MathUtil::Rectangle<int> crop_rect; 72 MathUtil::Rectangle<int> crop_rect;
73 }; 73 };
74 74
75 void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); 75 void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
76 boost::optional<u32> DequeueBuffer(u32 width, u32 height); 76 boost::optional<u32> DequeueBuffer(u32 width, u32 height);
77 const IGBPBuffer& RequestBuffer(u32 slot) const; 77 const IGBPBuffer& RequestBuffer(u32 slot) const;
78 void QueueBuffer(u32 slot, BufferTransformFlags transform, 78 void QueueBuffer(u32 slot, BufferTransformFlags transform,
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 570aa8493..a26a5f812 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -46,6 +46,10 @@ NVFlinger::~NVFlinger() {
46 CoreTiming::UnscheduleEvent(composition_event, 0); 46 CoreTiming::UnscheduleEvent(composition_event, 0);
47} 47}
48 48
49void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
50 nvdrv = std::move(instance);
51}
52
49u64 NVFlinger::OpenDisplay(std::string_view name) { 53u64 NVFlinger::OpenDisplay(std::string_view name) {
50 LOG_WARNING(Service, "Opening display {}", name); 54 LOG_WARNING(Service, "Opening display {}", name);
51 55
@@ -141,9 +145,6 @@ void NVFlinger::Compose() {
141 auto& igbp_buffer = buffer->igbp_buffer; 145 auto& igbp_buffer = buffer->igbp_buffer;
142 146
143 // Now send the buffer to the GPU for drawing. 147 // Now send the buffer to the GPU for drawing.
144 auto nvdrv = Nvidia::nvdrv.lock();
145 ASSERT(nvdrv);
146
147 // TODO(Subv): Support more than just disp0. The display device selection is probably based 148 // TODO(Subv): Support more than just disp0. The display device selection is probably based
148 // on which display we're drawing (Default, Internal, External, etc) 149 // on which display we're drawing (Default, Internal, External, etc)
149 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); 150 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 5374df175..f7112949f 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -16,6 +16,10 @@ namespace CoreTiming {
16struct EventType; 16struct EventType;
17} 17}
18 18
19namespace Service::Nvidia {
20class Module;
21}
22
19namespace Service::NVFlinger { 23namespace Service::NVFlinger {
20 24
21class BufferQueue; 25class BufferQueue;
@@ -44,6 +48,9 @@ public:
44 NVFlinger(); 48 NVFlinger();
45 ~NVFlinger(); 49 ~NVFlinger();
46 50
51 /// Sets the NVDrv module instance to use to send buffers to the GPU.
52 void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
53
47 /// Opens the specified display and returns the id. 54 /// Opens the specified display and returns the id.
48 u64 OpenDisplay(std::string_view name); 55 u64 OpenDisplay(std::string_view name);
49 56
@@ -70,6 +77,8 @@ private:
70 /// Returns the layer identified by the specified id in the desired display. 77 /// Returns the layer identified by the specified id in the desired display.
71 Layer& GetLayer(u64 display_id, u64 layer_id); 78 Layer& GetLayer(u64 display_id, u64 layer_id);
72 79
80 std::shared_ptr<Nvidia::Module> nvdrv;
81
73 std::vector<Display> displays; 82 std::vector<Display> displays;
74 std::vector<std::shared_ptr<BufferQueue>> buffer_queues; 83 std::vector<std::shared_ptr<BufferQueue>> buffer_queues;
75 84
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 889cdd41a..11951adaf 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -198,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
198} 198}
199 199
200/// Initialize ServiceManager 200/// Initialize ServiceManager
201void Init(std::shared_ptr<SM::ServiceManager>& sm) { 201void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) {
202 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 202 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
203 // here and pass it into the respective InstallInterfaces functions. 203 // here and pass it into the respective InstallInterfaces functions.
204 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); 204 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
@@ -221,7 +221,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
221 EUPLD::InstallInterfaces(*sm); 221 EUPLD::InstallInterfaces(*sm);
222 Fatal::InstallInterfaces(*sm); 222 Fatal::InstallInterfaces(*sm);
223 FGM::InstallInterfaces(*sm); 223 FGM::InstallInterfaces(*sm);
224 FileSystem::InstallInterfaces(*sm); 224 FileSystem::InstallInterfaces(*sm, rfs);
225 Friend::InstallInterfaces(*sm); 225 Friend::InstallInterfaces(*sm);
226 GRC::InstallInterfaces(*sm); 226 GRC::InstallInterfaces(*sm);
227 HID::InstallInterfaces(*sm); 227 HID::InstallInterfaces(*sm);
@@ -238,7 +238,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
238 NIFM::InstallInterfaces(*sm); 238 NIFM::InstallInterfaces(*sm);
239 NIM::InstallInterfaces(*sm); 239 NIM::InstallInterfaces(*sm);
240 NS::InstallInterfaces(*sm); 240 NS::InstallInterfaces(*sm);
241 Nvidia::InstallInterfaces(*sm); 241 Nvidia::InstallInterfaces(*sm, *nv_flinger);
242 PCIe::InstallInterfaces(*sm); 242 PCIe::InstallInterfaces(*sm);
243 PCTL::InstallInterfaces(*sm); 243 PCTL::InstallInterfaces(*sm);
244 PCV::InstallInterfaces(*sm); 244 PCV::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 046c5e18d..8a294c0f2 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -22,6 +22,10 @@ class ServerSession;
22class HLERequestContext; 22class HLERequestContext;
23} // namespace Kernel 23} // namespace Kernel
24 24
25namespace FileSys {
26struct VfsFilesystem;
27}
28
25namespace Service { 29namespace Service {
26 30
27namespace SM { 31namespace SM {
@@ -177,7 +181,8 @@ private:
177}; 181};
178 182
179/// Initialize ServiceManager 183/// Initialize ServiceManager
180void Init(std::shared_ptr<SM::ServiceManager>& sm); 184void Init(std::shared_ptr<SM::ServiceManager>& sm,
185 const std::shared_ptr<FileSys::VfsFilesystem>& vfs);
181 186
182/// Shutdown ServiceManager 187/// Shutdown ServiceManager
183void Shutdown(); 188void Shutdown();
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 9a8cdd0ff..915d525b0 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -7,6 +7,7 @@
7#include "common/file_util.h" 7#include "common/file_util.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/file_sys/content_archive.h" 9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/control_metadata.h"
10#include "core/gdbstub/gdbstub.h" 11#include "core/gdbstub/gdbstub.h"
11#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
12#include "core/hle/kernel/resource_limit.h" 13#include "core/hle/kernel/resource_limit.h"
@@ -17,8 +18,50 @@
17 18
18namespace Loader { 19namespace Loader {
19 20
20AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) 21AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_)
21 : AppLoader(std::move(file)) {} 22 : AppLoader(std::move(file_)) {
23 const auto dir = file->GetContainingDirectory();
24
25 // Icon
26 FileSys::VirtualFile icon_file = nullptr;
27 for (const auto& language : FileSys::LANGUAGE_NAMES) {
28 icon_file = dir->GetFile("icon_" + std::string(language) + ".dat");
29 if (icon_file != nullptr) {
30 icon_data = icon_file->ReadAllBytes();
31 break;
32 }
33 }
34
35 if (icon_data.empty()) {
36 // Any png, jpeg, or bmp file
37 const auto& files = dir->GetFiles();
38 const auto icon_iter =
39 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
40 return file->GetExtension() == "png" || file->GetExtension() == "jpg" ||
41 file->GetExtension() == "bmp" || file->GetExtension() == "jpeg";
42 });
43 if (icon_iter != files.end())
44 icon_data = (*icon_iter)->ReadAllBytes();
45 }
46
47 // Metadata
48 FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp");
49 if (nacp_file == nullptr) {
50 const auto& files = dir->GetFiles();
51 const auto nacp_iter =
52 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
53 return file->GetExtension() == "nacp";
54 });
55 if (nacp_iter != files.end())
56 nacp_file = *nacp_iter;
57 }
58
59 if (nacp_file != nullptr) {
60 FileSys::NACP nacp(nacp_file);
61 title_id = nacp.GetTitleId();
62 name = nacp.GetApplicationName();
63 }
64}
22 65
23AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( 66AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
24 FileSys::VirtualDir directory) 67 FileSys::VirtualDir directory)
@@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile
105 return ResultStatus::Success; 148 return ResultStatus::Success;
106} 149}
107 150
151ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
152 if (icon_data.empty())
153 return ResultStatus::ErrorNotUsed;
154 buffer = icon_data;
155 return ResultStatus::Success;
156}
157
158ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
159 if (name.empty())
160 return ResultStatus::ErrorNotUsed;
161 out_program_id = title_id;
162 return ResultStatus::Success;
163}
164
165ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
166 if (name.empty())
167 return ResultStatus::ErrorNotUsed;
168 title = name;
169 return ResultStatus::Success;
170}
171
108} // namespace Loader 172} // namespace Loader
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 7d5433563..b20804f75 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -39,11 +39,18 @@ public:
39 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 39 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
40 40
41 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 41 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
42 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
43 ResultStatus ReadProgramId(u64& out_program_id) override;
44 ResultStatus ReadTitle(std::string& title) override;
42 45
43private: 46private:
44 FileSys::ProgramMetadata metadata; 47 FileSys::ProgramMetadata metadata;
45 FileSys::VirtualFile romfs; 48 FileSys::VirtualFile romfs;
46 FileSys::VirtualDir dir; 49 FileSys::VirtualDir dir;
50
51 std::vector<u8> icon_data;
52 std::string name;
53 u64 title_id{};
47}; 54};
48 55
49} // namespace Loader 56} // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 57e6c0365..a288654df 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -43,10 +43,6 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
43 return FileType::Unknown; 43 return FileType::Unknown;
44} 44}
45 45
46FileType IdentifyFile(const std::string& file_name) {
47 return IdentifyFile(std::make_shared<FileSys::RealVfsFile>(file_name));
48}
49
50FileType GuessFromFilename(const std::string& name) { 46FileType GuessFromFilename(const std::string& name) {
51 if (name == "main") 47 if (name == "main")
52 return FileType::DeconstructedRomDirectory; 48 return FileType::DeconstructedRomDirectory;
@@ -68,7 +64,7 @@ FileType GuessFromFilename(const std::string& name) {
68 return FileType::Unknown; 64 return FileType::Unknown;
69} 65}
70 66
71const char* GetFileTypeString(FileType type) { 67std::string GetFileTypeString(FileType type) {
72 switch (type) { 68 switch (type) {
73 case FileType::ELF: 69 case FileType::ELF:
74 return "ELF"; 70 return "ELF";
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index e69ab85ef..6a9e5a68b 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -43,14 +43,6 @@ enum class FileType {
43FileType IdentifyFile(FileSys::VirtualFile file); 43FileType IdentifyFile(FileSys::VirtualFile file);
44 44
45/** 45/**
46 * Identifies the type of a bootable file based on the magic value in its header.
47 * @param file_name path to file
48 * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine
49 * a filetype, and will never return FileType::Error.
50 */
51FileType IdentifyFile(const std::string& file_name);
52
53/**
54 * Guess the type of a bootable file from its name 46 * Guess the type of a bootable file from its name
55 * @param name String name of bootable file 47 * @param name String name of bootable file
56 * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine 48 * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine
@@ -61,7 +53,7 @@ FileType GuessFromFilename(const std::string& name);
61/** 53/**
62 * Convert a FileType into a string which can be displayed to the user. 54 * Convert a FileType into a string which can be displayed to the user.
63 */ 55 */
64const char* GetFileTypeString(FileType type); 56std::string GetFileTypeString(FileType type);
65 57
66/// Return type for functions in Loader namespace 58/// Return type for functions in Loader namespace
67enum class ResultStatus { 59enum class ResultStatus {
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index dbc67c0b5..46f5cd393 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
77} 77}
78 78
79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { 79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
80 if (nca == nullptr) 80 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
81 return ResultStatus::ErrorNotLoaded; 81 return ResultStatus::ErrorInvalidFormat;
82 out_program_id = nca->GetTitleId(); 82 out_program_id = nca->GetTitleId();
83 return ResultStatus::Success; 83 return ResultStatus::Success;
84} 84}
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 0fd2d0417..7f7d8ea0b 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -33,7 +33,6 @@ public:
33 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 33 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
34 34
35 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 35 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
36
37 ResultStatus ReadProgramId(u64& out_program_id) override; 36 ResultStatus ReadProgramId(u64& out_program_id) override;
38 37
39 ~AppLoader_NCA(); 38 ~AppLoader_NCA();
@@ -41,6 +40,7 @@ public:
41private: 40private:
42 FileSys::ProgramMetadata metadata; 41 FileSys::ProgramMetadata metadata;
43 42
43 FileSys::NCAHeader header;
44 std::unique_ptr<FileSys::NCA> nca; 44 std::unique_ptr<FileSys::NCA> nca;
45 std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; 45 std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
46}; 46};
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index eb4dee2c2..d3fe24419 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -26,7 +26,25 @@ namespace Loader {
26AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) 26AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
27 : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), 27 : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
28 nca_loader(std::make_unique<AppLoader_NCA>( 28 nca_loader(std::make_unique<AppLoader_NCA>(
29 xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} 29 xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {
30 if (xci->GetStatus() != ResultStatus::Success)
31 return;
32 const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
33 if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
34 return;
35 const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS());
36 if (romfs == nullptr)
37 return;
38 for (const auto& language : FileSys::LANGUAGE_NAMES) {
39 icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat");
40 if (icon_file != nullptr)
41 break;
42 }
43 const auto nacp_raw = romfs->GetFile("control.nacp");
44 if (nacp_raw == nullptr)
45 return;
46 nacp_file = std::make_shared<FileSys::NACP>(nacp_raw);
47}
30 48
31AppLoader_XCI::~AppLoader_XCI() = default; 49AppLoader_XCI::~AppLoader_XCI() = default;
32 50
@@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
71 return nca_loader->ReadProgramId(out_program_id); 89 return nca_loader->ReadProgramId(out_program_id);
72} 90}
73 91
92ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
93 if (icon_file == nullptr)
94 return ResultStatus::ErrorInvalidFormat;
95 buffer = icon_file->ReadAllBytes();
96 return ResultStatus::Success;
97}
98
99ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
100 if (nacp_file == nullptr)
101 return ResultStatus::ErrorInvalidFormat;
102 title = nacp_file->GetApplicationName();
103 return ResultStatus::Success;
104}
74} // namespace Loader 105} // namespace Loader
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 0dbcfbdf8..973833050 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -33,12 +33,17 @@ public:
33 33
34 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 34 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
35 ResultStatus ReadProgramId(u64& out_program_id) override; 35 ResultStatus ReadProgramId(u64& out_program_id) override;
36 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
37 ResultStatus ReadTitle(std::string& title) override;
36 38
37private: 39private:
38 FileSys::ProgramMetadata metadata; 40 FileSys::ProgramMetadata metadata;
39 41
40 std::unique_ptr<FileSys::XCI> xci; 42 std::unique_ptr<FileSys::XCI> xci;
41 std::unique_ptr<AppLoader_NCA> nca_loader; 43 std::unique_ptr<AppLoader_NCA> nca_loader;
44
45 FileSys::VirtualFile icon_file;
46 std::shared_ptr<FileSys::NACP> nacp_file;
42}; 47};
43 48
44} // namespace Loader 49} // namespace Loader