summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/file_util.cpp82
-rw-r--r--src/common/file_util.h13
-rw-r--r--src/core/file_sys/vfs.cpp111
-rw-r--r--src/core/file_sys/vfs.h57
-rw-r--r--src/core/file_sys/vfs_offset.cpp2
-rw-r--r--src/core/file_sys/vfs_offset.h5
-rw-r--r--src/core/file_sys/vfs_real.cpp57
-rw-r--r--src/core/file_sys/vfs_real.h14
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/loader/loader.cpp3
10 files changed, 213 insertions, 133 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index a427372c9..1bc291cf9 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -792,66 +792,80 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
792 } 792 }
793} 793}
794 794
795std::vector<std::string> SplitPathComponents(const std::string& filename) { 795std::vector<std::string> SplitPathComponents(std::string_view filename) {
796 auto copy(filename); 796 std::string copy(filename);
797 std::replace(copy.begin(), copy.end(), '\\', '/'); 797 std::replace(copy.begin(), copy.end(), '\\', '/');
798 std::vector<std::string> out; 798 std::vector<std::string> out;
799 799
800 std::stringstream stream(filename); 800 std::stringstream stream(copy);
801 std::string item; 801 std::string item;
802 while (std::getline(stream, item, '/')) 802 while (std::getline(stream, item, '/')) {
803 out.push_back(std::move(item)); 803 out.push_back(std::move(item));
804 }
804 805
805 return out; 806 return out;
806} 807}
807 808
808std::string GetParentPath(const std::string& path) { 809std::string_view GetParentPath(std::string_view path) {
809 auto out = path; 810 const auto name_bck_index = path.rfind('\\');
810 const auto name_bck_index = out.find_last_of('\\'); 811 const auto name_fwd_index = path.rfind('/');
811 const auto name_fwd_index = out.find_last_of('/');
812 size_t name_index; 812 size_t name_index;
813 if (name_bck_index == std::string::npos || name_fwd_index == std::string::npos)
814 name_index = std::min<size_t>(name_bck_index, name_fwd_index);
815 else
816 name_index = std::max<size_t>(name_bck_index, name_fwd_index);
817 813
818 return out.erase(name_index); 814 if (name_bck_index == std::string_view::npos || name_fwd_index == std::string_view::npos) {
815 name_index = std::min(name_bck_index, name_fwd_index);
816 } else {
817 name_index = std::max(name_bck_index, name_fwd_index);
818 }
819
820 return path.substr(0, name_index);
819} 821}
820 822
821std::string GetPathWithoutTop(std::string path) { 823std::string_view GetPathWithoutTop(std::string_view path) {
822 if (path.empty()) 824 if (path.empty()) {
823 return ""; 825 return path;
826 }
827
824 while (path[0] == '\\' || path[0] == '/') { 828 while (path[0] == '\\' || path[0] == '/') {
825 path = path.substr(1); 829 path.remove_suffix(1);
826 if (path.empty()) 830 if (path.empty()) {
827 return ""; 831 return path;
832 }
828 } 833 }
829 const auto name_bck_index = path.find_first_of('\\'); 834
830 const auto name_fwd_index = path.find_first_of('/'); 835 const auto name_bck_index = path.find('\\');
836 const auto name_fwd_index = path.find('/');
831 return path.substr(std::min(name_bck_index, name_fwd_index) + 1); 837 return path.substr(std::min(name_bck_index, name_fwd_index) + 1);
832} 838}
833 839
834std::string GetFilename(std::string path) { 840std::string_view GetFilename(std::string_view path) {
835 std::replace(path.begin(), path.end(), '\\', '/'); 841 const auto name_index = path.find_last_of("\\/");
836 auto name_index = path.find_last_of('/'); 842
837 if (name_index == std::string::npos) 843 if (name_index == std::string_view::npos) {
838 return ""; 844 return {};
845 }
846
839 return path.substr(name_index + 1); 847 return path.substr(name_index + 1);
840} 848}
841 849
842std::string GetExtensionFromFilename(const std::string& name) { 850std::string_view GetExtensionFromFilename(std::string_view name) {
843 size_t index = name.find_last_of('.'); 851 const size_t index = name.rfind('.');
844 if (index == std::string::npos) 852
845 return ""; 853 if (index == std::string_view::npos) {
854 return {};
855 }
846 856
847 return name.substr(index + 1); 857 return name.substr(index + 1);
848} 858}
849 859
850std::string RemoveTrailingSlash(const std::string& path) { 860std::string_view RemoveTrailingSlash(std::string_view path) {
851 if (path.empty()) 861 if (path.empty()) {
852 return path; 862 return path;
853 if (path.back() == '\\' || path.back() == '/') 863 }
854 return path.substr(0, path.size() - 1); 864
865 if (path.back() == '\\' || path.back() == '/') {
866 path.remove_suffix(1);
867 return path;
868 }
855 869
856 return path; 870 return path;
857} 871}
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 090907c03..abfa79eae 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -9,6 +9,7 @@
9#include <fstream> 9#include <fstream>
10#include <functional> 10#include <functional>
11#include <string> 11#include <string>
12#include <string_view>
12#include <type_traits> 13#include <type_traits>
13#include <vector> 14#include <vector>
14#include "common/common_types.h" 15#include "common/common_types.h"
@@ -151,22 +152,22 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
151 152
152// Splits the path on '/' or '\' and put the components into a vector 153// Splits the path on '/' or '\' and put the components into a vector
153// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" } 154// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
154std::vector<std::string> SplitPathComponents(const std::string& filename); 155std::vector<std::string> SplitPathComponents(std::string_view filename);
155 156
156// Gets all of the text up to the last '/' or '\' in the path. 157// Gets all of the text up to the last '/' or '\' in the path.
157std::string GetParentPath(const std::string& path); 158std::string_view GetParentPath(std::string_view path);
158 159
159// Gets all of the text after the first '/' or '\' in the path. 160// Gets all of the text after the first '/' or '\' in the path.
160std::string GetPathWithoutTop(std::string path); 161std::string_view GetPathWithoutTop(std::string_view path);
161 162
162// Gets the filename of the path 163// Gets the filename of the path
163std::string GetFilename(std::string path); 164std::string_view GetFilename(std::string_view path);
164 165
165// Gets the extension of the filename 166// Gets the extension of the filename
166std::string GetExtensionFromFilename(const std::string& name); 167std::string_view GetExtensionFromFilename(std::string_view name);
167 168
168// Removes the final '/' or '\' if one exists 169// Removes the final '/' or '\' if one exists
169std::string RemoveTrailingSlash(const std::string& path); 170std::string_view RemoveTrailingSlash(std::string_view path);
170 171
171// Creates a new vector containing indices [first, last) from the original. 172// Creates a new vector containing indices [first, last) from the original.
172template <typename T> 173template <typename T>
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 3f690f12a..b99a4fd5b 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -13,7 +13,7 @@ namespace FileSys {
13VfsFile::~VfsFile() = default; 13VfsFile::~VfsFile() = default;
14 14
15std::string VfsFile::GetExtension() const { 15std::string VfsFile::GetExtension() const {
16 return FileUtil::GetExtensionFromFilename(GetName()); 16 return std::string(FileUtil::GetExtensionFromFilename(GetName()));
17} 17}
18 18
19VfsDirectory::~VfsDirectory() = default; 19VfsDirectory::~VfsDirectory() = default;
@@ -46,64 +46,80 @@ size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {
46 return Write(data.data(), data.size(), offset); 46 return Write(data.data(), data.size(), offset);
47} 47}
48 48
49std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(const std::string& path) const { 49std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
50 auto vec = FileUtil::SplitPathComponents(path); 50 auto vec = FileUtil::SplitPathComponents(path);
51 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 51 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
52 vec.end()); 52 vec.end());
53 if (vec.empty()) 53 if (vec.empty()) {
54 return nullptr; 54 return nullptr;
55 if (vec.size() == 1) 55 }
56
57 if (vec.size() == 1) {
56 return GetFile(vec[0]); 58 return GetFile(vec[0]);
59 }
60
57 auto dir = GetSubdirectory(vec[0]); 61 auto dir = GetSubdirectory(vec[0]);
58 for (size_t component = 1; component < vec.size() - 1; ++component) { 62 for (size_t component = 1; component < vec.size() - 1; ++component) {
59 if (dir == nullptr) 63 if (dir == nullptr) {
60 return nullptr; 64 return nullptr;
65 }
66
61 dir = dir->GetSubdirectory(vec[component]); 67 dir = dir->GetSubdirectory(vec[component]);
62 } 68 }
63 if (dir == nullptr) 69
70 if (dir == nullptr) {
64 return nullptr; 71 return nullptr;
72 }
73
65 return dir->GetFile(vec.back()); 74 return dir->GetFile(vec.back());
66} 75}
67 76
68std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(const std::string& path) const { 77std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) const {
69 if (IsRoot()) 78 if (IsRoot()) {
70 return GetFileRelative(path); 79 return GetFileRelative(path);
80 }
71 81
72 return GetParentDirectory()->GetFileAbsolute(path); 82 return GetParentDirectory()->GetFileAbsolute(path);
73} 83}
74 84
75std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(const std::string& path) const { 85std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const {
76 auto vec = FileUtil::SplitPathComponents(path); 86 auto vec = FileUtil::SplitPathComponents(path);
77 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 87 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
78 vec.end()); 88 vec.end());
79 if (vec.empty()) 89 if (vec.empty()) {
80 // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently 90 // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
81 // because of const-ness 91 // because of const-ness
82 return nullptr; 92 return nullptr;
93 }
94
83 auto dir = GetSubdirectory(vec[0]); 95 auto dir = GetSubdirectory(vec[0]);
84 for (size_t component = 1; component < vec.size(); ++component) { 96 for (size_t component = 1; component < vec.size(); ++component) {
85 if (dir == nullptr) 97 if (dir == nullptr) {
86 return nullptr; 98 return nullptr;
99 }
100
87 dir = dir->GetSubdirectory(vec[component]); 101 dir = dir->GetSubdirectory(vec[component]);
88 } 102 }
103
89 return dir; 104 return dir;
90} 105}
91 106
92std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(const std::string& path) const { 107std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
93 if (IsRoot()) 108 if (IsRoot()) {
94 return GetDirectoryRelative(path); 109 return GetDirectoryRelative(path);
110 }
95 111
96 return GetParentDirectory()->GetDirectoryAbsolute(path); 112 return GetParentDirectory()->GetDirectoryAbsolute(path);
97} 113}
98 114
99std::shared_ptr<VfsFile> VfsDirectory::GetFile(const std::string& name) const { 115std::shared_ptr<VfsFile> VfsDirectory::GetFile(std::string_view name) const {
100 const auto& files = GetFiles(); 116 const auto& files = GetFiles();
101 const auto iter = std::find_if(files.begin(), files.end(), 117 const auto iter = std::find_if(files.begin(), files.end(),
102 [&name](const auto& file1) { return name == file1->GetName(); }); 118 [&name](const auto& file1) { return name == file1->GetName(); });
103 return iter == files.end() ? nullptr : *iter; 119 return iter == files.end() ? nullptr : *iter;
104} 120}
105 121
106std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(const std::string& name) const { 122std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(std::string_view name) const {
107 const auto& subs = GetSubdirectories(); 123 const auto& subs = GetSubdirectories();
108 const auto iter = std::find_if(subs.begin(), subs.end(), 124 const auto iter = std::find_if(subs.begin(), subs.end(),
109 [&name](const auto& file1) { return name == file1->GetName(); }); 125 [&name](const auto& file1) { return name == file1->GetName(); });
@@ -128,77 +144,96 @@ size_t VfsDirectory::GetSize() const {
128 return file_total + subdir_total; 144 return file_total + subdir_total;
129} 145}
130 146
131std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(const std::string& path) { 147std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) {
132 auto vec = FileUtil::SplitPathComponents(path); 148 auto vec = FileUtil::SplitPathComponents(path);
133 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 149 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
134 vec.end()); 150 vec.end());
135 if (vec.empty()) 151 if (vec.empty()) {
136 return nullptr; 152 return nullptr;
137 if (vec.size() == 1) 153 }
154
155 if (vec.size() == 1) {
138 return CreateFile(vec[0]); 156 return CreateFile(vec[0]);
157 }
158
139 auto dir = GetSubdirectory(vec[0]); 159 auto dir = GetSubdirectory(vec[0]);
140 if (dir == nullptr) { 160 if (dir == nullptr) {
141 dir = CreateSubdirectory(vec[0]); 161 dir = CreateSubdirectory(vec[0]);
142 if (dir == nullptr) 162 if (dir == nullptr) {
143 return nullptr; 163 return nullptr;
164 }
144 } 165 }
145 166
146 return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path)); 167 return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path));
147} 168}
148 169
149std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(const std::string& path) { 170std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) {
150 if (IsRoot()) 171 if (IsRoot()) {
151 return CreateFileRelative(path); 172 return CreateFileRelative(path);
173 }
174
152 return GetParentDirectory()->CreateFileAbsolute(path); 175 return GetParentDirectory()->CreateFileAbsolute(path);
153} 176}
154 177
155std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(const std::string& path) { 178std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) {
156 auto vec = FileUtil::SplitPathComponents(path); 179 auto vec = FileUtil::SplitPathComponents(path);
157 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 180 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
158 vec.end()); 181 vec.end());
159 if (vec.empty()) 182 if (vec.empty()) {
160 return nullptr; 183 return nullptr;
161 if (vec.size() == 1) 184 }
185
186 if (vec.size() == 1) {
162 return CreateSubdirectory(vec[0]); 187 return CreateSubdirectory(vec[0]);
188 }
189
163 auto dir = GetSubdirectory(vec[0]); 190 auto dir = GetSubdirectory(vec[0]);
164 if (dir == nullptr) { 191 if (dir == nullptr) {
165 dir = CreateSubdirectory(vec[0]); 192 dir = CreateSubdirectory(vec[0]);
166 if (dir == nullptr) 193 if (dir == nullptr) {
167 return nullptr; 194 return nullptr;
195 }
168 } 196 }
197
169 return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path)); 198 return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path));
170} 199}
171 200
172std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(const std::string& path) { 201std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
173 if (IsRoot()) 202 if (IsRoot()) {
174 return CreateDirectoryRelative(path); 203 return CreateDirectoryRelative(path);
204 }
205
175 return GetParentDirectory()->CreateDirectoryAbsolute(path); 206 return GetParentDirectory()->CreateDirectoryAbsolute(path);
176} 207}
177 208
178bool VfsDirectory::DeleteSubdirectoryRecursive(const std::string& name) { 209bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
179 auto dir = GetSubdirectory(name); 210 auto dir = GetSubdirectory(name);
180 if (dir == nullptr) 211 if (dir == nullptr) {
181 return false; 212 return false;
213 }
182 214
183 bool success = true; 215 bool success = true;
184 for (const auto& file : dir->GetFiles()) { 216 for (const auto& file : dir->GetFiles()) {
185 if (!DeleteFile(file->GetName())) 217 if (!DeleteFile(file->GetName())) {
186 success = false; 218 success = false;
219 }
187 } 220 }
188 221
189 for (const auto& sdir : dir->GetSubdirectories()) { 222 for (const auto& sdir : dir->GetSubdirectories()) {
190 if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) 223 if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
191 success = false; 224 success = false;
225 }
192 } 226 }
193 227
194 return success; 228 return success;
195} 229}
196 230
197bool VfsDirectory::Copy(const std::string& src, const std::string& dest) { 231bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
198 const auto f1 = GetFile(src); 232 const auto f1 = GetFile(src);
199 auto f2 = CreateFile(dest); 233 auto f2 = CreateFile(dest);
200 if (f1 == nullptr || f2 == nullptr) 234 if (f1 == nullptr || f2 == nullptr) {
201 return false; 235 return false;
236 }
202 237
203 if (!f2->Resize(f1->GetSize())) { 238 if (!f2->Resize(f1->GetSize())) {
204 DeleteFile(dest); 239 DeleteFile(dest);
@@ -216,23 +251,23 @@ bool ReadOnlyVfsDirectory::IsReadable() const {
216 return true; 251 return true;
217} 252}
218 253
219std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(const std::string& name) { 254std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) {
220 return nullptr; 255 return nullptr;
221} 256}
222 257
223std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(const std::string& name) { 258std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) {
224 return nullptr; 259 return nullptr;
225} 260}
226 261
227bool ReadOnlyVfsDirectory::DeleteSubdirectory(const std::string& name) { 262bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
228 return false; 263 return false;
229} 264}
230 265
231bool ReadOnlyVfsDirectory::DeleteFile(const std::string& name) { 266bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
232 return false; 267 return false;
233} 268}
234 269
235bool ReadOnlyVfsDirectory::Rename(const std::string& name) { 270bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
236 return false; 271 return false;
237} 272}
238} // namespace FileSys 273} // namespace FileSys
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index db3c77eac..4a13b8378 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -6,11 +6,11 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include <string_view>
9#include <type_traits> 10#include <type_traits>
10#include <vector> 11#include <vector>
11#include "boost/optional.hpp" 12#include "boost/optional.hpp"
12#include "common/common_types.h" 13#include "common/common_types.h"
13#include "common/file_util.h"
14 14
15namespace FileSys { 15namespace FileSys {
16struct VfsFile; 16struct VfsFile;
@@ -112,7 +112,7 @@ struct VfsFile : NonCopyable {
112 } 112 }
113 113
114 // Renames the file to name. Returns whether or not the operation was successsful. 114 // Renames the file to name. Returns whether or not the operation was successsful.
115 virtual bool Rename(const std::string& name) = 0; 115 virtual bool Rename(std::string_view name) = 0;
116}; 116};
117 117
118// A class representing a directory in an abstract filesystem. 118// A class representing a directory in an abstract filesystem.
@@ -121,27 +121,27 @@ struct VfsDirectory : NonCopyable {
121 121
122 // Retrives the file located at path as if the current directory was root. Returns nullptr if 122 // Retrives the file located at path as if the current directory was root. Returns nullptr if
123 // not found. 123 // not found.
124 virtual std::shared_ptr<VfsFile> GetFileRelative(const std::string& path) const; 124 virtual std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const;
125 // Calls GetFileRelative(path) on the root of the current directory. 125 // Calls GetFileRelative(path) on the root of the current directory.
126 virtual std::shared_ptr<VfsFile> GetFileAbsolute(const std::string& path) const; 126 virtual std::shared_ptr<VfsFile> GetFileAbsolute(std::string_view path) const;
127 127
128 // Retrives the directory located at path as if the current directory was root. Returns nullptr 128 // Retrives the directory located at path as if the current directory was root. Returns nullptr
129 // if not found. 129 // if not found.
130 virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(const std::string& path) const; 130 virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const;
131 // Calls GetDirectoryRelative(path) on the root of the current directory. 131 // Calls GetDirectoryRelative(path) on the root of the current directory.
132 virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(const std::string& path) const; 132 virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(std::string_view path) const;
133 133
134 // Returns a vector containing all of the files in this directory. 134 // Returns a vector containing all of the files in this directory.
135 virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0; 135 virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0;
136 // Returns the file with filename matching name. Returns nullptr if directory dosen't have a 136 // Returns the file with filename matching name. Returns nullptr if directory dosen't have a
137 // file with name. 137 // file with name.
138 virtual std::shared_ptr<VfsFile> GetFile(const std::string& name) const; 138 virtual std::shared_ptr<VfsFile> GetFile(std::string_view name) const;
139 139
140 // Returns a vector containing all of the subdirectories in this directory. 140 // Returns a vector containing all of the subdirectories in this directory.
141 virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0; 141 virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0;
142 // Returns the directory with name matching name. Returns nullptr if directory dosen't have a 142 // Returns the directory with name matching name. Returns nullptr if directory dosen't have a
143 // directory with name. 143 // directory with name.
144 virtual std::shared_ptr<VfsDirectory> GetSubdirectory(const std::string& name) const; 144 virtual std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const;
145 145
146 // Returns whether or not the directory can be written to. 146 // Returns whether or not the directory can be written to.
147 virtual bool IsWritable() const = 0; 147 virtual bool IsWritable() const = 0;
@@ -161,53 +161,56 @@ struct VfsDirectory : NonCopyable {
161 161
162 // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr 162 // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr
163 // if the operation failed. 163 // if the operation failed.
164 virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) = 0; 164 virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) = 0;
165 // Creates a new file with name name. Returns a pointer to the new file or nullptr if the 165 // Creates a new file with name name. Returns a pointer to the new file or nullptr if the
166 // operation failed. 166 // operation failed.
167 virtual std::shared_ptr<VfsFile> CreateFile(const std::string& name) = 0; 167 virtual std::shared_ptr<VfsFile> CreateFile(std::string_view name) = 0;
168 168
169 // Creates a new file at the path relative to this directory. Also creates directories if 169 // Creates a new file at the path relative to this directory. Also creates directories if
170 // they do not exist and is supported by this implementation. Returns nullptr on any failure. 170 // they do not exist and is supported by this implementation. Returns nullptr on any failure.
171 virtual std::shared_ptr<VfsFile> CreateFileRelative(const std::string& path); 171 virtual std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path);
172 172
173 // Creates a new file at the path relative to root of this directory. Also creates directories 173 // Creates a new file at the path relative to root of this directory. Also creates directories
174 // if they do not exist and is supported by this implementation. Returns nullptr on any failure. 174 // if they do not exist and is supported by this implementation. Returns nullptr on any failure.
175 virtual std::shared_ptr<VfsFile> CreateFileAbsolute(const std::string& path); 175 virtual std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path);
176 176
177 // Creates a new directory at the path relative to this directory. Also creates directories if 177 // Creates a new directory at the path relative to this directory. Also creates directories if
178 // they do not exist and is supported by this implementation. Returns nullptr on any failure. 178 // they do not exist and is supported by this implementation. Returns nullptr on any failure.
179 virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(const std::string& path); 179 virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path);
180 180
181 // Creates a new directory at the path relative to root of this directory. Also creates 181 // Creates a new directory at the path relative to root of this directory. Also creates
182 // directories if they do not exist and is supported by this implementation. Returns nullptr on 182 // directories if they do not exist and is supported by this implementation. Returns nullptr on
183 // any failure. 183 // any failure.
184 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(const std::string& path); 184 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
185 185
186 // Deletes the subdirectory with name and returns true on success. 186 // Deletes the subdirectory with name and returns true on success.
187 virtual bool DeleteSubdirectory(const std::string& name) = 0; 187 virtual bool DeleteSubdirectory(std::string_view name) = 0;
188 // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes 188 // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes
189 // the subdirectory. Returns true on success. 189 // the subdirectory. Returns true on success.
190 virtual bool DeleteSubdirectoryRecursive(const std::string& name); 190 virtual bool DeleteSubdirectoryRecursive(std::string_view name);
191 // Returnes whether or not the file with name name was deleted successfully. 191 // Returnes whether or not the file with name name was deleted successfully.
192 virtual bool DeleteFile(const std::string& name) = 0; 192 virtual bool DeleteFile(std::string_view name) = 0;
193 193
194 // Returns whether or not this directory was renamed to name. 194 // Returns whether or not this directory was renamed to name.
195 virtual bool Rename(const std::string& name) = 0; 195 virtual bool Rename(std::string_view name) = 0;
196 196
197 // Returns whether or not the file with name src was successfully copied to a new file with name 197 // Returns whether or not the file with name src was successfully copied to a new file with name
198 // dest. 198 // dest.
199 virtual bool Copy(const std::string& src, const std::string& dest); 199 virtual bool Copy(std::string_view src, std::string_view dest);
200 200
201 // Interprets the file with name file instead as a directory of type directory. 201 // Interprets the file with name file instead as a directory of type directory.
202 // The directory must have a constructor that takes a single argument of type 202 // The directory must have a constructor that takes a single argument of type
203 // std::shared_ptr<VfsFile>. Allows to reinterpret container files (i.e NCA, zip, XCI, etc) as a 203 // std::shared_ptr<VfsFile>. Allows to reinterpret container files (i.e NCA, zip, XCI, etc) as a
204 // subdirectory in one call. 204 // subdirectory in one call.
205 template <typename Directory> 205 template <typename Directory>
206 bool InterpretAsDirectory(const std::string& file) { 206 bool InterpretAsDirectory(std::string_view file) {
207 auto file_p = GetFile(file); 207 auto file_p = GetFile(file);
208 if (file_p == nullptr) 208
209 if (file_p == nullptr) {
209 return false; 210 return false;
210 return ReplaceFileWithSubdirectory(file, std::make_shared<Directory>(file_p)); 211 }
212
213 return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p));
211 } 214 }
212 215
213protected: 216protected:
@@ -221,10 +224,10 @@ protected:
221struct ReadOnlyVfsDirectory : public VfsDirectory { 224struct ReadOnlyVfsDirectory : public VfsDirectory {
222 bool IsWritable() const override; 225 bool IsWritable() const override;
223 bool IsReadable() const override; 226 bool IsReadable() const override;
224 std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override; 227 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
225 std::shared_ptr<VfsFile> CreateFile(const std::string& name) override; 228 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
226 bool DeleteSubdirectory(const std::string& name) override; 229 bool DeleteSubdirectory(std::string_view name) override;
227 bool DeleteFile(const std::string& name) override; 230 bool DeleteFile(std::string_view name) override;
228 bool Rename(const std::string& name) override; 231 bool Rename(std::string_view name) override;
229}; 232};
230} // namespace FileSys 233} // namespace FileSys
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index 217e02235..a40331cef 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -80,7 +80,7 @@ size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, size_t r_offset) {
80 return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset); 80 return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
81} 81}
82 82
83bool OffsetVfsFile::Rename(const std::string& name) { 83bool OffsetVfsFile::Rename(std::string_view name) {
84 return file->Rename(name); 84 return file->Rename(name);
85} 85}
86 86
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index ded4827f5..4f471e3ba 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -4,6 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string_view>
9
7#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs.h"
8 11
9namespace FileSys { 12namespace FileSys {
@@ -30,7 +33,7 @@ struct OffsetVfsFile : public VfsFile {
30 bool WriteByte(u8 data, size_t offset) override; 33 bool WriteByte(u8 data, size_t offset) override;
31 size_t WriteBytes(const std::vector<u8>& data, size_t offset) override; 34 size_t WriteBytes(const std::vector<u8>& data, size_t offset) override;
32 35
33 bool Rename(const std::string& name) override; 36 bool Rename(std::string_view name) override;
34 37
35 size_t GetOffset() const; 38 size_t GetOffset() const;
36 39
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 27fd464ae..095fec77e 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -72,12 +72,15 @@ size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
72 return backing.WriteBytes(data, length); 72 return backing.WriteBytes(data, length);
73} 73}
74 74
75bool RealVfsFile::Rename(const std::string& name) { 75bool RealVfsFile::Rename(std::string_view name) {
76 const auto out = FileUtil::Rename(GetName(), name); 76 std::string name_str(name.begin(), name.end());
77 path = parent_path + DIR_SEP + name; 77 const auto out = FileUtil::Rename(GetName(), name_str);
78
79 path = (parent_path + DIR_SEP).append(name);
78 path_components = parent_components; 80 path_components = parent_components;
79 path_components.push_back(name); 81 path_components.push_back(std::move(name_str));
80 backing = FileUtil::IOFile(path, PermissionsToCharArray(perms).c_str()); 82 backing = FileUtil::IOFile(path, PermissionsToCharArray(perms).c_str());
83
81 return out; 84 return out;
82} 85}
83 86
@@ -135,36 +138,54 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
135 return std::make_shared<RealVfsDirectory>(parent_path, perms); 138 return std::make_shared<RealVfsDirectory>(parent_path, perms);
136} 139}
137 140
138std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(const std::string& name) { 141std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) {
139 if (!FileUtil::CreateDir(path + DIR_SEP + name)) 142 const std::string subdir_path = (path + DIR_SEP).append(name);
143
144 if (!FileUtil::CreateDir(subdir_path)) {
140 return nullptr; 145 return nullptr;
141 subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(path + DIR_SEP + name, perms)); 146 }
147
148 subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(subdir_path, perms));
142 return subdirectories.back(); 149 return subdirectories.back();
143} 150}
144 151
145std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(const std::string& name) { 152std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) {
146 if (!FileUtil::CreateEmptyFile(path + DIR_SEP + name)) 153 const std::string file_path = (path + DIR_SEP).append(name);
154
155 if (!FileUtil::CreateEmptyFile(file_path)) {
147 return nullptr; 156 return nullptr;
148 files.emplace_back(std::make_shared<RealVfsFile>(path + DIR_SEP + name, perms)); 157 }
158
159 files.emplace_back(std::make_shared<RealVfsFile>(file_path, perms));
149 return files.back(); 160 return files.back();
150} 161}
151 162
152bool RealVfsDirectory::DeleteSubdirectory(const std::string& name) { 163bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) {
153 return FileUtil::DeleteDirRecursively(path + DIR_SEP + name); 164 const std::string subdir_path = (path + DIR_SEP).append(name);
165
166 return FileUtil::DeleteDirRecursively(subdir_path);
154} 167}
155 168
156bool RealVfsDirectory::DeleteFile(const std::string& name) { 169bool RealVfsDirectory::DeleteFile(std::string_view name) {
157 auto file = GetFile(name); 170 const auto file = GetFile(name);
158 if (file == nullptr) 171
172 if (file == nullptr) {
159 return false; 173 return false;
174 }
175
160 files.erase(std::find(files.begin(), files.end(), file)); 176 files.erase(std::find(files.begin(), files.end(), file));
177
161 auto real_file = std::static_pointer_cast<RealVfsFile>(file); 178 auto real_file = std::static_pointer_cast<RealVfsFile>(file);
162 real_file->Close(); 179 real_file->Close();
163 return FileUtil::Delete(path + DIR_SEP + name); 180
181 const std::string file_path = (path + DIR_SEP).append(name);
182 return FileUtil::Delete(file_path);
164} 183}
165 184
166bool RealVfsDirectory::Rename(const std::string& name) { 185bool RealVfsDirectory::Rename(std::string_view name) {
167 return FileUtil::Rename(path, parent_path + DIR_SEP + name); 186 const std::string new_name = (parent_path + DIR_SEP).append(name);
187
188 return FileUtil::Rename(path, new_name);
168} 189}
169 190
170bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { 191bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 5b765a552..2151211c9 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string_view>
8
7#include "common/file_util.h" 9#include "common/file_util.h"
8#include "core/file_sys/mode.h" 10#include "core/file_sys/mode.h"
9#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs.h"
@@ -24,7 +26,7 @@ struct RealVfsFile : public VfsFile {
24 bool IsReadable() const override; 26 bool IsReadable() const override;
25 size_t Read(u8* data, size_t length, size_t offset) const override; 27 size_t Read(u8* data, size_t length, size_t offset) const override;
26 size_t Write(const u8* data, size_t length, size_t offset) override; 28 size_t Write(const u8* data, size_t length, size_t offset) override;
27 bool Rename(const std::string& name) override; 29 bool Rename(std::string_view name) override;
28 30
29private: 31private:
30 bool Close(); 32 bool Close();
@@ -47,11 +49,11 @@ struct RealVfsDirectory : public VfsDirectory {
47 bool IsReadable() const override; 49 bool IsReadable() const override;
48 std::string GetName() const override; 50 std::string GetName() const override;
49 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 51 std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
50 std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override; 52 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
51 std::shared_ptr<VfsFile> CreateFile(const std::string& name) override; 53 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
52 bool DeleteSubdirectory(const std::string& name) override; 54 bool DeleteSubdirectory(std::string_view name) override;
53 bool DeleteFile(const std::string& name) override; 55 bool DeleteFile(std::string_view name) override;
54 bool Rename(const std::string& name) override; 56 bool Rename(std::string_view name) override;
55 57
56protected: 58protected:
57 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; 59 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 671e0b8d0..dbfe06cbc 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -24,7 +24,7 @@ namespace Service::FileSystem {
24constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; 24constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
25 25
26static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, 26static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
27 const std::string& dir_name) { 27 std::string_view dir_name) {
28 if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\") 28 if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
29 return base; 29 return base;
30 30
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index e70f37677..4cbd9e285 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -49,7 +49,8 @@ FileType GuessFromFilename(const std::string& name) {
49 if (name == "main") 49 if (name == "main")
50 return FileType::DeconstructedRomDirectory; 50 return FileType::DeconstructedRomDirectory;
51 51
52 const std::string extension = Common::ToLower(FileUtil::GetExtensionFromFilename(name)); 52 const std::string extension =
53 Common::ToLower(std::string(FileUtil::GetExtensionFromFilename(name)));
53 54
54 if (extension == "elf") 55 if (extension == "elf")
55 return FileType::ELF; 56 return FileType::ELF;