summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/vfs_real.cpp55
-rw-r--r--src/core/file_sys/vfs_real.h15
2 files changed, 45 insertions, 25 deletions
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index fcc81a664..b0515ec05 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -76,6 +76,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
76VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size, 76VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
77 Mode perms) { 77 Mode perms) {
78 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 78 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
79 std::scoped_lock lk{list_lock};
79 80
80 if (auto it = cache.find(path); it != cache.end()) { 81 if (auto it = cache.find(path); it != cache.end()) {
81 if (auto file = it->second.lock(); file) { 82 if (auto file = it->second.lock(); file) {
@@ -88,7 +89,7 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op
88 } 89 }
89 90
90 auto reference = std::make_unique<FileReference>(); 91 auto reference = std::make_unique<FileReference>();
91 this->InsertReferenceIntoList(*reference); 92 this->InsertReferenceIntoListLocked(*reference);
92 93
93 auto file = std::shared_ptr<RealVfsFile>( 94 auto file = std::shared_ptr<RealVfsFile>(
94 new RealVfsFile(*this, std::move(reference), path, perms, size)); 95 new RealVfsFile(*this, std::move(reference), path, perms, size));
@@ -103,7 +104,10 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
103 104
104VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { 105VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
105 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 106 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
106 cache.erase(path); 107 {
108 std::scoped_lock lk{list_lock};
109 cache.erase(path);
110 }
107 111
108 // Current usages of CreateFile expect to delete the contents of an existing file. 112 // Current usages of CreateFile expect to delete the contents of an existing file.
109 if (FS::IsFile(path)) { 113 if (FS::IsFile(path)) {
@@ -133,8 +137,11 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_
133VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { 137VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
134 const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); 138 const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
135 const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); 139 const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
136 cache.erase(old_path); 140 {
137 cache.erase(new_path); 141 std::scoped_lock lk{list_lock};
142 cache.erase(old_path);
143 cache.erase(new_path);
144 }
138 if (!FS::RenameFile(old_path, new_path)) { 145 if (!FS::RenameFile(old_path, new_path)) {
139 return nullptr; 146 return nullptr;
140 } 147 }
@@ -143,7 +150,10 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
143 150
144bool RealVfsFilesystem::DeleteFile(std::string_view path_) { 151bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
145 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); 152 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
146 cache.erase(path); 153 {
154 std::scoped_lock lk{list_lock};
155 cache.erase(path);
156 }
147 return FS::RemoveFile(path); 157 return FS::RemoveFile(path);
148} 158}
149 159
@@ -182,14 +192,17 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
182 return FS::RemoveDirRecursively(path); 192 return FS::RemoveDirRecursively(path);
183} 193}
184 194
185void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, 195std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path,
186 FileReference& reference) { 196 Mode perms,
197 FileReference& reference) {
198 std::unique_lock lk{list_lock};
199
187 // Temporarily remove from list. 200 // Temporarily remove from list.
188 this->RemoveReferenceFromList(reference); 201 this->RemoveReferenceFromListLocked(reference);
189 202
190 // Restore file if needed. 203 // Restore file if needed.
191 if (!reference.file) { 204 if (!reference.file) {
192 this->EvictSingleReference(); 205 this->EvictSingleReferenceLocked();
193 206
194 reference.file = 207 reference.file =
195 FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); 208 FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile);
@@ -199,12 +212,16 @@ void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms,
199 } 212 }
200 213
201 // Reinsert into list. 214 // Reinsert into list.
202 this->InsertReferenceIntoList(reference); 215 this->InsertReferenceIntoListLocked(reference);
216
217 return lk;
203} 218}
204 219
205void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) { 220void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
221 std::scoped_lock lk{list_lock};
222
206 // Remove from list. 223 // Remove from list.
207 this->RemoveReferenceFromList(*reference); 224 this->RemoveReferenceFromListLocked(*reference);
208 225
209 // Close the file. 226 // Close the file.
210 if (reference->file) { 227 if (reference->file) {
@@ -213,14 +230,14 @@ void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference
213 } 230 }
214} 231}
215 232
216void RealVfsFilesystem::EvictSingleReference() { 233void RealVfsFilesystem::EvictSingleReferenceLocked() {
217 if (num_open_files < MaxOpenFiles || open_references.empty()) { 234 if (num_open_files < MaxOpenFiles || open_references.empty()) {
218 return; 235 return;
219 } 236 }
220 237
221 // Get and remove from list. 238 // Get and remove from list.
222 auto& reference = open_references.back(); 239 auto& reference = open_references.back();
223 this->RemoveReferenceFromList(reference); 240 this->RemoveReferenceFromListLocked(reference);
224 241
225 // Close the file. 242 // Close the file.
226 if (reference.file) { 243 if (reference.file) {
@@ -229,10 +246,10 @@ void RealVfsFilesystem::EvictSingleReference() {
229 } 246 }
230 247
231 // Reinsert into closed list. 248 // Reinsert into closed list.
232 this->InsertReferenceIntoList(reference); 249 this->InsertReferenceIntoListLocked(reference);
233} 250}
234 251
235void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { 252void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) {
236 if (reference.file) { 253 if (reference.file) {
237 open_references.push_front(reference); 254 open_references.push_front(reference);
238 } else { 255 } else {
@@ -240,7 +257,7 @@ void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) {
240 } 257 }
241} 258}
242 259
243void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) { 260void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) {
244 if (reference.file) { 261 if (reference.file) {
245 open_references.erase(open_references.iterator_to(reference)); 262 open_references.erase(open_references.iterator_to(reference));
246 } else { 263 } else {
@@ -271,7 +288,7 @@ std::size_t RealVfsFile::GetSize() const {
271 288
272bool RealVfsFile::Resize(std::size_t new_size) { 289bool RealVfsFile::Resize(std::size_t new_size) {
273 size.reset(); 290 size.reset();
274 base.RefreshReference(path, perms, *reference); 291 auto lk = base.RefreshReference(path, perms, *reference);
275 return reference->file ? reference->file->SetSize(new_size) : false; 292 return reference->file ? reference->file->SetSize(new_size) : false;
276} 293}
277 294
@@ -288,7 +305,7 @@ bool RealVfsFile::IsReadable() const {
288} 305}
289 306
290std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { 307std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
291 base.RefreshReference(path, perms, *reference); 308 auto lk = base.RefreshReference(path, perms, *reference);
292 if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { 309 if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
293 return 0; 310 return 0;
294 } 311 }
@@ -297,7 +314,7 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset)
297 314
298std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { 315std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
299 size.reset(); 316 size.reset();
300 base.RefreshReference(path, perms, *reference); 317 auto lk = base.RefreshReference(path, perms, *reference);
301 if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { 318 if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
302 return 0; 319 return 0;
303 } 320 }
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 67f4c4422..26ea7df62 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <map> 6#include <map>
7#include <mutex>
7#include <optional> 8#include <optional>
8#include <string_view> 9#include <string_view>
9#include "common/intrusive_list.h" 10#include "common/intrusive_list.h"
@@ -48,22 +49,24 @@ private:
48 std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache; 49 std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache;
49 ReferenceListType open_references; 50 ReferenceListType open_references;
50 ReferenceListType closed_references; 51 ReferenceListType closed_references;
52 std::mutex list_lock;
51 size_t num_open_files{}; 53 size_t num_open_files{};
52 54
53private: 55private:
54 friend class RealVfsFile; 56 friend class RealVfsFile;
55 void RefreshReference(const std::string& path, Mode perms, FileReference& reference); 57 std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms,
58 FileReference& reference);
56 void DropReference(std::unique_ptr<FileReference>&& reference); 59 void DropReference(std::unique_ptr<FileReference>&& reference);
57 void EvictSingleReference();
58
59private:
60 void InsertReferenceIntoList(FileReference& reference);
61 void RemoveReferenceFromList(FileReference& reference);
62 60
63private: 61private:
64 friend class RealVfsDirectory; 62 friend class RealVfsDirectory;
65 VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size, 63 VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
66 Mode perms = Mode::Read); 64 Mode perms = Mode::Read);
65
66private:
67 void EvictSingleReferenceLocked();
68 void InsertReferenceIntoListLocked(FileReference& reference);
69 void RemoveReferenceFromListLocked(FileReference& reference);
67}; 70};
68 71
69// An implementation of VfsFile that represents a file on the user's computer. 72// An implementation of VfsFile that represents a file on the user's computer.