Merge pull request #10806 from liamwhite/worst-fs-implementation-ever

vfs_real: misc optimizations
This commit is contained in:
bunnei 2023-06-22 21:46:50 -07:00 committed by GitHub
commit 3f3e4efb30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 29 deletions

View file

@ -436,7 +436,7 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable
if (True(filter & DirEntryFilter::File) && if (True(filter & DirEntryFilter::File) &&
entry.status().type() == fs::file_type::regular) { entry.status().type() == fs::file_type::regular) {
if (!callback(entry.path())) { if (!callback(entry)) {
callback_error = true; callback_error = true;
break; break;
} }
@ -444,7 +444,7 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable
if (True(filter & DirEntryFilter::Directory) && if (True(filter & DirEntryFilter::Directory) &&
entry.status().type() == fs::file_type::directory) { entry.status().type() == fs::file_type::directory) {
if (!callback(entry.path())) { if (!callback(entry)) {
callback_error = true; callback_error = true;
break; break;
} }
@ -493,7 +493,7 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
if (True(filter & DirEntryFilter::File) && if (True(filter & DirEntryFilter::File) &&
entry.status().type() == fs::file_type::regular) { entry.status().type() == fs::file_type::regular) {
if (!callback(entry.path())) { if (!callback(entry)) {
callback_error = true; callback_error = true;
break; break;
} }
@ -501,7 +501,7 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
if (True(filter & DirEntryFilter::Directory) && if (True(filter & DirEntryFilter::Directory) &&
entry.status().type() == fs::file_type::directory) { entry.status().type() == fs::file_type::directory) {
if (!callback(entry.path())) { if (!callback(entry)) {
callback_error = true; callback_error = true;
break; break;
} }

View file

@ -66,6 +66,6 @@ DECLARE_ENUM_FLAG_OPERATORS(DirEntryFilter);
* @returns A boolean value. * @returns A boolean value.
* Return true to indicate whether the callback is successful, false otherwise. * Return true to indicate whether the callback is successful, false otherwise.
*/ */
using DirEntryCallable = std::function<bool(const std::filesystem::path& path)>; using DirEntryCallable = std::function<bool(const std::filesystem::directory_entry& entry)>;
} // namespace Common::FS } // namespace Common::FS

View file

@ -153,7 +153,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir}; std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
if (load_dir != nullptr && load_dir->GetSize() > 0) { if (load_dir != nullptr) {
const auto load_patch_dirs = load_dir->GetSubdirectories(); const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end()); patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
} }
@ -354,8 +354,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
((load_dir == nullptr || load_dir->GetSize() <= 0) && (load_dir == nullptr && sdmc_load_dir == nullptr)) {
(sdmc_load_dir == nullptr || sdmc_load_dir->GetSize() <= 0))) {
return; return;
} }
@ -496,7 +495,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
// General Mods (LayeredFS and IPS) // General Mods (LayeredFS and IPS)
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
if (mod_dir != nullptr && mod_dir->GetSize() > 0) { if (mod_dir != nullptr) {
for (const auto& mod : mod_dir->GetSubdirectories()) { for (const auto& mod : mod_dir->GetSubdirectories()) {
std::string types; std::string types;
@ -540,7 +539,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
// SDMC mod directory (RomFS LayeredFS) // SDMC mod directory (RomFS LayeredFS)
const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0) { if (sdmc_mod_dir != nullptr) {
std::string types; std::string types;
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) { if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) {
AppendCommaIfNotEmpty(types, "LayeredExeFS"); AppendCommaIfNotEmpty(types, "LayeredExeFS");

View file

@ -10,6 +10,7 @@
#include "common/fs/fs.h" #include "common/fs/fs.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
// For FileTimeStampRaw // For FileTimeStampRaw
@ -72,7 +73,8 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
return VfsEntryType::File; return VfsEntryType::File;
} }
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
Mode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
if (auto it = cache.find(path); it != cache.end()) { if (auto it = cache.find(path); it != cache.end()) {
@ -81,20 +83,24 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
} }
} }
if (!FS::Exists(path) || !FS::IsFile(path)) { if (!size && !FS::IsFile(path)) {
return nullptr; return nullptr;
} }
auto reference = std::make_unique<FileReference>(); auto reference = std::make_unique<FileReference>();
this->InsertReferenceIntoList(*reference); this->InsertReferenceIntoList(*reference);
auto file = auto file = std::shared_ptr<RealVfsFile>(
std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, std::move(reference), path, perms)); new RealVfsFile(*this, std::move(reference), path, perms, size));
cache[path] = file; cache[path] = file;
return file; return file;
} }
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
return OpenFileFromEntry(path_, {}, perms);
}
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
cache.erase(path); cache.erase(path);
@ -243,10 +249,10 @@ void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) {
} }
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
const std::string& path_, Mode perms_) const std::string& path_, Mode perms_, std::optional<u64> size_)
: base(base_), reference(std::move(reference_)), path(path_), : base(base_), reference(std::move(reference_)), path(path_),
parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)), parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)),
perms(perms_) {} size(size_), perms(perms_) {}
RealVfsFile::~RealVfsFile() { RealVfsFile::~RealVfsFile() {
base.DropReference(std::move(reference)); base.DropReference(std::move(reference));
@ -257,11 +263,14 @@ std::string RealVfsFile::GetName() const {
} }
std::size_t RealVfsFile::GetSize() const { std::size_t RealVfsFile::GetSize() const {
base.RefreshReference(path, perms, *reference); if (size) {
return reference->file ? reference->file->GetSize() : 0; return *size;
}
return FS::GetSize(path);
} }
bool RealVfsFile::Resize(std::size_t new_size) { bool RealVfsFile::Resize(std::size_t new_size) {
size.reset();
base.RefreshReference(path, perms, *reference); base.RefreshReference(path, perms, *reference);
return reference->file ? reference->file->SetSize(new_size) : false; return reference->file ? reference->file->SetSize(new_size) : false;
} }
@ -287,6 +296,7 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset)
} }
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
size.reset();
base.RefreshReference(path, perms, *reference); base.RefreshReference(path, perms, *reference);
if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
return 0; return 0;
@ -309,10 +319,11 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
std::vector<VirtualFile> out; std::vector<VirtualFile> out;
const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { const FS::DirEntryCallable callback = [this,
const auto full_path_string = FS::PathToUTF8String(full_path); &out](const std::filesystem::directory_entry& entry) {
const auto full_path_string = FS::PathToUTF8String(entry.path());
out.emplace_back(base.OpenFile(full_path_string, perms)); out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), perms));
return true; return true;
}; };
@ -330,8 +341,9 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
std::vector<VirtualDir> out; std::vector<VirtualDir> out;
const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { const FS::DirEntryCallable callback = [this,
const auto full_path_string = FS::PathToUTF8String(full_path); &out](const std::filesystem::directory_entry& entry) {
const auto full_path_string = FS::PathToUTF8String(entry.path());
out.emplace_back(base.OpenDirectory(full_path_string, perms)); out.emplace_back(base.OpenDirectory(full_path_string, perms));
@ -483,12 +495,10 @@ std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries()
std::map<std::string, VfsEntryType, std::less<>> out; std::map<std::string, VfsEntryType, std::less<>> out;
const FS::DirEntryCallable callback = [&out](const std::filesystem::path& full_path) { const FS::DirEntryCallable callback = [&out](const std::filesystem::directory_entry& entry) {
const auto filename = FS::PathToUTF8String(full_path.filename()); const auto filename = FS::PathToUTF8String(entry.path().filename());
out.insert_or_assign(filename, out.insert_or_assign(filename,
FS::IsDir(full_path) ? VfsEntryType::Directory : VfsEntryType::File); entry.is_directory() ? VfsEntryType::Directory : VfsEntryType::File);
return true; return true;
}; };

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <optional>
#include <string_view> #include <string_view>
#include "common/intrusive_list.h" #include "common/intrusive_list.h"
#include "core/file_sys/mode.h" #include "core/file_sys/mode.h"
@ -20,6 +21,8 @@ struct FileReference : public Common::IntrusiveListBaseNode<FileReference> {
}; };
class RealVfsFile; class RealVfsFile;
class RealVfsDirectory;
class RealVfsFilesystem : public VfsFilesystem { class RealVfsFilesystem : public VfsFilesystem {
public: public:
RealVfsFilesystem(); RealVfsFilesystem();
@ -56,6 +59,11 @@ private:
private: private:
void InsertReferenceIntoList(FileReference& reference); void InsertReferenceIntoList(FileReference& reference);
void RemoveReferenceFromList(FileReference& reference); void RemoveReferenceFromList(FileReference& reference);
private:
friend class RealVfsDirectory;
VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
Mode perms = Mode::Read);
}; };
// An implementation of VfsFile that represents a file on the user's computer. // An implementation of VfsFile that represents a file on the user's computer.
@ -78,13 +86,14 @@ public:
private: private:
RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference, RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
const std::string& path, Mode perms = Mode::Read); const std::string& path, Mode perms = Mode::Read, std::optional<u64> size = {});
RealVfsFilesystem& base; RealVfsFilesystem& base;
std::unique_ptr<FileReference> reference; std::unique_ptr<FileReference> reference;
std::string path; std::string path;
std::string parent_path; std::string parent_path;
std::vector<std::string> path_components; std::vector<std::string> path_components;
std::optional<u64> size;
Mode perms; Mode perms;
}; };