summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/file_util.cpp11
-rw-r--r--src/common/file_util.h3
-rw-r--r--src/core/file_sys/mode.h6
-rw-r--r--src/core/file_sys/vfs_real.cpp47
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp45
5 files changed, 75 insertions, 37 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 1bc291cf9..b8dd92b65 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -826,7 +826,7 @@ std::string_view GetPathWithoutTop(std::string_view path) {
826 } 826 }
827 827
828 while (path[0] == '\\' || path[0] == '/') { 828 while (path[0] == '\\' || path[0] == '/') {
829 path.remove_suffix(1); 829 path.remove_prefix(1);
830 if (path.empty()) { 830 if (path.empty()) {
831 return path; 831 return path;
832 } 832 }
@@ -870,6 +870,15 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
870 return path; 870 return path;
871} 871}
872 872
873std::string SanitizePath(std::string_view path_) {
874 std::string path(path_);
875 std::replace(path.begin(), path.end(), '\\', '/');
876 path.erase(std::unique(path.begin(), path.end(),
877 [](char c1, char c2) { return c1 == '/' && c2 == '/'; }),
878 path.end());
879 return std::string(RemoveTrailingSlash(path));
880}
881
873IOFile::IOFile() {} 882IOFile::IOFile() {}
874 883
875IOFile::IOFile(const std::string& filename, const char openmode[], int flags) { 884IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
diff --git a/src/common/file_util.h b/src/common/file_util.h
index abfa79eae..bc9272d89 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -178,6 +178,9 @@ std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t la
178 return std::vector<T>(vector.begin() + first, vector.begin() + first + last); 178 return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
179} 179}
180 180
181// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'.
182std::string SanitizePath(std::string_view path);
183
181// simple wrapper for cstdlib file functions to 184// simple wrapper for cstdlib file functions to
182// hopefully will make error checking easier 185// hopefully will make error checking easier
183// and make forgetting an fclose() harder 186// and make forgetting an fclose() harder
diff --git a/src/core/file_sys/mode.h b/src/core/file_sys/mode.h
index b4363152a..c95205668 100644
--- a/src/core/file_sys/mode.h
+++ b/src/core/file_sys/mode.h
@@ -11,7 +11,13 @@ namespace FileSys {
11enum class Mode : u32 { 11enum class Mode : u32 {
12 Read = 1, 12 Read = 1,
13 Write = 2, 13 Write = 2,
14 ReadWrite = 3,
14 Append = 4, 15 Append = 4,
16 WriteAppend = 6,
15}; 17};
16 18
19inline u32 operator&(Mode lhs, Mode rhs) {
20 return static_cast<u32>(lhs) & static_cast<u32>(rhs);
21}
22
17} // namespace FileSys 23} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 095fec77e..9ce2e1efa 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -13,24 +13,31 @@
13 13
14namespace FileSys { 14namespace FileSys {
15 15
16static std::string PermissionsToCharArray(Mode perms) { 16static std::string ModeFlagsToString(Mode mode) {
17 std::string out; 17 std::string mode_str;
18 switch (perms) { 18
19 case Mode::Read: 19 // Calculate the correct open mode for the file.
20 out += "r"; 20 if (mode & Mode::Read && mode & Mode::Write) {
21 break; 21 if (mode & Mode::Append)
22 case Mode::Write: 22 mode_str = "a+";
23 out += "r+"; 23 else
24 break; 24 mode_str = "r+";
25 case Mode::Append: 25 } else {
26 out += "a"; 26 if (mode & Mode::Read)
27 break; 27 mode_str = "r";
28 else if (mode & Mode::Append)
29 mode_str = "a";
30 else if (mode & Mode::Write)
31 mode_str = "w";
28 } 32 }
29 return out + "b"; 33
34 mode_str += "b";
35
36 return mode_str;
30} 37}
31 38
32RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_) 39RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_)
33 : backing(path_, PermissionsToCharArray(perms_).c_str()), path(path_), 40 : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_),
34 parent_path(FileUtil::GetParentPath(path_)), 41 parent_path(FileUtil::GetParentPath(path_)),
35 path_components(FileUtil::SplitPathComponents(path_)), 42 path_components(FileUtil::SplitPathComponents(path_)),
36 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), 43 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
@@ -53,11 +60,11 @@ std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
53} 60}
54 61
55bool RealVfsFile::IsWritable() const { 62bool RealVfsFile::IsWritable() const {
56 return perms == Mode::Append || perms == Mode::Write; 63 return (perms & Mode::WriteAppend) != 0;
57} 64}
58 65
59bool RealVfsFile::IsReadable() const { 66bool RealVfsFile::IsReadable() const {
60 return perms == Mode::Read || perms == Mode::Write; 67 return (perms & Mode::ReadWrite) != 0;
61} 68}
62 69
63size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { 70size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
@@ -79,7 +86,7 @@ bool RealVfsFile::Rename(std::string_view name) {
79 path = (parent_path + DIR_SEP).append(name); 86 path = (parent_path + DIR_SEP).append(name);
80 path_components = parent_components; 87 path_components = parent_components;
81 path_components.push_back(std::move(name_str)); 88 path_components.push_back(std::move(name_str));
82 backing = FileUtil::IOFile(path, PermissionsToCharArray(perms).c_str()); 89 backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str());
83 90
84 return out; 91 return out;
85} 92}
@@ -93,7 +100,7 @@ RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_)
93 path_components(FileUtil::SplitPathComponents(path)), 100 path_components(FileUtil::SplitPathComponents(path)),
94 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), 101 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
95 perms(perms_) { 102 perms(perms_) {
96 if (!FileUtil::Exists(path) && (perms == Mode::Write || perms == Mode::Append)) 103 if (!FileUtil::Exists(path) && perms & Mode::WriteAppend)
97 FileUtil::CreateDir(path); 104 FileUtil::CreateDir(path);
98 105
99 if (perms == Mode::Append) 106 if (perms == Mode::Append)
@@ -120,11 +127,11 @@ std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories()
120} 127}
121 128
122bool RealVfsDirectory::IsWritable() const { 129bool RealVfsDirectory::IsWritable() const {
123 return perms == Mode::Write || perms == Mode::Append; 130 return (perms & Mode::WriteAppend) != 0;
124} 131}
125 132
126bool RealVfsDirectory::IsReadable() const { 133bool RealVfsDirectory::IsReadable() const {
127 return perms == Mode::Read || perms == Mode::Write; 134 return (perms & Mode::ReadWrite) != 0;
128} 135}
129 136
130std::string RealVfsDirectory::GetName() const { 137std::string RealVfsDirectory::GetName() const {
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index dbfe06cbc..fdd2fda18 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -24,7 +24,8 @@ 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 std::string_view dir_name) { 27 std::string_view dir_name_) {
28 std::string dir_name(FileUtil::SanitizePath(dir_name_));
28 if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\") 29 if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
29 return base; 30 return base;
30 31
@@ -38,7 +39,8 @@ std::string VfsDirectoryServiceWrapper::GetName() const {
38 return backing->GetName(); 39 return backing->GetName();
39} 40}
40 41
41ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 size) const { 42ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
43 std::string path(FileUtil::SanitizePath(path_));
42 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 44 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
43 auto file = dir->CreateFile(FileUtil::GetFilename(path)); 45 auto file = dir->CreateFile(FileUtil::GetFilename(path));
44 if (file == nullptr) { 46 if (file == nullptr) {
@@ -52,7 +54,8 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path, u64 s
52 return RESULT_SUCCESS; 54 return RESULT_SUCCESS;
53} 55}
54 56
55ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const { 57ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
58 std::string path(FileUtil::SanitizePath(path_));
56 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 59 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
57 if (path == "/" || path == "\\") { 60 if (path == "/" || path == "\\") {
58 // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... 61 // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
@@ -60,14 +63,15 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path) const
60 } 63 }
61 if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) 64 if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr)
62 return FileSys::ERROR_PATH_NOT_FOUND; 65 return FileSys::ERROR_PATH_NOT_FOUND;
63 if (!backing->DeleteFile(FileUtil::GetFilename(path))) { 66 if (!dir->DeleteFile(FileUtil::GetFilename(path))) {
64 // TODO(DarkLordZach): Find a better error code for this 67 // TODO(DarkLordZach): Find a better error code for this
65 return ResultCode(-1); 68 return ResultCode(-1);
66 } 69 }
67 return RESULT_SUCCESS; 70 return RESULT_SUCCESS;
68} 71}
69 72
70ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path) const { 73ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
74 std::string path(FileUtil::SanitizePath(path_));
71 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 75 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
72 if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty()) 76 if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty())
73 dir = backing; 77 dir = backing;
@@ -79,7 +83,8 @@ ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path)
79 return RESULT_SUCCESS; 83 return RESULT_SUCCESS;
80} 84}
81 85
82ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path) const { 86ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const {
87 std::string path(FileUtil::SanitizePath(path_));
83 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 88 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
84 if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { 89 if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) {
85 // TODO(DarkLordZach): Find a better error code for this 90 // TODO(DarkLordZach): Find a better error code for this
@@ -88,7 +93,8 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path)
88 return RESULT_SUCCESS; 93 return RESULT_SUCCESS;
89} 94}
90 95
91ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path) const { 96ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const {
97 std::string path(FileUtil::SanitizePath(path_));
92 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 98 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
93 if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { 99 if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) {
94 // TODO(DarkLordZach): Find a better error code for this 100 // TODO(DarkLordZach): Find a better error code for this
@@ -97,8 +103,10 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
97 return RESULT_SUCCESS; 103 return RESULT_SUCCESS;
98} 104}
99 105
100ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path, 106ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
101 const std::string& dest_path) const { 107 const std::string& dest_path_) const {
108 std::string src_path(FileUtil::SanitizePath(src_path_));
109 std::string dest_path(FileUtil::SanitizePath(dest_path_));
102 auto src = backing->GetFileRelative(src_path); 110 auto src = backing->GetFileRelative(src_path);
103 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { 111 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
104 // Use more-optimized vfs implementation rename. 112 // Use more-optimized vfs implementation rename.
@@ -130,8 +138,10 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path,
130 return RESULT_SUCCESS; 138 return RESULT_SUCCESS;
131} 139}
132 140
133ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path, 141ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
134 const std::string& dest_path) const { 142 const std::string& dest_path_) const {
143 std::string src_path(FileUtil::SanitizePath(src_path_));
144 std::string dest_path(FileUtil::SanitizePath(dest_path_));
135 auto src = GetDirectoryRelativeWrapped(backing, src_path); 145 auto src = GetDirectoryRelativeWrapped(backing, src_path);
136 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { 146 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
137 // Use more-optimized vfs implementation rename. 147 // Use more-optimized vfs implementation rename.
@@ -154,8 +164,9 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa
154 return ResultCode(-1); 164 return ResultCode(-1);
155} 165}
156 166
157ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path, 167ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
158 FileSys::Mode mode) const { 168 FileSys::Mode mode) const {
169 std::string path(FileUtil::SanitizePath(path_));
159 auto npath = path; 170 auto npath = path;
160 while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\')) 171 while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\'))
161 npath = npath.substr(1); 172 npath = npath.substr(1);
@@ -171,7 +182,8 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
171 return MakeResult<FileSys::VirtualFile>(file); 182 return MakeResult<FileSys::VirtualFile>(file);
172} 183}
173 184
174ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path) { 185ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
186 std::string path(FileUtil::SanitizePath(path_));
175 auto dir = GetDirectoryRelativeWrapped(backing, path); 187 auto dir = GetDirectoryRelativeWrapped(backing, path);
176 if (dir == nullptr) { 188 if (dir == nullptr) {
177 // TODO(DarkLordZach): Find a better error code for this 189 // TODO(DarkLordZach): Find a better error code for this
@@ -188,7 +200,8 @@ u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
188} 200}
189 201
190ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( 202ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
191 const std::string& path) const { 203 const std::string& path_) const {
204 std::string path(FileUtil::SanitizePath(path_));
192 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 205 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
193 if (dir == nullptr) 206 if (dir == nullptr)
194 return FileSys::ERROR_PATH_NOT_FOUND; 207 return FileSys::ERROR_PATH_NOT_FOUND;
@@ -272,9 +285,9 @@ void RegisterFileSystems() {
272 sdmc_factory = nullptr; 285 sdmc_factory = nullptr;
273 286
274 auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>( 287 auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
275 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::Write); 288 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite);
276 auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>( 289 auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
277 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::Write); 290 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite);
278 291
279 auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); 292 auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
280 save_data_factory = std::move(savedata); 293 save_data_factory = std::move(savedata);