diff options
| -rw-r--r-- | src/common/file_util.cpp | 16 | ||||
| -rw-r--r-- | src/common/file_util.h | 8 | ||||
| -rw-r--r-- | src/core/core.cpp | 8 | ||||
| -rw-r--r-- | src/core/core.h | 12 | ||||
| -rw-r--r-- | src/core/file_sys/savedata_factory.h | 1 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.cpp | 148 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.h | 66 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_real.cpp | 341 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_real.h | 56 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/filesystem.cpp | 16 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/filesystem.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/service.h | 7 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 4 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 8 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 14 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 3 | ||||
| -rw-r--r-- | src/yuzu/game_list_p.h | 5 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/main.h | 3 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 1 |
21 files changed, 602 insertions, 129 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 7aeda737f..3ce590062 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -884,11 +884,21 @@ std::string_view RemoveTrailingSlash(std::string_view path) { | |||
| 884 | return path; | 884 | return path; |
| 885 | } | 885 | } |
| 886 | 886 | ||
| 887 | std::string SanitizePath(std::string_view path_) { | 887 | std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { |
| 888 | std::string path(path_); | 888 | std::string path(path_); |
| 889 | std::replace(path.begin(), path.end(), '\\', '/'); | 889 | char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\'; |
| 890 | char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/'; | ||
| 891 | |||
| 892 | if (directory_separator == DirectorySeparator::PlatformDefault) { | ||
| 893 | #ifdef _WIN32 | ||
| 894 | type1 = '/'; | ||
| 895 | type2 = '\\'; | ||
| 896 | #endif | ||
| 897 | } | ||
| 898 | |||
| 899 | std::replace(path.begin(), path.end(), type1, type2); | ||
| 890 | path.erase(std::unique(path.begin(), path.end(), | 900 | path.erase(std::unique(path.begin(), path.end(), |
| 891 | [](char c1, char c2) { return c1 == '/' && c2 == '/'; }), | 901 | [type2](char c1, char c2) { return c1 == type2 && c2 == type2; }), |
| 892 | path.end()); | 902 | path.end()); |
| 893 | return std::string(RemoveTrailingSlash(path)); | 903 | return std::string(RemoveTrailingSlash(path)); |
| 894 | } | 904 | } |
diff --git a/src/common/file_util.h b/src/common/file_util.h index d0987fb57..2711872ae 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -182,8 +182,12 @@ std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t la | |||
| 182 | return std::vector<T>(vector.begin() + first, vector.begin() + first + last); | 182 | return std::vector<T>(vector.begin() + first, vector.begin() + first + last); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. | 185 | enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault }; |
| 186 | std::string SanitizePath(std::string_view path); | 186 | |
| 187 | // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' | ||
| 188 | // depending if directory_separator is BackwardSlash or PlatformDefault and running on windows | ||
| 189 | std::string SanitizePath(std::string_view path, | ||
| 190 | DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); | ||
| 187 | 191 | ||
| 188 | // simple wrapper for cstdlib file functions to | 192 | // simple wrapper for cstdlib file functions to |
| 189 | // hopefully will make error checking easier | 193 | // hopefully will make error checking easier |
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 | ||
| 91 | System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { | 91 | System::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 | |||
| 214 | private: | 224 | private: |
| 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/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 | ||
| 12 | namespace FileSys { | 13 | namespace 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 | ||
| 11 | namespace FileSys { | 13 | namespace FileSys { |
| 12 | 14 | ||
| 15 | VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {} | ||
| 16 | |||
| 17 | VfsFilesystem::~VfsFilesystem() = default; | ||
| 18 | |||
| 19 | std::string VfsFilesystem::GetName() const { | ||
| 20 | return root->GetName(); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool VfsFilesystem::IsReadable() const { | ||
| 24 | return root->IsReadable(); | ||
| 25 | } | ||
| 26 | |||
| 27 | bool VfsFilesystem::IsWritable() const { | ||
| 28 | return root->IsWritable(); | ||
| 29 | } | ||
| 30 | |||
| 31 | VfsEntryType 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 | |||
| 41 | VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | ||
| 42 | const auto path = FileUtil::SanitizePath(path_); | ||
| 43 | return root->GetFileRelative(path); | ||
| 44 | } | ||
| 45 | |||
| 46 | VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | ||
| 47 | const auto path = FileUtil::SanitizePath(path_); | ||
| 48 | return root->CreateFileRelative(path); | ||
| 49 | } | ||
| 50 | |||
| 51 | VirtualFile 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 | |||
| 77 | VirtualFile 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 | |||
| 90 | bool 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 | |||
| 98 | VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { | ||
| 99 | const auto path = FileUtil::SanitizePath(path_); | ||
| 100 | return root->GetDirectoryRelative(path); | ||
| 101 | } | ||
| 102 | |||
| 103 | VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { | ||
| 104 | const auto path = FileUtil::SanitizePath(path_); | ||
| 105 | return root->CreateDirectoryRelative(path); | ||
| 106 | } | ||
| 107 | |||
| 108 | VirtualDir 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 | |||
| 140 | VirtualDir 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 | |||
| 153 | bool 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 | |||
| 13 | VfsFile::~VfsFile() = default; | 161 | VfsFile::~VfsFile() = default; |
| 14 | 162 | ||
| 15 | std::string VfsFile::GetExtension() const { | 163 | std::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 | ||
| 15 | namespace FileSys { | 16 | namespace FileSys { |
| 17 | |||
| 18 | struct VfsFilesystem; | ||
| 16 | struct VfsFile; | 19 | struct VfsFile; |
| 17 | struct VfsDirectory; | 20 | struct VfsDirectory; |
| 18 | 21 | ||
| 19 | // Convenience typedefs to use VfsDirectory and VfsFile | 22 | // Convenience typedefs to use Vfs* interfaces |
| 20 | using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>; | 23 | using VirtualFilesystem = std::shared_ptr<VfsFilesystem>; |
| 21 | using VirtualFile = std::shared_ptr<FileSys::VfsFile>; | 24 | using VirtualDir = std::shared_ptr<VfsDirectory>; |
| 25 | using VirtualFile = std::shared_ptr<VfsFile>; | ||
| 26 | |||
| 27 | // An enumeration representing what can be at the end of a path in a VfsFilesystem | ||
| 28 | enum 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. | ||
| 37 | struct 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 | |||
| 78 | protected: | ||
| 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. |
| 24 | struct VfsFile : NonCopyable { | 84 | struct 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 | ||
| 39 | RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_) | 41 | RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {} |
| 40 | : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_), | 42 | |
| 43 | std::string RealVfsFilesystem::GetName() const { | ||
| 44 | return "Real"; | ||
| 45 | } | ||
| 46 | |||
| 47 | bool RealVfsFilesystem::IsReadable() const { | ||
| 48 | return true; | ||
| 49 | } | ||
| 50 | |||
| 51 | bool RealVfsFilesystem::IsWritable() const { | ||
| 52 | return true; | ||
| 53 | } | ||
| 54 | |||
| 55 | VfsEntryType 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 | |||
| 65 | VirtualFile 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 | |||
| 84 | VirtualFile 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 | |||
| 91 | VirtualFile 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 | |||
| 103 | VirtualFile 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 | |||
| 125 | bool 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 | |||
| 135 | VirtualDir 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 | |||
| 141 | VirtualDir 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 | |||
| 149 | VirtualDir 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 | |||
| 162 | VirtualDir 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 | |||
| 193 | bool 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 | |||
| 206 | RealVfsFile::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 | ||
| 50 | size_t RealVfsFile::GetSize() const { | 218 | size_t RealVfsFile::GetSize() const { |
| 51 | return backing.GetSize(); | 219 | return backing->GetSize(); |
| 52 | } | 220 | } |
| 53 | 221 | ||
| 54 | bool RealVfsFile::Resize(size_t new_size) { | 222 | bool RealVfsFile::Resize(size_t new_size) { |
| 55 | return backing.Resize(new_size); | 223 | return backing->Resize(new_size); |
| 56 | } | 224 | } |
| 57 | 225 | ||
| 58 | std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const { | 226 | std::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 | ||
| 62 | bool RealVfsFile::IsWritable() const { | 230 | bool RealVfsFile::IsWritable() const { |
| @@ -68,62 +236,118 @@ bool RealVfsFile::IsReadable() const { | |||
| 68 | } | 236 | } |
| 69 | 237 | ||
| 70 | size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { | 238 | size_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 | ||
| 76 | size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { | 244 | size_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 | ||
| 82 | bool RealVfsFile::Rename(std::string_view name) { | 250 | bool 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 | |||
| 254 | bool 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()); | 261 | template <> |
| 262 | std::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 | ||
| 94 | bool RealVfsFile::Close() { | 279 | template <> |
| 95 | return backing.Close(); | 280 | std::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 | ||
| 98 | RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_) | 297 | RealVfsDirectory::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) | 307 | std::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( | 314 | std::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)); | 321 | std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const { |
| 117 | return true; | 322 | return GetFileRelative(name); |
| 118 | }); | 323 | } |
| 324 | |||
| 325 | std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const { | ||
| 326 | return GetDirectoryRelative(name); | ||
| 327 | } | ||
| 328 | |||
| 329 | std::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 | |||
| 334 | std::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 | |||
| 340 | bool 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 | ||
| 121 | std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { | 345 | std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { |
| 122 | return files; | 346 | return IterateEntries<RealVfsFile, VfsFile>(); |
| 123 | } | 347 | } |
| 124 | 348 | ||
| 125 | std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { | 349 | std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { |
| 126 | return subdirectories; | 350 | return IterateEntries<RealVfsDirectory, VfsDirectory>(); |
| 127 | } | 351 | } |
| 128 | 352 | ||
| 129 | bool RealVfsDirectory::IsWritable() const { | 353 | bool 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 | ||
| 148 | std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) { | 372 | std::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 | ||
| 159 | std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) { | 377 | std::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 | ||
| 170 | bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) { | 382 | bool 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 | ||
| 176 | bool RealVfsDirectory::DeleteFile(std::string_view name) { | 387 | bool 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 | ||
| 192 | bool RealVfsDirectory::Rename(std::string_view name) { | 392 | bool 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 | ||
| 198 | std::string RealVfsDirectory::GetFullPath() const { | 397 | std::string RealVfsDirectory::GetFullPath() const { |
| @@ -202,16 +401,6 @@ std::string RealVfsDirectory::GetFullPath() const { | |||
| 202 | } | 401 | } |
| 203 | 402 | ||
| 204 | bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { | 403 | bool 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 | ||
| 13 | namespace FileSys { | 14 | namespace FileSys { |
| 14 | 15 | ||
| 16 | class RealVfsFilesystem : public VfsFilesystem { | ||
| 17 | public: | ||
| 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 | |||
| 35 | private: | ||
| 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. |
| 16 | struct RealVfsFile : public VfsFile { | 40 | class 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 | ||
| 47 | public: | ||
| 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 { | |||
| 31 | private: | 58 | private: |
| 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. |
| 43 | struct RealVfsDirectory : public VfsDirectory { | 71 | class 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 | |||
| 76 | public: | ||
| 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 | ||
| 62 | private: | 100 | private: |
| 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/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 | |||
| 59 | ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { | 59 | ResultCode 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 | ||
| 284 | void RegisterFileSystems() { | 284 | void 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 | ||
| 301 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 301 | void 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. |
| 39 | void InstallInterfaces(SM::ServiceManager& service_manager); | 39 | void 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/service.cpp b/src/core/hle/service/service.cpp index 6f286ea74..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 |
| 201 | void Init(std::shared_ptr<SM::ServiceManager>& sm) { | 201 | void 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); |
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; | |||
| 22 | class HLERequestContext; | 22 | class HLERequestContext; |
| 23 | } // namespace Kernel | 23 | } // namespace Kernel |
| 24 | 24 | ||
| 25 | namespace FileSys { | ||
| 26 | struct VfsFilesystem; | ||
| 27 | } | ||
| 28 | |||
| 25 | namespace Service { | 29 | namespace Service { |
| 26 | 30 | ||
| 27 | namespace SM { | 31 | namespace SM { |
| @@ -177,7 +181,8 @@ private: | |||
| 177 | }; | 181 | }; |
| 178 | 182 | ||
| 179 | /// Initialize ServiceManager | 183 | /// Initialize ServiceManager |
| 180 | void Init(std::shared_ptr<SM::ServiceManager>& sm); | 184 | void Init(std::shared_ptr<SM::ServiceManager>& sm, |
| 185 | const std::shared_ptr<FileSys::VfsFilesystem>& vfs); | ||
| 181 | 186 | ||
| 182 | /// Shutdown ServiceManager | 187 | /// Shutdown ServiceManager |
| 183 | void Shutdown(); | 188 | void Shutdown(); |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 0781fb8c1..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 | ||
| 46 | FileType IdentifyFile(const std::string& file_name) { | ||
| 47 | return IdentifyFile(std::make_shared<FileSys::RealVfsFile>(file_name)); | ||
| 48 | } | ||
| 49 | |||
| 50 | FileType GuessFromFilename(const std::string& name) { | 46 | FileType GuessFromFilename(const std::string& name) { |
| 51 | if (name == "main") | 47 | if (name == "main") |
| 52 | return FileType::DeconstructedRomDirectory; | 48 | return FileType::DeconstructedRomDirectory; |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 7bd0adedb..6a9e5a68b 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -43,14 +43,6 @@ enum class FileType { | |||
| 43 | FileType IdentifyFile(FileSys::VirtualFile file); | 43 | FileType 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 | */ | ||
| 51 | FileType 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 |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 5f47f5a2b..1c738d2a4 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "common/string_util.h" | 15 | #include "common/string_util.h" |
| 16 | #include "core/file_sys/content_archive.h" | 16 | #include "core/file_sys/content_archive.h" |
| 17 | #include "core/file_sys/control_metadata.h" | 17 | #include "core/file_sys/control_metadata.h" |
| 18 | #include "core/file_sys/romfs.h" | ||
| 18 | #include "core/file_sys/vfs_real.h" | 19 | #include "core/file_sys/vfs_real.h" |
| 19 | #include "core/loader/loader.h" | 20 | #include "core/loader/loader.h" |
| 20 | #include "game_list.h" | 21 | #include "game_list.h" |
| @@ -197,7 +198,8 @@ void GameList::onFilterCloseClicked() { | |||
| 197 | main_window->filterBarSetChecked(false); | 198 | main_window->filterBarSetChecked(false); |
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | GameList::GameList(GMainWindow* parent) : QWidget{parent} { | 201 | GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent) |
| 202 | : QWidget{parent}, vfs(std::move(vfs)) { | ||
| 201 | watcher = new QFileSystemWatcher(this); | 203 | watcher = new QFileSystemWatcher(this); |
| 202 | connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); | 204 | connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); |
| 203 | 205 | ||
| @@ -341,7 +343,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { | |||
| 341 | 343 | ||
| 342 | emit ShouldCancelWorker(); | 344 | emit ShouldCancelWorker(); |
| 343 | 345 | ||
| 344 | GameListWorker* worker = new GameListWorker(dir_path, deep_scan); | 346 | GameListWorker* worker = new GameListWorker(vfs, dir_path, deep_scan); |
| 345 | 347 | ||
| 346 | connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); | 348 | connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); |
| 347 | connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating, | 349 | connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating, |
| @@ -414,8 +416,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 414 | bool is_dir = FileUtil::IsDirectory(physical_name); | 416 | bool is_dir = FileUtil::IsDirectory(physical_name); |
| 415 | QFileInfo file_info(physical_name.c_str()); | 417 | QFileInfo file_info(physical_name.c_str()); |
| 416 | if (!is_dir && file_info.suffix().toStdString() == "nca") { | 418 | if (!is_dir && file_info.suffix().toStdString() == "nca") { |
| 417 | auto nca = std::make_shared<FileSys::NCA>( | 419 | auto nca = |
| 418 | std::make_shared<FileSys::RealVfsFile>(physical_name)); | 420 | std::make_shared<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read)); |
| 419 | if (nca->GetType() == FileSys::NCAContentType::Control) | 421 | if (nca->GetType() == FileSys::NCAContentType::Control) |
| 420 | nca_control_map.insert_or_assign(nca->GetTitleId(), nca); | 422 | nca_control_map.insert_or_assign(nca->GetTitleId(), nca); |
| 421 | } | 423 | } |
| @@ -436,7 +438,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 436 | if (!is_dir && | 438 | if (!is_dir && |
| 437 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { | 439 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { |
| 438 | std::unique_ptr<Loader::AppLoader> loader = | 440 | std::unique_ptr<Loader::AppLoader> loader = |
| 439 | Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); | 441 | Loader::GetLoader(vfs->OpenFile(physical_name, FileSys::Mode::Read)); |
| 440 | if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || | 442 | if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || |
| 441 | loader->GetFileType() == Loader::FileType::Error) && | 443 | loader->GetFileType() == Loader::FileType::Error) && |
| 442 | !UISettings::values.show_unknown)) | 444 | !UISettings::values.show_unknown)) |
| @@ -459,7 +461,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 459 | // Use from metadata pool. | 461 | // Use from metadata pool. |
| 460 | if (nca_control_map.find(program_id) != nca_control_map.end()) { | 462 | if (nca_control_map.find(program_id) != nca_control_map.end()) { |
| 461 | const auto nca = nca_control_map[program_id]; | 463 | const auto nca = nca_control_map[program_id]; |
| 462 | const auto control_dir = nca->GetSubdirectories()[0]; | 464 | const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS()); |
| 463 | 465 | ||
| 464 | const auto nacp_file = control_dir->GetFile("control.nacp"); | 466 | const auto nacp_file = control_dir->GetFile("control.nacp"); |
| 465 | FileSys::NACP nacp(nacp_file); | 467 | FileSys::NACP nacp(nacp_file); |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 3bc14f07f..afe624b32 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -59,7 +59,7 @@ public: | |||
| 59 | QToolButton* button_filter_close = nullptr; | 59 | QToolButton* button_filter_close = nullptr; |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | explicit GameList(GMainWindow* parent = nullptr); | 62 | explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr); |
| 63 | ~GameList() override; | 63 | ~GameList() override; |
| 64 | 64 | ||
| 65 | void clearFilter(); | 65 | void clearFilter(); |
| @@ -90,6 +90,7 @@ private: | |||
| 90 | void PopupContextMenu(const QPoint& menu_location); | 90 | void PopupContextMenu(const QPoint& menu_location); |
| 91 | void RefreshGameDirectory(); | 91 | void RefreshGameDirectory(); |
| 92 | 92 | ||
| 93 | FileSys::VirtualFilesystem vfs; | ||
| 93 | SearchField* search_field; | 94 | SearchField* search_field; |
| 94 | GMainWindow* main_window = nullptr; | 95 | GMainWindow* main_window = nullptr; |
| 95 | QVBoxLayout* layout = nullptr; | 96 | QVBoxLayout* layout = nullptr; |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index a22025e67..114a0fc7f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -139,8 +139,8 @@ class GameListWorker : public QObject, public QRunnable { | |||
| 139 | Q_OBJECT | 139 | Q_OBJECT |
| 140 | 140 | ||
| 141 | public: | 141 | public: |
| 142 | GameListWorker(QString dir_path, bool deep_scan) | 142 | GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan) |
| 143 | : dir_path(std::move(dir_path)), deep_scan(deep_scan) {} | 143 | : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan) {} |
| 144 | 144 | ||
| 145 | public slots: | 145 | public slots: |
| 146 | /// Starts the processing of directory tree information. | 146 | /// Starts the processing of directory tree information. |
| @@ -163,6 +163,7 @@ signals: | |||
| 163 | void Finished(QStringList watch_list); | 163 | void Finished(QStringList watch_list); |
| 164 | 164 | ||
| 165 | private: | 165 | private: |
| 166 | FileSys::VirtualFilesystem vfs; | ||
| 166 | QStringList watch_list; | 167 | QStringList watch_list; |
| 167 | QString dir_path; | 168 | QString dir_path; |
| 168 | bool deep_scan; | 169 | bool deep_scan; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a6241e63e..67e3c6549 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "common/string_util.h" | 24 | #include "common/string_util.h" |
| 25 | #include "core/core.h" | 25 | #include "core/core.h" |
| 26 | #include "core/crypto/key_manager.h" | 26 | #include "core/crypto/key_manager.h" |
| 27 | #include "core/file_sys/vfs_real.h" | ||
| 27 | #include "core/gdbstub/gdbstub.h" | 28 | #include "core/gdbstub/gdbstub.h" |
| 28 | #include "core/loader/loader.h" | 29 | #include "core/loader/loader.h" |
| 29 | #include "core/settings.h" | 30 | #include "core/settings.h" |
| @@ -83,7 +84,9 @@ void GMainWindow::ShowCallouts() {} | |||
| 83 | 84 | ||
| 84 | const int GMainWindow::max_recent_files_item; | 85 | const int GMainWindow::max_recent_files_item; |
| 85 | 86 | ||
| 86 | GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | 87 | GMainWindow::GMainWindow() |
| 88 | : config(new Config()), emu_thread(nullptr), | ||
| 89 | vfs(std::make_shared<FileSys::RealVfsFilesystem>()) { | ||
| 87 | 90 | ||
| 88 | debug_context = Tegra::DebugContext::Construct(); | 91 | debug_context = Tegra::DebugContext::Construct(); |
| 89 | 92 | ||
| @@ -132,7 +135,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 132 | render_window = new GRenderWindow(this, emu_thread.get()); | 135 | render_window = new GRenderWindow(this, emu_thread.get()); |
| 133 | render_window->hide(); | 136 | render_window->hide(); |
| 134 | 137 | ||
| 135 | game_list = new GameList(this); | 138 | game_list = new GameList(vfs, this); |
| 136 | ui.horizontalLayout->addWidget(game_list); | 139 | ui.horizontalLayout->addWidget(game_list); |
| 137 | 140 | ||
| 138 | // Create status bar | 141 | // Create status bar |
| @@ -406,6 +409,7 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 406 | } | 409 | } |
| 407 | 410 | ||
| 408 | Core::System& system{Core::System::GetInstance()}; | 411 | Core::System& system{Core::System::GetInstance()}; |
| 412 | system.SetFilesystem(vfs); | ||
| 409 | 413 | ||
| 410 | system.SetGPUDebugContext(debug_context); | 414 | system.SetGPUDebugContext(debug_context); |
| 411 | 415 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6e335b8f8..74487c58c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -161,6 +161,9 @@ private: | |||
| 161 | bool emulation_running = false; | 161 | bool emulation_running = false; |
| 162 | std::unique_ptr<EmuThread> emu_thread; | 162 | std::unique_ptr<EmuThread> emu_thread; |
| 163 | 163 | ||
| 164 | // FS | ||
| 165 | FileSys::VirtualFilesystem vfs; | ||
| 166 | |||
| 164 | // Debugger panes | 167 | // Debugger panes |
| 165 | ProfilerWidget* profilerWidget; | 168 | ProfilerWidget* profilerWidget; |
| 166 | MicroProfileDialog* microProfileDialog; | 169 | MicroProfileDialog* microProfileDialog; |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index d637dbd0c..0605c92e3 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -161,6 +161,7 @@ int main(int argc, char** argv) { | |||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | Core::System& system{Core::System::GetInstance()}; | 163 | Core::System& system{Core::System::GetInstance()}; |
| 164 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | ||
| 164 | 165 | ||
| 165 | SCOPE_EXIT({ system.Shutdown(); }); | 166 | SCOPE_EXIT({ system.Shutdown(); }); |
| 166 | 167 | ||