summaryrefslogtreecommitdiff
path: root/src/core/file_sys/vfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/file_sys/vfs.cpp')
-rw-r--r--src/core/file_sys/vfs.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
new file mode 100644
index 000000000..f859ef33f
--- /dev/null
+++ b/src/core/file_sys/vfs.cpp
@@ -0,0 +1,238 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <numeric>
7#include "common/file_util.h"
8#include "common/logging/backend.h"
9#include "core/file_sys/vfs.h"
10
11namespace FileSys {
12
13VfsFile::~VfsFile() = default;
14
15std::string VfsFile::GetExtension() const {
16 return FileUtil::GetExtensionFromFilename(GetName());
17}
18
19VfsDirectory::~VfsDirectory() = default;
20
21boost::optional<u8> VfsFile::ReadByte(size_t offset) const {
22 u8 out{};
23 size_t size = Read(&out, 1, offset);
24 if (size == 1)
25 return out;
26
27 return boost::none;
28}
29
30std::vector<u8> VfsFile::ReadBytes(size_t size, size_t offset) const {
31 std::vector<u8> out(size);
32 size_t read_size = Read(out.data(), size, offset);
33 out.resize(read_size);
34 return out;
35}
36
37std::vector<u8> VfsFile::ReadAllBytes() const {
38 return ReadBytes(GetSize());
39}
40
41bool VfsFile::WriteByte(u8 data, size_t offset) {
42 return Write(&data, 1, offset) == 1;
43}
44
45size_t VfsFile::WriteBytes(std::vector<u8> data, size_t offset) {
46 return Write(data.data(), data.size(), offset);
47}
48
49std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(const std::string& path) const {
50 auto vec = FileUtil::SplitPathComponents(path);
51 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
52 vec.end());
53 if (vec.empty())
54 return nullptr;
55 if (vec.size() == 1)
56 return GetFile(vec[0]);
57 auto dir = GetSubdirectory(vec[0]);
58 for (size_t component = 1; component < vec.size() - 1; ++component) {
59 if (dir == nullptr)
60 return nullptr;
61 dir = dir->GetSubdirectory(vec[component]);
62 }
63 if (dir == nullptr)
64 return nullptr;
65 return dir->GetFile(vec.back());
66}
67
68std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(const std::string& path) const {
69 if (IsRoot())
70 return GetFileRelative(path);
71
72 return GetParentDirectory()->GetFileAbsolute(path);
73}
74
75std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(const std::string& path) const {
76 auto vec = FileUtil::SplitPathComponents(path);
77 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
78 vec.end());
79 if (vec.empty())
80 // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
81 // because of const-ness
82 return nullptr;
83 auto dir = GetSubdirectory(vec[0]);
84 for (size_t component = 1; component < vec.size(); ++component) {
85 if (dir == nullptr)
86 return nullptr;
87 dir = dir->GetSubdirectory(vec[component]);
88 }
89 return dir;
90}
91
92std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(const std::string& path) const {
93 if (IsRoot())
94 return GetDirectoryRelative(path);
95
96 return GetParentDirectory()->GetDirectoryAbsolute(path);
97}
98
99std::shared_ptr<VfsFile> VfsDirectory::GetFile(const std::string& name) const {
100 const auto& files = GetFiles();
101 const auto iter = std::find_if(files.begin(), files.end(),
102 [&name](const auto& file1) { return name == file1->GetName(); });
103 return iter == files.end() ? nullptr : *iter;
104}
105
106std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(const std::string& name) const {
107 const auto& subs = GetSubdirectories();
108 const auto iter = std::find_if(subs.begin(), subs.end(),
109 [&name](const auto& file1) { return name == file1->GetName(); });
110 return iter == subs.end() ? nullptr : *iter;
111}
112
113bool VfsDirectory::IsRoot() const {
114 return GetParentDirectory() == nullptr;
115}
116
117size_t VfsDirectory::GetSize() const {
118 const auto& files = GetFiles();
119 const auto file_total =
120 std::accumulate(files.begin(), files.end(), 0ull,
121 [](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
122
123 const auto& sub_dir = GetSubdirectories();
124 const auto subdir_total =
125 std::accumulate(sub_dir.begin(), sub_dir.end(), 0ull,
126 [](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
127
128 return file_total + subdir_total;
129}
130
131std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(const std::string& path) {
132 auto vec = FileUtil::SplitPathComponents(path);
133 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
134 vec.end());
135 if (vec.empty())
136 return nullptr;
137 if (vec.size() == 1)
138 return CreateFile(vec[0]);
139 auto dir = GetSubdirectory(vec[0]);
140 if (dir == nullptr) {
141 dir = CreateSubdirectory(vec[0]);
142 if (dir == nullptr)
143 return nullptr;
144 }
145
146 return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path));
147}
148
149std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(const std::string& path) {
150 if (IsRoot())
151 return CreateFileRelative(path);
152 return GetParentDirectory()->CreateFileAbsolute(path);
153}
154
155std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(const std::string& path) {
156 auto vec = FileUtil::SplitPathComponents(path);
157 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
158 vec.end());
159 if (vec.empty())
160 return nullptr;
161 if (vec.size() == 1)
162 return CreateSubdirectory(vec[0]);
163 auto dir = GetSubdirectory(vec[0]);
164 if (dir == nullptr) {
165 dir = CreateSubdirectory(vec[0]);
166 if (dir == nullptr)
167 return nullptr;
168 }
169 return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path));
170}
171
172std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(const std::string& path) {
173 if (IsRoot())
174 return CreateDirectoryRelative(path);
175 return GetParentDirectory()->CreateDirectoryAbsolute(path);
176}
177
178bool VfsDirectory::DeleteSubdirectoryRecursive(const std::string& name) {
179 auto dir = GetSubdirectory(name);
180 if (dir == nullptr)
181 return false;
182
183 bool success = true;
184 for (const auto& file : dir->GetFiles()) {
185 if (!DeleteFile(file->GetName()))
186 success = false;
187 }
188
189 for (const auto& sdir : dir->GetSubdirectories()) {
190 if (!dir->DeleteSubdirectoryRecursive(sdir->GetName()))
191 success = false;
192 }
193
194 return success;
195}
196
197bool VfsDirectory::Copy(const std::string& src, const std::string& dest) {
198 const auto f1 = GetFile(src);
199 auto f2 = CreateFile(dest);
200 if (f1 == nullptr || f2 == nullptr)
201 return false;
202
203 if (!f2->Resize(f1->GetSize())) {
204 DeleteFile(dest);
205 return false;
206 }
207
208 return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
209}
210
211bool ReadOnlyVfsDirectory::IsWritable() const {
212 return false;
213}
214
215bool ReadOnlyVfsDirectory::IsReadable() const {
216 return true;
217}
218
219std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(const std::string& name) {
220 return nullptr;
221}
222
223std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(const std::string& name) {
224 return nullptr;
225}
226
227bool ReadOnlyVfsDirectory::DeleteSubdirectory(const std::string& name) {
228 return false;
229}
230
231bool ReadOnlyVfsDirectory::DeleteFile(const std::string& name) {
232 return false;
233}
234
235bool ReadOnlyVfsDirectory::Rename(const std::string& name) {
236 return false;
237}
238} // namespace FileSys